zer0lfsrCTF密码学题目技术解析

admin 2026-01-08 02:13:39 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详解基于LFSR的CTF题目,利用Z3求解器攻击稀疏反馈流密码。文章分析LFSR线性弱点,通过符号变量与约束方程模拟状态更新,成功从密钥流恢复初始状态并获取Flag。内容涵盖LFSR安全缺陷、Z3应用技巧及现代密码设计原则建议。 综合评分: 96 文章分类: CTF,漏洞分析,二进制安全


cover_image

zer0lfsr CTF密码学题目技术解析

原创

破镜安全

破镜安全

2026年1月7日 08:01 四川

zer0lfsr CTF密码学题目技术解析

一、题目概述

本题是一道基于线性反馈移位寄存器(LFSR)的流密码破解挑战。题目提供了加密算法源代码chall.py和生成的密钥流文件keystream。我们的目标是通过分析算法和密钥流,恢复出三个LFSR的初始状态,并计算出flag。

题目文件包括:

  • chall.py: 包含LFSR实现、组合函数和密钥流生成逻辑
  • keystream: 使用未知初始状态生成的8192字节密钥流

二、算法分析

2.1 LFSR基本原理

线性反馈移位寄存器(Linear Feedback Shift Register, LFSR)是一种常用的伪随机数生成器,广泛应用于流密码系统中。其基本工作原理如下:

  1. 维护一个固定长度的二进制状态
  2. 每次迭代时,状态左移一位
  3. 根据反馈多项式(由mask定义)选择特定位进行异或运算,得到反馈位
  4. 将反馈位填入状态的最低位
  5. 输出反馈位作为密钥流的一位

让我们详细分析题目中的LFSR实现:

class lfsr():
    def __init__(self, init, mask, length):
        self.init = init
        self.mask = mask
        self.lengthmask = 2**(length+1)-1  # 注意:是length+1,即49位掩码

    def next(self):
&nbsp; &nbsp; &nbsp; &nbsp; nextdata = (self.init <<&nbsp;1) & self.lengthmask &nbsp;# 左移并保持在49位以内
&nbsp; &nbsp; &nbsp; &nbsp; i = self.init & self.mask & self.lengthmask &nbsp;&nbsp;# 提取mask选中的位
&nbsp; &nbsp; &nbsp; &nbsp; output =&nbsp;0
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 计算mask选中位的异或
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;i !=&nbsp;0:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output ^= (i &&nbsp;1)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i = i >>&nbsp;1
&nbsp; &nbsp; &nbsp; &nbsp; nextdata ^= output &nbsp;# 将输出异或到最低位
&nbsp; &nbsp; &nbsp; &nbsp; self.init = nextdata
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;output

关键观察点:

  1. 状态扩展: 初始状态是48位,但lengthmask = 2^49 – 1,这意味着状态在迭代过程中会扩展到49位
  2. 反馈机制: mask决定了哪些位参与反馈计算,通过异或运算得到输出位
  3. 稀疏mask: 每个LFSR的mask只有2位被设置为1,这是一个重要的弱点

2.2 三个LFSR的配置

题目使用了三个独立的LFSR,配置如下:

l1 = lfsr(int.from_bytes(init1,"big"),&nbsp;0b100000000000000000000000010000000000000000000000,&nbsp;48)
l2 = lfsr(int.from_bytes(init2,"big"),&nbsp;0b100000000000000000000000000000000010000000000000,&nbsp;48)
l3 = lfsr(int.from_bytes(init3,"big"),&nbsp;0b100000100000000000000000000000000000000000000000,&nbsp;48)

通过分析mask的二进制表示(从右往左,从第0位开始计数):

  • LFSR1: 第47位和第22位参与反馈
  • LFSR2: 第47位和第13位参与反馈
  • LFSR3: 第47位和第41位参与反馈

每个LFSR的初始状态为6字节(48位),mask中只有2个位置为1,这意味着每个输出位只依赖于当前状态中的2个位。

2.3 组合函数

三个LFSR的输出通过combine函数组合成最终的密钥流:

def&nbsp;combine(x1, x2, x3):
&nbsp; &nbsp;&nbsp;return&nbsp;(x1*x2)^(x2*x3)^(x1*x3)

由于x1、x2、x3都是单比特值(0或1),乘法运算等价于按位与(AND)操作。因此该函数可以改写为:

def&nbsp;combine(x1, x2, x3):
&nbsp; &nbsp;&nbsp;return&nbsp;(x1 & x2) ^ (x2 & x3) ^ (x1 & x3)

这是一个多数表决函数(majority function):

  • 当三个输入中至少有两个为1时,输出为1
  • 否则输出为0

真值表如下:

| x1 | x2 | x3 | 输出 | | — | — | — | — | | 0 | 0 | 0 | 0 | | 0 | 0 | 1 | 0 | | 0 | 1 | 0 | 0 | | 0 | 1 | 1 | 1 | | 1 | 0 | 0 | 0 | | 1 | 0 | 1 | 1 | | 1 | 1 | 0 | 1 | | 1 | 1 | 1 | 1 |

2.4 密钥流生成过程

密钥流的生成代码如下:

with&nbsp;open("keystream","wb")&nbsp;as&nbsp;f:
&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;range(8192):
&nbsp; &nbsp; &nbsp; &nbsp; b =&nbsp;0
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;j&nbsp;in&nbsp;range(8):
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b = (b<<1)+combine(l1.next(),l2.next(),l3.next())
&nbsp; &nbsp; &nbsp; &nbsp; f.write(chr(b).encode())

生成过程:

  1. 外层循环8192次,每次生成一个字节
  2. 内层循环8次,每次从三个LFSR各取一位,通过combine函数组合得到一位输出
  3. 将8位组合成一个字节b
  4. 使用chr(b).encode()将字节转换为字符并编码为UTF-8写入文件

重要发现: 这里使用了chr(b).encode(),这意味着文件是UTF-8编码的文本文件,而不是二进制文件。这在后续读取密钥流时需要特别注意。

三、攻击原理分析

3.1 LFSR的安全弱点

本题中LFSR实现存在以下几个关键弱点:

  1. 状态空间较小: 每个LFSR的状态只有48位,总共144位的密钥空间。虽然看起来很大(约2^144),但对于现代密码分析来说是可以攻破的。
  2. 稀疏反馈多项式: 每个LFSR的mask只有2位被设置,意味着每个输出位只依赖于状态中的2个位。这大大降低了系统的复杂度。
  3. 线性特性: LFSR的状态更新完全是线性的,可以用线性方程组或布尔约束来表示。
  4. 已知密钥流: 我们拥有大量的输出密钥流,可以建立足够多的约束方程。

3.2 单个LFSR的比特传播分析

让我们深入分析单个LFSR的行为。以LFSR1为例,其mask的第47位和第22位为1。

假设初始状态为S0(48位),我们用S0[i]表示第i位(从0开始计数)。

第1次迭代:

  • 输出: o0 = S0[47] XOR S0[22]
  • 状态左移: S0 << 1
  • 新状态最低位: o0
  • 新状态S1 = (S0 << 1) XOR o0

第2次迭代:

  • 当前状态S1中,第47位是原来S0的第46位,第22位是原来S0的第21位
  • 输出: o1 = S1[47] XOR S1[22] = S0[46] XOR S0[21]
  • 新状态S2 = (S1 << 1) XOR o1

第3次迭代:

  • 输出: o2 = S2[47] XOR S2[22] = S0[45] XOR S0[20]

可以看到一个规律: 每个输出位都可以表示为初始状态中两个特定位的异或。这种线性关系是LFSR的本质特征。

3.3 使用约束求解器的攻击思路

由于LFSR的状态更新和组合函数都可以表示为布尔约束,我们可以使用SMT(Satisfiability Modulo Theories)求解器来恢复初始状态。Z3是微软研究院开发的一个强大的SMT求解器,非常适合解决这类问题。

基本攻击思路:

  1. 创建符号变量: 为三个LFSR的初始状态创建符号变量(未知数)
  2. 模拟算法执行: 用符号变量模拟LFSR的状态更新过程
  3. 添加约束条件: 对于每个已知的输出比特,添加一个约束方程
  4. 求解: 让Z3求解器找到满足所有约束的初始状态值

