红帽杯

[2019红帽杯]Snake

ACTF新生赛

[ACTF新生赛2020]easyre

  • upx -d脱壳

alt text

  • IDA打开发现只有一个简单的加密,加密后为v4,即*F'\"N,\"(I?+@

alt text
alt text

  • shift+E提取数据,编写python解密
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
v4 = "*F'\"N,\"(I?+@"
__data_start__ = [
126, 125, 124, 123, 122, 121, 120, 119, 118, 117,
116, 115, 114, 113, 112, 111, 110, 109, 108, 107,
106, 105, 104, 103, 102, 101, 100, 99, 98, 97,
96, 95, 94, 93, 92, 91, 90, 89, 88, 87,
86, 85, 84, 83, 82, 81, 80, 79, 78, 77,
76, 75, 74, 73, 72, 71, 70, 69, 68, 67,
66, 65, 64, 63, 62, 61, 60, 59, 58, 57,
56, 55, 54, 53, 52, 51, 50, 49, 48, 47,
46, 45, 44, 43, 42, 41, 40, 39, 38, 37,
36, 35, 32, 33, 34, 0
]

for i in range(len(v4)):
for j in range(len(__data_start__)):
if v4[i] == chr(__data_start__[j]):
print(chr(j + 1), end='')

[ACTF新生赛2020]Oruga

迷宫题,与常规迷宫有点不一样

alt text

  • 迷宫,终点 !,迷宫在byte_201020

alt text

  • byte_201020[]shift+E提取迷宫,变为迷宫,指定行、列
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
unsigned char ida_chars_byte_201020[] =
{
0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x23, 0x23, 0x23, 0x23, 0x00, 0x00, 0x00, 0x23,
0x23, 0x00, 0x00, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4F, 0x4F, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x4F, 0x4F, 0x00, 0x50,
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x4F,
0x4F, 0x00, 0x4F, 0x4F, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x4C, 0x4C, 0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00,
0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x4F, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00,
0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4D, 0x4D, 0x4D, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x4D, 0x4D,
0x00, 0x00, 0x00, 0x00, 0x45, 0x45, 0x00, 0x00, 0x00, 0x30,
0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00,
0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x45, 0x54, 0x54,
0x54, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00,
0x00, 0x00, 0x45, 0x00, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4D,
0x00, 0x4D, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
0x00, 0x54, 0x00, 0x49, 0x00, 0x4D, 0x00, 0x4D, 0x00, 0x4D,
0x21, 0x00, 0x00, 0x00, 0x45, 0x45
};
# maze_str_to_list
maze_str = (" # #### ## OO OO PP L OO OO PP L OO OO P LL OO P OO P # # MMM # MMM EE 0 M M M E EETTTI M M M E T I M M M E T I M M M! EE")
print(len(maze_str))
index = 0
row = 16
col = 16
maze = []
for i in range(row):
tmp = []
for j in range(col):
tmp.append(maze_str[index])
index += 1
maze.append(tmp)
print(maze)

# 256
# [
# [' ', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', '#', '#', '#'],
# [' ', ' ', ' ', '#', '#', ' ', ' ', ' ', 'O', 'O', ' ', ' ', ' ', ' ', ' ', ' '],
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'O', 'O', ' ', 'P', 'P', ' ', ' ', ' '],
# [' ', ' ', ' ', 'L', ' ', 'O', 'O', ' ', 'O', 'O', ' ', 'P', 'P', ' ', ' ', ' '],
# [' ', ' ', ' ', 'L', ' ', 'O', 'O', ' ', 'O', 'O', ' ', 'P', ' ', ' ', ' ', ' '],
# [' ', ' ', 'L', 'L', ' ', 'O', 'O', ' ', ' ', ' ', ' ', 'P', ' ', ' ', ' ', ' '],
# [' ', ' ', ' ', ' ', ' ', 'O', 'O', ' ', ' ', ' ', ' ', 'P', ' ', ' ', ' ', ' '],
# ['#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', ' ', ' ', ' '],
# [' ', ' ', ' ', ' ', ' ', ' ', 'M', 'M', 'M', ' ', ' ', ' ', '#', ' ', ' ', ' '],
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', 'M', 'M', 'M', ' ', ' ', ' ', ' ', 'E', 'E'],
# [' ', ' ', ' ', '0', ' ', 'M', ' ', 'M', ' ', 'M', ' ', ' ', ' ', ' ', 'E', ' '],
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'E', 'E'],
# ['T', 'T', 'T', 'I', ' ', 'M', ' ', 'M', ' ', 'M', ' ', ' ', ' ', ' ', 'E', ' '],
# [' ', 'T', ' ', 'I', ' ', 'M', ' ', 'M', ' ', 'M', ' ', ' ', ' ', ' ', 'E', ' '],
# [' ', 'T', ' ', 'I', ' ', 'M', ' ', 'M', ' ', 'M', '!', ' ', ' ', ' ', 'E', 'E']

