64位Ubuntu系统下ROP攻击
64位Ubuntu系统下ROP攻击
基础知识
ROP攻击
- ROP全称为Retrun-oriented Programmming(面向返回的编程)是一种新型的基于代码复用技术的攻击,攻击者从已有的库或可执行文件中提取指令片段,构建恶意代码。
- ROP攻击同缓冲区溢出攻击,格式化字符串漏洞攻击不同,是一种全新的攻击方式,它利用代码复用技术。
- ROP的核心思想:攻击者扫描已有的动态链接库和可执行文件,提取出可以利用的指令片段(gadget),这些指令片段均以ret指令结尾,即用ret指令实现指令片段执行流的衔接。操作系统通过栈来进行函数的调用和返回。函数的调用和返回就是通过压栈和出栈来实现的。每个程序都会维护一个程序运行栈,栈为所有函数共享,每次函数调用,系统会分配一个栈桢给当前被调用函数,用于参数的传递、局部变量的维护、返回地址的填入等。栈帧是程序运行栈的一部分 ,在Linux中 ,通过%esp和 %ebp寄存器维护栈顶指针和栈帧的起始地址 ,%eip是程序计数器寄存器。而ROP攻击则是利用以ret结尾的程序片段 ,操作这些栈相关寄存器,控制程的流程,执行相应的gadget,实施攻击者预设目标 。ROP不同于retum-to-libc攻击之处在于,R0P攻击以ret指令结尾的函数代码片段 ,而不是整个函数本身去完成预定的操作。从广义角度讲 ,return-to-libc攻击是ROP攻的特例。最初ROP攻击实现在x86体系结构下,随后扩展到各种体系结构.。与以往攻击技术不同的是,ROP恶意代码不包含任何指令,将自己的恶意代码隐藏在正常代码中。因而,它可以绕过W⊕X的防御技术。
实验环境
- 虚拟机系统:Ubuntu 12.04(64位)

前期准备
- 根据X86_64 ABI的调用约定,函数间传递参数不再以压栈的方式,而是以寄存器方式传递参数,前面6个参数依次以rdi, rsi, rdx, rcx, r8和r9寄存来传递。在Linux系统,64位架构只使用48位的虚拟地址空间,也即每个地址高16位全部为0,因此在64位系统上,地址已天然零化,ret2libc攻击似乎没有了用武之地,在ret2libc的基础上我们采用ROP攻击方法。
- 我们现在先假设栈没有可执行属性,那么需要自己编写一个shell来执行,考虑通过execve系统调用来实现。我们直接将汇编代码放在shell.c文件中:
int main() {
asm("\
needle0: jmp there\n\
here: pop %rdi\n\
xor %rax, %rax\n\
movb $0x3b, %al\n\
xor %rsi, %rsi\n\
xor %rdx, %rdx\n\
syscall\n\
there: call here\n\
.string \"/bin/sh\"\n\
needle1: .octa 0xdeadbeef\n\
");
}
- 无论我们的代码在内存中的哪个地方结束,call-pop指令都将使用“/bin/sh\”字符串的地址加载rdi寄存器,接下来编译运行shell.c文件,成功获得了一个shell:

实践过程
我们先提取要注入的payload,查看机器代码:

在64位系统上,代码段通常位于0x400000,在该二进制文件中,我们的代码位于0x4b8的偏移量处,并在偏移量0x4d5之前完成,共有29个字节:

查看我们的shellcode:

接着,我们看一个被攻击的简单代码victim.c:
#include <stdio.h>
int main() {
char name[64];
puts("What's your name?");
gets(name);
printf("Hello, %s!\n", name);
return 0;
}
- 在Ubuntu系统上,有三种对策来保护堆栈,第一种是SSP,又名ProPolice,编译器重新排列堆栈布局,使缓冲区溢出不太危险,并插入运行时堆栈完整性检查;第二种是可执行空间保护(NX),当尝试在堆栈中执行代码时会导致分段错误;第三种地址空间布局随机化(ASLR),堆栈的位置每次运行都是随机的,所以即使我们可以覆盖返回地址,也不知道该放在哪里。
三种攻击尝试
第一种尝试
我们可以想办法绕过这些方法,使用gcc的-fno-stack-protector选项禁用堆栈保护,编译victim,然后使用execstack -s指令禁用可执行文件空间保护,发现提示没有安装:

