test1:speed

1,die查壳,发现无壳
2,运行exe,发现打开后迅速结束窗口
3,打开ida
ida
4,追踪WinMain函数,发现sleep(1u),设下断点
ida
5,动态调试
ida

test2:base

1,die查壳:无壳的PE64文件
2,虚拟机运行,发现需要填写flag
3,打开ida
4,Main函数:
ida
5,用cyberchef翻译base64
cyberchef

test3:catch

1,打开ida,查找可疑字符串
ida
2,发现字符串位数与moectf{}一致,怀疑是凯撒密码,解密后得到flag
decrypt

test4:upx

1,根据题目提示,die查壳
die
2,upx去壳
upx
3,打开ida,查找可能的字符串,最后发现核心加密在main函数
upx
4,分析函数,先寻找密文
upx
5,将密文重新组合后写出脚本

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
#include <bits/stdc++.h>
using namespace std;
int main()
{
unsigned char encrypt[]={
0x00000023, 0x0000002B, 0x00000027, 0x00000036,
0x00000033, 0x0000003C, 0x00000003, 0x00000048,
0x00000064, 0x0000000B, 0x0000001D, 0x00000076,
0x0000007B, 0x00000010, 0x0000000B, 0x0000003A,
0x0000003F, 0x00000065, 0x00000076, 0x00000029,
0x00000015, 0x00000037, 0x0000001C, 0x0000000A,
0x00000008, 0x00000021, 0x0000003E, 0x0000003C,
0x0000003D, 0x00000016, 0x0000000B, 0x00000024,
41,36,86
};//注意密文的顺序
unsigned char flag[]={};
flag[35]='\n';//根据提示,我们可以得知flag的最后一位是换行符
for(int i=34;i>=0;i--)
{
flag[i]=encrypt[i]^0x21^flag[i+1];
}
for(int i=0;i<=34;i++)
{
cout<<flag[i];
}
}

test5:ez3

1,打开ida,我们发现主函数前面的部分用来检测格式是否为moectf{}
2,然后将去除moectf{}的字符串传入check,进行加密,最后与密文比对
ez3
ez3
ez3
3,写出求解的Z3脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from z3 import *
enc=[0x0000B1B0, 0x00005678, 0x00007FF2, 0x0000A332, 0x0000A0E8, 0x0000364C, 0x00002BD4, 0x0000C8FE, 0x00004A7C, 0x00000018, 0x00002BE4, 0x00004144, 0x00003BA6, 0x0000BE8C, 0x00008F7E, 0x000035F8, 0x000061AA, 0x00002B4A, 0x00006828, 0x0000B39E, 0x0000B542, 0x000033EC, 0x0000C7D8, 0x0000448C, 0x00009310, 0x00008808, 0x0000ADD4, 0x00003CC2, 0x00000796, 0x0000C940, 0x00004E32, 0x00004E2E, 0x0000924A, 0x00005B5C]
flag=[BitVec(f'x{i}',64)for i in range(34)]
a =Solver()
for i in range(34):
a.add(flag[i]>=32)
a.add(flag[i]<=128)
part1=47806*(flag[i]+i)
if i>0:
part2=enc[i-1]^0x114514
part1=part1^part2
a.add(part1%51966==enc[i])
if a.check() == sat:
model = a.model()
result = ""
for i in range(34):

char_code = model[flag[i]].as_long()
result += chr(char_code)

print("Found Flag Content:", result)
print("Full Flag: moectf{" + result + "}")
else:
print("No solution found.")

test6:ezandroid

1,打开jadx,加载apk,进入主函数
2,发现是base64,直接cyberchef解密
ez3
ez3

test7:flower

