Introduccion a los buffers overflows

Hola, bueno pues voy a por mi primer mini-turorial a ver que os parece. Tratare sobre los overflows en este caso los stacks overflows ya que creo que es una tecnica donde entran conocimientos de informatica que son interesantes conocer

  • Programacion
  • Arquitectura de Ordenadores

En este primer contacto no voy a profundizar con todo lo que conlleva, de momento claro, este tipo de tecnica si no que intentare que sea divertido, ágil y sobre todo entendible para todos los publicos.

¿Que es un stack-overflow?

Un stack-overflow es el intento de controlar un flujo de ejecucion mediante un tamaño de datos inesperado. Vereis que cuando termine el tutorial entendereis perfectamente la definicion anterior.

En este primer mini-tutorial me centrare en explicar y demostrar como podemos controlar la ejecucion en este caso de un programa muy basico hecho en C

Registros del procesador

El procesador consta de varios registros para poder realizar su trabajo, pero nosotros por el momento solo nos vamos a centrar en uno el registro EIP

Este registro siempre almacena la siguiente instruccion a ejecutar, bueno mejor dicho este registro siempre tiene la siguiente dirección de memoria por la cual el procesador continuara ejecutando.

Imaginemos la siguiente secuencia 5 4 3 2 1 e imaginemos tambien que dicha secuencia son direcciones de memoria. Bien el procesador ejecuta la direccion 5, en ese momento el valor del registro EIP es 4, despues de ejecutar 5 el procesador ejecuta 4, en ese momento el valor del registro EIP es 3 y asi sucesivamente. Ha esto se le llama Flujo de Ejecución

Lo dicho el valor de EIP siempre sera la siguiente direccion de memoria a ejecutar por el procesador.

Ejemplo practico 🙂

 

#include <stdio.h>
#include <string.h>

void greeting(){
     printf("%sn", "HOLAAAA");
}

int main(int argc, char *argv[]){
    char buffer[16];
    strcpy(buffer, argv[1]);
    printf("%sn", buffer);

    return 0;
}

Aqui tenemos un programa, bastante inutil la verdad, pero nos ira de perlas para demostrar lo que hemos leido anteriormente. Doy por sentado que TODOS sabemos un poquito de C ¿verdad?

Bueno al grano, en la linea 10 vemos el fallo del programa la funcion strcpy. Esta funcion lo que hace es copiar, SIN CONTROLAR LA CANTIDAD DE BYTES, desde un origen de datos a un destino. En nuestro caso copia el 1er argumento de la funcion principal al buffer que hemos declarado de 16 bytes.

Bien y que pasa si el primer argumento que le pasamos a la funcion principal es superior a 16 bytes???

Pues los bytes sobrantes no se pierden por el limbo no, lo que haran son sobreescribir los contenidos de las direcciones de memoria contiguas.

En este dibujillo vemos dos registros nuevos y la pila o stack. Aun no voy a entrar en explicar la pila, de momento, porque os aseguro que es imprescindible conocer como funciona. Los dos registros nuevos son ESP este registro muestra la cima de la pila y EBP que nos muestra la base de la misma y por debajo de todo vemos el famoso registro EIP.

Como vemos en el programa hay una funcion que lo que hace es imprimir por pantalla un “Holaa” pero como podeis ver esa funcion no es llamada en ningun momento, con lo cual no se mostrara ese mensaje. Pues lo que vamos hacer es que el  mensaje se muestre y para eso vamos a controlar el flujo de ejecucion.

Herramientas.

Hay varias herramientas necesarias para poder explotar una vulnerabilidad de este tipo pero de momento nos centraremos en una… Ollydbg

Se trata de un debugger para windows bastante sencillo. El uso de este debugger queda fuera del alcance de este Mini-tutorial pero os aconsejo que pilleis un manual y os pongais con el.

Por supuesto necesitaremos un compilador, yo uso Dev-C++ bastante intuitivo.

Juguemos a los hackers

Bien una vez tenemos compilado el programilla de antes… A que no lo habeis hecho aun ¬¬ Va go go go

Lo dicho una vez compilado el programilla lo abrimos con el ollydbg.

 

 

 

 

Se nos abrira una ventana de dialogo, buscamos donde este el binario del resultado de compilar el programilla

 

 

 

 

 

 

 

 

 

 

 

 

