http://blog.51cto.com/13786619/2123970
一.实验要求
栈溢出+ ret2libc ROP 操作系统:Ubuntu 16.04 64bit
安全机制:不可执行位保护,ASLR(内存地址随机化)
打开安全机制,确保×××能绕过以上安全机制,利用漏洞完成attack,实现基本目标:调用system(“/bin/sh”),打开shell。
二.实验概述
ret2libc(return-into-libc)是一种利用缓冲区溢出的代码复用技术,主要通过覆盖栈帧的返回地址(EIP),使其返回到系统中的库函数,利用库函数中已有的功能来实施attack,而不是直接定位到注入的shellcode。
Linux系统关于缓冲区溢出主要有栈不可执行和ASLR的保护机制。ASLR 可以实现对进程的堆、栈、代码和共享库等的地址在程序每次运行的时候的随机化,大大增加了定位的难度。此外,在Linux64位系统中,函数间传递参数不再以压栈的方式,而是以寄存器方式传递参数。所以,要想在64位Ubuntu系统中实施attack操作,除了要绕过上述两个安全机制外,还需要控制用于传递参数的寄存器。本次attack主要有三个关键点:
1) 栈不可执行→代码复用(ret2libc调用系统函数)
2) ASLR→通过plt和got表获取系统函数的地址
3) 64位系统以寄存器方式传递参数→通过ROP控制寄存器
三.实验环境
Ubuntu desktop 16.04 LTS amd64
Gcc Gdb Python PwnTool
四.实验内容
4.1 漏洞程序
漏洞程序vul.c代码如下,main函数把“Hello ,World”读取到标准输出中,调用vulnerable_function()函数。在vulnerable_function()函数中,申请了128字节的buf,调用read()读取标准输入到buf中,未做边界检查,这就是漏洞所在。
![64位linux系统:栈溢出+ret2libc ROP attack](https://i-blog.csdnimg.cn/blog_migrate/57be0196330b3331cd3eadedfbfc2f67.png)
将地址空间随机化打开sudo sysctl –w kernel.randomize_va_space=2
gcc编译漏洞程序,显式指明-z noexecstack,正常运行效果如下图所示:
![64位linux系统:栈溢出+ret2libc ROP attack](https://i-blog.csdnimg.cn/blog_migrate/617a7fe5b27c0ddabe9653b06808c1d1.png)
4.2 attack漏洞程序
4.2.1 获取溢出点位置
为了正确定位溢出点位置,构造如下txt文件。
![64位linux系统:栈溢出+ret2libc ROP attack](https://i-blog.csdnimg.cn/blog_migrate/e064a85838bd9e89e5c5c00ae72af445.png)
在gdb调试中运行发现溢出,由于程序使用的内存地址不能大于0x00007fffffffffff,否则会抛出异常,所以程序停在了vulnerable_function()函数中。虽然PC不能跳转,但ret相当于“pop RIP”指令,所以只需看一下栈顶的数值就能知道PC跳转的地址。可以看到栈顶的数据为0x3765413665413565,即e5Ae6Ae7,在文件中是第137个字节,所以溢出点为136。
![64位linux系统:栈溢出+ret2libc ROP attack](https://i-blog.csdnimg.cn/blog_migrate/c78ae69f1c0dd872743c405aa1ed2977.png)
4.2.2 寻找gadgets
64位Ubuntu系统中前六个参数依次保存在RDI, RSI, RDX, RCX, R8和 R9寄存器里,如果有更多的参数再保存在栈上。漏洞程序中只有read()和write()两个函数,没有其他辅助组件。为了控制传递参数的寄存器,可以在程序初始化函数中提取通用的gadgets。
输入objdump –d ./vul观察_libc_csu_init()函数。
![64位linux系统:栈溢出+ret2libc ROP attack](https://i-blog.csdnimg.cn/blog_migrate/4c3264df411a48137d98c3f3ba522208.png)
有两处可以利用的配件:
配件1
4005f0: 4c 89 ea mov %R13,%RDX
4005f3: 4c 89 f6 mov %R14,%RSI
4005f6: 44