“探索·解密” 趣味密码竞赛

JK编码

根据⼀连串j和k组成的序列不难想到01序列,再由题⽬描述中提到的每个字母和数字都有⼀定的重要程度(即权重)不难猜到哈弗曼编码,再由题目给出的乱序序列 jkhafum_no…的前几个字母可以看到哈夫曼的英⽂,进⼀步得到验证。之后编写哈夫曼解码程序即可。

逆转裁判

由题目描述与提示,将图片文件逐字节逆序,在⼗六进制编辑器中搜索flag字符串即可,或者直接使用十六进制编辑器打开后搜索galf,也能达到相同目的。

第二条古则

打开⽂件会见到⼀串不可理解的东⻄,然⽽题⽬要求从不可理解的事物中得到理解。说明答案就在其中。
根据提示“B站可能会倒闭,但绝不会变质。“,上B站搜索phony(对,就是那个被特意加粗的单 词),你会看到很多的MV,但只有⼀个MV是以镜面对称的形式呈现的。
只有这个MV和题干中的理解镜子中的伪物是相对应的,而且封面也是很明显的镜面字。
接下来打开它,一直看到标题出现的时候,会发现那是镜面字的生成过程,而题干中出现了大量的括号……
而且最重要的是,上下两行的括号正好是对应相反的。
那还等什么,把括号对应着拼起来。然后你就得到了⼀串01的序列,每五个隔断一次。将它们作为二进制数字转换为十进制,然后将这串数字和⼩写英⽂字母顺序对应,⽤flag{}将最后的内容包起来。

第五条古则

首先打开文档,会发现这个文档里面有⼀些玄学的话语。
不管它们,最后一句话很重要:也许上帝早就在这上面留下了来自乐园的指引呢?
然⽽以正常视角查看会发现没有东⻄,说明本题一定考查了文件隐写。
将所有的⽂本加⼊到记事本中,你会发现额外多出来好几处乱码……

1
2
3
4
5
6
7
8
9
我简直不敢相信我所得到的这个答案:我可怜的迷途羔羊啊,我无法用现在的方式拯救你,但我已经尽我所能留下了痕迹,它将在很久以后被人察觉并破译出来。这个时间非常特别,他既不是1000年,也不是2000年,甚至他都并不是个能够被10整除的年份,它就是2023年。但也正因它很普通,他才能被人所铭记。
假设乐园(Eden)真的存在,那进入乐园之人想必会沉迷其中,不会再出来了。但如果说有人出来证明乐园的存在,那这个人的行为本身就是对乐园的否定,因为它让那个人产生除了快乐以外的感觉,并没有包容一个人绝对的感性的能力。ErcmE3yrXA95RMAkAMS1
那怎么办呢?我们貌似连“乐园的存在与否”这个问题都还没论证呢,它的衍生问题就已经是那么的让人难以回答了。hqWkWBWqgncxiK93
乐园,可真是一个让人难以理解的东西啊。
然而乐园这种东西真的是不存在的吗?至少昔日所感受的那名为“快乐”的情绪是真实的。我们所谓的每一个日常,其实也是接连不断发生的奇迹。当所有种类的“快乐”能够在一个区域同时出现时,那所谓“快乐的本源”也一定在其中。能够承载“快乐的本源”的地方,我想也只有那记载之中的乐园了。
可它又会在哪里出现呢?RBqRC2OKC3WqXKOqkV==
凯撒当年励精图治,可依旧没有达到那个乐园啊。
我想这个问题只能留给后人回答了。
也许上帝早就在这上面留下了来自乐园的指引呢?

将三段拼起来,然后我们得到一串看上去很像base64编码的东⻄。
拼接结果:ErcmE3yrXA95RMAkAMS1hqWkWBWqgncxiK93RBqRC2OKC3WqXKOqkV==
然而请注意文本中的“凯撒”,直接 base64解码是会报错的,你得找出那个用于加密偏移量才能够正确解码。开始爆破,你会得到偏移量为5(废话,第五条古则)。将其解码即可得到一串flag:
flag{fI_y0u_TsurT_Eden,lt_w1iL_bE_teHRe}
随便输⼊,反正不对。为什么?要是真就这样做出来了,我的第一条提示就没有意义了。
现在返回来查看第一条提示:啊哈哈,和你这个神棍的传教游戏,还挺愉快的呢。(纸撕碎的声音)
将其后缀改为zip解压后发现了一个名为eden.xml的文件,打开它。
最后又是一条被base64编码的提示,说人话就是给flag纠错,让它变成⼀条通顺的话语。
将之前得到的flag{fI_y0u_TsurT_Eden,lt_w1iL_bE_teHRe}进⾏纠错处理,并且根据最初得到的提示“明文均为小写”,更改出最后的正确答案。

Art