Una vez cargado le damos a ejecutar que es el botoncillo ese del play

NOTA: Hay gente que solo al abrir el programa el ollydbg ya le carga el modulo del programa. Si os fijais en la imagen de arriba vereis como a mi me abre con… main thread, module ntdll si os abre como a mi tendreis que darle al boton de play. Si no es vuestro caso y os abre con el module [nombre Programa] No hace falta que le deis al boton play.

 

Ahora nos centraremos en este desensamblado

 

 

 

 

 

 

 

 

 

 

Os acordais de antes cuando hablaba de la secuencia aquella de numeros 5 4 3 2 1 que representaban direcciones de memoria??

Pues los numeros que veis a la izquierda  004012xx 004013xx eso son las direcciones de memoria

Si os fijais bien el valor de la direccion 00401296 es “HOLAAA” el mensaje que queremos que se muestre, mmmm interesante

Seguimos viendo el codigo y mmmm vemos en 004012E8 la sentencia strcpy, que como he comentado antes, esta funcion copia un origen de datos a un destino sin comprobar el tamaño de datos.

observemos el dibujo de la pila y pensemos un poco

 

 

 

 

 

 

 

 

Vemos que debajo de Buffer esta EBP y despues de EBP tenemos EIP Bien pensemos en todo lo que ya se ha explicado… strcpy copiara en buffer todo lo que le pasemos como parametro, como no controla la cantidad de datos podemos pasarnos de los 16 bytes. Tambien sabemos que pasa con los bytes sobrantes que sobreescriben mmmm podriamos llegar a sobreescribir EIP ??

Por supuesto que podemos sobreescribirla y de hecho es lo que queremos, recordad que EIP siempre apunta a la siguiente direccion a ejecutar, pues cojonudo vamos a darle a EIP la direccion del mensaje a mostrar. Vamos a ver como lo hacemos

Arrancamos el ollydbg y cargamos el programa compilado. Vamos a la pestaña Debugg y le damos a Arguments

Copiamos treinta A mayusculas y le damos a OK. Olly nos avisara de que los cambios no tendran efecto hasta que hagais un restart en el ollydbg. Pues en Debugg tenemos la opcion restart le damos.

Ahora le damos al Play del ollydbg y pondremos un breakpoint en la linea del strcpy con esto conseguiremos detener la ejecucion del programa justo en el strcpy

Nos situamos encima de la direccion de memoria del strcpy

 

 

 

Pulsamos boton derecho vamos a breakpoint y seleccionamos toggle

 

 

 

 

 

 

 

Le damos a restart y a play otra vez. Se iniciara el programa pulsamos F9 e iremos directamente al breakpoint. volvemos a ejecutar F9 y zasss Mensaje de error

 

 

 

Lo primero para el que no lo sepa, el valor hexadecimal de la A es 41 Si os fijais bien El valor de EBP es 41414141 mmmm que significa? Pues que hemos sobrepasado el tamaño de buffer con las A y hemos sobreescrito EBP

Y el valor de EIP ?? Pues el valor es 00004141 Esos ceros significa que no hemos sobreescrito completamente el registro EIP. Ningun problema añadamos dos A mas a los argumentos en el ollydbg

 

Ahora si !!!! ahora tenemos EIP sobreescrito completamente con nuestras A. Bien ahora mismo sabemos que con 32 bytes sobreescriremos el valor de EIP.

Ok pero no conseguimos nada sobreescribiendo con EIP con A

Correcto con A no sirve de nada pero y si en lugar de A usaramos la direccion de memoria donde esta ubicada la funcion del mensaje de saludo???

Pues como EIP siempre apunta a la siguiente instruccion a ejecutar por el procesador se mostraria el mensaje de la funcion la cual nunca es llamada.

Los viajes de gulliver de Jonathan Swift

Supongo que la mayoria conoce este libro / pelicula y me gustaría hacer hincapie en un acontecimiento de la historia en el cual una ley antiquisima de liliput obliga a la gente a abrir los huevos para comerselos por el lado estrecho, mientras otra gente le gusta abrirlos pero el lado ancho.

Y para que esta historia ??? Pues porque me apetecia contarla esto es un blog no??? Y tambien porque hemos de hablar de los endiannes que se basan en esta novela.

