April 26, 2022

网刃杯2022 Reverse

一般来说会尊重每一道题,给每一道题一篇文章,不过工控的比赛有些无聊..也没啥新知识点,就写一块了。

freestyle

打开主程序会发现两个fun1

fun1

直接手算也行,直接写个程序也可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
__int64 fun1()
{
char input1[24]; // [rsp+0h] [rbp-20h] BYREF
unsigned __int64 v2; // [rsp+18h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("Welcome to Alaska!!!");
puts("please input key: ");
fgets(input1, 20, stdin);
if ( 4 * (3 * atoi(input1) / 9 - 9) != 4400 )
exit(0);
puts("ok,level_1 over!\n\n");
return 1LL;
}

fun2

第二个是要找等式最小的数值,直接相同语句爆破就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
__int64 fun2()
{
char input[24]; // [rsp+0h] [rbp-20h] BYREF
unsigned __int64 v2; // [rsp+18h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("Welcome to Paradise Lost!!!");
puts("The code value is the smallest divisible");
puts("please input key: ");
fgets(input, 20, stdin);
if ( 2 * (atoi(input) % 56) != 98 )
exit(0);
puts("ok,level_2 over!");
return 1LL;
}

GetFlag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

int main(void)
{
int i;

printf("%d\n", 1109 * 9 / 3);

for ( i = 56; i < 200; i++ )
if ( i % 56 == 49 )
printf("%d ", i);

return 0;
}

拿到数据程序跑一下试一下即可,两个拼接起来MD5加密提交即可

image-20220426135159233

Re_function

压缩包密码

接收到压缩包发现有个密码,然后还在压缩包旁边还看到一堆信息,看文件前缀 89 50 4E可得知这是PNG文件

image-20220426135545241

直接拿出来查看即可得知压缩包密码:3CF8

image-20220426135709340

解压出来两个文件,分别分析一下

re_easy_func1

进到主程序可以发现IDA解析异常,原因是401019处有花,程序执行根本不会执行到

因为xor eax, eax会把标志位ZF设置为1,于是JZ必定跳转

image-20220426135948515

于是我们把401019变成nop即可,再在401000处按u转成未定义,按c转成代码,按p形成结构块,即可恢复再F5即可查看反汇编

image-20220426140146628

逻辑较为简单,就是偶数位异或

image-20220426140440483

EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <string.h>

int main(void)
{
unsigned char encData[] =
{
100, 113, 84, 84, 100, 120, 116, 120, 100, 65,
64, 72, 112, 109, 24, 74, 0x41, 0x78, 0x66, 0x72,
0x41, 0x78, 0x5E, 0x4E, 0x5D, 0x52, 0x0E, 0x3D
};
int i;

for ( i = 0; i < strlen(encData); i += 2 )
printf("%c%c", encData[i] ^ 0x37, encData[i + 1]);

return 0;
}

获得输入

1
SqcTSxCxSAwHGm/JvxQrvxiNjR9=+

re_easy_func2

明显还要个文件,还没完

进去就一个函数,很明显的base64加密,不过换了码表

image-20220426140640427

直接拿Cyber解密即可,填入码表,再输入我们从re_easy_func1获得的输入,即可flag

image-20220426140818584

定时启动

  1. 在被这程序加密一次后得知(就是当前目标的所有文件后缀被加了.WNCRY),还会有个ReadMe文件生成
  2. 再运行此squid.WNCRY,就会有个提示,就是要在指定时间运行这个文件
  3. 修改系统时间,再把ReadMe删掉即可出flag

image-20220426142633145

ez_algorithm

分析主函数可得知就这一个加密函数,并可以从xyp1()获取密文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int __cdecl main(int argc, const char **argv, const char **envp)
{
const char *encFlag; // rax
char v5[1000]; // [rsp+20h] [rbp-60h] BYREF
char *encInput; // [rsp+408h] [rbp+388h]

_main(argc, argv, envp);
printf(Format);
scanf("%s", v5);
encInput = (char *)encryption(v5);
encFlag = (const char *)xyp1();
if ( !strcmp(encInput, encFlag) )
puts("Gj!You Win!!!");
else
puts("Sry!You Lost!!!");
system("pause");
return 0;
}

encryption

