第一部分:数据加解密
Q1 简单的数据解密
1.1 题目描述

1.2 考点分析
考点1:维吉尼亚密码
(1)维吉尼亚密码是什么?
维吉尼亚密码就是用一个循环表(key)来对字符串中的每个字母进行循有规律的平移。在标准密码学中,维吉尼亚密码只处理英文字母,遇到下划线、空格或标点符号时通常直接跳过并保留原样。
(2)维吉尼亚加密、解密过程过程
以下是一个维吉尼亚加密的示例:

以下是一个维吉尼亚解密的示例:

(3)CyberChef中进行维吉尼亚加解密
加密时搜索Vigenère encode:

解密时搜索Vigenère decode:

考点2:MD5加密
(1)什么是MD5哈希
MD5哈希就是将任意长度的输入数据,通过一系列复杂的数学变换,压缩成一个固定长度为128位的哈希值(32字节字符串),过程中无需输入KEY。
(2)CyberChef进行MD5哈希
直接搜索MD5即可。

1.3 扩展练习
题目链接 :https://buuoj.cn/challenges,搜索[MRCTF2020]vigenere
知识点:KEY分析、解密算法修改
思路分析 :题目附件中给了2个文件,第一个文件cipher.txt中存放的维吉尼亚加密后的密文,第二个文件vigenere.py中介绍了本题采用的维吉尼亚加密逻辑。
对py文件进行进一步解读,发现里面有2个关键信息:一是return(getchar((getdiff(src) + getdiff(key) + 1) % 26))这一行,意味着加密逻辑为 C i = ( P i + K i + 1 ) ( m o d 26 ) C_i = (P_i + K_i + 1) \pmod{26} Ci=(Pi+Ki+1)(mod26),而非传统的 C i = ( P i + K i ) ( m o d 26 ) C_i = (P_i + K_i) \pmod{26} Ci=(Pi+Ki)(mod26),因此对应设计的解密逻辑为 P i = ( C i − K i − 1 + 26 ) ( m o d 26 ) P_i = (C_i - K_i - 1 + 26) \pmod{26} Pi=(Ci−Ki−1+26)(mod26),将原来加密时多加的那个1给减掉;二是assert(len(key_string) > 5 and len(key_string) < 10)这一行,意味着密码长度为6-9,在设计Kasiski 测试法时尝试这几个长度的KEY即可。
操作 :
结合加密逻辑以及KEY长度的限制,编写维吉尼亚解密脚本:
python
# 纯标准库实现,适合离线环境
import string
# 标准英文字母频率表 (期望值)
ENGLISH_FREQS = {
'a': 0.08167, 'b': 0.01492, 'c': 0.02782, 'd': 0.04253, 'e': 0.12702,
'f': 0.02228, 'g': 0.02015, 'h': 0.06094, 'i': 0.06966, 'j': 0.00015,
'k': 0.00772, 'l': 0.04025, 'm': 0.02406, 'n': 0.06749, 'o': 0.07507,
'p': 0.01929, 'q': 0.00095, 'r': 0.05987, 's': 0.06327, 't': 0.09056,
'u': 0.02758, 'v': 0.00978, 'w': 0.02360, 'x': 0.00150, 'y': 0.01974,
'z': 0.00074
}
def get_ic(text):
"""计算文本的重合指数 (IC)"""
n = len(text)
if n <= 1: return 0
freqs = {char: text.count(char) for char in string.ascii_lowercase}
ic = sum(f * (f - 1) for f in freqs.values()) / (n * (n - 1))
return ic
def custom_decrypt_char(c_char, k_char):
"""题目的魔改解密逻辑:P = (C - K - 1 + 26) % 26"""
c_val = ord(c_char) - ord('a')
k_val = ord(k_char) - ord('a')
p_val = (c_val - k_val - 1 + 26) % 26
return chr(p_val + ord('a'))
def solve_vigenere(ciphertext):
# 清洗数据,只保留小写字母用于频率分析
clean_text = "".join([c for c in ciphertext.lower() if c.isalpha()])
print("[*] 第一步:通过重合指数 (IC) 寻找密钥长度 (范围 6-9)")
best_length = 0
best_ic = 0
for length in range(6, 10):
# 将密文按长度分组,计算所有列的平均 IC 值
avg_ic = 0
for i in range(length):
column = clean_text[i::length]
avg_ic += get_ic(column)
avg_ic /= length
print(f" 长度 {length} 的平均 IC 值为: {avg_ic:.5f}")
# 记录最接近 0.065 的那个长度
if avg_ic > best_ic:
best_ic = avg_ic
best_length = length
print(f"[+] 确定最优密钥长度为: {best_length}\n")
print("[*] 第二步:通过卡方检验逐字符爆破密钥")
final_key = ""
for i in range(best_length):
column = clean_text[i::best_length]
best_char = 'a'
lowest_chi_sq = float('inf')
# 尝试 a-z 26个字母
for guess_key in string.ascii_lowercase:
# 1. 尝试解密当前列
decrypted_col = [custom_decrypt_char(c, guess_key) for c in column]
col_len = len(decrypted_col)
# 2. 计算卡方值
chi_sq = 0
for char in string.ascii_lowercase:
observed = decrypted_col.count(char)
expected = ENGLISH_FREQS[char] * col_len
if expected > 0:
chi_sq += ((observed - expected) ** 2) / expected
if chi_sq < lowest_chi_sq:
lowest_chi_sq = chi_sq
best_char = guess_key
final_key += best_char
print(f"[+] 爆破成功!发现完整密钥: {final_key}\n")
print("[*] 第三步:执行最终解密")
plaintext = ""
key_idx = 0
for char in ciphertext:
if char.isalpha():
is_upper = char.isupper()
c_lower = char.lower()
k_char = final_key[key_idx % best_length]
p_char = custom_decrypt_char(c_lower, k_char)
plaintext += p_char.upper() if is_upper else p_char
key_idx += 1
else:
# 保留原文中的标点和下划线
plaintext += char
return plaintext
# ========= 执行区域 =========
# 请将 MRCTF2020 题目的实际密文填入下方
# 读取同目录下的 cipher.txt 文件内容作为密文
with open(r'C:\Users\Lxf\Desktop\cipher.txt', 'r', encoding='utf-8') as f:
target_ciphertext = f.read()
result = solve_vigenere(target_ciphertext)
print("[+] 最终还原的明文 (内含 Flag):\n")
print(result)
程序运行的最后一行中包含了flag,可知最终答案为flag{vigenere_crypto_crack_man}

