confianza

Reflexiones sobre la Confianza en la Confianza

Ken Thompson

Enlace original - Traducido al castellano por Ramiro Encinas en 2010

Reimpreso de Communication of the ACM, Vol. 27, No. 8, Agosto 1984, pp. 761-763. Copyright © 1984, Association for Computing Machinery, Inc. También aparece en ACM Turing Award Lectures: The First Twenty Years 1965-1985 Copyright © 1987 por ACM press y Computers Under Attack: Intruders, Worms, and Viruses Copyright © 1990 por ACM press.

He copiado esta página de ACM, no vaya a ser que algún día desaparezca.

Introducción

Quiero dar las gracias a ACM por este premio. Siento que este honor se debe más a la casualidad que al mérito técnico. UNIX ahora es más conocido por el cambio producido desde los grandes servidores a los miniordenadores personales. Creo que Daniel Bobrow (1) debería estar aquí sustituyéndome si él no pudo permitirse un PDP-10 y tuvo que "asentarse" para un PDP-11. Suficiente, el actual estado de UNIX es el producto del trabajo de mucha gente.

Hay un antiguo adagio, "Baila con el que te trajo," que quiere decir que debería hablar sobre UNIX. Desde hace varios años ya no trabajo en la línea principal de UNIX, así que puedo seguir recibiendo el crédito inmerecido del trabajo de otros. Por tanto, no voy a hablar sobre UNIX, pero quiero dar gracias a todos los que han contribuido.

Esto me lleva a Dennis Ritchie. Nuestra colaboración ha sido un producto de la belleza. En los diez años que hemos trabajado juntos, sólo recuerdo un caso de descoordinación. En esa ocasión, descubrí que habíamos escrito las mismas 20 líneas de código de un programa en lenguaje ensamblador. Comparé las fuentes y me asombré al ver que coincidían caracter por caracter. El resultado en conjunto de nuestro trabajo fue muy superior a la contribución de cada uno.

En mi formulario 1040 pone que soy un programador, y como programador escribo programas. Me gustaría enseñarte el programa más corto que he escrito, lo haré en tres partes y trataré de ponerlo todo junto al final.

Parte I

En la universidad, antes de los videojuegos, nos divertíamos planteando ejercicios de programación. Uno de mis favoritos era escribir el programa más corto que pudiera autoreproducirse. Debido a que es un ejercicio bastante irreal, lo normal era utilizar FORTRAN. Elegí FORTRAN por la misma razón que las carreras de tres piernas son tan populares.

Para ser más exactos, el problema es escribir un programa fuente que, una vez compilado y ejecutado, produzca como salida una copia exacta de su código fuente. Si nunca has hecho esto, te animo a que lo hagas. Descubrir cómo hacer esto es una revelación que supera de lejos a cualquier beneficio obtenido de contar como hacerlo. Respecto a hacerlo "más corto" viene a demostrar habilidades para determinar un ganador.

FIGURA 1

La Figura 1 muestra un programa que se autoreproduce en el lenguaje de programación C. (Los puristas sabrán que el programa no es precisamente un programa que se autoreproduzca, pero produce un programa que se autoreproduce). Esta entrada es demasiado grande para ganar un premio, pero demuestra la técnica y tiene dos propiedades importantes que necesito para completar mi historia: (1) Este programa puede ser escrito fácilmente por otro programa. (2) Este programa puede contener una cantidad arbitraria de información extra que puede ser reproducida con el algoritmo principal. En el ejemplo, se reproducen hasta los comentarios.

Parte II

El compilador de C está escrito en C. Lo que voy a describir es uno de los muchos problemas del tipo "¿qué fue primero, el huevo o la gallina?" cuando hablamos de compiladores escritos en su propio lenguaje. Para este caso voy a utilizar un ejemplo concreto del compilador de C.

C permite que un constructor de cadenas de texto especifique e inicialice una tabla de caracteres. Cada caracter en una cadena puede ser "escapado" para representar caracteres que no se ven. Por ejemplo

"Hola mundo\n"

representa a una cadena de texto donde el caracter "\n" representa al caracter de nueva línea.

FIGURA 2

La Figura 2 es una idea sobre cómo el compilador de C interpreta la secuencia de caracteres escapados. Esta es una maravillosa pieza de código. Esto "reconoce" qué caracter es compilado para una nueva línea en cualquier conjunto de caracteres y de forma portable. El hecho de saberlo le permite recompilarse a sí mismo y perpetuar su conocimiento.

FIGURA 3

Supongamos que queremos alterar el código fuente del compilador de C para incluir la secuencia "\v" y representar al tabulador vertical. La extensión de la Figura 2 es obvia y se presenta en la Figura 3. Entonces recompilamos el compilador de C, y tenemos un diagnóstico. Obviamente, como la versión binaria del compilador no sabe nada de "\v", la fuente no es C legal. Nosotros hemos "adiestrado" al compilador de forma que sabe lo que significa "\v", y entonces nuestro cambio se convierte en C legal. Podemos ver en una tabla ASCII que el tabulador vertical se corresponde con el número 11 decimal. Hemos alterado el código fuente para que se parezca a la Figura 4. Ahora el compilador antiguo acepta la nueva fuente, instalamos el binario resultante como el nuevo compilador oficial de C y ya podemos escribir versiones portables en la forma que tenemos en la Figura 3.