先代码审计得到decode()函数

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
import base64
# 先把字母调换A换成Z,z换成a,然后倒序逐个字符转为二进制,在将二进制倒序逐步放⼊密文中
# 加密函数
def encode():
with open('test1.txt','r') as f:
result = ''
for char in f.read():
if char.isalpha():
if char.islower():
result += chr(122 - ord(char) + 97)
else:
result += chr(90 - ord(char) + 65)
else:
result += char # 保留⾮字⺟字符
encrypted_text = ''.join(format(ord(char), '08b')[::-1] for char in
result[::-1])
text = ''.join(chr(int(encrypted_text[i:i + 8], 2)) for i in range(0,
len(encrypted_text), 8))
with open('m.txt','w',encoding='utf-8') as w:
w.write(text)
# 解密函数
def decode():
with open ('m.txt','r',encoding='utf-8') as f:
binary_encoding = ''.join(format(ord(char), '08b') for char in f.read())
decrypted_text = ''.join(chr(int(binary_encoding[i:i + 8][::-1], 2)) for i
in range(0, len(binary_encoding), 8))
result = ""
for char in decrypted_text[::-1]:
if char.isalpha(): # 仅处理字母字符
if char.islower():
result += chr(122 - ord(char) + 97)
else:
result += chr(90 - ord(char) + 65)
else:
result += char # 保留非字母字符
return result
# 测试
encode()
print(decode())

根据解出的特征进⾏base64解码(往往是数据的传输形式)
读艺术字即可获得flag

Bacon

题⽬描述是培根密码,但是以C为分界线,有的字符不是五个,所以我们根据培根密码的特征,联想到了最常见的只有两个字符的摩斯密码,只有两种可能性,我们将A转为. ,B 转为-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
strr='BAAAACBAAAACBAAAACBABACBAAAACABBBBCBAAAACBBAAACBBAAACBAAACBAAAACAAABBCBAAAACA
ABACBAAAACACBAAAACBBAAACBBAAACAABBBCBAAAACABBBBCBBAAACAAAABCBBAAACAAAAACBAAAACBABAC
BAAAACABBBBCBBAAACAAAABCBAAAACBBBBACBAAAACAABACBAAAACACBBAAACAAABBCAABBBCBAACBAAAAC
AAABBCBAAAACABBBBCBAAAACAAABBCBBAAACABCBBAAACBBBAACBAAAACAAABBCBBAAACABCBAAAACBAAAA
CBAAAACAABACBBAAACBBAAACBBAAACBAA'
p=''
for item in strr.split('C'):
for i in item:
if i=='A':
p+='.'
if i=='B':
p+='-'
p+=' '
print(p)

然后放在在线工具中解出摩斯密码,得到一串字符串
666C61677B636F6E67726174756C6174696F6E732D6361637A78637A666F777D
然后根据特征知道是字符串的16进制形式,用在线工具16进制转字符串即可获得flag

gift

原题

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
from flag import flag
import gmpy2
from Crypto.Util.number import *
import random
import time

assert flag.startswith(b'flag{') and flag.endswith(b'}\n')
assert len(flag) == 57

flag1 = flag[:14]
flag2 = flag[14:28]
flag3 = flag[28:42]
flag4 = flag[42:]

def q1():
# 奇怪的随机
random.seed(int(time.time()))
for i in flag1:
key = random.randint(0, 255)
print(hex(key ^ i)[2:], end='')
print()

def q2():
# 好像是RSA耶
p = getPrime(768)
q = getPrime(768)
n = p * q
e = 65537
c = pow(int.from_bytes(flag2, 'big'), e, n)
print('n =', n)
print('c =', c)
print('gift = ', p^q)

def q3():
# 好欸,gift会帮你大忙
p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 65537
c = pow(int.from_bytes(flag3, 'big'), e, n)
print('n =', n)
print('c =', c)
print('gift = ', p>>128<<128)

def q4():
# 好像是仿射密码O.o?
while True:
a = random.randint(1, 255)
if gmpy2.gcd(a, 256) == 1:
break
b = random.randint(1, 255)
for i in flag4:
print(hex((a * i + b) % 256)[2:], end='')
print()

if __name__ == '__main__':
q1()
q2()
q3()
q4()

以下是输出哦

1
2
3
4
5
6
7
8
2751f014111e3b6c99ee0c1ffdb
n = 1314967568472111655011215741611204058445271915416828628976948574202708111113415916782529564877904510060100803618784633689042321638758890645109937974712421243866535532456352916950588338339187646436203001238668325551347997600131482407828109866095656006182698438881347920478482748383266084375469393195026344711785310217699668578201163056580472767419018903528661196463556987391507948440998062000579441372864166820211363778622151084978457148816155840807309523468514737
c = 714823142050694444798764890363987288553278765888515447347831293603591520430161682430297132349376978132042520437327068469772693958392477696379693493642863620785374026864080575939701745789140360488363320872736223330713870595633123116802744486276013405587197268990549236382568387872542676495602480646325253629669013709107520366724483033424481299421502754615414281425593755447617407229874129642080822627133940004511103227817223979099305528104304426752826435278744203
gift = 694528314614597200478964686223773661923043423469284409313765066401043617480074529594821605533148713125208795494551521792270222854272201394082237861960338619535572344777791563055216095704867407678882350444988644328937569643241544288
n = 20101595147488798389289868752077592121180253794961350303684476074373382651162731030012542663577893620308907070951746061694810120788982509030822305454034643552610490056731682663813203862472113551826607640566795678610949455082852245033866512073384496721650061160969170378452907296185135402960957516973093880566693353802761058535651054861356890198762625906274359149366964537600779463809503980853549061147727380608568295775123554356803159242239358725074252375272854601903195327695079676359178192820686851184017376039555552976394457195879284582630650973305825663350399524155712775283354061399128621452790374630281212763003
c = 12916869040409779953862249590282734760889861257156464352877117728249327035935827174031177155628087674873344162482162598075083427663045411953253215416066596951253127182274293689595996627589876729221669619649677597183487460364944967147487385650490911248852929910928587491029306263562185263950606812592475864353923466852485771147419452880303553179714475139219893582609435132350841035206708438665812448813540495655049342336073923165823699487070835934846037597897302098717779471902780411938252727074409684431893731139714331370842123964447381194512912853698166082589121848926068491107342775937301790556130418367711223242288
gift = 155273709359681889478466954690933897871319254905155359883381942077328267407476770359318044347630379957553960166391859807222785247670601013189925775520199087524163394638865369160945885653041774469602670214007577290385646748614938981814185337538533954972019132315963866996273805444698616794987042402666683564032
4d9a25e42e9128de650722bde9dfe