安装完成之后,禁用可执行文件空间保护,然后在运行文件时禁用ASLR:

我们再在原victim.c代码的基础上加上一句
printf("%p\n", name);,打印缓冲区的位置,然后再编译运行:

后面的过程中应该也会出现该缓冲区的地址,我们让它以小端法显示:

这个时候我们攻击我们的victim.c程序,可以看到攻击成功:

第二种尝试
接着,我们再通过一个例子来看看打补丁的重要性,在以前,我们可以通过查看/proc/pid/stat来读取任何进程的ESP注册表,但是这种漏洞很早就被修复了,我们假装目前在没有打补丁的系统上,先查看所有进程的esp:

我们先运行禁用了ASLR的victim程序:

再在另一个终端窗口查看victim程序的esp:

因此,当程序正在等待用户输入时,它的堆栈指针0x7fffffece8,我们计算从这个指针到名称缓冲区的距离:

现在重新运行启用了ASLR的victim程序:

我们查找victim进程的esp指针,然后添加上偏移量,就是上一步中运行victim程序的缓冲区地址:

接着用管道命令来进行演示:

在另一个终端中输入如下命令:

可以看到攻击成功,获取到了shell:

第三种尝试
先通过运行execstack -c指令重新启动可执行空间保护,此外,在ROP攻击中代码片段从可执行内存中挑选出来,例如,它们可能是libc的片段,所以我们还要通过locate指令找到libc的位置,如图所示,我们选择第一个:

我们希望执行
pop %rdi retq,而指向“/bin/sh”的指针位于堆栈的顶部。这将在推进堆栈指针之前将指针分配给rdi,相应的机器代码是两个字节的序列0x5f 0xc3,它应该在libc的某处发生。但是没有Linux工具能够直接在文件中搜索给定的字节序列,所以我们可以用下面的grep指令来实现检索:

在ROP中,以RET结尾的一系列指令称为gadget,如果我们用以下顺序覆盖返回地址:libc的地址+ 0x22a12;“/bin/sh”的地址;libc的system()函数的地址,然后在执行下一个ret指令时,程序将弹出“/bin/sh”的地址到rdi,然后跳转到系统函数,我们就可以达到我们的目的。先输入如下指令运行禁用了ASLR的victim程序:

再在另一个终端中输入如下指令:

我们可以看到,libc被加载到从0x7ffff7a1a000开始的内存中,因此gadget地址是0x7ffff7a1a000 + 0x22a12,“/bin/sh”的地址我们之前已经找到了,是0x7fffffffed40,最后我们通过下面的指令来找libc的system()函数的地址:

我们可以得到libc的system()函数的地址是0x7ffff7a1a000 + 0x45730,最后将它们放到一起,成功得到了shell:

64位Ubuntu系统下ROP攻击的更多相关文章
- premake 在64位Ubuntu系统下编译32位GCC程序
首先,要安装GCC 4.8, 参考前文:Ubuntu 12.04 & 13.04 安装 GCC4.8.1 其中,重点是安装multilib apt-get install gcc-4.8-mu ...
- 64位Win8系统下安装Oracle12c
经过3个小时的折腾,终于在64位win8系统下成功安装了Oracle 12c.这篇文章主要把安装过程中遇到的一些问题总结一下,以便帮助后来人参考. 首先我把我的机器的主要配制情况列举出来: 1. 系统 ...
- 在64位Ubuntu系统上安装32位程序包
在64位Ubuntu系统上安装32位的程序包 $sudo apt-get install package_name:i386 例如: $sudo apt-get install openjdk-7-j ...
- 64位Windows系统下32位应用程序连接MySql
1.首先得安装“Connector/ODBC”,就是Mysql的ODBC驱动,这个是与应用程序相关的,而不是与操作系统相关的,也就是说,不管你的系统是x64还是x86,只要你的应用程序是x86的那么, ...
- 64位Win7系统下vs2010调试无法连接oracle
64位win7系统的Program Files (x86)路径中有括号,oracle不认识这样的路径,所以就出现不能连接数据库的问题.所以我们可以将vs2010的内部调试web服务器WebDev.We ...
- 64位Win7系统下vs2010调试无法连接oracle解决办法
具体的解决办法如下: 1.先将WebDev.WebServer20.EXE和WebDev.WebServer40.EXE文件从Program Files (x86)目录中拷贝出来放到c:\dev目录中 ...
- 64位debian系统下安装inodeClient
linux下的inodeClient下载: 链接:http://pan.baidu.com/s/1jIoX6Zk 密码:vnws 里面包括一份说明书,一个32位的,一个64位的文件: 对于64位的客户 ...
- centos 64位linux系统下安装appt命令
首先,安装apktool包 1. wget http://android-apktool.googlecode.com/files/apktool-install-linux-r04-brut1.ta ...
- 关于64位Windows7系统下INF的安装问题
原文 http://bbs.csdn.net/topics/360262492 我的电脑 ——>属性 ——>设备管理器 ——>操作 ——>添加过时硬件 但是,64位系统上报“指 ...
随机推荐
- 牛客训练赛25-A-因数个数
题目链接https://www.nowcoder.com/acm/contest/158/A 无语...这题很迷啊,原谅我的菜,刚开始想用预处理欧拉筛和前缀和,可是这题太血崩了,这样一样要遍历,1-e ...
- Some questions after Reading 《移山之道》
很少见到用故事的形式来写技术书籍的,这是我看到的第一本,书写得比较有趣,看了之后也是有一定的收获. 作者在此书中旁征博引,引用的东西虽不能一个一个查询是否正确,但是每次读到时候,感觉一种现代的软件工 ...
- Linux内核分析 笔记七 可执行程序的装载 ——by王玥
一.预处理.编译.链接和目标文件的格式 (一)可执行程序是怎么得来的? 1. 2.可执行文件的创建——预处理.编译和链接 shiyanlou:~/ $ cd Code ...
- Linux内核分析——第三章 进程管理
第三章 进程管理 3.1 进程 1.进程就是处于执行期的程序:进程就是正在执行的程序代码的实时结果:进程是处于执行期的程序以及相关的资源的总称:进程包括代码段和其他资源. 线程:是在进程中活动的对象. ...
- Maven的课堂笔记3
8 仓库管理 仓库可以分为三种:1.本地仓库(本机).2.私服(公司局域网内的maven服务器).3.中央仓库(互联上,例如 struts2官网,或者hibernate官网) 可以根据maven坐标定 ...
- RBAC权限管理及使用原生PHP实现
关于RBAC的原理讲解在网上可以找到很多,推荐:编程浪子的RBAC讲解,本篇博客就不再累述RBAC的原理到底是什么样的. 传统的权限控制有ACL和RBAC方式,ACL的耦合度很高,扩展性不佳,RBAC ...
- 将字符串以用二进制流的形式读入XML文件
其实将字符串写入XML文件本身并不复杂,这里只是写一些需要注意的地方,特别是编码格式,这里需要的是XML默认的编码方式是UTF-8,在对字符串进行编码的时候一定要注意, string strRecei ...
- vue render function & dataset
vue render function & dataset https://vuejs.org/v2/guide/render-function.html#The-Data-Object-In ...
- 线性代数的本质与几何意义 03. 矩阵与线性变换 (3blue1brown 咪博士 图文注解版)
首先,恭喜你读到了咪博士的这篇文章.本文可以说是该系列最重要.最核心的文章.你对线性代数的一切困惑,根源就在于没有真正理解矩阵到底是什么.读完咪博士的这篇文章,你一定会有一种醍醐灌顶.豁然开朗的感觉! ...
- DevexpressVCL v51
Dev经典套件v49版 支持Delphi2010 DevExpress公司出品的Borland Delphi和C++ Builder的控件(包含完整源代码).ExpressVerticalGrid:就 ...