# ]
# 起点' '00) ,终点'!'15,10
  • 同一障碍为#以便后续脚本,当后来发现这不是通常的迷宫,用bfs算法走的路径是错的,关键在v2 += v4这表示一直移动,所以移动应该是按下面图片来走
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
maze_str = ("    #       ####   ##   OO              OO PP      L OO OO PP      L OO OO P      LL OO    P         OO    P    #                           #         MMM   #          MMM    EE   0 M M M    E               EETTTI M M M    E  T I M M M    E  T I M M M!   EE")
print(len(maze_str))
index = 0
row = 16
col = 16
maze = []
for i in range(row):
tmp = []
for j in range(col):
if maze_str[index] == '!' or maze_str[index] == ' ':
tmp.append(maze_str[index])
else:
tmp.append('#')
index += 1
maze.append(tmp)
print(maze)
# 256
# [
# [' ', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', '#', '#', '#'],
# [' ', ' ', ' ', '#', '#', ' ', ' ', ' ', '#', '#', ' ', ' ', ' ', ' ', ' ', ' '],
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', '#', ' ', '#', '#', ' ', ' ', ' '],
# [' ', ' ', ' ', '#', ' ', '#', '#', ' ', '#', '#', ' ', '#', '#', ' ', ' ', ' '],
# [' ', ' ', ' ', '#', ' ', '#', '#', ' ', '#', '#', ' ', '#', ' ', ' ', ' ', ' '],
# [' ', ' ', '#', '#', ' ', '#', '#', ' ', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' '],
# [' ', ' ', ' ', ' ', ' ', '#', '#', ' ', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' '],
# ['#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', ' ', ' ', ' '],
# [' ', ' ', ' ', ' ', ' ', ' ', '#', '#', '#', ' ', ' ', ' ', '#', ' ', ' ', ' '],
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', '#', '#', ' ', ' ', ' ', ' ', '#', '#'],
# [' ', ' ', ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', ' ', ' ', ' ', '#', ' '],
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', '#'],
# ['#', '#', '#', '#', ' ', '#', ' ', '#', ' ', '#', ' ', ' ', ' ', ' ', '#', ' '],
# [' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', ' ', ' ', ' ', '#', ' '],
# [' ', '#', ' ', '#', ' ', '#', ' ', '#', ' ', '#', '!', ' ', ' ', ' ', '#', '#']
# ]

向下移动:M

向左移动:J

向上移动:E

向右移动:W

flag{MEWEMEWJMEWJM}

  • 找的网图大概这样走

alt text

[ACTF新生赛2020]Universe_final_answer

  • 64位,无壳,IDA打开

alt text

  • 用z3处理,根据图中,v1和v2,v6和v7要交换一下
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
from z3 import *

s = Solver()
v1 = Int('v2') # 交换
v2 = Int('v1')
v3 = Int('v3')
v4 = Int('v4')
v5 = Int('v5')
v6 = Int('v7') # 交换
v7 = Int('v6')
v8 = Int('v8')
v9 = Int('v9')
v11 = Int('v11')

