BeginCTF 2024冬

写的题不多,从师傅们写的特别好的wp们学到了很多,

以下是学习复现后的一些笔记

参考了很多师傅的文章:

官方wp

直接写了很多不会的题的题解

这哥们思路图非常好,借鉴

除密码的全能师傅

RE

题目附件

real checkin xor

这道题是,因为签到逆向题有点难,出题师傅又出的真真签到题,确实不难。

直接给的就是代码

1
2
3
4
5
6
7
8
9
10
11
12
13
def verify_func(ciper,key):
encrypted = []
for i in range(len(ciper)):
encrypted.append(ord(ciper[i])^ord(key[i%len(key)]))
return encrypted

secret = [7, 31, 56, 25, 23, 15, 91, 21, 49, 15, 33, 88, 26, 48, 60, 58, 4, 86, 36, 64, 23, 54, 63, 0, 54, 22, 6, 55, 59, 38, 108, 39, 45, 23, 102, 27, 11, 56, 32, 0, 82, 24]
print("这是一个保险箱,你能输入相关的key来进行解密吗?")
input_line = input("请输入key > ")
if verify_func(input_line,"ez_python_xor_reverse") == secret:
print("密码正确")
else:
print("密码错误")

image-20240206205429012

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

char a[100]={ 7, 31, 56, 25, 23, 15, 91, 21,
49, 15, 33, 88, 26, 48, 60, 58, 4, 86, 36,
64, 23, 54, 63, 0, 54, 22, 6, 55, 59, 38,
108, 39, 45, 23, 102, 27, 11, 56, 32, 0, 82, 24
};
char key[100]={"ez_python_xor_reverse"};
int main()
{
for(int i=0;i<42;i++)
{
printf("%c",a[i]^key[i%strlen(key)]);
}
return 0;
}

//begin{3z_PY7hoN_r3V3rSE_For_TH3_Be9inNEr!}
1
2
3
4
5
6
7
8
9
10
11
def decrypt_func(encrypted, key):
decrypted = []
for i in range(len(encrypted)):
decrypted.append(chr(encrypted[i] ^ ord(key[i % len(key)])))
return ''.join(decrypted)

key = "ez_python_xor_reverse"
ciper = [7, 31, 56, 25, 23, 15, 91, 21, 49, 15, 33, 88, 26, 48, 60, 58, 4, 86, 36, 64, 23, 54, 63, 0, 54, 22, 6, 55, 59, 38, 108, 39, 45, 23, 102, 27, 11, 56, 32, 0, 82, 24]

decrypted_text = decrypt_func(ciper, key)
print("解密后的文本:", decrypted_text)

红白机

要注意下载的文件名呜呜

指令集

# 6502汇编码 直接编译运行

Easy 6502

或者自己手搓

偏移为0x200,黑色地方提取画图

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
screen = [[0] * 32 for _ in range(1000)]

def addr_to_coords(addr):
addr -= 0x200
return divmod(addr, 32)

for base in range(0x200, 0x600, 0x100):
for offset in range(0xFF):
row, col = addr_to_coords(base + offset)
screen[row][col] = 1

ops = [
(0x201, 0), (0x202, 0), (0x221, 0), (0x240, 0), (0x241, 0), (0x242, 0), (0x261, 0), (0x281, 0),
(0x204, 0), (0x224, 0), (0x244, 0), (0x264, 0), (0x284, 0), (0x246, 0), (0x247, 0), (0x248, 0),
..........................
..........................

]

for addr, val in ops:
row, col = addr_to_coords(addr)
screen[row][col] = val

for row in screen:
print("".join(' ' if pixel else ' * ' for pixel in row))

xor

upx壳+反调试

rdata段:用于从远程服务器获取当前日期和时间的命令行实用程序,通常用于UNIX类操作系统以将系统时钟与远程时间服务器同步。

走弯路做法:分析加密原理,找静态资源

image-20240206224417017

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
#include<stdio.h>
char dec3[33];

char dec4[] = "`agh{^bvuwTooahlYocPtmyiijj|ek'p";
char key1[] = "63290794207715587679621386735000";
char key2[] = "41803873625901363092606632787947";