简单分析一下可得知不同字符对应的不同加密,但其实都是单字符替换,唯一注意的是大写字母和小写字母会根据下标进行不同操作

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
char *__fastcall encryption(char *input)
{
int v1; // eax
char v2; // al
char v3; // al
__int64 v4; // kr00_8
char v5; // al
char v6; // al
int v7; // eax
char v8; // al
char v9; // al
char v10; // al
char v11; // al
char v12; // al
size_t index; // rbx
char v15[1012]; // [rsp+20h] [rbp-60h] BYREF
int v16; // [rsp+414h] [rbp+394h]
__int64 v17; // [rsp+418h] [rbp+398h]
__int64 v18; // [rsp+420h] [rbp+3A0h]
int v19; // [rsp+42Ch] [rbp+3ACh]
char *t; // [rsp+430h] [rbp+3B0h]
char *v21; // [rsp+438h] [rbp+3B8h]

v18 = xyp2();
v17 = xyp3();
v21 = v15;
t = input;
v19 = 0;
v16 = 1;
while ( 1 )
{
index = v19;
if ( index >= strlen(input) )
return v15;
if ( *t <= 64 || *t > 90 ) // 不是大写
{
if ( *t <= 96 || *t > 122 ) // 不是小写
{
if ( *t == '_' ) // 特殊字符
{
switch ( v16 + rand() % 7 ) // 伪随机 完成可知
{
case 0:
*v21 = 58;
break;
case 1:
*v21 = 38;
break;
case 2:
*v21 = 43;
break;
case 3:
*v21 = 42;
break;
case 4:
*v21 = 92;
break;
case 5:
*v21 = 63;
break;
case 6:
*v21 = 36;
break;
case 7:
*v21 = 35;
break;
default:
break;
}
}
else if ( *t <= 47 || *t > 57 ) // 不是数字
{
*v21 = *t;
}
else
{
v12 = encryption2(*t); // 是数字
*v21 = v12;
}
}
else // 小写字母
{
v7 = v19 % 4;
if ( v19 % 4 == 1 )
{
v9 = encryption2(*(_BYTE *)((*t - 97) * (v19 % 4) + v18));
*v21 = v9;
}
else if ( v7 > 1 )
{
if ( v7 == 2 )
{
v10 = encryption2(*(_BYTE *)(((*t - 97) ^ (v19 % 4)) + v18));
*v21 = v10;
}
else if ( v7 == 3 )
{
v11 = encryption2(*(_BYTE *)(*t - 97 + v19 % 4 + v18));
*v21 = v11;
}
}
else if ( !v7 )
{
v8 = encryption2(*(_BYTE *)(*t - 97 - v19 % 4 + v18));
*v21 = v8;
}
}
}
else // 大写字母
{
v1 = v19 % 4;
if ( v19 % 4 == 1 )
{
v3 = encryption2(*(_BYTE *)(*t - 65 + v19 % 4 + v17));
*v21 = v3;
}
else if ( v1 > 1 )
{
if ( v1 == 2 )
{
v4 = v19 * (*t - 65);
v5 = encryption2(*(_BYTE *)((((HIDWORD(v4) >> 30) + (unsigned __int8)v19 * (*t - 65)) & 3)
- (HIDWORD(v4) >> 30)
+ v17));
*v21 = v5;
}
else if ( v1 == 3 )
{
v6 = encryption2(*(_BYTE *)(((*t - 65) ^ (v19 % 4)) + v17));
*v21 = v6;
}
}
else if ( !v1 )
{
v2 = encryption2(*(_BYTE *)(*t - 65 - v19 % 4 + v17));
*v21 = v2;
}
}
++v19;
++t;
++v21;
}
}

GetFlag

于是现在加密算法有,数据有,我们直接爆破每个字符即可

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

char encFlag[] = "BRUF{E6oU9Ci#J9+6nWAhwMR9n:}";
char data1[] = "ckagevdxizblqnwtmsrpufyhoj";
char data2[] = "TMQZWKGOIAGLBYHPCRJSUXEVND";

__int64 encryption3(char a1)
{
unsigned __int8 v2; // [rsp+10h] [rbp+10h]

v2 = a1;
if ( a1 > 64 && a1 <= 70 || a1 > 96 && a1 <= 102 )
return (unsigned __int8)(a1 + 20);
if ( a1 > 84 && a1 <= 90 || a1 > 116 && a1 <= 122 )
return (unsigned __int8)(a1 - 20);
if ( a1 > 71 && a1 <= 77 || a1 > 103 && a1 <= 109 )
return (unsigned __int8)(a1 + 6);
if ( a1 > 77 && a1 <= 83 || a1 > 109 && a1 <= 115 )
return (unsigned __int8)(a1 - 6);
if ( a1 == 71 || a1 == 103 )
return (unsigned __int8)(a1 + 13);
if ( a1 == 84 || a1 == 116 )
return (unsigned __int8)(a1 - 13);
if ( a1 > 47 && a1 <= 57 )
v2 = 105 - a1;
return v2;
}

