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攻击的更多相关文章

  1. premake 在64位Ubuntu系统下编译32位GCC程序

    首先,要安装GCC 4.8, 参考前文:Ubuntu 12.04 & 13.04 安装 GCC4.8.1 其中,重点是安装multilib apt-get install gcc-4.8-mu ...

  2. 64位Win8系统下安装Oracle12c

    经过3个小时的折腾,终于在64位win8系统下成功安装了Oracle 12c.这篇文章主要把安装过程中遇到的一些问题总结一下,以便帮助后来人参考. 首先我把我的机器的主要配制情况列举出来: 1. 系统 ...

  3. 在64位Ubuntu系统上安装32位程序包

    在64位Ubuntu系统上安装32位的程序包 $sudo apt-get install package_name:i386 例如: $sudo apt-get install openjdk-7-j ...

  4. 64位Windows系统下32位应用程序连接MySql

    1.首先得安装“Connector/ODBC”,就是Mysql的ODBC驱动,这个是与应用程序相关的,而不是与操作系统相关的,也就是说,不管你的系统是x64还是x86,只要你的应用程序是x86的那么, ...

  5. 64位Win7系统下vs2010调试无法连接oracle

    64位win7系统的Program Files (x86)路径中有括号,oracle不认识这样的路径,所以就出现不能连接数据库的问题.所以我们可以将vs2010的内部调试web服务器WebDev.We ...

  6. 64位Win7系统下vs2010调试无法连接oracle解决办法

    具体的解决办法如下: 1.先将WebDev.WebServer20.EXE和WebDev.WebServer40.EXE文件从Program Files (x86)目录中拷贝出来放到c:\dev目录中 ...

  7. 64位debian系统下安装inodeClient

    linux下的inodeClient下载: 链接:http://pan.baidu.com/s/1jIoX6Zk 密码:vnws 里面包括一份说明书,一个32位的,一个64位的文件: 对于64位的客户 ...

  8. centos 64位linux系统下安装appt命令

    首先,安装apktool包 1. wget http://android-apktool.googlecode.com/files/apktool-install-linux-r04-brut1.ta ...

  9. 关于64位Windows7系统下INF的安装问题

    原文 http://bbs.csdn.net/topics/360262492 我的电脑 ——>属性 ——>设备管理器 ——>操作 ——>添加过时硬件 但是,64位系统上报“指 ...

随机推荐

  1. ecna2017-Sheba’s Amoebas

    很简单的深搜的一道题,由于这道题要找环的个数,并且认为相连当一个点的8个方向种中有一个方向和这个点相连. 这个题做法无非就是暴力每个点,然后满足条件的深搜即可. 感觉我自己的代码写的很无趣,大佬的代码 ...

  2. 牛客小白月赛6-E对弈-简单搜索

    https://www.nowcoder.com/acm/contest/136/E 我搜索很差啊,看了学长代码,自己在下面手敲了一遍,感觉学长的极其精巧,把我繁琐的搜索步骤给简化了不少 其实本题想法 ...

  3. 第三周Linux学习报告

    Linux内核源代码简介: arch/x86中内容重点关注 init目录重要,内核启动相关的代码基本上都在init目录下.如main.c等.Start_kernel函数相当于普通C程序的main函数. ...

  4. [BUAA2017软工]第1次个人项目 数独

    [BUAA软工]第1次作业 个人项目 数独 一.项目地址 github地址:https://github.com/BuaaAlen/sudoku 二.PSP表格 三.解题思路描述 在拿到这个题目时,我 ...

  5. ThreadPoolExecutor源码解读

    1. 背景与简介 在Java中异步任务的处理,我们通常会使用Executor框架,而ThreadPoolExecutor是JUC为我们提供的线程池实现. 线程池的优点在于规避线程的频繁创建,对线程资源 ...

  6. Docker for windows 入门一(下载安装)

    预安装条件,可以查阅官方文档,本人是Win10 x64(必要条件)教育版+开启Hyper-V(Feature特性),具体可参考云栖社区的文章: https://yq.aliyun.com/articl ...

  7. ionic动态切换主题皮肤

    本来想通过css自定义属性值: :root{ --red:red; } p{ color:var(--red); } div{ background:var(--red); } 在ionic2设置动态 ...

  8. Java 死锁

    什么是死锁? 当一个线程永远地持有一个锁,并且其他线程都尝试去获得这个锁时,那么它们将永远被阻塞,当线程A持有锁1想获取锁2,当线程B持有锁2想获取锁1 这种情况下就会产生2个线程一直在阻塞等待其他线 ...

  9. Ubuntu 18.10 版本发布

    Ubuntu 是一个基于 Debian 的以桌面为主的 Linux 发行版,以其应用性而闻名.Ubuntu 提供三种官方版本:用于个人计算机的 Ubuntu 桌面,用于服务器和云的 Ubuntu 服务 ...

  10. BZOJ1045 HAOI2008糖果传递(贪心)

    显然最后每个小朋友所拥有的糖果数就是糖果数总和的平均数.设该平均数为t. 环的问题一般断成链,但这个题似乎没有什么很好的办法在枚举断点的时候快速算出答案(我甚至不知道会不会有断点) 于是我们假装把他断 ...