void dec(char *output,char *key) {
char dec1[33];
char dec2[33];
char key1[33];
char key2[33];
for (int i = 0; i < 16; i++) {
key1[i] = key[i];
}
for (int i = 0; i < 16; i++) {
key2[i] = key[i + 16];
}
for (int i = 0; i < 16; i++) {
dec1[i] = output[i + 16];
}
for (int i = 0; i < 16; i++) {
dec2[i] = output[i];
}
for (int i = 0; i < 16; i++) {
dec1[i] ^= key1[16 - i];
}
for (int i = 0; i < 16; i++) {
dec2[i] ^= key2[16 - i];
}
for (int i = 0; i < 16; i++) {
dec1[i] ^= key2[16 - i];
}
for (int i = 0; i < 16; i++) {
dec2[i] ^= key1[16 - i];
}
for (int i = 0; i < 16; i++) {
dec1[i] ^= key1[i];
}
for (int i = 0; i < 16; i++) {
dec2[i] ^= key2[i];
}
for (int i = 0; i < 16; i++) {
dec1[i] ^= key2[i];
}
for (int i = 0; i < 16; i++) {
dec2[i] ^= key1[i];
}
for (int i = 0; i < 16; i++) {
dec3[i] = dec1[i];
}
for (int i = 0; i < 16; i++) {
dec3[i + 16] = dec2[i];
}
}
int main()
{
dec(dec4,key2);
dec(dec3,key1);
printf(dec3);
return 0;
}

简单粗暴法:异或是可逆的

但是得考虑反调试,要不然出不来,