s.add(-85 * v9 + 58 * v8 + 97 * v6 + v7 + -45 * v5 + 84 * v4 + 95 * v2 - 20 * v1 + 12 * v3 == 12613)
s.add(30 * v11 + -70 * v9 + -122 * v6 + -81 * v7 + -66 * v5 + -115 * v4 + -41 * v3 + -86 * v1 - 15 * v2 - 30 * v8 == -54400)
s.add(-103 * v11 + 120 * v8 + 108 * v7 + 48 * v4 + -89 * v3 + 78 * v1 - 41 * v2 + 31 * v5 - (v6 * 64) - 120 * v9 == -10283)
s.add(71 * v6 + (v7 * 128) + 99 * v5 + -111 * v3 + 85 * v1 + 79 * v2 - 30 * v4 - 119 * v8 + 48 * v9 - 16 * v11 == 22855)
s.add(5 * v11 + 23 * v9 + 122 * v8 + -19 * v6 + 99 * v7 + -117 * v5 + -69 * v3 + 22 * v1 - 98 * v2 + 10 * v4 == -2944)
s.add(-54 * v11 + -23 * v8 + -82 * v3 + -85 * v2 + 124 * v1 - 11 * v4 - 8 * v5 - 60 * v7 + 95 * v6 + 100 * v9 == -2222)
s.add(-83 * v11 + -111 * v7 + -57 * v2 + 41 * v1 + 73 * v3 - 18 * v4 + 26 * v5 + 16 * v6 + 77 * v8 - 63 * v9 == -13258)
s.add(81 * v11 + -48 * v9 + 66 * v8 + -104 * v6 + -121 * v7 + 95 * v5 + 85 * v4 + 60 * v3 + -85 * v2 + 80 * v1 == -1559)
s.add(101 * v11 + -85 * v9 + 7 * v6 + 117 * v7 + -83 * v5 + -101 * v4 + 90 * v3 + -28 * v1 + 18 * v2 - v8 == 6308)
s.add(99 * v11 + -28 * v9 + 5 * v8 + 93 * v6 + -18 * v7 + -127 * v5 + 6 * v4 + -9 * v3 + -93 * v1 + 58 * v2 == -1697)

if s.check() == sat:
result = s.model()

print(result)
# [v1 = 70,
# v2 = 48,
# v4 = 82,
# v11 = 64,
# v3 = 117,
# v5 = 84,
# v7 = 95,
# v9 = 119,
# v8 = 55,
# v6 = 121]
flag = [
70, 48, 117, 82, 84, 121, 95, 55, 119, 64
]
for c in flag:
print(chr(c), end='')
# F0uRTy_7w@

  • 还有一步sub_C50,再运行程序输入F0uRTy_7w@,得到F0uRTy_7w@_42

alt text

1
flag{F0uRTy_7w@_42}

[ACTF新生赛2020]SoulLike

sub_83A显示不出来问题解决方法:找到ida目录中的cfg/hexrays.cfg文件,将其中MAX_FUNCSIZE = 64修改为1024

image-20250216203738791

进行了3000多行的异或操作,然后用异或结果与v3进行对比

image-20250216205842849

flag{b0Nf|Re_LiT!}

找到的三种方法

exp1:暴力破解

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 <bits/stdc++.h>
using namespace std;
int v3[] = {126, 50, 37, 88, 89, 107, 53, 110, 0, 19, 30, 56};
int a1[20], flag[20];
inline void sub_83A(int *a1) {
*a1 ^= 0x2Bu;
a1[1] ^= 0x6Cu;
a1[2] ^= 0x7Eu;
a1[3] ^= 0x56u;
a1[4] ^= 0x39u;
a1[5] ^= 3u;
a1[6] ^= 0x2Du;
a1[7] ^= 0x28u;
a1[8] ^= 8u;
++a1[9];
...... //太长了这里就不放了,其实就是把IDA里的异或部分全部复制粘贴下来
}
int main() {
for (int i = 0; i < 12; i++) {
for (int j = 0; j <= 126; j++) {
for (int k = 0; k < i; k++) a1[k] = flag[k];
a1[i] = j;
sub_83A(a1);
if (a1[i] == v3[i]) {
flag[i] = j;
break;
}
}
}
for (int i = 0; i < 12; i++) cout << (char)flag[i];
return 0;
}

exp2:使用pwntool暴力破解,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
flag = "actf{"
k = 0
for n in range(12):
for i in range(33,127):
p = process('./SoulLike')
_flag = flag + chr(i) # _flag(临时flag) = "actf{" + chr(i)
print(_flag)
p.sendline(_flag) # 发送临时flag
s = p.recvline().decode() # 接收回显

if "on #" in s: # 如果回显中有"on #"
r = int(s.split("on #")[1].split("\n")[0]) # 先按换行符"\n"分割取前面的,再按"on #"分割去后面部分,如"wrong on # 34\n try again\n",则取到"34"
if r == k+1:
print(s)
flag += chr(i) # 更新flag
k += 1
p.close()
print(flag)