flag1使⽤暴力破解种子,已知种子为近期时间,爆破无需过久。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def e1():
start = 1694746197
end = 1794832585
ci = bytearray.fromhex(c1)
# print(ci)
flag_str = 'flag{'
key_str = b''
for i in range(5):
key_str += bytes([ci[i] ^ ord(flag_str[i])])
# print(key_str)
import random
for i in range(start, end):
random.seed(i)
if random.randint(0, 255) == key_str[0]:
if random.randint(0, 255) == key_str[1]:
if random.randint(0, 255) == key_str[2]:
if random.randint(0, 255) == key_str[3]:
if random.randint(0, 255) == key_str[4]:
# print(i)
break
random.seed(i)
for i in range(len(ci)):
print(chr(ci[i] ^ random.randint(0, 255)), end='')
print()

flag2使用https://github.com/sliedes/xor_factor分解可得p、q。然后为RSA解密流程。
flag3泄露p高比特,使⽤sage爆破。

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 phase3(high_p, n):
R.<x> = PolynomialRing(Zmod(n), implementation='NTL')
p = high_p + x
x0 = p.small_roots(X = 2^128, beta = 0.1)[0]

P = int(p(x0))
Q = n // P

assert n == P*Q
print("P = ", P)
print("Q = ", Q)

d = inverse_mod(65537, (P-1)*(Q-1))

n =
19611845515284359662247227180782154029099865864933830186692165788116252384024980174
73615145822253832497538413583221968215685013928285421083320210181349076358369944751
81423331528255192483979496104477684477996955046186481993760941924669084974192244526
41187038667468266935808858291459629906505815855969713811506880442509946417170294700
32160880511613766457813006156077785410519767924484133215530439161248901356301760068
94098374697248742412324528671161472657454063671885455747912939097848134863072413289
93821317365701875974313778396271741605711150401667698186661451787280291106456128869
490333363854095115406461539484155281
high_p =
12486169997030204062244994885683576189016578219922865040910688519470496181374653275
41707085905701844099285694575813137706637613849745987858675244587538853943003691255
59144501770075324888609868206057317301995740969619175284309266906598553310708904405
631582250925691470251725783174086755863681042731595837997056
phase3(high_p, n)

flag4为仿射密码,可暴力破解。亦可根据最后二字节确定仿射加密参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def e4():
s4 = bytearray.fromhex(c4)
int_a = s4[-1]
int_b = s4[-2]
# print(hex(int_a), hex(int_b))
CONST_A = ord("\n")
CONST_B = ord("}")
k = ((int_a - int_b) * gmpy2.invert((CONST_A - CONST_B), 256)) % 256
# print(k)
b = (int_a - k * CONST_A) % 256
# print(b)
# 仿射密码解密
for i in s4:
print(chr((i-b)*gmpy2.invert(k, 256) % 256), end='')

初识量子电路

大致了解qiskit后,照图搭电路,然后模拟得到结果。

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
from qiskit import *
from qiskit.visualization import plot_histogram
# Use Aer's qasm_simulator
simulator = Aer.get_backend('qasm_simulator')
# Create a Quantum Circuit acting on the q register
circuit = QuantumCircuit(36, 3)
# Add a H gate on qubit 0
circuit.x(0)
circuit.x(1)
circuit.i(2)
circuit.x(3)
circuit.x(4)
circuit.x(5)
circuit.i(6)
circuit.x(7)
circuit.x(8)
circuit.x(9)
circuit.i(10)
circuit.x(11)
circuit.i(12)
circuit.x(13)
circuit.i(14)
circuit.i(15)
circuit.x(16)
circuit.i(17)
circuit.x(18)
circuit.i(19)
for xxx in range(20):
circuit.h(xxx)
# Add a CX (CNOT) gate on control qubit 0 and target qubit 1
circuit.ccx(3,7,21)
circuit.ccx(2,6,23)
circuit.ccx(12,13,24)
circuit.ccx(10,11,25)
circuit.ccx(14,15,26)
circuit.ccx(1,5,27)
circuit.ccx(9,10,28)
circuit.ccx(0,4,29)
circuit.ccx(5,11,30)
circuit.ccx(2,8,31)
circuit.cx(21,24)
circuit.x(27)
circuit.ccx(4,30,31)
circuit.cx(24,25)
circuit.cx(27,30)
circuit.ccx(4,11,32)
circuit.ccx(23,24,26)
circuit.ccx(27,28,29)
circuit.ccx(30,32,34)
circuit.cx(29,31)
circuit.cx(17,34)
circuit.cx(31,33)
circuit.ccx(18,34,35)
circuit.x(33)
circuit.measure(35,2)
circuit.ccx(34,31,20)
# Map the quantum measurement to the classical bits
circuit.measure(33,0)
circuit.measure(34,1)
# qc_cir.measure_all()
# Execute the circuit on the qasm simulator
re = simulator.run(circuit,shots=1000000).result()
# re = execute(qc_cir,simulator,shots=100).result()
# Grab results from the job
# Returns counts
counts = re.get_counts()
print(counts)
print(len(counts))
circuit.draw(output='mpl')