superguesser(动态调试

a?静态猜测!牛

image-20240206235813820

1
2
3
4
data = bytearray.fromhex("5151525f59435d5f59495a59562e261d2a371a27291728242a3825213d0f323a3c3d36332a")

for i in range(37):
print(chr(data[i] ^ (i + 51)), end="")

俄语学习

IDA后发现答案都是明文,(但是好多题

image-20240207224620727

最后的求flag才是正菜

image-20240207222416136

image-20240207231022742

image-20240207231040398

flag输入后,内容是要去func2中的tmpStr(明文)比较的,所以需要运行并提取tmpStr加密前后的内容,还有两个盒子以及Str2_0

主要加密是rc4,而且str的加密结果和tmpStr的加密结果是相同的,间接的给出了str的结果

image-20240208010234042

爆破rc4

#硬写。

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
#include<bits/stdc++.h>
using namespace std;
unsigned char box3[256] = { 0 };
unsigned char box4[256] = { 0 };

// 第一个盒子 box
unsigned char box[] =
{
0x35, 0xF1, 0xDA, 0x19, 0x7A, 0xF6, 0x31, 0x9C, 0xD9, 0x2C,
0xC1, 0xFC, 0xE2, 0xD8, 0x1D, 0x8D, 0x4F, 0x97, 0x81, 0x26,
0xC0, 0xB8, 0x96, 0x27, 0xD5, 0x5B, 0xAA, 0x18, 0x85, 0xFA,
0x61, 0xE4, 0xA1, 0xBC, 0xF8, 0xA4, 0x56, 0x37, 0x43, 0x58,
0x2B, 0xC9, 0x77, 0x64, 0xCC, 0x6B, 0x98, 0x65, 0x75, 0x38,
0x80, 0x09, 0x11, 0x3D, 0xD0, 0xE6, 0x8F, 0xA9, 0x57, 0x99,
0x06, 0x10, 0x5D, 0xC5, 0x69, 0xBD, 0x2D, 0x68, 0x7E, 0xE3,
0x67, 0xD1, 0xFF, 0x5E, 0xF9, 0xF5, 0x41, 0x8C, 0xDD, 0x21,
0x4B, 0xA7, 0x47, 0x86, 0x6D, 0xC3, 0x2A, 0x9A, 0x9F, 0x20,
0x48, 0xBB, 0x94, 0xB9, 0xB4, 0x92, 0x02, 0x74, 0x7D, 0x1B,
0x1E, 0x5F, 0xBA, 0x49, 0xD6, 0xE7, 0x53, 0x04, 0xCB, 0x28,
0x3F, 0xE8, 0x33, 0x3E, 0x00, 0x9B, 0x6A, 0xFD, 0xBE, 0x1C,
0x90, 0xED, 0xDF, 0x4D, 0x25, 0x6F, 0xB5, 0x13, 0x70, 0x3C,
0x9E, 0x16, 0x0C, 0x05, 0x4A, 0x73, 0xDE, 0xB1, 0x8A, 0x51,
0x3B, 0x54, 0x14, 0xE0, 0x5A, 0xDC, 0x91, 0x62, 0xA3, 0x95,
0xD3, 0x3A, 0x17, 0xEE, 0x32, 0xF2, 0x7C, 0xAF, 0xB3, 0x88,
0xEC, 0x0E, 0xAE, 0x9D, 0x5C, 0x0D, 0x55, 0x4E, 0xFB, 0x46,
0x22, 0x44, 0x45, 0xBF, 0x52, 0x12, 0x66, 0x07, 0xD2, 0x36,
0x93, 0x6E, 0x42, 0x1A, 0x0F, 0xE9, 0x60, 0xCA, 0xB2, 0x6C,
0x83, 0xF0, 0x03, 0x76, 0xA8, 0x1F, 0x63, 0xEF, 0xA5, 0xCD,
0x79, 0x7B, 0x0A, 0x0B, 0xAB, 0xDB, 0xD4, 0x7F, 0x01, 0x34,
0x23, 0x59, 0xE1, 0x29, 0xC6, 0xAC, 0xA2, 0x40, 0xC8, 0xAD,
0xC4, 0x89, 0xC2, 0xB6, 0x71, 0xA0, 0xEB, 0x2F, 0x78, 0xF3,
0xB0, 0xFE, 0xCE, 0xF7, 0x84, 0x72, 0xF4, 0xCF, 0xC7, 0xD7,
0xB7, 0x8E, 0x4C, 0x82, 0x30, 0x50, 0x2E, 0x24, 0x87, 0x08,
0x39, 0xE5, 0xEA, 0xA6, 0x8B, 0x15
};

// 对输入进行处理的字符串 Str2_0
unsigned char Str2_0[] =
{
0x35, 0x6D, 0x35, 0x64, 0x35, 0x77, 0x35, 0x64, 0x35, 0x62,
0x35, 0x6E, 0x35, 0x6D, 0x35, 0x64, 0x35, 0x77, 0x35, 0x64,
0x35, 0x62, 0x35, 0x6E, 0x35, 0x6D, 0x35, 0x64, 0x35, 0x77,
0x35, 0x64, 0x35, 0x62, 0x35, 0x6E, 0x8E, 0x00
};

// 处理后的 tmpStr
unsigned char tmpStr[] =
{
0x38, 0x9A, 0xFA, 0xC3, 0x5B, 0x89, 0xA5, 0xE6, 0xD0, 0xAB,
0x42, 0x58, 0x57, 0x09, 0x42, 0xAB, 0x33, 0x2F, 0x98, 0x42,
0x2E, 0x59, 0x6D, 0x41, 0x00
};

// 处理前的 tmpStr
unsigned char tmpstr[] = "+i&[@Y:g8[&l$f8S8v$Y&e>{";

// 加密函数
void rc4_crypt(unsigned char* box, unsigned char* data, unsigned long datalen)
{
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp = 0;
for (k = 0; k < datalen; k++)
{
i = (i + 1) % 256;
j = (j + box[i]) % 256;
tmp = box[i];
box[i] = box[j];
box[j] = tmp;
t = (box[i] + box[j]) % 256;
data[k] ^= box[t];
}
}

unsigned char flag[30] = { 0 };

void func()
{
// 先备份一份 box
memcpy(box3,box,256);
int k = 0;
unsigned char tmp = 0;
int v1, v2, v3;
int v11, v21, v31;

while (1)
{
v1 = v2 = v3 = 0;
memcpy(box3, box, 256);
for (int i = 0; i < strlen((char*)tmpStr); i++)
{
if (flag[i] != 0) // 先根据flag的内容来
{
v1 = (v1 + 1) % 256;
v2 = (v2 + box3[v1]) % 256;
tmp = box3[v1];
box3[v1] = box3[v2];
box3[v2] = tmp;
v3 = (box3[v1] + box3[v2]) % 256;
//tmpstr[i] ^= box3[v3];
}
else // 爆破
{
//先保存上一次正确的 v1、v2、v3
v11 = v1;
v21 = v2;
v31 = v3;
for (char j = 32; j < 127; j++)
{
k = j + Str2_0[i] - 112;
memcpy(box4, box3, 256);
v1 = v11;
v2 = v21;
v3 = v31;

v1 = (v1 + 1) % 256;
v2 = (v2 + box4[v1]) % 256;
tmp = box4[v1];
box4[v1] = box4[v2];
box4[v2] = tmp;
v3 = (box4[v1] + box4[v2]) % 256;
k ^= box4[v3];

if (k == tmpStr[i])
{
flag[i] = j;
break;
}
}
}
}
if (strlen((char*)flag) == strlen((char*)tmpStr))
{
cout << flag << endl;
return;
}
}
}
int main()
{
func();
return 0;
}

rc4逆向

1
2
3
4
5
6
7
8
9
10
11
t = b"5m5d5w5d5b5n5m5d5w5d5b5n5m5d5w5d5b5n\x8e"
# tmp[i] = flag[i] + t[i]-112
from Crypto.Cipher.ARC4 import *
enc = bytes([0x38, 0x9A, 0xFA, 0xC3, 0x5B, 0x89, 0xA5, 0xE6, 0xD0, 0xAB, 0x42, 0x58, 0x57, 0x09, 0x42, 0xAB, 0x33, 0x2F, 0x98, 0x42, 0x2E, 0x59, 0x6D, 0x41])
rc4 = new(t)
p = rc4.decrypt(enc)
print(p)
p = list(p)
for i in range(len(p)):
p[i] = (p[i]+112-t[i])&0xff
print(bytes(p))

不经过rc4

对box进行交叉引用可以发现,box和box2其实是相同的

image-20240208000241839

那么rc4加密在使用相同box的前提下,想要得到的密文相同,就必须保证明文在进行rc4加密之前就是相同的,即key和temStr在加密前就是相同的。

这样我们就可以简化成如下步骤:

key = 用户输入 + str2_0 - 112

temStr = +i&[@Y:g8[&l$f8S8v$Y&e>{

str2_0 = unk_6C8E68 - 114

unk_6C8E68就是俄文单词нечего重复3次

几个问答全都没用,看中间关键的几个加密函数

中间涉及到rc4,但是最后用于比对的key2和str1经过同一个S盒的RC4加密,等于没加密

几个长得像key的几个字符串是有用的,排除干扰之后逻辑非常简单

http://t.csdnimg.cn/QKP71

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
#include<string.h>
int main()
{
int i;
char rus[38] = "нечегонечегонечего";//37
char key2[26] = "+i&[@Y:g8[&l$f8S8v$Y&e>{";//25
char key1[38] = { 0 };//37
char flag[26] = { 0 };
for (i = 0; i <= strlen(rus); ++i)
key1[i] = rus[i] - 114;
printf("%s %d", key1, strlen(key1));//5m5d5w5d5b5n5m5d5w5d5b5n5m5d5w5d5b5n 37
for (i = 0; i <= strlen(key2); ++i)
flag[i] = key2[i] - key1[i] + 112;
printf("%s", flag);//flag{Russian_is_so_easy}
return 0;
}

Ezpython

考点:sm4,python

pyinstaller打包python生成的exe

pyinstxtractor工具拆包—ezpython.exe_extracted

里面找到ezpython.pyc文件,使用uncompyle6 反编译出源码

uncompyle6.exe .\ezpython.pyc

SM4加密

寻找密文和key进行解密

由于编码问题,使用uncompyle6.exe .\ezpython.pyc > ezpython.py会出现报错

于是将上述反编译出的源码贴进一个自己新建的ezpython.py文件中,把这个文件放进ezpython.exe_extracted文件里,用vscode打开这个文件夹

为了得到key和enc

需要在文件夹里面找到secret.pyc,然后对其进行反编译

uncompyle6.exe .\secret.pyc > .\secret.py

1
2
3
key = 'BeginCTFBeginCTF'
enc =
b'JmjJEAJGMT6F9bmC+Vyxy8Z1lpfaJzdEX6BGG/qgqUjUpQaYSON1CnZyX9YXTEClSRYm7PFZtGxmJw6LPuw1ww=='

但是赛博厨子求不出,猜测魔改sm4算法

ezpython.py中导入了sm4库,于是将文件夹内的sm4.pyc进行反编译

uncompyle6.exe .\sm4.pyc > sm4.py

根据题目提示,魔改可能与密钥相关,于是直接查找key

容易发现CryptSM4类下的set_key方法存在魔改

将原始key值异或了37

image-20240208001132113

出题人的密码是什么

#花指令

恢复main函数逻辑

image-20240208001311389

主要加密是一个魔改crc64

通过和零比较,从而进行不同的加密,实际上是比较的最高位

看密文最低位,根据最低位,判断这个数在加密前最高位是1还是0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
key = 0x33077d

def decrypt(value, key):
for i in range(64):
if value & 1:
value = (value ^ key) >> 1
value |= 0x8000000000000000 #还原最高位
else:
value = value >> 1
return value

out = bytes.fromhex('B4BBD8EBD06EABCA658E4BE94DD44AF37D29C2F99589A4859DCDDF77FD45CB5D7DFD934BBCF67CF32442F5D2DDE356AE')
out = [((i ^ 0x25) - 5) & 0xff for i in out]
print(out)

flag = b''
for i in range(0, len(out), 8):
v = int.from_bytes(out[i: i + 8], 'little')
flag += decrypt(v, key).to_bytes(8, 'little')

print(flag.decode())

同时这个题目里面还有简单的时间反调试

Arc(没学过的(会学的

z3?考点:单字节爆破,混淆

Not main

考点:TEA,XXTEA,VEH异常处理,反调试

veh反调试,全局变量初始化init(没学,继续

EZVM(不太会

vm题 c++

Goforfun(不会

考点:go语言,rc4魔改,单字节爆破

go语言编写的程序,go 1.21

可以装一个idagolanghelper插件帮助恢复符号表

恢复之后确定主函数就需要动调

Babyvm(不太会,留着

考点:vm,二进制文件读写,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
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

with open("D:\opcode.vm", "rb") as file:
bincode= list(file.read())
opcode= open ("D:\\opcode.txt","wb")

def byte_to_int(a,b,c,d):
return a|(b<<8)|(c<<16)|(d<<24)

i=0
op_list=[]

while i <= 3643:
k=byte_to_int(bincode[4*i],bincode[4*i+1],bincode[4*i+2],bincode[4*i+3])
match k:
case 1:
add_list=[]
for j in range(i+1,i+4,1):
add_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
op_list.append(str(add_list[0])+'='+str(add_list[1])+'+'+str(add_list[2]))
i+=4
case 2:
sub_list=[]
for j in range(i+1,i+4,1):
sub_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
op_list.append(str(sub_list[0])+'='+str(sub_list[1])+'-'+str(sub_list[2]))
i+=4
case 3:
mul_list=[]
for j in range(i+1,i+4,1):
mul_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
op_list.append(str(mul_list[0])+'='+str(mul_list[1])+'*'+str(mul_list[2]))
i+=4
case 4:
div_list=[]
for j in range(i+1,i+4,1):
div_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
op_list.append(str(div_list[0])+'='+str(div_list[1])+'+'+str(div_list[2]))
i+=4
case 5:
op_list.append("in_pointer=0")
i+=1
case 6:
op_list.append("out_pointer=0")
i+=1
case 7:
popin_list=[]
for j in range(i+1,i+3,1):
popin_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
op_list.append("popin "+str(popin_list[0])+' '+str(popin_list[1]))
i+=3
case 8:
popout_list=[]
for j in range(i+1,i+3,1):
popout_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
op_list.append("popout "+str(popout_list[0])+' '+str(popout_list[1]))
i+=3
case 9:
read_list=[]
for j in range(i+1,i+2,1):
read_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
if(read_list[0]<=199):
op_list.append("read "+str(read_list[0]))
i+=2
case 10:
wri_list=[]
for j in range(i+1,i+2,1):
wri_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
op_list.append("write "+str(wri_list[0]))
i+=2
case 11:
jmp_list=[]
for j in range(i+1,i+3,1):
jmp_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
op_list.append("jmp "+str(jmp_list[0])+' '+str(jmp_list[1]))
i+=3
case 12:
njmp_list=[]
for j in range(i+1,i+3,1):
njmp_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
op_list.append("njmp "+str(njmp_list[0])+' '+str(njmp_list[1]))
i+=3
case 13:
len_list=[]

for j in range(i+1,i+3,1):
len_list.append(byte_to_int(bincode[4*j],bincode[4*j+1],bincode[4*j+2],bincode[4*j+3]))
op_list.append("len "+str(len_list[0])+' '+str(len_list[1]))
i+=3
case 0:
i+=1

with open('D:\\opcode.txt','w') as fp:
[fp.write(str(item)+'\n') for item in op_list]
fp.close()

汇编有点长主逻辑就只是一个线性方程式,用z3一把梭,这个留给大家自己尝试了

stick game

修改得分(web题?

考点:Js,ob混淆

image-20240208010936245

想法:https://linmur.top/post/beginctf-2024-reverse-writeup/

真龙之力(不会

java?贴个题解

https://www.yuque.com/u37581038/mrtw91/be9vb75fxnmah7s5?singleDoc#Fw1my

考点:XTEA,Mobile,Mobile调试

MISC

tupper

用这个网站讲附加拼接的字符串转化为图片,即得到flag https://tuppers-formula.ovh/

又学到了一种加密方式。。

devil’s word

看附件:

1
leu lia leu ng leu cai leu jau leu e cai b cai jau sa leng cai ng ng f leu b leu e sa leng cai cai ng f cai cai sa sa leu e cai a leu bo leu f cai ng ng f leu sii leu jau sa sii leu c leu ng leu sa cai sii cai d

看题目”魔鬼的语言”,搜一下猜想是温州话,其实就是温州话的0-9发音,单个字母就表示单个字母(无语了,当时没想到)。根据温州话的发音,得到这个对应关系:

1
2
3
4
5
6
7
8
9
leng 0
lia 2
sa 3
sii 4
ng 5
leu 6
cai 7
bo 8
jau 9

赛博厨子解码得到flag

你知道中国文化吗1.0

文本24个字符分一组→base32解码→八卦转8进制→8进制转字符串→字符串转社会主义编码→社会主义解码→字符串栅栏解密得到最后的flag。

八卦对应数字:

☰ 0
☱ 1
☲ 2
☳ 3
☴ 4
☵ 5
☶ 6
☷ 7

其中base32解码脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
import base64
with open("附件.txt", 'r',encoding='utf-8') as f:
while True:
a = f.readline()
if a == "":
break
a = a.strip()
try:
b = base64.b32decode(a)
except:
pass
with open("八卦.txt", 'a',encoding='utf-8') as m:
m.write(b.decode('utf-8')+"\n")

这题麻烦的地方就是有的分组里面有特殊字符 $ & @,这些特殊字符需要替换成大写英文字母或者数字才能正确编码,这里的一个思路就是找有没有相似的分组,将特殊字符替换成对应位置的字符即可。(一个特殊字符替换成多个字符都有可能正确解码为八卦符,但是这样好像并不影响结果)

下一站上岸!

题目描述: 某同学在考公的时候看到这样一道题,发现自己怎么也找不到图形的共同特征或规律你能帮帮他吗?

给的图片:image-20240206234443538

zsteg图片,发现隐写内容:

image-20240206234456075

即: 5o+Q56S6OuaRqeaWr+WvhueggQ==

base64解密得到(base64编码由a-zA-Z0-9+/组成):

根据每个图形的交点数得到: 221022201122120120111011110222012101
将0替换成’ ‘ 1替换成’.’ 2替换成’-‘再解码得到flag
(至于为什么这么替换一共6种情况可以fuzz一下)