image-20250216230202330

exp3: 使用angr

angr_ctf——从0学习angr(一):angr简介与核心概念 - Uiharu - 博客园

1
2
3
4
5
6
7
8
9
10
11
12
13
import angr
base_addr=0x400000
p=angr.Project("SoulLike",auto_load_libs=False,main_opts={"base_addr":base_addr})

init_state=p.factory.entry_state()
sm=p.factory.simgr(init_state)
sm.explore(find=base_addr+0x1117d)
if sm.found:
found_state=sm.found[0]
found_state.posix.dumps(0)
print("success")
else:
raise Exception("no")

虽然一开始都处理,但现在这三种方法都弄懂了,还是收获满满的

[ACTF新生赛2020]fungame

image-20250216231222662

一个简单的异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
y1 = [
0x23, 0x61, 0x3E, 0x69, 0x54, 0x41, 0x18, 0x4D, 0x6E, 0x3B,
0x65, 0x53, 0x30, 0x79, 0x45, 0x5B, 0x71
]
y2 = [
0x71, 0x04, 0x61, 0x58, 0x27, 0x1E, 0x4B, 0x22, 0x5E, 0x64,
0x03, 0x26, 0x5E, 0x17, 0x3C, 0x7A, 0xFF
]
a1 = ''
for i in range(16):
a1 += chr(y2[i] ^ y1[i])

print(a1, end='')
# Re_1s_So0_funny!

提交然后发现不对,结合在字符串表里看到的please input angin:base64表,因为运行程序提示输入的是please input,且输错就退出了,所以查看一下please input angin:所在地方

image-20250216233058059

image-20250216232654497

但还是有问题,最后经人提醒才知道,还考了栈溢出的知识,也就是a1s0_pWn的提示

Destination[12]长度只有12,而第一部分长度位16,也就是说溢出了4,刚好把栈底填满(32位程序),返回地址传入了_X的地址

image-20250216233500622

传入的地址为40233D,即为ret返回的地址

  • 验证
1
2
3
4
5
6
7
flag = 'flag{Re_1s_So0_funny!'
flag += chr(0x3D)
flag += chr(0x23)
flag += chr(0x40)
flag += 'a1s0_pWn}'
print(flag)
# flag{Re_1s_So0_funny!=#@a1s0_pWn}

BJDCTF

[BJDCTF2020]BJD-hamburger-competition

WP

  • 第一次做的Unity3D题目,抽象的老八秘制小汉堡游戏

alt text

1
2
3
4
5
6
Unity3D是由Unity Technologies开发的一个让玩家轻松创建互动内容的多平台的综合型游戏开发工具,
Unity3D是用C#开发的,
C#的反汇编工具为dnspy,但是把哪个东西丢进去呢?

unity在打包玩程序后,会将所有的代码打进一个Assembly-CSharp.dll的文件里面,
通过这个文件的反编译,就能详细看见里面的代码内容。(这个文件在Managed目录下)

alt text

  • 意思是sha1str加密结果为图中那一串,再用strMD5的前20位作为flag

alt text

  • 所以在线sha1解密,在MD5加密就行

alt text

alt text

1
B8C37E33DEFDE51CF91E1E03E51657DA

取前20个

1
flag{B8C37E33DEFDE51CF91E}

MRCTF

[MRCTF2020]hello_world_go

  • 应该是个签到题,IDA打开就是flag

alt text

[MRCTF2020]PixelShooter

  • unity游戏逆向还得是dnspy

alt text

alt text

[MRCTF2020]Transform

alt text

  • 64位,无壳

alt text

  • 不懂,搜的,但对解题没影响,因为提取的数据(data)都小于2^8^=128
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
对于 LOBYTE(9),我们首先需要理解 LOBYTE 宏的作用:它提取一个 16 位数的低 8 位部分。

LOBYTE(w) 宏通常是这样定义的:

#define LOBYTE(w) ((unsigned char)(w & 0xFF))
分析
给定输入值 9

9 的二进制表示是 0000 0000 0000 1001 (16 位的二进制表示),在低字节中,我们看到它的低 8 位是 0000 1001,即 9

执行 LOBYTE(9):