__int64 encryption2(char a1)
{
unsigned __int8 v2; // [rsp+30h] [rbp+10h]

v2 = a1;
if ( a1 > 64 && a1 <= 90 ) // 大写
return (unsigned __int8)encryption3(a1 + 32);
if ( a1 > 96 && a1 <= 122 ) // 小写
return (unsigned __int8)encryption3(a1 - 32);
if ( a1 > 47 && a1 <= 57 ) // 数字
v2 = encryption3(a1);
return v2;
}

int encryption(char input, int index)
{
int v1; // eax
char v2; // al
char v3; // al
__int64 v4; // kr00_8
char v5; // al
char v6; // al
int v7; // eax
char v8; // al
char v9; // al
char v10; // al
char v11; // al
char v12; // al
size_t count; // rbx
char v15[10]; // [rsp+20h] [rbp-60h] BYREF
int v16; // [rsp+414h] [rbp+394h]
int len; // [rsp+42Ch] [rbp+3ACh]
char t; // [rsp+430h] [rbp+3B0h]
char encBuff; // [rsp+438h] [rbp+3B8h]

t = input;
len = 0;
v16 = 1;
while ( 1 )
{
len = index;
if ( t <= 64 || t > 90 ) // 不是大写字母
{
if ( t <= 96 || t > 122 ) // 不是小写字母
{
if ( t == '_' ) // 特定字符
{
switch ( v16 + rand() % 7 ) // 伪随机可得
{
case 0:
encBuff = ':';
break;
case 1:
encBuff = '&';
break;
case 2:
encBuff = '+';
break;
case 3:
encBuff = '*';
break;
case 4:
encBuff = '\\';
break;
case 5:
encBuff = '?';
break;
case 6:
encBuff = '$';
break;
case 7:
encBuff = '#';
break;
default:
break;
}
}
else if ( t <= 47 || t > 57 ) // 不是数字
{
encBuff = t; // 不是字母也不是_也不是数字就直接赋值
}
else
{
v12 = encryption2(t); // 是数字
encBuff = v12;
}
}
else // 小写字母
{
v7 = len % 4; // 根据v7 0 1 2 3进行不同操作
if ( len % 4 == 1 )
{
v9 = encryption2(data1[(t - 97) * (len % 4)]);
encBuff = v9;
}
else if ( v7 > 1 )
{
if ( v7 == 2 )
{
v10 = encryption2(data1[(t - 97) ^ (len % 4)]);
encBuff = v10;
}
else if ( v7 == 3 )
{
v11 = encryption2(data1[t - 97 + len % 4]);
encBuff = v11;
}
}
else if ( !v7 )
{
v8 = encryption2(data1[t - 97 - len % 4]);
encBuff = v8;
}
}
}
else // 大写字母
{
v1 = len % 4; // 根据v1 0 1 2 3进行不同 操作
if ( len % 4 == 1 )
{
v3 = encryption2(data2[t - 65 + len % 4]);
encBuff = v3;
}
else if ( v1 > 1 )
{
if ( v1 == 2 )
{
v4 = len * (t - 65);
v5 = encryption2(data2[(((unsigned __int8)len * (t - 65)) & 3)]);
encBuff = v5;
}
else if ( v1 == 3 )
{
v6 = encryption2(data2[(t - 65) ^ (len % 4)]);
encBuff = v6;
}
}
else if ( !v1 )
{
v2 = encryption2(data2[t - 65 - len % 4]);
encBuff = v2;
}
}

return encBuff == encFlag[index];
}
}

int main(void)
{
char input[] = "BRUF{E6oU9Ci_J9_6nWAhwMR9n_}";
int i, j;
int count = 0;

for ( i = 0; i < strlen(input); i++ )
{
for ( j = 32; j <= 127; j++ )
{
input[i] = j;
if (encryption(j, i))
break;
}
printf("%c", input[i]);
}

return 0;
}

//flag{w3Lc0mE_t0_3NcrYPti0N:}

//BRUF{E6oU9Ci#J9+6nWAhwMR9n:}

GetFlag!

image-20220426144028537

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

This post is written by P.Z, licensed under CC BY-NC 4.0.