Está en la página 1de 12

Stack

Buffer
Overflow

2 de febrero

2009

Aprenda Stack Buffer Overflow como si estuviera en primero

http://www.sinfocol.org
Perverthso

Introduccin
Bueno, ante todo, saludar a todos mis amigos de las diferentes webs, este es un manual
o tutorial que promet hacer hace mucho y por motivos de tiempo no lo pude hacer, pero
aqu est.
En esta oportunidad hablaremos de los Stack buffer overflows en el sistema operativo
Windows y la elaboracin de un exploit.

Algunos Conceptos Bsicos


Ahora explicaremos algunos de los conceptos de los Stack Buffer Overflow necesarios
para empezar ya que los dems conceptos los iremos viendo a medida que
desarrollemos el tutorial.
Stack todo programa lo que hace al compilar es traducir su cdigo a lenguaje
ensamblador y este es el lenguaje el que traduce cada instruccin a lenguaje maquina
que es lo que entiende nuestro procesador, ahora, un programa en ensamblado o cdigo
ensamblador se divide en 3 partes:
1. Stack Segment. Segmento de Pila
2. Data Segment. Segmento de Datos
3. Code Segment. Segmento de Codigo
Pero que es la Pila?
La pila (stack) es una estructura tipo LIFO, Last In, First Out, ultimo en entrar, primero
en salir. Piensen en una pila de libros, solo puedes aadir y quitar libros por la "cima"
de la pila, por donde los aades. El libro de mas "abajo", ser el ultimo en salir, cuando
se vace la pila. Si tratas de quitar uno del medio, se puede desmoronar.
Bien, pues el SO (tanto Windows como Linux, como los Unix o los Macs) se basa en
una pila para manejar las variables locales de un programa, los retornos (rets) de las
llamadas a una funcin (calls), las estructuras de excepciones (SEH, en Windows),
argumentos, variables de entorno.
Por ejemplo, para llamar a una funcin cualquiera, que necesite dos argumentos, se
mete primero el argumento 2 en la pila del sistema, luego el argumento 1, y luego se
llama a la funcin.
Si el sistema quiere hacer una suma (5+3), primero introduce el 2 argumento en la pila
(el nmero tres), luego el 1 argumento (el nmero cinco) y luego llama a la funcin
suma.
Una "llamada" a una funcin o direccin de memoria, se hace con la instruccin de
ensamblador Call.

Su sintaxis es la siguiente:
Call direccin (llamar a la direccin)
Call registro (llama a lo que contenga ese registro).
El registro EIP recoge dicha direccin, y la siguiente instruccin a ejecutar esta en
dicha direccin, hemos "saltado" a esa direccin.
Pero antes, el sistema debe saber que hacer cuando termine la funcin, por donde debe
seguir ejecutando el cdigo.
Justo al ejecutar el call, se GUARDA la direccin de la siguiente instruccin en la pila.
Esa instruccin se denomina normalmente RET o RET ADDRESS, direccin de
"retorno" al programa principal (o a lo que sea).
Entonces, el call se ejecuta, se guarda la direccin, coge los argumentos de la suma, se
produce la suma y, como esta guardada la direccin por donde iba el programa,
RETORNA a la direccin de memoria que haba guardada en la pila (el ret), es decir, a
la direccin siguiente del call.
Stack Buffer OverFlow: Como su nombre refiere, es el desbordamiento de la pila,
quiere decir que cuando nosotros reservamos espacio en la memoria, sta tiene una
longitud determinada, ya sea definida por el programa o por nosotros mismos, y al
momento de ingresar mas datos de los permitidos se producir un desbordamiento o
salida de datos fuera de los limites establecidos.

Manos A La Obra
Ahora para poder explicar mejor el stack buffer overflow, usaremos el programa
llamado exploitme.exe, con el cual entenderemos mejor todos los conceptos.
Descripcin del Exploitme
El objetivo del siguiente exploitme es que a travs de los argumentos enviados, nos
muestre un mensaje que nos diga muy bien, y nuestro objetivo ser ejecutar la
calculadora de Windows, sobrescribiendo el retorno de la pila.
Ahora abrimos el exploitme y vemos que es lo pasa:

4
Bueno nos manda un mensaje diciendo que lo intentemos otra vez , muy bien, ahora
lo abrimos con ollydbg.
Ollydbg: Es un desensamblador de ejecutables, esto es que interpreta el ejecutable en
cdigo ensamblador. Con el podemos ver a nivel ensamblador lo que ocurre en el
ejecutable, pero antes una breve explicacin del ollydbg