1,打开ida,先查找可疑的字符串
flower
2,跳转过去,发现无法编译
flower
3,找到花指令,清除花指令
flower
flower
4,发现核心逻辑在solve函数,即flag[i]^key=enc[i]
flower
5,写出解密脚本,发现结果不对,怀疑是key出问题了,动态调试一下,发现有反调试,绕过
flower
6,获取key值
flower
7,写出真解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
int main()
{
int key=0x29;
unsigned int enc[100] = {
0x0000004F, 0x0000001A, 0x00000059, 0x0000001F, 0x0000005B, 0x0000001D, 0x0000005D, 0x0000006F,
0x0000007B, 0x00000047, 0x0000007E, 0x00000044, 0x0000006A, 0x00000007, 0x00000059, 0x00000067,
0x0000000E, 0x00000052, 0x00000008, 0x00000063, 0x0000005C, 0x0000001A, 0x00000052, 0x0000001F,
0x00000020, 0x0000007B, 0x00000021, 0x00000077, 0x00000070, 0x00000025, 0x00000074, 0x0000002B, };
char flag[33];
flag[32]='\0';
for(int i=0;i<32;i++)
{

flag[i]=enc[i]^key;
key++;
}
printf("%s",flag);
}

test8:2048_master_re

1,=,打开ida,查一下可疑字符串,我们发现这一条:
2048
2,点击进去查引用,我们发现这个函数:sub_401C83
2048
3,不难看出这个函数是用来最后检验的
4,点击进去,找到主验证逻辑:sub_401A81,然后找出最后要比对的密文
2048
2048
5,点进去,我们发现一共有三部分,最后需要的是加密完的block
2048
2048
2048
2048
6,我们发现这是xxtea加密,写出脚本,得到结果

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
#include <stdio.h>
#include <stdint.h>
int main()
{
char str[38];
str[38]='\0';
int n=10;
unsigned short enc[20] = {
0x7935, 0xCC77, 0x131B, 0x3441, 0xFFF9,
0x919F, 0x5BFF, 0x7894, 0x2A86, 0xAEAF,
0x9ED7, 0x4D31, 0xC47A, 0x51A5, 0xD9D1,
0x446E, 0x5218, 0x1B86, 0x8A42, 0x63C9,};
unsigned int block[10];
for(int i=0;i<10;i++)
block[i]=(enc[2*i+1]<<16)|enc[2*i];
char key[17]="2048master2048ma";
uint32_t *k = (uint32_t *)key;
int rounds = 52 /n + 6;
uint32_t delta = 0x3E9779B9 * rounds;

uint32_t sum = delta;
uint32_t y = block[0];

for (int i = 0; i < rounds; i++) {
uint32_t e = (sum >> 2) & 3;

for (int j = n - 1; j > 0; j--) {
uint32_t z = block[j - 1];
block[j] -= (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum ^ y) + (k[(j ^ e) & 3] ^ z));
y = block[j];
}

uint32_t z = block[n - 1];
block[0] -= (((z >> 5) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((sum ^ y) + (k[e] ^ z));
y = block[0];

sum -= 0x3E9779B9;
}
for (size_t i = 0; i < 37; i++) {
uint32_t dword = block[i >> 2];
str[i] = (dword >> (8 * (i & 3))) & 0xFF;
}
printf("%s",str);
}
1
moectf{@_N1c3_cup_0f_XXL_te4_1n_2O48}

test9:A cup of tea

1,查字符串,核心函数为sub_1400162E0和sub_14001109B
tea
tea
2,进入sub_14001109B,发现是一般的tea加密,写出求解脚本即可
tea

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
#include <stdio.h>
#include <stdint.h>
void decrypt(uint32_t *a,uint32_t *key)
{
uint32_t v4=*a;
uint32_t v5=a[1];
int delta=0x114514;
uint32_t sum=32*delta;
for ( int i = 0; i < 32; ++i )
{
v5 -= (key[3] + (v4 >> 5)) ^ (sum + v4) ^ (key[2] + 16 * v4);

v4 -= (key[1] + (v5 >> 5)) ^ (sum + v5) ^ (*key + 16 * v5);
sum -= 0x114514;
}
a[0]=v4;
a[1]=v5;
}
int main()
{
uint32_t key[4]={0x11451419,0x19810114,0x51419198,0x10114514};
uint32_t enc[11]={0x78C594AB,0x22813B59,0x472A3144,0xF255108A,0x45CFB34,0x3949EA0C,0xCB760968,0x1559C979,0xDEF9929D,0x71D1AAB,0};
for(int i=0;i<10;i=i+2)
{

decrypt(&enc[i],key);

}
printf("%s",(char*)enc);
}
1
moectf{h3r3_4_cuP_0f_734_f0R_y0U!!!!!!}

test10:ezpy

1,发现是pyc文件,去在线网站,获取原代码
ezpy
2,发现格式和凯撒密码相似,直接得到解
ezpy

test11:hava_fun

1,追踪核心函数,发现Func函数
fun
fun
2,发现是简单的异或,求解即可

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
unsigned short enc[16] = {
0x0047, 0x0045, 0x004F, 0x0049, 0x005E, 0x004C, 0x0051, 0x0062,
0x006A, 0x005C, 0x001E, 0x0075, 0x004C, 0x007F, 0x0044, 0x0057
};
for(int i=0;i<16;i++)
printf("%c",enc[i]^0x2A);
}
1
moectf{H@v4_fUn}