关键优势:

  • 不需要手工推导复杂的数学关系
  • 可以直接表达算法的逻辑约束
  • 自动处理非线性的组合函数

3.4 所需密钥流长度分析

理论上,要唯一确定144位的初始状态(3个LFSR各48位),我们至少需要144个独立的约束方程。但由于:

  1. 组合函数引入了非线性关系
  2. 可能存在冗余约束
  3. 需要一定的冗余度来保证求解成功

实践中,使用48个字符(384个比特)的密钥流就足够恢复初始状态。这远超理论最小值,确保了求解的可靠性。

四、解题实现

4.1 密钥流文件的正确读取

首先需要注意密钥流文件的编码问题。题目使用chr(b).encode()写入文件,这会将字节值转换为Unicode字符再编码为UTF-8。因此读取时必须使用UTF-8解码:

with&nbsp;open("keystream",&nbsp;'r', encoding='utf-8')&nbsp;as&nbsp;f:
&nbsp; &nbsp; data = f.read()

如果使用二进制模式读取(‘rb’),会得到UTF-8编码的字节序列,而不是原始的字节值。读取后,使用ord()函数可以恢复原始的字节值。

4.2 将密钥流转换为比特流

每个字符代表一个字节(8位),需要将其转换为比特流:

result_bits = []
for&nbsp;ch&nbsp;in&nbsp;keystream_chars:
&nbsp; &nbsp; byte_val = ord(ch)
&nbsp; &nbsp;&nbsp;# 从高位到低位提取8个比特
&nbsp; &nbsp; bits = [(byte_val >> (7-i)) &&nbsp;1&nbsp;for&nbsp;i&nbsp;in&nbsp;range(8)]
&nbsp; &nbsp; result_bits.extend(bits)

这样就得到了一个由0和1组成的比特序列,对应于combine函数的输出序列。

4.3 创建Z3符号变量和约束

使用Z3求解器的核心步骤如下:

步骤1: 创建求解器和符号变量

import&nbsp;z3

# 创建求解器
s = z3.Solver()

# 创建3个49位的符号变量(状态会扩展到49位)
state_bits =&nbsp;49
x = z3.BitVec('x', state_bits)
y = z3.BitVec('y', state_bits)
z_var = z3.BitVec('z', state_bits)
inits = [x, y, z_var]

步骤2: 约束初始状态为48位

虽然运行时状态会扩展到49位,但初始状态只有48位,需要添加约束:

init_mask = (1&nbsp;<<&nbsp;48) -&nbsp;1&nbsp;&nbsp;# 48位全1的掩码
s.add(z3.ULT(x, init_mask +&nbsp;1)) &nbsp;# x < 2^48
s.add(z3.ULT(y, init_mask +&nbsp;1)) &nbsp;# y < 2^48
s.add(z3.ULT(z_var, init_mask +&nbsp;1)) &nbsp;# z < 2^48

步骤3: 为每个输出比特添加约束

这是最核心的部分,需要模拟LFSR的运行过程并添加约束:

# mask位索引
mask_indices = [(47,&nbsp;22), (47,&nbsp;13), (47,&nbsp;41)]
len_mask_int = (2&nbsp;**&nbsp;49) -&nbsp;1

# 遍历每个输出比特
for&nbsp;idx, result&nbsp;in&nbsp;enumerate(result_bits):
&nbsp; &nbsp; combs = []
&nbsp; &nbsp; new_inits = []

