LiNUX KERNEL MODULES: LKMs

Ocultando el módulo y los símbolos del módulo:

El kernel almacena el nombre y las características de los módulos cargados en una lista enlazada circular. Cada elemento de esta estructura tiene un campo - next - que apunta al siguiente módulo. Para ocultar un módulo solo tenemos que hacer que el módulo que está justo "detras" de él apunte al que esta delante.

Esta técnica se usa en el kernel 2.2.x, porque en el 2.0.x hay otra forma, que ya explicare.

¿Como podemos saber la dirección de esta lista circular? Pues a la hora de "insmodear" el módulo, la dirección de la estructura que apunta al módulo que estamos "insmodeando" suele estar en el registro ebx o en el ebp. Entonces el campo next de esta estructura apunta al ULTIMO módulo que hemos cargado.

Para ocultarlo el módulo "ocultador" tiene que hacer que su "next" apunte al "next" del siguiente módulo, ocultándolo, y después devolver un error, porque no queremos cargar el módulo. Explicado gráficamente:

Insertamos mi_módulo, que es un troyano:

modulo1->next ---------> mi_modulo->next ---------> modulo2->next -----> ...

Ahora insertamos el módulo "hider", y deja la lista enlazada asi:

modulo1->next ---\      mi_modulo->next ------> modulo2->next ---> ...                   \__________________________/

Si en este momento hiciéramos un lsmod nuestro módulo troyano no aparecería. El código de un módulo hider sacado de Phrack esta al final.

El el kernel 2.0.x no hace falta usar otro módulo para ocultarse. Hay que averiguar la dirección de la estructura que apunta a nuestro módulo y a continuación poner el nombre, el tamaño y sus referencias a 0.

Pero todavía pueden averiguar que hemos insertado un módulo troyano mirando los símbolos del kernel con ksyms. Para burlar esto en el kernel 2.2.x basta con localizar la estructura que apunta a nuestro módulo y poner el campo nsyms a 0. Rápido, limpio y facil :).

En el 2.0.x la cosa se complica un poco, porque no tiene campo nsyms, así que tenemos que parchear la syscall get_kernel_syms, y eliminar los símbolos de nuestro módulo, pero yo lo he intentado y lo único que he conseguido es que el ksyms me dijera:

"is someone else playing with modules?"

XD. Que cabrón. Haciendo un strace se ve que lo que hace es llamar a get_kernel_syms con dirección destino 0, y esta devuelve el numero de símbolos. Después llama otra vez con una dirección de memoria valida y mi función le devuelve menos símbolos de los le había dicho al principio :).

Intente arreglarlo, pero lo único que conseguí es que se me colgara el kernel (mal rollo), así que opte por una solución mas radikal: devolver siempre 0. No es muy elegante, pero si el admin no es muy listo colara :-P

Anterior

(c) 2000 KIKO81