test11:mazegame

经典maze,找出地图,交给ai即可
maze

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
import collections

def solve_maze():
# 从 sub_1400010E0 提取的完整迷宫地图 (56行 x 56列)
# 1 = 墙, 0 = 路
maze_data = [
"11111111111111111111111111111111111111111111111111111111", # Row 0
"10100000000000000010000011011101011111111101011100000111", # Row 1 (Start at idx 1)
"10111010111111111010111011000001000001000001000101110111", # Row 2
"10000010000010000010001011011111111101110111011101110111", # Row 3
"10111111111011101110111011010000000000010100010001110111", # Row 4
"10100000001000101000100011010101111111011101110101110111", # Row 5
"10101011111110111011101011010101000001000000010101110111", # Row 6
"10101010000010100000101011110101110101111101111111110111", # Row 7
"10111010111010101111101011100101000100000101000101110111", # Row 8
"10000010001010001000001011001111011111010101011101110111", # Row 9
"11111011101011111011111111101000100000101100101001110111", # Row 10
"10001010001000100010000010001010011000100010010011000001", # Row 11
"10111010111110101010111011011001011111010101011101011101", # Row 12
"10001010001000001010001011000101000100000101000101011101", # Row 13
"11101011101111111011101011110101110111111101110101011101", # Row 14
"10001000101000001010001011000100010100000101000101011101", # Row 15 (Target Y=15, X=32)
"10111111101011101110111011011111110101110111011101011101",
"10001000001000100000001011000100000100010000000101011001",
"11101011111011111111101011110101111101111111110101011011",
"10101000000010001000101011010100000001000100010101011011",
"10101111111110101010101011010111111111010101010101011011",
"10100000000000100010101011010000000000010001010101011011",
"10111111111111111110111011011111111111111111011101011011",
"10000000001111000000000011110111010000111100011111011011",
"11101111100000011011011111111010110111011101100001011011",
"11101111111111111011011111111101110111101101100001011011",
"10001000111111000010000011111010110111011101100001011011",
"10111010111111111010111011110111010000111101100001010011",
"10000010000010000010001011111111111111111101100001010111",
"10111111111011101110111011110001000110001101100001010001",
"10100000001000101000100011110111011101111101100001011101",
"10101011111110111011101011110001000101111101100001011101",
"10101010000010100000101011111101011101111101100001011101",
"10111010111010101111101011110001000110001101100001011101",
"10000010001010101000001011111111111111111101100001011101",
"11111011101011111011111110000000000000001101100001011101",
"10001010001000100010000011111111111111111100110011011101",
"10111010111110101010111010010000000011111110001111011101",
"10001010001000001010001010110111000001111110100101011101",
"11101011101111111011101000110011001111111100110111011101",
"10001000101000001010001011111111111111111111110111010001",
"10111111101011101110111010100001001100000000000011011011",
"10001000001000100000001011111111111101011101111001011011",
"10101011111011111111101011000000000001000100010111011011",
"10101000000010001000101010010111111111111111111111011011",
"10101111111110101010101010110111111111111111111101011011",
"10100000000000100010101011100000000000000000000011011011",
"10111111111111111110011011111111111111111111111011011011",
"10000011111111111111000010000000000000000000000000011001",
"11111011111111111111111111111111111111111111111111111101",
"11111011100001100110110111000000000000000000000111111101",
"11111011101111011010000111011111111111111111110111111101",
"11111011100001000010110110000111111111111111110000000001",
"11111011101111011010110111101111111111111111111111111111",
"11110000000000011000110000000000000000000000000000000011",
"11111111111111111111111111111111111111111111111111111111" # Row 55
]

