您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Model Center   Code  
会员   
   
 
     
   
 订阅
  捐助
ARM 架构—探究绕过NX的一种方式Ret2ZP
 
作者:TigerTiger
  120  次浏览      50
 2021-9-18
 
编辑推荐:
本文主要介绍了ARM和X86对缓冲区溢出利用的区别,使用Raspbian 虚拟机搭建环境,希望对您的学习有所帮助。
本文来自于安全客,由火龙果软件Alice编辑、推荐。

01 前 言

ARM 指令集架构,常用于嵌入式设备和智能手机中,是从RISC衍生而来的。并且ARM处理器几乎出现在所有的流行智能手机中,包括IOS、Android、Window Phone和黑莓操作系统,并且在嵌入式设备中经常出现,如电视机、路由器、智能网关等。ARM和x86指令集架构先比,ARM由于起精简指令集,具有高效,低耗能等优点,可以去确保在嵌入式系统上提供出色的性能。

02 缓冲区溢出原理

缓冲区是用于保存数据的临时内存空间。缓冲区溢出通常发生在写入缓冲区的数据大于缓冲区大小时,由于边界检查不足,缓冲区溢出并写入相邻的内存位置,这些位置可能是一些重要的数据或返回地址等。

并且局部变量一般来说在程序中是充当缓冲变量或者缓冲区。

在缓冲区溢出中,我们的主要目的是用一些手段来修改返回地址,通过控制链接寄存器(LR)来控制程序执行流。

一旦我们控制了返回地址,返回地址将赋值给PC寄存器,劫持了PC,你就掌控了一切。

03 ARM和X86对缓冲区溢出利用的区别

当一个程序开启NX保护之后,X86 架构下,首先想到的是Ret2Libc 来绕过NX ,篇幅有限,这里Ret2Libc就不展开说了。

但是在ARM架构中,Ret 到 Libc 是无法做到的,因为在ARM处理器中,函数的参数是通过寄存器传递的,而不是如X86,函数的参数通过堆栈传递。因此在ARM实现和x86 中Ret2Libc一样的效果,我们需要将参数放入到寄存器中。

这里使用到了Ret2ZP技术(Return To Zero Prevention)

举个例子,我们在栈溢出利用中,一般的思路是构造gadgets,来执行system(“/bin/sh”) 来获取shell。但是在构造gadgets, 需要将 “/bin/sh” 传递到system 函数执行时调用的寄存器R0中。

这里在 Ret2ZP 中常用的在libc 中的gadgets 有以下这些,是实际利用时,并不是每个都有用,选在实际环境中可以使用的就行。

erand48

lrand48

seed48

04 环境搭建

这里使用的的Raspbian 虚拟机,下载安装方法搜索引擎有很详细的文章。这里说明一下我搭建过程遇到的问题。

首先是在Raspbian 虚拟机中 下载gdb , 建议手动编译。因为apt 下载的gdb 是版本小于8.1。在实际gdb 调试会出现如下图所示问题

解决方案:这是gdb 因 ARM 程序内存损坏而造成的错误,最好的解决方式是安装gdb-8.1版本。https://github.com/hugsy/gef/issues/206

编译完之后。运行gdb 会出现如下错误