&nbsp; &nbsp;&nbsp;# 对于3个LFSR
&nbsp; &nbsp;&nbsp;for&nbsp;lfsr_idx&nbsp;in&nbsp;range(3):
&nbsp; &nbsp; &nbsp; &nbsp; bit_idx1 = mask_indices[lfsr_idx][0]
&nbsp; &nbsp; &nbsp; &nbsp; bit_idx2 = mask_indices[lfsr_idx][1]

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 使用Extract提取特定位
&nbsp; &nbsp; &nbsp; &nbsp; bit1 = z3.Extract(bit_idx1, bit_idx1, inits[lfsr_idx])
&nbsp; &nbsp; &nbsp; &nbsp; bit2 = z3.Extract(bit_idx2, bit_idx2, inits[lfsr_idx])

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 计算单个LFSR的输出
&nbsp; &nbsp; &nbsp; &nbsp; output = bit1 ^ bit2
&nbsp; &nbsp; &nbsp; &nbsp; combs.append(output)

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 模拟LFSR状态更新
&nbsp; &nbsp; &nbsp; &nbsp; shifted = inits[lfsr_idx] <<&nbsp;1
&nbsp; &nbsp; &nbsp; &nbsp; output_extended = z3.ZeroExt(48, output) &nbsp;# 将1位扩展到49位
&nbsp; &nbsp; &nbsp; &nbsp; new_init = (shifted ^ output_extended) & len_mask_int
&nbsp; &nbsp; &nbsp; &nbsp; new_inits.append(new_init)

&nbsp; &nbsp;&nbsp;# 添加combine函数的约束
&nbsp; &nbsp; combined = (combs[0] & combs[1]) ^ (combs[1] & combs[2]) ^ (combs[0] & combs[2])
&nbsp; &nbsp; s.add(combined == result)

&nbsp; &nbsp;&nbsp;# 更新状态
&nbsp; &nbsp; inits = new_inits

4.4 关键技术要点解析

在实现过程中,有几个关键的技术细节需要特别注意:

1. BitVec的位数选择

必须使用49位而不是48位,因为LFSR的lengthmask是2^49-1,状态在运行过程中会扩展到49位。如果使用48位,会导致状态溢出,求解失败。

2. Extract操作的使用

使用z3.Extract()提取特定位,而不是使用Python的位运算符。这是因为Z3的BitVec类型和Python整数类型不能混合使用:

# 正确做法
bit1 = z3.Extract(47,&nbsp;47, inits[0]) &nbsp;# 提取第47位

# 错误做法
bit1 = (inits[0] >>&nbsp;47) &&nbsp;1&nbsp;&nbsp;# 会导致类型错误

3. ZeroExt操作的必要性

LFSR的输出是1位,但需要与49位的状态进行异或运算。必须使用z3.ZeroExt()将1位扩展到49位:

output_extended = z3.ZeroExt(48, output) &nbsp;# 将1位扩展到49位(48+1=49)

4. 约束数量的权衡

使用48个字符(384个比特)的密钥流就足够。更多的约束会增加求解时间,更少的约束可能导致无解或多解。

4.5 求解并提取结果

添加完所有约束后,调用Z3求解器并提取结果:

# 求解
check_result = s.check()

if&nbsp;check_result == z3.sat:
&nbsp; &nbsp; print("[+] 找到解!")
&nbsp; &nbsp; model = s.model()

&nbsp; &nbsp;&nbsp;# 提取解(只取低48位作为初始状态)
&nbsp; &nbsp; x_res = model[x].as_long() & init_mask
&nbsp; &nbsp; y_res = model[y].as_long() & init_mask
&nbsp; &nbsp; z_res = model[z_var].as_long() & init_mask

&nbsp; &nbsp;&nbsp;return&nbsp;x_res, y_res, z_res
else:
&nbsp; &nbsp; print("[-] 无解")
&nbsp; &nbsp;&nbsp;return&nbsp;None,&nbsp;None,&nbsp;None

4.6 计算FLAG

恢复初始状态后,按照题目要求计算flag:

from&nbsp;Crypto.Util.number&nbsp;import&nbsp;long_to_bytes
import&nbsp;hashlib

# 将初始状态转换为字节(每个48位=6字节)
init1 = long_to_bytes(x_res,&nbsp;6)
init2 = long_to_bytes(y_res,&nbsp;6)
init3 = long_to_bytes(z_res,&nbsp;6)

# 计算SHA256哈希
flag_hash = hashlib.sha256(init1 + init2 + init3).hexdigest()
flag =&nbsp;f"flag{{{flag_hash}}}"

print(f"FLAG:&nbsp;{flag}")

4.7 运行结果

