Leaking libc address with ROP
Resumen Rápido
Encontrar el desplazamiento del desbordamiento
Encontrar el gadget
POP_RDI
,PUTS_PLT
yMAIN
Utilizar los gadgets anteriores para filtrar la dirección de memoria de puts u otra función de libc y encontrar la versión de libc (descárgala)
Con la biblioteca, calcular el ROP y explotarlo
Otros tutoriales y binarios para practicar
Este tutorial va a explotar el código/binario propuesto en este tutorial: https://tasteofsecurity.com/security/ret2libc-unknown-libc/ Otros tutoriales útiles: https://made0x78.com/bseries-ret2libc/, https://guyinatuxedo.github.io/08-bof_dynamic/csaw19_babyboi/index.html
Código
Nombre de archivo: vuln.c
Plantilla ROP - Filtrando la dirección de LIBC
Descarga el exploit y colócalo en el mismo directorio que el binario vulnerable y proporciona los datos necesarios al script:
pageLeaking libc - template1- Encontrando el desplazamiento
La plantilla necesita un desplazamiento antes de continuar con el exploit. Si no se proporciona ninguno, ejecutará el código necesario para encontrarlo (por defecto OFFSET = ""
):
Ejecuta python template.py
se abrirá una consola de GDB con el programa estrellado. Dentro de esa consola de GDB ejecuta x/wx $rsp
para obtener los bytes que iban a sobrescribir el RIP. Finalmente, obtén el desplazamiento usando una consola de python:
Después de encontrar el desplazamiento (en este caso 40), cambia la variable OFFSET dentro de la plantilla usando ese valor.
OFFSET = "A" * 40
Otra forma sería usar: pattern create 1000
-- ejecutar hasta ret -- pattern search $rsp
desde GEF.
2- Encontrar Gadgets
Ahora necesitamos encontrar gadgets ROP dentro del binario. Estos gadgets ROP serán útiles para llamar a puts
para encontrar la libc que se está utilizando, y luego para lanzar el exploit final.
El PUTS_PLT
es necesario para llamar a la función puts.
El MAIN_PLT
es necesario para llamar a la función principal nuevamente después de una interacción para explotar el desbordamiento nuevamente (rondas infinitas de explotación). Se utiliza al final de cada ROP para llamar al programa nuevamente.
El POP_RDI es necesario para pasar un parámetro a la función llamada.
En este paso no es necesario ejecutar nada, ya que todo será encontrado por pwntools durante la ejecución.
3- Encontrando la biblioteca libc
Ahora es el momento de encontrar qué versión de la biblioteca libc se está utilizando. Para hacerlo, vamos a filtrar la dirección en memoria de la función puts
y luego vamos a buscar en qué versión de la biblioteca se encuentra la versión de puts en esa dirección.
Para hacerlo, la línea más importante del código ejecutado es:
Esto enviará algunos bytes hasta sobrescribir el RIP es posible: OFFSET
.
Luego, establecerá la dirección del gadget POP_RDI
para que la siguiente dirección (FUNC_GOT
) se guarde en el registro RDI. Esto se debe a que queremos llamar a puts pasándole la dirección del PUTS_GOT
ya que la dirección en memoria de la función puts se guarda en la dirección apuntada por PUTS_GOT
.
Después de eso, se llamará a PUTS_PLT
(con PUTS_GOT
dentro del RDI) para que puts lea el contenido dentro de PUTS_GOT
(la dirección de la función puts en memoria) y lo imprima.
Finalmente, se llama a la función principal nuevamente para que podamos explotar el desbordamiento nuevamente.
De esta manera hemos engañado a la función puts para que imprima la dirección en memoria de la función puts (que está dentro de la biblioteca libc). Ahora que tenemos esa dirección podemos buscar qué versión de libc se está utilizando.
Como estamos explotando un binario local no es necesario averiguar qué versión de libc se está utilizando (solo encontrar la biblioteca en /lib/x86_64-linux-gnu/libc.so.6
).
Pero, en caso de una explotación remota, explicaré cómo puedes encontrarlo aquí:
3.1- Buscando la versión de libc (1)
Puedes buscar qué biblioteca se está utilizando en la página web: https://libc.blukat.me/ También te permitirá descargar la versión descubierta de libc
3.2- Buscando la versión de libc (2)
También puedes hacer:
$ git clone https://github.com/niklasb/libc-database.git
$ cd libc-database
$ ./get
Esto tomará algo de tiempo, ten paciencia. Para que esto funcione necesitamos:
Nombre del símbolo de libc:
puts
Dirección de libc filtrada:
0x7ff629878690
Podemos averiguar qué libc es la que más probablemente se está utilizando.
Obtenemos 2 coincidencias (deberías probar la segunda si la primera no funciona). Descarga la primera:
3.3- Otras funciones para filtrar
Copia la libc desde libs/libc6_2.23-0ubuntu10_amd64/libc-2.23.so
a nuestro directorio de trabajo.
4- Encontrar la dirección de la libc base y explotar
En este punto deberíamos conocer la biblioteca libc utilizada. Como estamos explotando un binario local, usaré simplemente: /lib/x86_64-linux-gnu/libc.so.6
Entonces, al principio de template.py
cambia la variable libc a: libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #Establecer la ruta de la biblioteca cuando se conozca
Proporcionando la ruta a la biblioteca libc, el resto de la explotación se calculará automáticamente.
Dentro de la función get_addr
se calculará la dirección base de libc:
Ten en cuenta que la dirección base final de libc debe terminar en 00. Si no es tu caso, es posible que hayas filtrado una biblioteca incorrecta.
Luego, la dirección de la función system
y la dirección de la cadena "/bin/sh" se van a calcular a partir de la dirección base de libc y la biblioteca libc proporcionada.
Finalmente, la explotación de ejecución de /bin/sh va a ser preparada y enviada:
Explicación del ROP final
El último ROP (rop1
) terminó llamando nuevamente a la función principal, por lo que podemos explotar nuevamente el desbordamiento (por eso el OFFSET
está aquí nuevamente). Luego, queremos llamar a POP_RDI
apuntando a la dirección de "/bin/sh" (BINSH
) y llamar a la función system (SYSTEM
) porque la dirección de "/bin/sh" se pasará como parámetro.
Finalmente, se llama a la dirección de la función exit para que el proceso finalice correctamente y no se genere ninguna alerta.
De esta manera, el exploit ejecutará un shell _/bin/sh.
4(2)- Usando ONE_GADGET
También podrías usar ONE_GADGET para obtener un shell en lugar de usar system y "/bin/sh". ONE_GADGET encontrará dentro de la biblioteca libc alguna forma de obtener un shell usando solo una dirección ROP.
Sin embargo, normalmente hay algunas restricciones, las más comunes y fáciles de evitar son como [rsp+0x30] == NULL
. Como controlas los valores dentro del RSP, solo tienes que enviar algunos valores NULL adicionales para evitar la restricción.
ARCHIVO DE EXPLOTACIÓN
Puedes encontrar una plantilla para explotar esta vulnerabilidad aquí:
pageLeaking libc - templateProblemas comunes
MAIN_PLT = elf.symbols['main'] no encontrado
Si el símbolo "main" no existe. Entonces puedes encontrar dónde está el código principal:
y establecer la dirección manualmente:
Puts no encontrado
Si el binario no está utilizando Puts, debes verificar si está utilizando
sh: 1: %s%s%s%s%s%s%s%s: not found
sh: 1: %s%s%s%s%s%s%s%s: not found
Si encuentras este error después de crear todo el exploit: sh: 1: %s%s%s%s%s%s%s%s: not found
Intenta restar 64 bytes a la dirección de "/bin/sh":
Última actualización