Creo que con la imagen se entiende gran parte del programa.


Lo nico que se ve ah algo confuso es la session registros y flags, para nuestro estudio
solo hablaremos de los registros, en pocas palabras los registros son donde se almacena
las variables, datos, direcciones de las operaciones que se realizo en ese momento.
Luego de esa breve explicacin del ollydbg, podemos empezar nuestro anlisis del
exploitme para lo cual en el ollydbg le damos File>Open y seleccionamos el archivo
ejecutable exploitme.exe, ahora en la sesin de cdigo ensamblador le damos clic
derecho y escogemos la opcin como se muestra en la imagen.

Ahora buscamos el mensaje que nos mostr al momento de ejecutarlo intenta otra
vez, una vez ubicado le damos doble clic y nos mandara al lugar donde se ejecuta
dicho mensaje. Luego de esto vemos unos cdigos mas arriba, le ponemos un
breakpoint con la tecla f2 en la direccin 00401321.
Para poder enviarle datos como lo hicimos por consola, vamos a debug>Arguments
Aparecer una caja de texto donde pondremos los argumentos, en mi caso
AAAAAA. Unas 10 veces.
Puara probar luego les pedir que reinicien el programa para lo cual le dan en el botn
<<, para ejecutar presionamos la tecla f9 y el programa se detendr en la direccin
00401321 que es donde le dijimos que se detuviera. Muy bien, ahora empezamos a
ejecutarlo lnea por lnea con la tecla f8 hasta que lleguemos al offset 00401329
00401329 |. C74424 04 004>MOV DWORD PTR SS:[ESP+4],exploitm.00404000
; ||ASCII "bien;)"
Lo que realiza el programa es enviar el dato ubicado en la direccion 00404000 al stack
en este caso carga la frase bien ;)
Luego, en la siguiente instruccin, mueve al stack lo que se encuentra ubicado en la
direccin almacenada en EAX que en este caso es 0022FF60
00401331 |. 890424

MOV DWORD PTR SS:[ESP],EAX

; ||

La siguiente instruccin lo que hace es comparar los valores almacenados en las


direcciones del stack. en Si nos fijamos en la sesin de memoria del ollydbg, la
direccin 0022FF50 es el inicio de los datos que nosotros enviamos al programa.
Podremos modificar los datos de la direccin 0022FF60, para poder hacerlo,
tendramos que escribir una cadena de texto con longitud igual a la diferencia
0022FF60-0022FF50, lo cual en base hexadecimal nos da una longitud de 10h que en
si equivalente decimal son 16 letras, las cuales son el nmero de caracteres para lograr
llegar a dicha direccin, PERO si queremos sobrescribirla tendramos que sumarle
cuatro (4) caracteres mas.
Escribimos una cadena con 20 de longitud, y para darnos cuenta que es lo que pasa,
escribimos primero 16 As y 4 Bs como hicimos al principio debug>Arguments
(AAAAAAAAAAAAAAAABBBB)
Y le damos f9 y se detiene en la direccin del breakpoint, luego le damos f8 hasta la
siguiente instruccin:
00401334 |. E8 070F0000 CALL <JMP.&msvcrt.strcmp>

; |\strcmp

Donde llama a la API strcmp, la cual hace comparaciones entres dos direcciones de
memoria. Fijmonos como queda el stack en dicho momento:

Y sorpresa! ahora comparara BBBB con bien ;), entonces pensamos un ratito y
concluimos que nos mandar un mensaje correcto cuando las dos cadenas sean
iguales, as que en vez de escribir BBBB colocamos bien ;) y veremos que pasa!
Repetimos
el
mismo
proceso,
reemplazando
el
argumento
por
AAAAAAAAAAAAAAAAbien;), le damos aceptar y reiniciamos el ollydbg, luego f9
y de nuevo nos detenemos en el breakpoint, de nuevo le damos f8 hasta llegar a
CALL <JMP.&msvcrt.strcmp> y de nuevo verificamos la pila para ver que pasa

Ahora el resultado del API ser exitosa, y nos mostrar el mensaje de que hemos pasado
la prueba.

Segunda Parte
Como hacemos entonces para explotar el programa y ejecutar cdigo arbitrario?
Empezamos a analizar la estructura de los programas en lenguaje ensamblador y vemos
algo muy interesante los RETN

RETN - Regreso cercano, solo obtiene una palabra del stack,


transfiere el control al offset almacenado en la palabra.
Ejecutamos de nuevo el programa hasta llegar al primer RETN y analicemos que pasa.