FIGURA 4

Este es un concepto profundo y se acerca a "aprender" programación en la forma que yo lo he visto. Con sólo decírselo una vez, puedes utilizar esta definición de autoreferencia.

Parte III

FIGURA 5

De nuevo, en el compilador de C, la Figura 5 representa un control de alto nivel del compilador de C donde llama a la rutina "compile" para compilar la siguiente línea de código fuente. La Figura 6 muestra una simple modificación en el compilador para que de forma deliberada deje de compilar la línea correspondiente de código fuente para en su lugar compilar el "bug" al encontrar un patrón concreto. Si esto no es deliberado, podemos decir que el compilador tiene un "bug", pero como esto es deliberado, lo deberíamos llamar "Caballo de Troya".

FIGURA 6

El bug que hemos planteado en el compilador puede utilizarse para compilar el comando "login" de UNIX. La sustitución de código puede hacer que el comando "login" acepte una contraseña cifrada o una contraseña concreta. Además, si este código fuera instalado en un binario y el binario se utiliza para compilar el comando login, yo podría iniciar sesión en ese sistema con cualquier usuario.

Aunque código tan descarado como éste no sería detectado en mucho tiempo, la lectura más casual del código fuente del compilador de C podría levantar sospechas.

FIGURA 7

El paso final lo representa la Figura 7. Simplemente agrega un segundo caballo de Troya al ya existente. El segundo patrón también tiene como objetivo el compilador de C. El código de sustitución es un programa que se autoreproduce (Parte I) e inserta ambos caballos de Troya en el compilador. Esto requiere una fase de aprendizaje como la del ejemplo de la Parte II. Primero compilamos el código fuente modificado con el compilador normal de C y generamos un binario con "bugs". Instalamos ese binario como C oficial. Ahora eliminamos los bugs del código fuente del compilador y cuando compilemos con el binario nuevo, éste insertará de nuevo los bugs. Y por supuesto, el comando login contendrá los bugs sin dejar rastro en ningún código fuente.

Moral

El aspecto moral es obvio. No puedes confiar en el código que no has escrito (especialmente código de compañías que emplean a gente como yo). Aunque exista mucha verificación de código fuente, ésto no te librará de utilizar código no confiable. Como demostración de esta posibilidad de ataque, he utilizado el compilador de C, pero podría haber utilizado cualquier otro manipulador de programas como un ensamblador, un cargador, o incluso microcódigo hardware. Cuanto más a bajo nivel sea el programa, más difícil será detectar los bugs. Un bug de microcódigo bien instalado prácticamente es casi imposible de detectar.

Después de convencerte de que no puedes fiarte de mí, me gustaría tocar la moral del asunto. Podría criticar a la prensa en cuanto a su manejo de los "hackers", la banda 414, la banda de los Dalton, etc. Los hechos perpetrados por estos críos son vandalismo en el mejor de los casos y probablemente transgresión y robo en el peor. Sólo la no adecuación del código criminal salva a los hackers de una persecución seria. Las compañías vulnerables a estas actividades (y la mayoría de ellas son muy vulnerables) hacen mucha presión para actualizar el código criminal. El acceso no autorizado a sistemas de computación ya es un crimen serio en algunos estados y actualmente está siendo considerado en muchos otros más, al igual que en el Congreso.

Se avecina una situación explosiva. Por un lado la prensa, la televisión y las películas hacen héroes a vándalos llamándolos los chicos listos y por otro lado tenemos actos realizados por estos chicos que dentro de poco serán imputables con varios años de prisión.

He visto a chicos testificando en el Congreso, y está claro que no se dan cuenta de la seriedad de sus actos. Existe un vacío cultural obvio. El hecho de entrar en un sistema computacional sin autorización tiene el mismo estigma social que el de allanamiento de morada. Da igual que la puerta esté abierta. La prensa debería aprender que el uso equivocado de un ordenador no es más sorprendente que la conducción de un coche por parte de un borracho.

Agradecimientos

La primera vez que ví la posibilidad de tal caballo de Troya fue en una crítica (4) de seguridad en una implementación antigua de Multics en la Fuerza Aérea.

Referencias

  1. Bobrow, D.G., Burchfiel, J.D., Murphy, D.L., and Tomlinson, R.S. TENEX, a paged time-sharing system for the PDP-10. Commun. ACM 15, 3 (Mar. 1972), 135-143.
  2. Kernighan, B.W., and Ritchie, D.M. The C Programming Language. Prentice-Hall, Englewood Cliffs, N.J., 1978.
  3. Ritchie, D.M., and Thompson, K. The UNIX time-sharing system. Commun. ACM 17, 7(July 1974), 365-375.
  4. Karger, P.A., and Schell, R.R. Multics Security Evaluation: Vulnerability Analysis. ESD-TR-74-193, Vol II, June 1974, p 52.