Los procesadores intel se basan en little-endian , mientras que motorolas se basan en big-endian.

Basicamente una direccion de memoria en intel (little-endian) se almacena de la siguiente manera…

Direccion de memoria: 47EF152A Formato Little-Endian: 2A15EF47

Se tiene que invertir el orden. En cambio en big-endian queda de la misma manera 47EF152A

Probando el “Exploit”

Bien pues vamos al lio, ejecutemos el programilla inutil desde un cmd. Sabemos que para sobreescribir EIP tenemos que utilizar 32 bytes, bien pues tenemos que conseguir que EIP contenga la direccion del mensaje a mostrar, miremos la dirección.

Cargamos el programa en el ollydbg le damos al play y buscamos la direccion del mensaje

Vemos que ASCII “HOLAAA” esta en 00401296 pero como somos gente elegante lo que vamos hacer es llamar a la funcion entera pa que muestre el saludo y eso se encuentra en la instruccion PUSH EBP direccion 00401290. PUSH es una instruccion que lo que hace es insertar en la pila pero eso es otro cuento que os prometo contare en los proximos tutos. Eso si, si veo que este lo mira la gente si no va ha escribir mi prima.

Bueno pues eso con 32 bytes sobreescribimos EIP y vemos que las direcciones son 4 bytes. Pues invocamos a pitagoras y deducimos que para alinear la direccion que queremos con EIP hay que restarle 4 bytes a las 32. Nos quedan 28 bytes o sea 28 A, pues ahora a las 28 A le añadimos la direccion del PUSH EBP 00401290 pero recordad que hemos dicho que usamos formato little-endian entonces las pondremos al reves o sea AAAAAAAAAAAAAAAAAAAAAAAAAAAA90124000

Quietos y paraos que aun esto no funciona, ya os veo metiendolo rapidamente como argumento… Pues no, no funcionara. Antes de eso vamos a comentar un par de cosas… Una de ellas es la direccion de memoria que vamos a utilizar, fijaros que empieza por 00

Pues es un problema y no lo es. Es un problema porque 00 lo interpretara como fin de cadena, con lo cual dejaria de escribir en el buffer y no lo es porque como esta en formato little-endian y lo vamos a poner al reves no nos cortara nada de nada jajajajajajajjajajaj me encantaaaaaa. Es que asi me libro de escribir como podriamos solucionar el problema del 00 :p

Y el segundo es que no podemos poner directamente la direccion si no tenemos que pasarlo a ASCII.

Yo lo hago con el notepad++ y un plugin, pero bueno hacedlo con el que querais no hay problema

el exploit seria… AAAAAAAAAAAAAAAAAAAAAAAAAAAA901240 y omitimos los 00 del final ya que no hacen falta

Recordad que el 901240 teneis que pasarlo a ASCII

Probemos

Fijaros como queda mi direccion cuando la paso a ASCII, ahora pulsemos ENTER!!!! que nerviosssssss….

Zasssskaaaa en toa la bocaaaa ahi esta el Saludeteeeeee 🙂

No ha sido muy dificil no? Espero que os haya funcionado si no es asi repasad y mirad no os hayais dejado algo por hacer. Las direcciones de memoria no tienen porque ser las mismas que las mias asi que no seais gañanes y mirad bien eso.

He intentado demostrar que es controlar el flujo de ejecucion y creo que lo hemos conseguido, hemos controlado ese flujo mediante un tamaño de datos no esperado ergo hemos provocado un stack-overflow. No os penseis que con esto ya podremos “Dominar el mundo” nada mas lejos de la realidad, aun falta un caminito para poder aprovechar como dios manda un fallo de este tipo. ASLR, cookie(canary), DEP son terminos que nos tocaran las narices, peroooo para eso estamos para SALTARNOS esas cosas 😉

Si teneis cualquier duda ya sabeis postead e intentare ayudaros en lo que buenamente pueda.

Seria interesante que os mirarais para los proximos tutos temas como..

  • La pila (Stack)
  • Programacion C y python (Me encanta)
  • ensambler

Sera muy util la verdad.

Bueno ha sido un placer escribir, espero que os haya gustado y espero veros en los proximos diassssss.

Saludos.

bt380