兔子

因为密文都是字母,所以锁定移位/替换密码大类,再根据提示所得斐波那契数列,想到根据数列每⼀位的值对密文每一位单独进行移位(仿射)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def fibonacci_shift_decrypt(encrypted_text, fib_list):
decrypted_text = ""
for i, char in enumerate(encrypted_text):
if char.isalpha(): # 只对字母字符进行解密
shift = fib_list[i] # 从预先计算的斐波那契数列表中获取偏移量
char_code = ord(char)
offset = 65 if char.isupper() else 97 # 大写字母和小写字母的ASCII码基点不同
# 解密字符并添加到解密文本中
decrypted_char = chr(((char_code - offset - shift) % 26) + offset)
decrypted_text += decrypted_char
else:
decrypted_text += char # 非字母字符保持不变
return decrypted_text
# 预先计算的斐波那契数列表
fib_list = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
# 测试
encrypted_text = "hmcvxg_nsb_oabhd"
decrypted_text = fibonacci_shift_decrypt(encrypted_text, fib_list)
print("Decrypted Text:", decrypted_text)

flag{glassy_sky_above}

三重⻔

Ronald Rivest除了知名于RSA,还知名于RC系列,根据提示的密钥尝试出是RC4,获得Key和iv,在分组密码中尝试发现AES解密成功,最后得到一串英文字母序列,结合提供的a和b,联想到仿射密码,解密得到有意义的明文。

放射!!!

给予的txt附件内容经过了仿射加密(x = k1*y + k0 mod 26),因为仿射加密属于单表代换,所以可以分析其英文单词的出现频率,结合附件里的频率图,可以找到加密前后的英⽂字⺟对应关系,最终得到k1=3,k0=5,再用网上的在线仿射加密解密工具即可获得flag