# 验证地图大小
height = len(maze_data)
width = len(maze_data[0])
# print(f"Map Size: {width}x{height}")

# 配置参数
start_x, start_y = 1, 1
# main 函数中 if ( n0x37 == 15 && n32 == 32 ) break;
# n0x37 是 Y 坐标, n32 是 X 坐标
target_x, target_y = 32, 15

# 广度优先搜索 (BFS)
# 队列存储 (x, y, path)
queue = collections.deque([(start_x, start_y, "")])
visited = set()
visited.add((start_x, start_y))

# 方向映射
directions = [
(0, -1, 'w'), # 上
(0, 1, 's'), # 下
(-1, 0, 'a'), # 左
(1, 0, 'd') # 右
]

print("[*] 开始寻找路径...")

while queue:
cx, cy, path = queue.popleft()

# 到达终点检查
if cx == target_x and cy == target_y:
print(f"\n[+] 成功找到路径!")
print(f"[+] 路径长度: {len(path)}")
print(f"[+] Flag: moectf{{{path}}}")
return

# 遍历四个方向
for dx, dy, move in directions:
nx, ny = cx + dx, cy + dy

# 边界检查
if 0 <= nx < width and 0 <= ny < height:
# 墙壁检查 (字符 '1' 是墙)
if maze_data[ny][nx] == '0':
if (nx, ny) not in visited:
visited.add((nx, ny))
queue.append((nx, ny, path + move))

print("[-] 未找到路径,请检查逻辑。")

if __name__ == "__main__":
solve_maze()
1
moectf{ssddddwwddssddddssddssssddwwddwwddwwwwddddssssaassssaaaassaassaawwaawwwwaaaassddssaassddssssaaaassddddddwwwwddddssddddwwddwwaawwddddssssssssssssaaasssdddssssaassssaaaassaassaawwaawwwwaaaassddssaassddssssaaaassddddddwwwwddddssddddwwddwwaawwddddssssssssssssaaawawwwaassaawwaassaaaaaaaaaawwwwaassssssddddssssssdddddddddwwdddssddwwwdddsssdddddwwawwddddddddddddddddddddssddddddddwwwwawwwwwwwwdwwwwwwwwwwwaawwdwwwwwwwwwwdwwwwwwaaaasssssssssssssssssssssssssssssssssssssaaawwaaaaaaaaaaaaaaaaaaawwwddddddddwwddddddddddwwwawaawawwwwwwwwwwwwwddwwwwaassaawwaassaaaaaaaaaawwwwaawwddwwaawwdwwwdwwwwddddddddddssddddssssdsdssddssaassaaaawwaaaassssaaaaaawwddddwwwwaawwawaassdsssdd}

test12:upx_revenge

1,查了一圈,发现是UPX!被删了,加上就可以正常upx -d脱壳了
upx2
upx2
2,进入ida,发现密密麻麻的写了很多,不过看到类似于base64的密文,用一般密文表解密发现是乱码
upx2
3,找到被加密的base64字母表,bloc异或了一个0xE,可以通过动调取得block
upx2
upx2
4,可以通过给密文异或的方式来代替给字母表异或

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <string.h>
int main()
{
char enc[]="lY7bW=\\ck?eyjX7]TZ\\}CVbh\\tOyTH6>jH7XmFifG]H7";
for(int i=0;i<strlen(enc);i++)
{
printf("%c",enc[i]^0xe);
}
}
1
bW9lY3Rme1kwdV9SZTRsMXlfRzAwZF80dF9VcHghISF9

5,正常解码即可
upx2

test13:guess

1,直接反编译发现失败,可以看见是花指令,全nop就可以了
guess
guess
guess
2,发现其实就是随机生成一个数,比对正确后就输出flag
3,下个断点获取数,输出即可
guess
guess
guess

test14:A simple program

1,进入ida,发现直接有个flag,不过是错的
simple
2,查str2的调用,发现还有一个加密,写出脚本即可
simple
simple

1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main()
{
unsigned char flag[20] = {0x4E, 0x4C, 0x46, 0x40, 0x57, 0x45, 0x58, 0x7A, 0x13, 0x56, 0x7C, 0x73, 0x17, 0x50, 0x50, 0x66, 0x47, 0x02, 0x02, 0x5E, };

for(int i=0;i<20;i++){
printf("%c",flag[i]^0x23);
}
}
1
moectf{Y0u_P4ssEd!!}