Vemos el registro ESP, el cual contiene la direccin del stack 0022FF7C, vemos
tambin que la pila en dicha direccin contiene una direccin del programa y al pulsar
una vez ms f8, el programa saltar a la ubicacin 004011E7 almacenada en el stack.
Reiniciamos
el
programa,
y
le
pasamos
el
siguiente
argumento:
AAAAAAAAAAAAAAAABBBB
Si observamos la pila, la direccin 0022FF50 es donde empieza a almacenarse los datos
que nosotros ingresamos. Si no existe un adecuado control de los datos de entrada
podemos poner una cadena muy larga y sobrescribiremos la direccin 0022FF7C que
es donde se guarda el salto del RETN.
Probemos, y para no poner datos a ciegas, hacemos como en la comparacin, restamos
0022FF7C-0022FF50 que es igual a 2C en base hexadecimal y su valor equivalente en
decimal es 44, para llegar a la direccin del salto, llenaremos los datos con 44 Aes y
como antes 4 Bes y veremos que pasa!

Primero que todo, el registro ESP sigue apuntando a la direccin de memoria


0022FF7C, podemos observar que en tal direccin los datos cambiaron, ahora ya no
esta el valor anterior (004011e7) sino que ahora vale 42424242, y que al ejecutar el
RETN ira a esa direccin, que no est apuntando a ninguna instruccin de ensamblador.
Tal valor (42424242), fue el que nosotros colocamos, porque 42424242 equivale en
ASCII a BBBB. Podemos luego controlar el salto del programa y redirigirlo a donde
queramos!

10

Sabemos que los datos que metemos se guardan en la pila y como podemos ver en la
ventana principal, el programa contiene unos OPCODES, el cual en ollydbg, lo
podemos ver como cdigo hexadecimal de las instrucciones, entonces est claro que
podemos generar un cdigo en hexadecimal (Conteniendo instrucciones de
ensamblador), colocarlo como dato de entrada y hacer que el programa retorne a dicho
cdigo para empezar a interpretarlo.

Armando un Exploit
Normalmente todo exploit consta de tres partes:
1. Cdigo Basura: Yo denomino as al cdigo con el cual logramos hacer que ocurra
un error y por medio de este llegamos al RETN. En s, es rellenar la pila si fuera
necesario para poder explotar el fallo. En este ejemplo seria las 44 Aes que colocamos
para poder llegar al retorno. Este contenido puede ser aleatorio, ya que realmente no
importa mucho su contenido.
2. Direccin de retorno: En esta parte es donde re direccionamos el programa para que
empiece a ejecutar nuestra shellcode.
3. Shellcode: Son el conjunto de instrucciones que el procesador puede entender.
Comnmente estn codeados en hexadecimal, ya que podemos representar fcilmente
los OPCODES con esta forma de representacin de la informacin.

11

El registro ESP guarda la siguiente direccin despus de nuestra cadena de entrada.


Usaremos dicha estructura para nuestro bien, buscamos una instruccin en el programa
o en cualquiera de las DLL que usa, una instruccin que haga referencia al registro
ESP, puede ser call ESP o jmp ESP
Para cumplir con tal objetivo, usaremos el programa findjmp.exe de la siguiente forma:

El programa nos da el offset donde existe saltos hacia el contenido del registro ESP,
pero aqu hay algo muy importante, ya que las direcciones de los saltos son diferentes
para cada versin de Windows, es por esta razn que muchos exploits no son
universales, porque queremos usarlo en un Windows para el cual no fue diseado, pero
esto se soluciona cambiando esta direccin de salto, en nuestro caso, el exploit solo
funciona para Sistemas Operativos Windows XP sp2 en espaol.
Colocaremos la direccin de retorno al revs (ED1E957C), por la forma como el
procesador Intel maneja las direcciones del lenguaje ensamblador (Little Endian).
Ya tenemos la direccin del salto. Poniendo esa direccin haremos que nuestro
programa salta a la que tiene almacenado ESP que en nuestro caso ser 0022FF80 y es
desde esta direccin donde colocaremos nuestro shellcode. Para nuestra suerte es la
siguiente lnea de cdigo, entonces solo tendremos que realizar el exploit de la siguiente
forma:
Cdigo Basura + Direccin de Retorno + Shellcode
Como lo presenta el siguiente cdigo:
Code = basura + salto + shellcode
Win32api.WinExec(exploitme.exe +Code)

12

Y ejecutando el exploit, vemos que primero nos saca el mensaje de que intentemos otra
cosa, e inmediatamente se ejecuta la Shell.

También podría gustarte