antes de nada, ya sabemos, 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
###############################################
(sabéis que Fare9, hace copy-paste siempre con los preparativos del anterior post...)
Bien, vamos a ver un código en C, con el cual intentaremos entender esto:
Como vemos, el código es muy parecido al que vimos en el post anterior, pero esta vez, en el límite en lugar de sumar 4 sumamos 1, y el objetivo es que al comparar "cookie" con 0xdefaced, salga lo mismo.
Bien "off-by-one" es referido a que esta vez, sobreescribimos 1 byte, con lo cual intentaremos que eso juege a nuestro favor.
En este reto es interesante ver como se realiza la comparación de "cookie" con 0xdefaced:
Ejecutamos el programa con cualquier argumento y dentro de nuestro debugger visual edb.
Después de navegar un poco por el código, vemos que la comparación es la siguiente, que se compara "cookie", pero esta variable se referencia como [ebp-28] y resulta que un byte de EBP lo podemos modificar (el último byte) ...
Bien, vamos a volver a ejecutar y veamos el valor de EBP que se metió en la pila a la hora de realizar el stack frame (recordais de anteriores posts, el stack frame), vamos mirando por la pila y lo tenemos antes de un return:
bfff:f141 - 1Ch (valor 28 en hexadecimal) = bfff:f125
Bien la dirección donde tendrá que estar el 0xdefaced es bfff:f125, ahora veremos donde empieza a copiar nuestros valores, para ello ejecutamos realizamos un par de veces el bucle for, y vemos donde empieza a copiar, no hay más dificultad (guiño guiño):
Como vemos, empezó a copiarse en bfff:f030, y que podemos llegar a escribir hasta bfff:f135 (el lugar donde se realiza el off-by-one), bfff:f125 está entre medias...
Ahora realizamos los siguientes pasos:
- Calcular cuanta basura tenemos que meter antes de meter el 0xdefaced:
bfff:f125 - bfff:f030 = f5h = 245 bytes - Meter 0xdefaced
- Meter más basura hasta el último byte que meteremos una 'A' (yo meto un montón de 'A's y que se encargue el programa de parar, por tanto nunca falla).
Con el método pack, de struct, pasamos el 0xdefaced a Little-endian, luego como vemos metemos 245 'A' antes del defaced y luego todo 'A' de basura.
Ejecutemos y veamos que pasa en la pila (podemos establecer un breakpoint en el leave de la función, así el bucle for se ejecuará completo):
Breakpoint en el leave, para ejecutar el for.
Vemos que al comienzo del buffer se han metido un montón de 'A's
Al final del buffer, hemos modificado el último byte que se metará en EBP, con una 'A', ahora vale bffff141.
Y como vemos, en bfff:f125, se empieza a meter defaced, al contrario (pues estamos en Little-Endian) y con un 0 al final, ya que para tener un total de 8 bytes había que meter eso. Por tanto se ha metido ed, ac, ef, 0d (Recordemos que son números en hexadecimal, no letras).
Sigamos ejecutando y veamos en qué acaba la comparación:
Vemos que, vamos a realizar la comparación y el debugger, ya nos muestra abajo el valor de la dirección de memoria [ebp-28]... Vaya parece que es 0x0defaced (como dijo Nostradamus). Por tanto la comparación sale correcta y tachaaaan, conseguimos una shell.
Bien, para ejecutarlo directamente en shell, vamos a comentar el primer os.system... y descomentar el segundo del código del exploit y ejecutamos:
Como vemos, ya tenemos nuestra rica shell. Para el programador que se le pasó por una:
Hasta aquí el post de "De 0 a exploiting" de hoy, en el siguiente post ya veremos "Return to libc", algo que cuando lo vi por primera vez, me pareció muy muy interesante.
Nos vemos en los próximos post de Fare9
--------------------------------------------------------FIN