test15:Two cups of tea

1,两个tea加密,第一个可以直接动调获得结果
tea2
tea2
tea2
tea2
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
27
28
29
30
31
32
33
#include <stdio.h>
#include <stdint.h>
void decrypt(uint32_t *flag,uint32_t* key)
{
uint32_t sum=11*(-1640531527);
for (int r=0;r<11;r++)
{
uint32_t k0 = key[((sum >> 2) & 3)];
uint32_t k1 = key[((sum >> 2) & 3) ^ 1];
uint32_t k2 = key[((sum >> 2) & 3) ^ 2];
uint32_t k3 = key[((sum >> 2) & 3) ^ 3];
flag[9] -= ((flag[8] ^ k1) + (sum ^ flag[0])) ^ (((16 * flag[8]) ^ (flag[0] >> 3)) + ((flag[8] >> 5) ^ (4 * flag[0])));
flag[8] -= ((flag[7] ^ k0) + (sum ^ flag[9])) ^ (((16 * flag[7]) ^ (flag[9] >> 3)) + ((flag[7] >> 5) ^ (4 * flag[9])));
flag[7] -= ((flag[6] ^ k3) + (sum ^ flag[8])) ^ (((16 * flag[6]) ^ (flag[8] >> 3)) + ((flag[6] >> 5) ^ (4 * flag[8])));
flag[6] -= ((flag[5] ^ k2) + (sum ^ flag[7])) ^ (((16 * flag[5]) ^ (flag[7] >> 3)) + ((flag[5] >> 5) ^ (4 * flag[7])));
flag[5] -= ((flag[4] ^ k1) + (sum ^ flag[6])) ^ (((16 * flag[4]) ^ (flag[6] >> 3)) + ((flag[4] >> 5) ^ (4 * flag[6])));
flag[4] -= ((flag[3] ^ k0) + (sum ^ flag[5])) ^ (((16 * flag[3]) ^ (flag[5] >> 3)) + ((flag[3] >> 5) ^ (4 * flag[5])));
flag[3] -= ((flag[2] ^ k3) + (sum ^ flag[4])) ^ (((16 * flag[2]) ^ (flag[4] >> 3)) + ((flag[2] >> 5) ^ (4 * flag[4])));
flag[2] -= ((flag[1] ^ k2) + (sum ^ flag[3])) ^ (((16 * flag[1]) ^ (flag[3] >> 3)) + ((flag[1] >> 5) ^ (4 * flag[3])));
flag[1] -= ((flag[0] ^ k1) + (sum ^ flag[2])) ^ (((16 * flag[0]) ^ (flag[2] >> 3)) + ((flag[0] >> 5) ^ (4 * flag[2])));
flag[0] -= ((flag[9] ^ k0) + (sum ^ flag[1])) ^ (((16 * flag[9]) ^ (flag[1] >> 3)) + ((flag[9] >> 5) ^ (4 * flag[1])));
sum+=1640531527;
}
}
int main() {
uint32_t enc[11] = {0x5D624C34, 0x8629FEAD, 0x9D11379B, 0xFCD53211,0x460F63CE, 0xC5816E68, 0xFE5300AD, 0x0A0015EE,0x9806DBBB, 0xEF4A2648,0};
uint32_t key[4] = {0x63656F6D, 0x21216674, 0x12345678, 0x9ABCDEF0};
decrypt(enc, key);
printf("%s", enc);


}

1
moectf{X7e4_And_xx7EA_I5_BeautifuL!!!!!}

test16:ezandroid.pro

1,jadx打开,看主函数,发现核心是so文件的check函数
ezandroid_pro
2,解压,在ida中打开so文件,进入check函数,注意到其中有SM4,怀疑是SM4加密
ezandroid_pro
3,发现没有传入IV,怀疑是ECB,直接cyberchef一把梭
ezandroid_pro

test17:rusty_sudoku

1,rust语言写出来的数独,直接字符串查找+在线工具求解后输入即可
rusty_sudoku
rusty_sudoku
rusty_sudoku