9 的二进制表示 0000 1001,低 8 位是 0000 1001,它的值为 9
结论
LOBYTE(9) 的结果是 9

  • 脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
data = [
103, 121, 123, 127, 117, 43, 60, 82, 83, 121,
87, 94, 93, 66, 123, 45, 42, 102, 66, 126,
76, 87, 121, 65, 107, 126, 101, 60, 92, 69,
111, 98, 77
]

index = [9, 10, 15, 23, 7, 24, 12, 6, 1, 16, 3, 17, 32, 29, 11, 30, 27,
22, 4, 13, 19, 20, 21, 2, 25, 5, 31, 8, 18, 26, 28, 14, 0, ]
# print(len(data))
# print(len(index))
flag = [0] * 33
for i in range(len(data)):
flag[index[i]] = chr(data[i] ^ index[i])
print(''.join(flag))
# MRCTF{Tr4nsp0sltiON_Clph3r_1s_3z}

GWCTF

HDCTF

WUSTCTF

[WUSTCTF2020]Cr0ssfun

  • 查壳,无

alt text

  • 单纯的套娃拼接,直接让kimi帮我提取了
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
_BOOL8 __fastcall iven_is_handsome(_BYTE *a1)
{
return a1[10] == 112
&& a1[13] == 64
&& a1[3] == 102
&& a1[26] == 114
&& a1[20] == 101
&& (unsigned int)iven_is_c0ol(a1);
}

_BOOL8 __fastcall iven_is_c0ol(_BYTE *a1)
{
return a1[7] == 48
&& a1[16] == 95
&& a1[11] == 112
&& a1[23] == 101
&& a1[30] == 117
&& (unsigned int)iven_1s_educated(a1);
}

_BOOL8 __fastcall iven_1s_educated(_BYTE *a1)
{
return *a1 == 119 && a1[6] == 50 && a1[22] == 115 && a1[31] == 110 && a1[12] == 95 && (unsigned int)iven_1s_brave(a1);
}

_BOOL8 __fastcall iven_1s_brave(_BYTE *a1)
{
return a1[15] == 100
&& a1[8] == 123
&& a1[18] == 51
&& a1[28] == 95
&& a1[21] == 114
&& (unsigned int)iven_1s_great(a1);
}

_BOOL8 __fastcall iven_1s_great(_BYTE *a1)
{
return a1[2] == 116
&& a1[9] == 99
&& a1[32] == 125
&& a1[19] == 118
&& a1[5] == 48
&& a1[14] == 110
&& (unsigned int)iven_and_grace(a1);
}

_BOOL8 __fastcall iven_and_grace(_BYTE *a1)
{
return a1[4] == 50 && a1[17] == 114 && a1[29] == 102 && a1[17] == 114 && a1[24] == 95 && (unsigned int)finally_fun(a1);
}

_BOOL8 __fastcall finally_fun(_BYTE *a1)
{
return a1[1] == 99 && a1[25] == 64 && a1[27] == 101;
}

a1[10] == 112
a1[13] == 64
a1[3] == 102
a1[26] == 114
a1[20] == 101
a1[7] == 48
a1[16] == 95
a1[11] == 112
a1[23] == 101
a1[30] == 117
a1[15] == 100
a1[8] == 123
a1[18] == 51
a1[28] == 95
a1[21] == 114
a1[2] == 116
a1[9] == 99
a1[32] == 125
a1[19] == 118
a1[5] == 48
a1[14] == 110
a1[4] == 50
a1[17] == 114
a1[29] == 102
a1[17] == 114
a1[24] == 95
a1[1] == 99
a1[25] == 64
a1[27] == 101

alt text

  • 最后用flag{}包裹
1
2
# cctf2000{cpp_@nd_r3verse_@re_fun}
# flag{cpp_@nd_r3verse_@re_fun}

[WUSTCTF2020]level2

  • UPX加壳了

alt text

  • upx -d去壳
alt text

alt text

[WUSTCTF2020]level3

alt text

  • 明示是Base64加密,shift+F12找到密文,用赛博厨子解密了一下,不对
    alt text
    alt text
  • 查看Base64表,按 X 查看表的引用,果然不对劲,发现有对表的操作
    alt text
    alt text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
base64_table = [
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64,
0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x2B, 0x2F, 0x00
]

