ASM Y Buffer Overflows
Enviado por stuxnet • 11 de Febrero de 2014 • 5.866 Palabras (24 Páginas) • 200 Visitas
-[ 0x08 ]--------------------------------------------------------------------
-[ ASM y Buffer Overflows ]--------------------------------------------------
-[ by Doing ]---------------------------------------------------------SET-21-
Asm y buffer overflows
------------------------
By Doing
------------------------
<jdoing@hotmail.com>
Bueno, por fin me he decidido a escribir un articulo para SET, espero que
lo encontreis interesante. Seguro que muchos de los hackers newbies que
ahora estan descubriendo el mundo del hacking habran oido hablar de los
tan famosos exploits, pero todavia no saben que hacen, ni como funcionan;
pues para eso escribo este co~azo.
Para entender esto te ayudara saber algo de C o ensamblador pero no es
indispensable. Voy a empezar explicando que #"@% es eso del stack.
==> El stack (o pila) <==
El stack es una region de memoria que las funciones usan para guardar sus
variables locales y para guadar temporalmente el contenido de los registros
del procesador (por ejemplo, cuando se llama a una funcion, los parametros
se pasan por el stack). El segmento de stack se guarda en un registro del
procesador, el SS. Tambien existe un registro que apunta al lugar en donde
se encuentra la "pila". La pila se usa para guardar temporalmente el
contenido de los registros (eso ya lo he dicho antes). Para guardar el
contenido de un registro en la pila se usa la instruccion push, y para
recuperar el ultimo dato almacenado en la pila su usa la instruccion pop.
Vamos a poner un ejemplo:
Esto es un segmento de stack:
0x00 0xFFFFFFFF
SS ==> [0000000000000000000000000[VAR1][VAR2][SBP][RET][ARGV1][ARGV2]...]
^
STACK POINTER
Como veis, nada mas llamar a una funcion, el ESP se encuentra justo detras
de la ultima variable declarada. Cuando usamos push, guardamos el dato desde
la posicion del ESP hacia ATRAS, y el ESP de decrementa en tantos bytes como
tenga nuestro dato.
Vamos a suponer que guardamos en la pila el reg EAX (4 BYTES)
pushl %eax (La "l" despues de push quiere decir que el operando ocupa 32 bits)
El segmento de antes quedaria asi:
0x00 0xFFFFFFFF
SS ==> [000000000000000000000[EAX][VAR2][VAR1][SBP][RET][ARGV1][ARGV2]...]
^
STACK POINTER
Ahora vamos a recuperarlo en otro registro:
popl %ebx
En este momento el ESP se incrementa en tantos bytes como tenga nuestro dato,
asi que se queda como al principio, usease, como antes de hacer el ultimo
push. Con esto se puede deducir una cosa: los datos que vas sacando de la
pila salen en orden inverso al que fueron introducidos. En jerga "tesnica"
se dice que la pila es una estructura LIFO (Last In, First Out).
Acabais de ver como el procesador accede a la pila, creo haber dicho que el
stack tambien se usa para acceder a las variables locales, pero, comorr?.
Para acceder a memoria necesitamos dos cosas: segmento y despazamiento. Bien,
el segmento ya lo tenemos, el SS, y el offset (NOTA: offset = desplazamiento)
se guarda (seguro que ya lo habeis adivinado ;) en otro registro, el EBP.
El EBP apunta al comienzo de la primera variable declarada.
Volvamos otra vez al segmento de antes:
0x00 0xFFFFFFFF
SS ==> [0000000000000000000000000[VAR2][VAR1][SBP][RET][ARGV1][ARGV2]...]
^ ^
ESP EBP
Vamos a poner otro ejemplo:
void ejemplo(char *argumento){
char buff[4];
}
void main()
{
char *VAR_MAIN;
ejemplo(VAR_MAIN);
}
Compilemos el codigo:
$ gcc ejem.c -o ejem
Ahora vamos a desensamblarlo para entender como llama a la funcion ejemplo y
que hace con los registros:
$ gdb ejem
(gdb) disassemble main
Dump of assembler code for function main:
0x8048458 <main>: pushl %ebp
0x8048459 <main+1>: movl %esp,%ebp
0x804845b <main+3>: subl $0x4,%esp
0x804845e <main+6>: movl 0xfffffffc(%ebp),%eax
0x8048461 <main+9>: pushl %eax
0x8048462 <main+10>: call 0x8048440 <ejemplo>
0x8048467 <main+15>: addl $0x4,%esp
0x804846a <main+18>: leave
0x804846b <main+19>: ret
End of assembler dump.
OK. En <main> guardamos el registro ebp en la pila, esto lo hacen todas las
funciones cuando son llamadas. Hemos dicho que ebp apunta a al comienzo de
las variables locales de una funcion, pero cuando se llama a otra funcion,
esta tambien tiene que almacenar en ebp la direccion de sus variables, asi
que se guarda en la pila para luego restaurarlo. En nuestro segmento esta
en [SBP].
En <main+1> copiamos en ebp el contenido de esp. Asi que tenemos que ebp
y esp apuntan justo detras de [SBP]. Otro dibujito:
0x00 0xFFFFFFFF
SS ==> [0000000000000000000000000000000000000[SBP][RET][ARGV1][ARGV2]...]
^
EBP
ESP
Si ahora hicieramos un push de lo que sea, en este momento escribiriamos
en la seccion de memoria donde queremos guardar VAR_MAIN, asi que en
<main+3> restamos el tama~o de VAR_MAIN a esp, quedando el famosisimo
segmento asi:
0x00
...