Q2 用户session 算法解密
第二部分
Q1 API接口分析

思路:python_api.py中的函数handle_client()解释了对数据的核心加密逻辑。服务器端先发送一个欢迎语,然后接收到客户输入的账户名account,提取出这个账户名对应的手机号,依次进行base64 -> AES-CBC(key为vndchwxkfqatkhnt,初始化向量IV为rrwynwinvzlogwmy) -> base64加密,然后将密文发送给客户端。因此,在本地中向192.168.239.131:8006发送请求获取到账户zhangsan的手机号加密信息后,依次进行base64 -> AES-CBC -> base64解密即可。
操作:
- Step1。获取账户zhangsan对应的手机号密文。kali-linux命令行窗口输入
nc 192.168.239.131:8006,会得到zhangshan的手机号密文。 - Step2。base64解码。打开CyberChef,Frombase64即可
- Step3。AES-CBC解密。CyberChef中选择AES Decrypt,配置如下参数

- Step4。base64解码。就能得到手机号信息了!
Q2 数据窃取程序分析
题目描述 :

思路:本题考察逆向分析。sendc本质上是一个编译好的C/C++文件,直接把它丢进IDA Pro中,查看main的strings视图即可。
操作 :
由于没有原题,本题编写一个c程序进行编译后还原原题环境。
- Step1。将下面这个文件
sendc.c写好后,kali中使用指令gcc sendc.c -o sendc将c文件编译成二进制文件sendc。
c
#include <stdio.h>
#include <string.h>
int main() {
// 假设这就是那个窃取程序,目标IP被硬编码了
char *target_ip = "192.168.233.66";
char stolen_data[] = "/etc/passwd content...";
printf("Initializing network...\n");
// 模拟建立连接并发送数据
printf("Connecting to %s to send data...\n", target_ip);
return 0;
- Step2。查看反编译结果。在IDA Pro中打开文件sendc,双击左侧栏中的main,然后点击工具栏中的View -> Open Subviews -> Strings以查看原程序中的所有可见文本。也可View -> Open Subviews -> Generate pesuecode直接查看反编译结果

配置的指令 :指令idea64用于打开idea pro软件, 切回分析数据文件所在目录后使用指令idaclean清除所有缓存文件
Q3 安全风险数据识别与分析
题目描述 :

思路:本题考察日志分析。