运行完整的求解脚本后,得到以下结果:

[*] 使用 384 个比特的密钥流
[*] 开始添加约束条件...
[*] 已添加 100 个约束条件
[*] 已添加 200 个约束条件
[*] 已添加 300 个约束条件
[*] 开始求解约束条件...
[*] 求解结果: sat
[+] 找到解!

[+] 恢复的LFSR初始状态:
&nbsp; &nbsp; LFSR1: 0x40907168b76f
&nbsp; &nbsp; LFSR2: 0xa4a712d8249f
&nbsp; &nbsp; LFSR3: 0xae32a61e80e9

FLAG: flag{b527e2621131134ec22250cfbca75e8c9f5ae4f40370871fd55910927f66a1b4}

验证结果显示,使用恢复的初始状态生成的密钥流与原始密钥流完全匹配,证明我们成功破解了这个流密码系统。

五、技术总结与安全启示

5.1 LFSR流密码的安全性问题

通过本题的分析,我们可以总结出基于LFSR的流密码存在以下几个关键安全问题:

1. 线性特性是致命弱点

LFSR的状态更新完全是线性的,每个输出位都可以表示为初始状态位的线性组合(异或运算)。这种线性特性使得系统容易受到代数攻击,可以通过建立线性方程组或使用约束求解器来破解。

2. 稀疏反馈多项式降低安全性

本题中每个LFSR的mask只有2位,意味着每个输出位只依赖于2个状态位。这大大降低了系统的复杂度。即使使用了三个LFSR组合,由于反馈多项式过于稀疏,仍然容易被攻破。

3. 状态空间不足

48位的状态空间(约2^48 ≈ 2.8×10^14)在现代计算能力下是不够的。对于密码学应用,通常需要至少128位的安全强度。

4. 简单的组合函数无法提供足够保护

虽然使用了多数表决函数来组合三个LFSR的输出,但这个函数仍然是一个简单的布尔函数,可以被约束求解器有效处理。

5.2 约束求解器在密码分析中的应用

本题展示了SMT求解器(如Z3)在密码分析中的强大能力:

优势:

  • 可以直接表达密码算法的逻辑约束,无需手工推导数学关系
  • 自动处理复杂的布尔约束和位运算
  • 适用于状态空间较小的密码系统
  • 开发效率高,代码简洁易懂

局限性:

  • 对于大规模问题(如256位状态),求解时间可能过长
  • 需要足够的已知输出来建立约束
  • 对于高度非线性的系统,求解效率会显著下降

5.3 现代密码系统的设计原则

从本题的弱点中,我们可以总结出现代密码系统应该遵循的设计原则:

1. 足够的密钥长度

  • 对称密码至少128位密钥
  • 公钥密码至少2048位(RSA)或256位(ECC)
  • 避免使用短密钥以抵抗暴力破解

2. 非线性组件

  • 使用S盒(Substitution Box)引入非线性
  • 采用复杂的混淆和扩散机制
  • 避免纯线性的状态更新

3. 充分的轮数

  • 确保每个输入位影响所有输出位
  • 提供足够的安全边际
  • 抵抗差分和线性密码分析

4. 经过充分分析的算法

  • 优先使用标准算法(AES、ChaCha20等)
  • 避免自己设计密码算法
  • 新算法需要经过长期的密码学分析

5.4 解题过程中的关键技巧

在解决这类密码学CTF题目时,以下技巧非常重要:

1. 仔细分析算法实现

  • 注意边界条件和特殊处理(如本题的lengthmask是49位而非48位)
  • 理解每个参数的含义和作用
  • 识别算法的弱点和可利用点

2. 注意编码问题

  • 本题中chr(b).encode()导致文件是UTF-8编码而非二进制
  • 这类细节容易被忽略,但会导致解题失败
  • 始终验证数据的读取和解析是否正确

3. 先用已知数据测试

  • 在攻击真实数据前,先用已知初始状态生成测试数据
  • 验证求解器能否正确恢复已知的初始状态
  • 这种方法可以快速发现实现中的错误