for i in range(0, 10):
v1 = base64_table[i]
base64_table[i] = base64_table[19 - i]
result = 19 - i
base64_table[result] = v1

for i in base64_table
print(''.join(chr(i)), end='')

# TSRQPONMLKJIHGFEDCBAUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
  • 换表,赛博厨子解一下
1
wctf2020{Base64_is_the_start_of_reverse}

alt text

  • 之前看到的一个wp里的脚本,挺有意思的,直接本地换表(映射)解密,在这贴一下
1
2
3
4
5
6
7
8
9
10
11
12
import base64 #导入base64模块用于解密
s1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' #标准表
s2 = 'qvEJAfHmUYjBac+u8Ph5n9Od17FrICL/X0gVtM4Qk6T2z3wNSsyoebilxWKGZpRD' #base64换表
en_text = '5Mc58bPHLiAx7J8ocJIlaVUxaJvMcoYMaoPMaOfg15c475tscHfM/8==' #密文

map = str.maketrans(s2, s1) #用str类中的maketrans建立映射,注意第一个参数是需要映射的字符串,第二个参数是映射的目标
map_text = en_text.translate(map) #映射实现替换密文,替换前是base64换表加密,替换后则是base64标准表加密
print(map_text) #可以先看看标准表加密的密文
print(base64.b64decode(map_text)) #直接使用提供的base64解密函数,获得明文,就是flag

# TlNTQ1RGe2E4ZDQzNDc3MjI4MDBlNzJlMzRlMWFiYTNmZTkxNGFlfQ==
# b'NSSCTF{a8d4347722800e72e34e1aba3fe914ae}'

exp:

1
2
3
4
5
6
7
8
import base64
en_base64 = 'd2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD=='
de_base64 = ''
old_base64_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
new_base64_table = 'TSRQPONMLKJIHGFEDCBAUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

print((base64.b64decode((en_base64.translate(str.maketrans(new_base64_table, old_base64_table))).encode())).decode())
# wctf2020{Base64_is_the_start_of_reverse}

[WUSTCTF2020]level4

  • 64位,无壳

alt text

alt text

  • 一眼没看出来,仔细看了才知道,Date Structure考了个数据结构

  • 二叉树中序遍历

1
2
3
4
5
6
7
8
9
10
11
12
__int64 __fastcall type1(char *a1)
{
__int64 result; // rax

if ( a1 )
{
type1(*((_QWORD *)a1 + 1));
putchar(*a1);
return type1(*((_QWORD *)a1 + 2));
}
return result;
}
  • 二叉树后序遍历
1
2
3
4
5
6
7
8
9
10
11
12
int __fastcall type2(char *a1)
{
int result; // eax

if ( a1 )
{
type2(*((_QWORD *)a1 + 1));
type2(*((_QWORD *)a1 + 2));
return putchar(*a1);
}
return result;
}
  • 程序运行的结果
1
2
Traversal type 1:2f0t02T{hcsiI_SwA__r7Ee}
Traversal type 2:20f0Th{2tsIS_icArE}e7__w
  • 已知后序中序输出前序
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
def build_tree(post, mid):
# 如果没有元素,返回空树
if not post or not mid:
return None

root_val = post[-1] # 后序遍历的最后一个元素是当前树的根节点
root_index = mid.index(root_val) # 找到根节点在中序遍历中的位置
root = {'val': root_val, 'left': None, 'right': None} # 创建树的根节点
root['left'] = build_tree(post[:root_index], mid[:root_index]) # 递归构建左子树
root['right'] = build_tree(post[root_index:-1], mid[root_index + 1:]) # 递归构建右子树
return root

def preorder_traversal(root):
# 如果树为空,返回空列表
if root is None:
return []
# 返回根节点值 + 左子树的前序遍历 + 右子树的前序遍历
return [root['val']] + preorder_traversal(root['left']) + preorder_traversal(root['right'])

# 输入后序遍历和中序遍历
post_order = "20f0Th{2tsIS_icArE}e7__w"
in_order = "2f0t02T{hcsiI_SwA__r7Ee}"
# 重建二叉树
tree_root = build_tree(list(post_order), list(in_order))
# 获取前序遍历结果
pre_order_result = ''.join(preorder_traversal(tree_root))
print(pre_order_result)

# wctf2020{This_IS_A_7reE}

Other