Python Exception <type 'exceptions.ImportError'
> No module named gdb:
/usr/local/bin/gdb: warning:
Could not load the Python gdb module from
`/home/pi/gdb-8.2/=/usr/share/gdb/python'.
Limited Python support is available from
the _gdb module.
Suggest passing --data-directory=/path/to
/gdb/data-directory.

解决方案:这是因为在编译的的时候需要指定编译环境是python3.5,默认是2.5,因此需要 ./configure —prefix=/usr —with-system-readline —with-python= / usr / bin / python3 . 5m 。

在编译的过程中还有可能会出现如下图所示的缺少库文件 “/usr/bin/ld: cannot find -lreadline “

解决方案:sudo apt-get install libreadline6-dev

然后就是安装gef 插件了。QAQ

05 缓冲区溢出实例

1)漏洞代码

这里用一个最简单的代码来学习Ret2ZP技术,并且缓冲区溢出点特别明确,有strcpy函数将输入的大于buf分配内存大小的参数传入到固定大小的buf缓冲区,从而造成缓冲区溢出。

漏洞代码

 

关闭ALSR保护

echo 0 | sudo tee /proc/sys/kernel/randomize _ va _ space

编译代码

pi@raspberrypi:~$ gcc -fno-stack-protector echo _ arm1 . c -o echo_arm

查看编译后文件的保护情况。

2) 确定溢出点并计算偏移

使用gdb 打开文件调试,并且查看文件中函数的汇编代码,如下图所示。

利用pattern.py 生成字符串

这里在do_echo 函数的0x00010468处打断点。

运行程序并将pattern生成的字符串输入可以看到在执行到0x00010468处,R11寄存器中值是”a5Aa”,接下来计算出栈溢出的偏移地址

经过计算,buf缓冲区溢出到返回地址需要16个字节,也就是说劫持PC寄存器需要16个padding。

3) 构造ROP Chain

这里利用seed48代码片段,当然也可以用我上面说的lrand48。这里使用 seed48 比lrand48 的gadgets 要复杂一点点。

可以看到R11寄存器后的值

查找system函数地址 0xb6eab154

查找“/bin/sh” 所在的地址 0xb6f91944

构造ROP chain 如下图所示,根据 ARM 的特性,system 函数需要的参数需要R0寄存器传入到 system。因此需要将 “/bin/sh” 字符串的地址放入到 R0 寄存器中,这里 gadgets1 首先将栈上 “/bin/sh” 的地址传入到R4寄存器中,由于在 gadgets2 中 R0=R4+6 ,因此这个时候需要0xb6f91944 减 6 ,然后在PC寄存器中放入 gadgets ,在执行 gadgets2 的过程中,会把“/bin/sh” 正确的地址传入到 R0,然后输入 padding(“DDDD” ) 传入到 R4 , 再执行system 函数从而获取shell 。

这里在构造的 payload 的时候,需要注意大小端的问题,这里文件是小端的,在小端字节序中,最低有效字节存储在最低地址。

AAAABBBBCCCCDDDD\x88\x30\xea\xb6\x3e\ x19 \ xf9 \ xb6 \ x84 \ x30 \ xea \ xb6DDDD \ x54 \ xb1 \ xea \ xb6

将构造的payload 发送过去

r `printf "AAAABBBBCCCCDDDD\x88\x30\ xea \ xb6 \ x3e \ x19 \ xf9 \ xb6 \ x84 \ x30 \ xea\ xb6DDDD \ x54 \ xb1 \ xea\ xb6"`

可以看到栈上成功覆盖到我们构造的payload

继续往下执行就可以拿到shell

06 总 结

Ret2ZP 技术,和Ret2lib的原理相差不大,但是由于ARM处理器的特性,函数执行的过程中,需要从R0~R3寄存器中获取参数,因此在构造ROP的时候,需要多考虑一点是将函数参数的值传入到R0~R3 寄存器中。

 
   
120 次浏览       50
 
相关文章

云计算的架构
对云计算服务模型
云计算核心技术剖析
了解云计算的漏洞
 
相关文档

云计算简介
云计算简介与云安全
下一代网络计算--云计算
软浅析云计算
 
相关课程

云计算原理与应用
云计算应用与开发
CMMI体系与实践
基于CMMI标准的软件质量保证
最新课程计划
 
最新文章
基于FPGA的异构计算在多媒体中的应用
深入Linux内核架构——简介与概述
Linux内核系统架构介绍
浅析嵌入式C优化技巧
进程间通信(IPC)介绍
最新课程
嵌入式Linux驱动开发
代码整洁之道-态度、技艺与习惯
嵌入式软件测试
嵌入式C高质量编程
嵌入式软件可靠性设计
更多...   
成功案例
某军工所 嵌入式软件架构
中航工业某研究所 嵌入式软件开发指南
某轨道交通 嵌入式软件高级设计实践
深圳 嵌入式软件架构设计—高级实践
某企业 基于IPD的嵌入式软件开发
更多...