4. 注意类型一致性

  • 在使用Z3时,避免Python类型和Z3类型混合
  • 使用Extract、ZeroExt等Z3专用操作
  • 类型错误是使用约束求解器时最常见的问题

六、扩展思考

6.1 如果增加mask位数会怎样?

假设每个LFSR的mask有8位而不是2位:

影响分析:

  • 每个输出位依赖的初始状态位从2个增加到8个
  • 约束方程的复杂度显著增加
  • 但仍然是线性关系,Z3仍然可以求解
  • 求解时间会增加,但对于48位状态仍然可行

结论: 增加mask位数可以提高安全性,但无法从根本上解决线性特性的问题。

6.2 如果状态长度更长会怎样?

假设状态长度从48位增加到128位或256位:

影响分析:

  • 搜索空间呈指数级增长(2^128或2^256)
  • 需要更多的密钥流数据来唯一确定初始状态
  • Z3求解时间会显著增加,可能变得不可行
  • 需要考虑其他攻击方法,如时间-内存权衡攻击

结论: 增加状态长度可以有效提高安全性,但仍需要配合其他安全措施。

6.3 如何改进这个密码系统?

如果要改进本题的密码系统,可以考虑以下方向:

1. 使用非线性反馈移位寄存器(NLFSR)

  • 在反馈函数中引入非线性项(如AND、OR等)
  • 破坏线性特性,使代数攻击更加困难
  • 例如: Grain流密码使用了NLFSR

2. 增加LFSR数量和状态长度

  • 使用5个或更多的LFSR
  • 每个LFSR的状态长度至少128位
  • 增加系统的复杂度和搜索空间

3. 使用更复杂的组合函数

  • 采用非线性的S盒进行组合
  • 使用多层的混淆和扩散
  • 参考现代流密码的设计(如Trivium、ChaCha20)

4. 定期重新初始化

  • 不使用同一初始状态生成大量密钥流
  • 定期更换密钥或重新初始化状态
  • 限制单个密钥的使用量

5. 添加初始化向量(IV)

  • 使用公开的IV与密钥组合初始化状态
  • 确保相同密钥在不同消息下产生不同密钥流
  • 防止密钥流重用攻击

但需要强调的是,即使进行这些改进,基于LFSR的流密码在现代密码学中已经较少使用。实际应用中更推荐使用经过充分分析和标准化的算法,如:

  • ChaCha20: 现代流密码,安全性高,性能优秀
  • AES-CTR: 将分组密码AES用于流密码模式
  • AES-GCM: 提供加密和认证的组合模式

七、结语

本题是一道典型的LFSR流密码破解挑战,通过分析我们学习到:

  1. LFSR的工作原理: 理解了线性反馈移位寄存器的状态更新机制和输出生成过程
  2. 线性密码的弱点: 认识到纯线性系统容易受到代数攻击,可以通过约束求解器破解
  3. Z3求解器的应用: 掌握了使用SMT求解器进行密码分析的方法,包括符号变量创建、约束添加和结果提取
  4. 实现细节的重要性: 学会了注意编码问题、类型一致性等实现细节,这些往往是解题成败的关键
  5. 现代密码学原则: 了解了安全密码系统应该具备的特性,包括足够的密钥长度、非线性组件、充分的轮数等

这道题目不仅是一次密码破解的实践,更是对密码学基本原理和现代密码分析技术的深入学习。通过这类CTF挑战,我们可以更好地理解密码系统的设计原则和安全性要求,为实际的安全工作打下坚实基础。


参考资料:

  • Z3 Solver官方文档: https://github.com/Z3Prover/z3
  • 《应用密码学》(Applied Cryptography) – Bruce Schneier
  • 《现代密码学》(Introduction to Modern Cryptography) – Jonathan Katz, Yehuda Lindell

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:破镜安全 破镜安全《zer0lfsr CTF密码学题目技术解析》

DIDCTF-应急响应 网络安全文章

DIDCTF-应急响应

文章总结: 本文档汇总了DIDCTF及长城杯等CTF竞赛中应急响应与取证题目的Writeup,涵盖日志审计、流量解密、数据恢复及恶意软件逆向。内容详细解析了We
评论:0   参与:  0