ATAQUE FORMAT STRING RET2SHELLCODE 2 BYTES
Análisis del programa vulnerable FS1
Código Fuente
¿Qué hace el programa?
El programa vulnerable copia en buf
el primer parámetro ingresado por el usuario. Imprime por salida estándar el contenido de buf
y guarda en plen
la cantidad de bytes impresos. Si la variable zero
se mantiene intacta el loop while(zero)
no se ejecuta y el proceso finaliza.
¿Cuál es la dificultad principal?
Si se sigue la estrategia de sobreescribir la dirección de retorno de
main
, de manera colateral se pisa el valor dezero
provocando un loop infinito. Frente a esto el proceso nunca retorna y la reescritura de la dirección de retorno en la pila es inútil.
Es necesario pensar en un ataque combinado de desbordamiento de búfer y el aprovechamiento de una vulnerabilidad del tipo format string.
Layout de la pila antes del exploit:
Ataque Format String:
La reescritura de la dirección de retorno de main
a través de un desbodamiento de búfer -en la función strcpy
- obliga a sobreescribir la variable zero
(por su ubicación en la pila entre buf
y la dirección de retorno). Para que el ataque funcione es necesario que main
retorne y por ende que zero
continúe siendo 0.
Consideraciones: no es plausible como solución sobreescribir
zero
con el valor numérico de0000
. Como el desbordamiento de bufer se logra a travésstrcpy
, una función que manipula strings, si optamos por escribir enzero
el string “0000” estaríamos almacenando enzero
el código ascii:0x30303030
. Y por ende no lograríamos el objetivo de que el programa retorne.
Para solucionar este escollo es necesario combinar el ataque de desbordamiento de búfer con un ataque del tipo format string.
Este ataque tomará dos pasos. Primero, aprovechar strcpy(buf,argc[1])
para inyectar el shellcode y sobreescribir la dirección de retorno de main()
almacenada en la pila para que apunte a él. Y en un segundo paso, aprovechamos printf("%s%hn\n",buf,plen)
para volver a zero = 0
de manera indirecta a través de plen
, gracias a una vulnerabilidad del tipo format string. Paso a paso la estrategia será la siguiente:
Primera parte: aprovechando el código strcpy(buf,argc[1])
:
Inyectamos el shellcode en
buf
.Con un desbordamiento sobreescribimos
plen
para que apunte azero
.Y sobreescribimos la dirección de retorno de
main()
para que apunte abuf
.
Segunda parte: aprovechando printf("%s%hn\n",buf,plen)
:
Esta línea de código nos va a permitir escribir un valor arbitrario de no más de dos bytes en
plen
. Como se indicó previamente el parámetro%n
escribe la cantidad de bytes impresos en la dirección especificada. Cuando se lo utiliza como%hn
como en este caso (con unah
de half como formato adicional de longitud) va a escribir la cantidad de caracteres impresos pero en un short de 2 bytes.Gracias al desbordamiento de búfer previo,
plen
apunta azero
. El primer%s
del format string va a imprimir el string enbuf
hasta llegar a un caracter nulo, si logramos que la extensión de ese string sea de 10000 en hexa -como%hn
escribe sólo dos bytes- logramos escribir0000
enplen
(quedando descartado el 1 inicial de (1)0000). Entonces comoplen
apunta azero
si manipulamos adecuadamente la extensión debuf
logramos el objetivo de quezero = 0
indirectamente a través deplen
. Con ello evitamos el loop infinito delwhile(zero)
y logramos quemain
retorne al código malicioso inyectado en el primer paso.
Para lograrlo llevamos a cabo los siguientes pasos.
Identificamos la dirección de
buf
engdb
Consideraciones: como el argumento que le vamos a pasar a
strcpy
se almacena en la pila, su longitud afecta el cálculo de la dirección debuf
. En este caso sabemos que la longitud total del argumento (es decir la cantidad de caracteres que va a imprimirprintf
) debe ser de0x(1)0000
que en decimal es65536
. Por eso para conocer la dirección que tendrábuf
debugeamos el programa con un argumento cualquiera pero de esa longitud.Armamos un archivo en Python para ingresar el input:
exploit.py
Y ejecutamos el programa vulnerable con ese argumento para conocer la dirección de
buf
:La dirección de
buf
es entonces0xbffef680
.Planificamos el argumento de entrada
Inyectamos el shellcode en
buf
.Hacemos que
plen
apunte azero
.Escribimos basura en
zero
(porque vamos a pisar su valor).Incluimos una dirección válida cualquiera en
ebp
.Sobreescribimos la dirección de retorno para que apunte al shellcode.
Extendemos longitud del input para imprimir un total de (1)0000 bytes, cantidad almacenada en
plen
(que apuntará azero
).
Con eso en mente editamos el archivo en Python con el argumento definitivo:
exploit.py
Ejecutamos el exploit
Layout de la pila después del exploit:
Gráficamente logramos el siguiente resultado:
Última actualización