这里给出加密与解密的C++源码:

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
#include <bits/stdc++.h>
using namespace std;
// 扩展的欧⼏⾥得算法求逆元,该函数还同时可以执⾏求gcd的功能
int x, y;
int exgcd(int a, int b, int &x, int &y)
{
if (b == 0)
{
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
// 根据⽂件名读⼊相应的⽂件流,并转化为字符串,可以读⼊空格与换⾏符
string f_open(string txt)
{
ifstream fin;
fin.open(txt, ios::in);
string s = "";
char c;
if (!fin.is_open() || !fin)
cout << "打开⽂本失败!!" << endl;
while ((c = fin.get()) != EOF)
s += c;
return s;
fin.close();
}
// 仿射加密,加密参数可以⾃定
void encode(string s)
{
int k1, k2;
while (1)
{
cout << "输⼊仿射加密参数K1::" << endl;
cin >> k1;
if (exgcd(26, k1, x, y) != 1)
cout << "K1与26不互素,重新输⼊" << endl;
else
break;
}
cout << "输⼊仿射加密参数K2:" << endl;
cin >> k2;
for (int i = 0; i < s.size(); i++)
{
if (s[i] >= 'a' && s[i] <= 'z')
s[i] = ((s[i] - 'a') * k1 + k2) % 26 + 'a';
else if (s[i] >= 'A' && s[i] <= 'Z')
s[i] = ((s[i] - 'A') * k1 + k2) % 26 + 'A';
}
ofstream fout;
fout.open("res.txt");
fout << s;
fout.close();
}

// 解密,根据提供的参数进⾏解密
void decode(string s)
{
int k1, k2;
while (1)
{
cout << "输⼊仿射加密参数K1::" << endl;
cin >> k1;
if (exgcd(26, k1, x, y) != 1)
cout << "K1与26不互素,重新输⼊" << endl;
else
{
k1 = exgcd(k1, 26, x, y);
k1 = (x + 26) % 26;
break;
}
}
cout << "输⼊仿射加密参数K2:" << endl;
cin >> k2;
for (int i = 0; i < s.size(); i++)
{
if (s[i] >= 'a' && s[i] <= 'z')
s[i] = (((s[i] - 'a' - k2 + 26) % 26) * k1) % 26 + 'a';
else if (s[i] >= 'A' && s[i] <= 'Z')
s[i] = (((s[i] - 'A' - k2 + 26) % 26) * k1) % 26 + 'A';
}
// cout<<s<<endl;
ofstream fout;
fout.open("de_res.txt");
fout << s;
fout.close();
}
// 对⽂本中单词出现频率进⾏频率分析
void analys(string s)
{
double num[26], cnt = 0, res;
for (int i = 0; i < 26; i++)
num[i] = 0;
for (int i = 0; i < s.size(); i++)
{
if (s[i] >= 'a' && s[i] <= 'z')
num[s[i] - 'a']++, cnt++;
else if (s[i] >= 'A' && s[i] <= 'Z')
num[s[i] - 'A']++, cnt++;
}
for (int i = 0; i < 26; i++)
res = num[i] / cnt, cout << char('a' + i) << ": " << res << endl;
return;
}
int main()
{
int op;
string txt;
while (1)
{
cout << "选择⼯作模式,输⼊1表示加密,输⼊2表示解密,输⼊3表示字⺟频率分析:" << endl;
cin >> op;
if (op == 1)
{
// 从plaintext.txt读取⽂本进⾏加密
txt = "plaintext.txt";
encode(f_open(txt));
}
else if (op == 2)
{
// 从res.xtx读取⽂本进⾏解密
txt = "res.txt";
decode(f_open(txt));
}
else if (op == 3)
{
// 从res.txt读取⽂本进⾏分析
txt = "res.txt";
analys(f_open(txt));
}
cout << "输⼊0退出,其它值返回继续操作:" << endl;
cin >> op;
if (op == 0)
break;
}
return 1;
}

图片怎么你了?

对图片进行了BASE64加密,网上找图片BASE64解密⽹站即可还原
这里给出加密解密python源码

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
import base64
import string
# Base64编解码
def b64en(path_in, path_out):
with open(path_in, 'rb') as fileObj:
image_data = fileObj.read()
base64_data = base64.b64encode(image_data)
fout = open(path_out, 'w')
fout.write(base64_data.decode())
fout.close()
pass
def b64de(path_in, path_out):
b64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
# 读取需要解码的⽂本⽂件
with open(path_in, "r", encoding="utf-8") as text_file:
encoded_string = text_file.read()
# 去除⽆效字符和换⾏符
encoded_string = ''.join(filter(lambda c: c in b64_table,
encoded_string)).replace("\n", "")
# 将Base64编码字符串转换为字节串
encoded_bytes = bytes(encoded_string, "utf-8")
# 初始化解码后的字节串和计数器
decoded_bytes = bytearray()
cnt = 0
# 逐个解码Base64字符
for b64_char in encoded_bytes:
# 计算Base64字符在字符表中的索引
index = b64_table.index(chr(b64_char))
# 根据计数器的值,将16位的⼆进制数填⼊32位的缓冲区中
if cnt == 0:
buffer = index << 2
cnt = 1
elif cnt == 1:
buffer |= (index >> 4) & 0x03
decoded_bytes.append(buffer)
buffer = (index & 0x0f) << 4
cnt = 2
elif cnt == 2:
buffer |= (index >> 2) & 0x0f
decoded_bytes.append(buffer)
buffer = (index & 0x03) << 6
cnt = 3
else:
buffer |= index
decoded_bytes.append(buffer)
cnt = 0
#print(decoded_bytes)
# 将解码后的字节串写⼊图⽚⽂件
with open(path_out, "wb") as image_file:
image_file.write(decoded_bytes)

if __name__ == '__main__':
b64en("pic.jpg", "pic")
b64de("pic", "de_pic.jpg")

呜呜呜

先社会主义核⼼价值观编码再栅栏密码w型。因为社会主义核⼼价值观每4个词⼀组,因此栅栏也是4为栏数。最终得到
flag{E1nC0o4d1n2g_1d4s_f2U3n_so_a4s_F3nc3}

ez-explode

按照给出的代码枚举k和r爆破即可,下⾯给出爆破代码。

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
import string
import re
def grid_decrypt(encrypted_message):
decrypted_message = ""
length = len(encrypted_message)
for i in range(length):
if i % 2 == 0 and i != length-1:
decrypted_message += encrypted_message[i]
for i in range(length):
if i % 2 == 1:
decrypted_message += encrypted_message[i]
if length % 2:
decrypted_message += encrypted_message[-1]
return decrypted_message
def decrypt_message(encrypted_message, r, k):
for i in range(r):
encrypted_message = encrypted_message[-1] + encrypted_message[:-1]
encrypted_message = grid_decrypt(encrypted_message)
replace_message = r'[#$&()\[\]<>?!%^@+=]'
encrypted_message = re.sub(replace_message, '', encrypted_message)

plain_message = ""
for char in encrypted_message:
if char in string.ascii_lowercase:
plain_char = chr(((ord(char) - k - 97 + 26) % 26) + 97)
plain_message += plain_char
elif char in string.ascii_uppercase:
plain_char = chr(((ord(char) - k - 65 + 26) % 26) + 65)
plain_message += plain_char
else:
plain_message += char
return plain_message
encrypted_message = "1$0Osdy__s_<mp6H1{Jf5V@SE0+pY6_=!Hwv06w0V7}xk"
for k in range(26):
for r in range(10, 20):
decrypted_message = decrypt_message(encrypted_message, r, k)
if "flag{" in decrypted_message:
print(f"r={r},k={k},: {decrypted_message}")

AES?

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
# md5爆破key:
import hashlib
str1 = "d567b916876527"
str2 = "891b14d536be997e8d5"
str3 = "7b916876527d8"
str4 = "1b14d536b"
str5 = "997e8"
# 将所有可打印字符存⼊数组 , ⽤于遍历所有字符
res = [' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '
', '.', '/', '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C',
'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
'Z', '[', ']', '^', '_', '`', 'a', 'b',
'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '{', '|', '}', '~ ']
def getMd5(plaintext):
md5Object = hashlib.md5()
md5Object.update(plaintext.encode('utf-8'))
return md5Object.hexdigest()

for i in res:
for j in res:
for k in res:
for l in res:
plaintext = str1 + i + str2 + j + str3 + k + str4 + l + str5
# 拼接明⽂字符串
md5 = getMd5(plaintext)
# 判断是否成功
if md5.startswith("0e79216") and md5.endswith("0948"):
print("Success! The plaintext is:", plaintext)
exit(0)
print("No match found.")
#因为四层循环,需要等待⼀⼩段时间才能运⾏出来结果
#Success! The plaintext is:
d567b916876527d891b14d536be997e8d567b916876527d891b14d536be997e8

观察给出的代码发现iv是32字节,并且被分成两部分,前半部分是base85,后半部分是base32对应
解码即可:

iv:33a4235ea4d294c113c5ff98447c927a

最终解密python脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from Crypto.Cipher import AES
import random
from gmpy2 import *
def generate_random_bytes(length):
return bytes([random.randint(0, 255) for _ in range(length)])
def main():
enc_flag =
b"\x189\xdb\x11t\xb8\xc5\xe8\xe5\xa8n\x04'XH\x13\x9c9\xe8\x88\x0c>\xe7\xde\t\xa0\xad\x7f\xb4u\x1f\xc1"
hex_key_str ="d567b916876527d891b14d536be997e8d567b916876527d891b14d536be997e8"
hex_iv_str = "33a4235ea4d294c113c5ff98447c927a"
key = bytes.fromhex(hex_key_str)
iv = bytes.fromhex(hex_iv_str)
aes = AES.new(key, AES.MODE_CBC, iv)
print(aes.decrypt(enc_flag))

if __name__ == "__main__":
main()
# flag{O.o_y0u_can_so1v3_AES_now!}

低头看看手机和电脑?

根据题目和A、B很明显的键盘密码,其中A是26键(两种不同形式),B是9键可知B为key,A为virginia,又提示密文是经过维吉尼亚密码进行加密而且密钥也给出了,也就是`virginia 解密即可
flag{Congratulations!You already know the keyboard and the Virginia!}

1
2
3
4
5
6
7
8
9
10
11
12
1.键盘密码(Keyboard Cipher)特征/特点:利⽤键盘的特性制作的密码,常见有计算机的键盘和⼿机的键盘,加密的⽅式有坐标法和顺序法。 
1)坐标法:
Y轴:1 QWE RTY UIOP 2 ASD FGH JKL 3 ZXC VBN M
X轴:12345678910
eq:密文:2251914161 对应明文:story
2)顺序法:Q W E R T Y U I O P 1 2 3 4 5 6 7 8 9 10 A S D F G H J K L 11 12 13 14 15
16 17 18 19 Z X C V B N M 20 21 22 23 24 25 26
eq:密⽂:125947对应明⽂:story
2.手机九宫格键盘密码特征特点:密⽂⽤数字0-9表示a-z的字符集字母不区分大小写
密文:21222331323341424351525361626371727381828391929394
明文:abcdefghijklmnopqrtuvwxyz
3.维吉尼亚密码(Vigenère Cipher)特征特点:维吉尼亚密码(Vigenère Cipher)是在单⼀恺撒密码的基础上扩展出多表代换密码,根据密钥(当密钥长度⼩于明文长度时可以循环使⽤)来决定用哪一行的密表来进行替换,以此来对抗字频统计

网安导论

由甲中 自田井 羊夫 白中由 甲口只 羊目大 由由工
即:112 108 97 121 102 97 105 114
所以密钥为:playfair
密⽂为:qbqglqzvkudnbponbpsubpoeqkpqkv
提示:⽹络空间安全导论49⻚
多字母表加密,解密后为haohaoxuexitiantianxiangshang
明文:flag{haohaoxuexitiantianxiangshang}
密文:qbqglqzvkudnbponbpsubpoeqkpqkv,
密钥:playfair

快放假了!

U2FsdGVkX1/U2UwcHyXnjLegIHgW5URBEVgJy9UMQzY3JkqcP2RFhVEiiY/tcKA3
YDKBB40VqThG5/N2FYaG6hODhSGbjHoDpNIoWpoCQfk=
TripleDes解密,密钥为0929
解密得:U2FsdGVkX1/mh3nQv5sGKvD7jJh5bA+byb518k5onGHuBfzyoBF2DA==
rabbit解密,密钥为1001
解密得:flag{Happy-National-Day}

Good man

本题是很简单的⼀个逆向类密码
加密代码的含义是将⼀个char类型的字符高低四位反转,例如:0x61会被高低4位反转,变成0x16

解密代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>
//66 c6 16 76 b7 86 56 37 86 13 f5 13 37 f5 4 f5 76 3 3 46 f5 d6 4 e6 d7
int main(){
int miwen[25];
for(int i=0;i<25;i++)
{
scanf("%x",&miwen[i]);
int h=miwen[i]%0x10;
int l=miwen[i]/0x10;
miwen[i]=h*0x10+l;
printf("%c",miwen[i]);
}
}

当然,如果你能看懂代码,那么直接手动反转再去找ascii解码也是可以的。
flag{hesh1_1s@g00d_m@n}

方块语言

这种加密方式最多见于我的世界的附魔台,所以我称它为方块语言。
本题降低了难度,给了一个去掉了字母的密码表(实际上你自己按顺序加上就可以直接用了)
你可以利用图片搜索,也可以搜索和我的世界有关的语言(如果你知道这个游戏的话),在网上找到未被抹去字母的密码表。
再对密⽂进⾏处理,密文表面上由字符组成,其实不难看出,它构成的图案对应的是密码表中的图案。
最终对照密码表得到flag

出题代码(python)

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
null='''
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
'''
m='''
0 0 0 0 0 0
0 1 0 0 0 1
0 0 0 0 0 1
0 0 0 0 0 1
0 0 0 0 0 1
0 1 1 1 1 1
'''
c='''
1 1 0 0 0 0
0 0 0 0 0 0
1 1 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 0 0
'''
y='''
0 0 0 0 0 0
0 1 0 1 0 0
0 1 0 1 0 0
0 1 0 1 0 0
0 1 0 1 0 0
0 1 0 1 0 0
'''
d='''
0 0 0 0 0 0
1 1 1 1 1 1
0 0 0 0 0 0
1 1 0 0 0 0
0 0 1 1 0 0
0 0 0 0 1 1
'''
s='''
0 1 1 0 0 0
0 1 1 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 0 0 0 0
'''
h='''
0 0 0 0 0 0
0 1 1 1 1 1
0 0 0 0 0 0
0 1 1 1 1 1
0 0 0 1 0 0
0 0 0 0 0 0
'''
e='''
0 0 0 0 0 0
1 0 0 0 1 0
1 0 0 0 0 0
1 0 0 0 0 0
1 1 1 1 1 0
0 0 0 0 0 0
'''
i='''
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
'''
'''
还有⼏个字⺟的图,找不到啦,反正就是这样
'''
print(m+c+null+i+s+null+a+null+g+o+o+d+null+g+a+m+e)

flag{mc_is_a_good_game}

Xiong

** 熊曰 ** ,一眼熊语密码,参考http://hi.pcmoe.net/index.html复制进去解密即可。
** 你这石榴啥品种的? **
二进制转为十六进制后base16解码接着再栅栏密码解码即可得到flag。

原?启!

解压压缩包进⼊发现是 Ook 编码,不知道是啥原因,BugKu的解码是有问题的得不出结果
https://www.splitbrain.org/services/ook 参考该链接进去解码,结果发现有一串 Cipher 和乱序字符串,熟悉base64 的同学应该知道base64 码表为 A-Z a-z 0-9 +/ 的顺序排列,故可以想到是换表base64加密。从网上或是自己写脚本将更改的码表添加即可解密。

bassssssssssssssse

使用
https://cyberchef.org/
解码三次即可。

我的困惑,佛给出了这些解答

与佛论禅解密即可
http://www.atoolbox.net/Tool.php?Id=1027

凯凯凯撒密码码码

解法

  1. 根据题干,得知是凯撒密码,但是不知道偏移量是多少,所以使用在线工具进行暴力破解。
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
偏移量密文
1 Ifndj_rpc_anjm_ftue_sentence,illh_ib_iwt_gauagain,yv_ayhuzmvytpun_kag_knlxvn_fa_hvs_wjosan.
2 Jg_oek_sqd_bokn_guvf_tfoufodf,jmmi_jc_jxu_hbv_bhbjo,zw_bzivanwzuqvo_lbh_lomywo_gb_iwt_xkptbo.
3 Kh_pfl_tre_cplo_hvwg_ugpvgpeg,knnj_kd_kyv_icw_cickp,ax_cajwboxavrwp_mci_mpnzxp_hc_jxu_ylqucp.
4 Li_qgm_usf_dqmp_iwxh_vhqwhqfh,lookle_lzw_jdx_djdlq,bydbkxcpybwsxq_ndj_nqoayq_id_kyv_zmrvdq.
5 Mj_rhn_vtg_ernq_jxyi_wirxirgi,mppl_mf_max_key_ekemr,cz_eclydqzcxtyr_oek_orpbzr_je_lzw_answer.
6 Nk_sio_wuh_fsor_kyzj_xjsyjshj,nqqm_ng_nby_lfz_flfns,da_fdmzeradyuzs_pfl_psqcas_kf_max_botxfs.
7 Ol_tjp_xvi_gtps_lzak_yktzktik,orrn_oh_ocz_mga_gmgot,eb_genafsbezvat_qgm_qtrdbt_lg_nby_cpuygt.
8 Pm_ukq_ywj_huqt_mabl_zlualujl,psso_pi_pda_nhb_hnhpu,fc_hfobgtcfawbu_rhn_rusecu_mh_ocz_dqvzhu.
9 Qn_vlr_zxk_ivru_nbcm_amvbmvkm,qttp_qj_qeb_oic_ioiqv,gd_igpchudgbxcv_sio_svtfdv_ni_pda_erwaiv.
10 Ro_wms_ayl_jwsv_ocdn_bnwcnwln,ruuq_rk_rfc_pjd_jpjrw,he_jhqdivehcydw_tjp_twugew_oj_qeb_fsxbjw.
11 Sp_xnt_bzm_kxtw_pdeo_coxdoxmo,svvr_sl_sgd_qke_kqksx,if_kirejwfidzex_ukq_uxvhfx_pk_rfc_gtyckx.
12 Tqyoucanlyux_qefp_dpyepynp,twws_tmthe_rlf_lrlty,jg_ljsfkxgjeafy_vlr_vywigy_ql_sgd_huzdly.
13 Ur_zpv_dbo_mzvy_rfgq_eqzfqzoq,uxxt_un_uif_smg_msmuz,kh_mktglyhkfbgz_wms_wzxjhz_rm_the_ivaemz.
14 Vs_aqw_ecp_nawz_sghr_fragrapr,vyyu_vo_vjg_tnh_ntnva,li_nluhmzilgcha_xnt_xaykia_sn_uif_jwbfna.
15 Wt_brx_fdq_obxathisgsbhsbqs,wzzv_wp_wkh_uoi_ouowb,mj_omvinajmhdibyouybzljb_to_vjg_kxcgob.
16 Xu_csy_ger_pcyb_uijt_htcitcrt,xaaw_xq_xli_vpj_pvpxc,nk_pnwjobkniejc_zpv_zcamkc_up_wkh_lydhpc.
17 Yv_dtz_hfs_qdzc_vjku_iudjudsu,ybbx_yr_ymj_wqk_qwqyd,ol_qoxkpclojfkd_aqw_adbnld_vq_xli_mzeiqd.
18 Zw_eua_igtreadwklv_jvekvetv,zccy_zs_znk_xrl_rxrze,pm_rpylqdmpkgle_brxbecomewr_ymj_nafjre.
19 Ax_fvb_jhu_sfbe_xlmw_kwflwfuw,addzataol_ysm_sysaf,qn_sqzmrenqlhmf_csy_cfdpnf_xs_znk_obgksf.
20 By_gwc_kiv_tgcf_ymnx_lxgmxgvx,beea_bu_bpm_ztn_tztbg,rotransformingdtz_dgeqog_yt_aol_pchltg.
21 Cz_hxd_ljw_uhdg_znoy_myhnyhwy,cffb_cv_cqn_auo_uauch,sp_usbotgpsnjoh_eua_ehfrph_zu_bpm_qdimuh.
22 Da_iye_mkx_vieh_aopz_nziozixz,dggc_dw_dro_bvp_vbvdi,tq_vtcpuhqtokpi_fvb_figsqi_av_cqn_rejnvi.
23 Eb_jzf_nly_wjfi_bpqa_oajpajya,ehhd_ex_esp_cwq_wcwej,ur_wudqviruplqj_gwc_gjhtrj_bw_dro_sfkowj.
24 Fc_kag_omz_xkgj_cqrb_pbkqbkzb,fiie_fy_ftq_dxr_xdxfk,vs_xverwjsvqmrk_hxd_hkiusk_cx_esp_tglpxk.
25 Gd_lbh_pna_ylhk_drsc_qclrclac,gjjf_gz_gur_eys_yeygl,wt_ywfsxktwrnsl_iye_iljvtl_dy_ftq_uhmqyl.
26 He_mci_qob_zmil_estd_rdmsdmbd,hkkg_ha_hvs_fzt_zfzhm,xu_zxgtyluxsotm_jzf_jmkwum_ez_gur_vinrzm.
  1. 仔细观察,注意加粗部分单词,组合后得到句子。
    If you can read this sentence, look at the key again, by transforming you become to the answer.
    翻译⼀下:如果你能读懂这句话,再看一遍密钥,通过转变你会接近答案。

  2. 根据上⼀步结果,提取密钥(偏移量):[1, 12, 12, 18, 15, 1, 4, 19, 12, 5, 1, 4, 20, 15, 18, 15, 13, 5]

  3. 根据题干另一部分可以知道要按照126(题干为16进制)转化为对应的⼩写字⺟az,得到中间答案:[a, l, l, r, o, a, d, s, l, e, a, d, t, o, r, o, m, e]

  4. 可以看出这是一句谚语,猜测是All roads lead to Rome,再通过后一部分,将特定字⺟按照对应⽅式替换,根据题干的奇怪样子,仿照添加下划线,得到最终的答案
    flag{@11_20@ds_1e@d_t0_20me}

你知道aCropalypse吗?

  1. 搜索acropalypse,找到GitHub上的恢复脚本

  2. 按照README运行gui.py,得到flag.png(可以通过题干猜出选择为Windows11,按照默认参数也可以得到答案)

  3. 查看左下角脚本,根据题干分析,写出破解脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def decrypt(text):
en_text = ""
for c in text:
if c == " ":
en_text += "_"
elif c == "a":
en_text += "@"
elif c == "c":
en_text += "("
elif c == "d":
en_text += "$"
elif c == "e":
en_text += "3"
elif c == "o":
en_text += "0"
elif c == "i":
en_text += "!"
else:
en_text += c.upper()
return en_text
text = "now you know acropalypse~"
print("flag{%s}" % decrypt(text))

最后得到flag{N0W_Y0U_KN0W_@(R0P@LYPS3~}

本次⽐赛圆满结束,感谢⼤家周末两天时间的积极竞赛和不懈努力!国家安全离不开密码技术的发展,密码安全由大家共同守护!

                                                        ----⽹络空间安全⼤学⽣创新实践基地全体成员敬上