Buenas amigos soy Fare9, y desde mi retiro espiritual, hoy escribo la quinta edición de "De 0 a exploiting", vamos a realizar hoy una nueva técnica de exploiting, la cual se conoce como "Abuso del Frame Pointer". Para aquellos programadores que añadieron:
Pero antes, aquí los preparativos:
###############################################
Desactivar la aleatoriedad en las direcciones de la pila, para ello debeis ejecutar el comando (como root):
echo 0 > /proc/sys/kernel/randomize_va_space
Compilar (hoy si) con:
gcc -g -fno-stack-protector -z execstack codigo.c -o programa
###############################################
Para empezar, y hace mucho que no pongo nada, voy a recomendar un poquito de música para trabajar :) (Kavinsky - Nightcall).
Bien ¿qué es esto de abuso del Frame Pointer?, más o menos, vamos a recordar un dibujo que vimos en "De 0 a exploiting (II)":
Veíamos que cuando llamabamos a un método a través de un CALL, en la pila se creaba una zona para las variables locales, o stack frame o marco de pila... Bien veíamos que se guardaba EIP y después EBP, los cuales pues luego se recuperan y aquí era donde sobreescribiendo EIP, petabamos el programa y todo guay y de maravilla.
Imaginemos que el programador es lo suficientemente inteligente y dice "si no llegan a EIP, no pueden conseguir explotar el programa":
Pero gente muy lista se dio cuenta de como funcionaban las llamadas a CALL y como retornaban de esas llamadas, y a partir de aquí, llevar a cabo la explotación.
Para ver como podemos explotar un programa así, vamos a ver un poquito de teoría.
Teoría del abuso de Frame Pointer
Veamos que se hace cada vez que realizamos una llamada a CALL, estas llamadas nos permiten ejecutar funciones o por decirlo de otra manera, otras partes de código guardadas en memoria.
Lo primero que se realiza es guardar como no, el puntero a la siguiente instrucción al CALL para cuando volvamos ejecutar la instrucción correcta. Se realizaría por tanto algo como
PUSH EIP
Se realiza entonces un salto a la primera instrucción de la función, estas primeras instrucciones, normalmente, se encargan de crear el stack frame, y harían algo así:
PUSH EBP // guardo el valor de EBP
MOV EBP,ESP // meto el valor de ESP en EBP
SUB ESP,X // dejo espacio en la pila para las variables locales
Antes de continuar, veamos a que corresponden en ensamblador las funciones de PUSH y POP, lo cual entenderlo nos ayudará a comprender este ataque, así que aquí va una NOTA:
################ NOTA
En ensamblador las instrucciones push y pop pueden realizarse con suma, resta y movimiento
push:
sub $4,%esp #aumentamos tamaño de pila
mov registro o valor, (%esp) #movemos lo que queremos meter en la pila a la direccion de pila
pop:
mov (%esp),registro #metemos lo que apunta la pila en un registro
add $4,%esp #disminuimos el tamaño de la pila
#######################
Una vez comprendamos esto, la vida se nos volverá más fácil. Bien imaginemos que al realizar una copia con strcpy o strncpy o de cualquier forma, de un buffer a otro de memoria, el límite está en el registro EBP, sólo podríamos modificar este registro, lo cual a primera vista no parece malicioso...
Antes hemos puesto el prologo a una función cuando se crea el stack frame, ahora vamos a ver el epílogo, cuando la función se destruye :)
MOV ESP, EBP //el valor que tiene el registro EBP pasa a ESP, adiós a variables locales
POP EBP // EBP recupera el valor que tenia antes de memoria
RET // EIP recupera su valor de memoria y volvemos
Esto actualmente se hace con dos instrucciones:
LEAVE
RET
Pero para el caso, es lo mismo, bien el primer EBP que movemos a ESP es el que está guardado en el registro, no la posible memoria que hemos podido modificar, ahora viene lo gracioso, cuando hacemos el POP, coge de memoria, lo que nosotros hayamos metido, por tanto EBP ya lo hemos manipulado :) . Vamos a verlo con unas fotitos, en el que vamos a meter un montón de basura en un programa (luego ya pondré el código del programa y todo eso):
Bien, vamos a ejecutarlo con un montón de basura.
Prólogo de la función explotable, de momento sólo nos fijaremos en las instrucciones, que son como antes dijimos.
La pila antes de ejecutar el epílogo, vemos que ya está el valor de EIP metido, ahora vamos a ejecutar las dos primeras funciones del prólogo:
Como vemos, el valor de EBP, se ha metido en la pila, y ahora EBP tiene el valor de ESP, luego ESP disminuirá para dejar paso a variables locales. Vamos a ejecutar la función que copia los valores, así que recordad bien la dirección donde se ha guardado el valor de EBP (bffb:d1d8):
Como vemos, ahora hay basura, por tanto veamos que pasa al ejecutar el epílogo de la función (leave y ret), veremos que valor toma EBP:
Como vemos, ahora EBP se ha modificado y tiene un valor que nosotros queríamos...
Bien, esta función que ha realizado la copia, normalmente es llamada por otra función, la cual tiene su propio epílogo, pero esta vez nos encontraremos que EBP no tiene un valor lógico, tiene un valor que nosotros hemos metido, por tanto se ejecutarán las funciones del epílogo con nuestro nuevo EBP, veamos que pasa:
Como vemos tenemos un fallo, ya que la dirección AAAA, no es posible acceder.
¿Por qué este fallo?
Al realizar el epílogo ejecuta lo siguiente:
MOV ESP,EBP //mete en ESP el valor AAAA o 0x41414141 (el cual no es accesible)
POP EBP //al intentar sacar el valor de EBP de 0x41414141 nos manda al garete
//en caso de que fuera posible, ahora ESP valdría 0x41414145 (os acordais la nota que puse antes, ahora es cuando vale saberlo bien)
RET //finalmente intentaríamos meter el valor de la dirección de memoria 0x41414145 en EIP
Ahora pensemos como poder aprovecharnos de esto, vemos que hemos modificado EBP y con esto finalmente podríamos intentar modificar EIP. Vemos que al meter una dirección en EBP, luego se mete en ESP y se le sumaría 4 a esa dirección por el POP EBP, entonces a esa nueva dirección se accede para obtener EIP...
Y si...?, metemos una dirección donde tengamos un puntero a nuestro shellcode - 4, luego al hacer el POP EBP, tendríamos en ESP la dirección de un puntero a nuestro shellcode, entonces meteríamos ese puntero en EIP, y al hacer el RET, el código saltaría a nuestro shellcode...
A que mola, muy sencillito, al menos en mi cabeza todo funciona:
Bien entonces tenemos que saber en que lugar de memoria se establece nuestro shellcode y en donde empieza EBP, para saber cuantos caracteres podemos meter para petar la memoria y poder hacer el truco.
Vamos a ver el código primero del programa que vamos a usar:
Seguis entonces la nota del principio de como compilarlo. Y ahora vamos a ver como obtenemos la dirección de memoria:
Según arrancamos el programa, nos encontraremos según EIP en /lib..., para ir al comienzo ejecutaremos F9, el cual es RUN, y nos llevará al principio de código:
Ya estamos en el main, como vemos en el código, tenemos que si no metemos un argumento el programa sale, por tanto al meter un argumento se llamará a una de las funciones, la cual llamará a la de copiar, así que vayamos directos a la de copiar. Con F7 vamos pasando linea a linea, y si encuentra un call, entrará, vemos el primer call del main:
Nos meteremos en él, que es la primera función, y dentro tendremos otro call que es la función para copiar:
Dentro de esta función podemos ejecutar para ver donde se copia la cadena Fare9, y vemos donde se encuentra EBP, para realizar la resta. Ejecutemos hasta casi el epílogo y examinemos la pila:
Podemos observar en que dirección empezó a copiarse la cadena y en que dirección está EBP guardado, hagamos la resta:
bfff:f348 - bfff:f23c = 10c = 268 en decimal
Por tanto después de meter 268 bytes, lo siguiente que entra sobreescribe el valor guardado de EBP.
Ahora vamos a ver como podemos montar el exploit, necesitamos la dirección a la que vuelva - 4, luego necesitamos la dirección del shellcode, vamos a ver mi código en python de un exploit, recordemos que para encontrar las direcciones ejecutar el programa con edb dentro del código python, esto nos dará las direcciones más correctas:
Como se puede observar, al ejecutar mi código con python , busqué con edb el principio del buffer y esta vez era bfff:f12c, por tanto tenemos que la dirección de retorno (RET) es bfff:f12c - 4, la dirección del shellcode será bfff:f12c + 4, allí encontraremos una cama de NOPS, bastante grande, y el shellcode que nos devuelve una shell. Vamos a ejecutarlo primero con edb y luego sin él:
Como vemos, se ha copiado primero la dirección a donde tiene que saltar y después la cama de NOPS, vamos a ver donde estaba EBP:
Como vemos, donde estaba EBP, está la dirección del puntero a nuestra shellcode - 4, ahora sigamos ejecutando hasta llegar al epílogo de la función anterior:
Como vemos EIP acabó apuntando a nuestra shell y ahora a los NOPS, si ejecutamos este shellcode, veremos que obtenemos una shell. Ahora vamos a ejecutarlo sin edb:
Como vemos acabamos de obtener una shell, sin poder llegar a EIP, a esto sólo queda decir:
MAGIAAAAAAAAAAAAAAAAAAAAAAA
Pues mundo de hackers, hasta aquí el De 0 a exploiting(V) , espero que fuera divertido, me ha costado la verdad con tanta imagen (LOCURA), pero es entretenido tener nuevas formas de explotación además de sobreescribir directamente EIP.
Antes de acabar me gustaría pedir a quien pudiera y quisiera, que ya que en estas fechas nos encontramos en época de cacería y post navidad, tanto Galgos como cachorros los cuales crecieron, serán abandonados o cosas peores, que quien pueda donar un mínimo, les dejo unos enlaces de protectoras las cuales necesitarían de esta ayuda:
http://www.galgos112.com/
http://www.proaweb.org/
http://www.anaaweb.org/es/
http://www.protectorahuellas.org/
Yo cada año gran parte de mis regalos monetarios, van destinados a diferentes protectoras, y es un dinero que por poco que sea, bien vendrá.
Hasta aquí De 0 a exploiting y nos vemos en próximos POST de Fare9.
--------------------------------------------------------FIN
Pero antes, aquí los preparativos:
###############################################
Desactivar la aleatoriedad en las direcciones de la pila, para ello debeis ejecutar el comando (como root):
echo 0 > /proc/sys/kernel/randomize_va_space
Compilar (hoy si) con:
gcc -g -fno-stack-protector -z execstack codigo.c -o programa
###############################################
Para empezar, y hace mucho que no pongo nada, voy a recomendar un poquito de música para trabajar :) (Kavinsky - Nightcall).
Bien ¿qué es esto de abuso del Frame Pointer?, más o menos, vamos a recordar un dibujo que vimos en "De 0 a exploiting (II)":
Veíamos que cuando llamabamos a un método a través de un CALL, en la pila se creaba una zona para las variables locales, o stack frame o marco de pila... Bien veíamos que se guardaba EIP y después EBP, los cuales pues luego se recuperan y aquí era donde sobreescribiendo EIP, petabamos el programa y todo guay y de maravilla.
Imaginemos que el programador es lo suficientemente inteligente y dice "si no llegan a EIP, no pueden conseguir explotar el programa":
Pero gente muy lista se dio cuenta de como funcionaban las llamadas a CALL y como retornaban de esas llamadas, y a partir de aquí, llevar a cabo la explotación.
Para ver como podemos explotar un programa así, vamos a ver un poquito de teoría.
Teoría del abuso de Frame Pointer
Veamos que se hace cada vez que realizamos una llamada a CALL, estas llamadas nos permiten ejecutar funciones o por decirlo de otra manera, otras partes de código guardadas en memoria.
Lo primero que se realiza es guardar como no, el puntero a la siguiente instrucción al CALL para cuando volvamos ejecutar la instrucción correcta. Se realizaría por tanto algo como
PUSH EIP
Se realiza entonces un salto a la primera instrucción de la función, estas primeras instrucciones, normalmente, se encargan de crear el stack frame, y harían algo así:
PUSH EBP // guardo el valor de EBP
MOV EBP,ESP // meto el valor de ESP en EBP
SUB ESP,X // dejo espacio en la pila para las variables locales
Antes de continuar, veamos a que corresponden en ensamblador las funciones de PUSH y POP, lo cual entenderlo nos ayudará a comprender este ataque, así que aquí va una NOTA:
################ NOTA
En ensamblador las instrucciones push y pop pueden realizarse con suma, resta y movimiento
push:
sub $4,%esp #aumentamos tamaño de pila
mov registro o valor, (%esp) #movemos lo que queremos meter en la pila a la direccion de pila
pop:
mov (%esp),registro #metemos lo que apunta la pila en un registro
add $4,%esp #disminuimos el tamaño de la pila
#######################
Una vez comprendamos esto, la vida se nos volverá más fácil. Bien imaginemos que al realizar una copia con strcpy o strncpy o de cualquier forma, de un buffer a otro de memoria, el límite está en el registro EBP, sólo podríamos modificar este registro, lo cual a primera vista no parece malicioso...
Antes hemos puesto el prologo a una función cuando se crea el stack frame, ahora vamos a ver el epílogo, cuando la función se destruye :)
MOV ESP, EBP //el valor que tiene el registro EBP pasa a ESP, adiós a variables locales
POP EBP // EBP recupera el valor que tenia antes de memoria
RET // EIP recupera su valor de memoria y volvemos
Esto actualmente se hace con dos instrucciones:
LEAVE
RET
Pero para el caso, es lo mismo, bien el primer EBP que movemos a ESP es el que está guardado en el registro, no la posible memoria que hemos podido modificar, ahora viene lo gracioso, cuando hacemos el POP, coge de memoria, lo que nosotros hayamos metido, por tanto EBP ya lo hemos manipulado :) . Vamos a verlo con unas fotitos, en el que vamos a meter un montón de basura en un programa (luego ya pondré el código del programa y todo eso):
Bien, vamos a ejecutarlo con un montón de basura.
Prólogo de la función explotable, de momento sólo nos fijaremos en las instrucciones, que son como antes dijimos.
La pila antes de ejecutar el epílogo, vemos que ya está el valor de EIP metido, ahora vamos a ejecutar las dos primeras funciones del prólogo:
Como vemos, el valor de EBP, se ha metido en la pila, y ahora EBP tiene el valor de ESP, luego ESP disminuirá para dejar paso a variables locales. Vamos a ejecutar la función que copia los valores, así que recordad bien la dirección donde se ha guardado el valor de EBP (bffb:d1d8):
Como vemos, ahora hay basura, por tanto veamos que pasa al ejecutar el epílogo de la función (leave y ret), veremos que valor toma EBP:
Como vemos, ahora EBP se ha modificado y tiene un valor que nosotros queríamos...
Bien, esta función que ha realizado la copia, normalmente es llamada por otra función, la cual tiene su propio epílogo, pero esta vez nos encontraremos que EBP no tiene un valor lógico, tiene un valor que nosotros hemos metido, por tanto se ejecutarán las funciones del epílogo con nuestro nuevo EBP, veamos que pasa:
Como vemos tenemos un fallo, ya que la dirección AAAA, no es posible acceder.
¿Por qué este fallo?
Al realizar el epílogo ejecuta lo siguiente:
MOV ESP,EBP //mete en ESP el valor AAAA o 0x41414141 (el cual no es accesible)
POP EBP //al intentar sacar el valor de EBP de 0x41414141 nos manda al garete
//en caso de que fuera posible, ahora ESP valdría 0x41414145 (os acordais la nota que puse antes, ahora es cuando vale saberlo bien)
RET //finalmente intentaríamos meter el valor de la dirección de memoria 0x41414145 en EIP
Ahora pensemos como poder aprovecharnos de esto, vemos que hemos modificado EBP y con esto finalmente podríamos intentar modificar EIP. Vemos que al meter una dirección en EBP, luego se mete en ESP y se le sumaría 4 a esa dirección por el POP EBP, entonces a esa nueva dirección se accede para obtener EIP...
Y si...?, metemos una dirección donde tengamos un puntero a nuestro shellcode - 4, luego al hacer el POP EBP, tendríamos en ESP la dirección de un puntero a nuestro shellcode, entonces meteríamos ese puntero en EIP, y al hacer el RET, el código saltaría a nuestro shellcode...
A que mola, muy sencillito, al menos en mi cabeza todo funciona:
Bien entonces tenemos que saber en que lugar de memoria se establece nuestro shellcode y en donde empieza EBP, para saber cuantos caracteres podemos meter para petar la memoria y poder hacer el truco.
Vamos a ver el código primero del programa que vamos a usar:
Seguis entonces la nota del principio de como compilarlo. Y ahora vamos a ver como obtenemos la dirección de memoria:
Según arrancamos el programa, nos encontraremos según EIP en /lib..., para ir al comienzo ejecutaremos F9, el cual es RUN, y nos llevará al principio de código:
Ya estamos en el main, como vemos en el código, tenemos que si no metemos un argumento el programa sale, por tanto al meter un argumento se llamará a una de las funciones, la cual llamará a la de copiar, así que vayamos directos a la de copiar. Con F7 vamos pasando linea a linea, y si encuentra un call, entrará, vemos el primer call del main:
Nos meteremos en él, que es la primera función, y dentro tendremos otro call que es la función para copiar:
Dentro de esta función podemos ejecutar para ver donde se copia la cadena Fare9, y vemos donde se encuentra EBP, para realizar la resta. Ejecutemos hasta casi el epílogo y examinemos la pila:
Podemos observar en que dirección empezó a copiarse la cadena y en que dirección está EBP guardado, hagamos la resta:
bfff:f348 - bfff:f23c = 10c = 268 en decimal
Por tanto después de meter 268 bytes, lo siguiente que entra sobreescribe el valor guardado de EBP.
Ahora vamos a ver como podemos montar el exploit, necesitamos la dirección a la que vuelva - 4, luego necesitamos la dirección del shellcode, vamos a ver mi código en python de un exploit, recordemos que para encontrar las direcciones ejecutar el programa con edb dentro del código python, esto nos dará las direcciones más correctas:
Como se puede observar, al ejecutar mi código con python , busqué con edb el principio del buffer y esta vez era bfff:f12c, por tanto tenemos que la dirección de retorno (RET) es bfff:f12c - 4, la dirección del shellcode será bfff:f12c + 4, allí encontraremos una cama de NOPS, bastante grande, y el shellcode que nos devuelve una shell. Vamos a ejecutarlo primero con edb y luego sin él:
Como vemos, se ha copiado primero la dirección a donde tiene que saltar y después la cama de NOPS, vamos a ver donde estaba EBP:
Como vemos, donde estaba EBP, está la dirección del puntero a nuestra shellcode - 4, ahora sigamos ejecutando hasta llegar al epílogo de la función anterior:
Como vemos EIP acabó apuntando a nuestra shell y ahora a los NOPS, si ejecutamos este shellcode, veremos que obtenemos una shell. Ahora vamos a ejecutarlo sin edb:
Como vemos acabamos de obtener una shell, sin poder llegar a EIP, a esto sólo queda decir:
MAGIAAAAAAAAAAAAAAAAAAAAAAA
Pues mundo de hackers, hasta aquí el De 0 a exploiting(V) , espero que fuera divertido, me ha costado la verdad con tanta imagen (LOCURA), pero es entretenido tener nuevas formas de explotación además de sobreescribir directamente EIP.
Antes de acabar me gustaría pedir a quien pudiera y quisiera, que ya que en estas fechas nos encontramos en época de cacería y post navidad, tanto Galgos como cachorros los cuales crecieron, serán abandonados o cosas peores, que quien pueda donar un mínimo, les dejo unos enlaces de protectoras las cuales necesitarían de esta ayuda:
http://www.galgos112.com/
http://www.proaweb.org/
http://www.anaaweb.org/es/
http://www.protectorahuellas.org/
Yo cada año gran parte de mis regalos monetarios, van destinados a diferentes protectoras, y es un dinero que por poco que sea, bien vendrá.
Hasta aquí De 0 a exploiting y nos vemos en próximos POST de Fare9.
--------------------------------------------------------FIN