2026软件系统安全赛Writeup - 综合题型解析教学
引言
本文档基于2026年软件系统安全赛的官方Writeup,系统性地解析了其中涉及的关键安全技术与解题思路。内容涵盖逆向工程、密码学、网络流量分析、隐写术、Web安全等多个领域,旨在为学习者提供一套完整、深入的分析框架和方法论。
第一部分:逆向工程(Reverse Engineering)
题目1:PyC文件恢复与ELF提取
1.1 初始分析
- 目标:从提供的Base64数据中恢复Python字节码(.pyc)文件
- 核心代码片段显示,多个Base64片段拼接后解码,可得到完整的
.pyc文件 - 关键工具:IDA Pro用于分析主函数,确定需要恢复pyc文件
1.2 恢复与反编译
- Base64解码:将提供的
b64_parts列表拼接后解码 - 文件写入:生成
payload_encoder.pyc文件 - 反编译工具:使用PyLingual等工具对pyc文件进行反编译
1.3 核心逻辑分析
反编译后得到Payload_To_PixelCode_video.py,其主要功能是将任意文件编码为视频:
- 读取输入文件,转换为二进制字符串
- 使用固定异或密钥
10101010(0xAA)对每8位进行异或加密 - 将加密后的比特流按8x8像素块映射到视频帧中(黑=1,白=0)
1.4 逆向恢复流程
要恢复原始文件(此处为ELF可执行文件),需执行反向操作:
- 视频帧解析:按8x8像素块读取每帧,根据平均像素值判断比特(黑=1,白=0)
- 比特流重组:将所有帧的比特按顺序拼接
- 异或解密:每8位为一组,与0xAA异或,恢复原始字节
- 文件重建:将字节流写入文件,得到原始ELF
1.5 进阶分析:ELF中的MD5字符表
恢复出的ELF文件中包含一系列32位十六进制字符串,经验证为单字符的MD5哈希值。
- 攻击方法:预计算可打印ASCII字符的MD5值,建立查找表
- 恢复脚本:提取ELF中的MD5字符串,通过查表反推原始字符,拼接得到flag
最终flag:dart{2ab1fb8a-b830-45e7-8830-66c7e3b3e05a}
题目2:多层壳保护程序分析
2.1 初步检测
- 使用查壳工具检测,发现程序被加壳
- 尝试使用UPX等工具脱壳,但可能遇到变种或自定义壳
2.2 导入表分析
导入函数极少,仅包含LoadLibraryA、GetProcAddress、VirtualProtect,表明程序动态解析API,是壳或Loader的典型特征。
2.3 动态脱壳与仿真
由于静态分析困难,采用动态或仿真方案:
- 工具:使用Speakeasy仿真框架
- 步骤:
- 加载样本到仿真环境
- 执行所有入口点
- 提取解包后的内存镜像(
unpacked.bin)
2.4 内存镜像分析
在unpacked.bin中搜索,发现一段很长的Base64数据,开头为TVqQ(即"MZ"的Base64编码),表明内嵌了一个PE文件。
2.5 第二阶段载荷提取
- 使用正则提取Base64 blob
- Base64解码,写入
stage2.exe
2.6 第二阶段深入分析
stage2.exe为正常PE结构,但关键节区(.hello、.mydata)被加密。
- 加密算法识别:通过反汇编识别出典型的RC4算法特征(KSA和PRGA函数)
- 密钥位置:存储在
.rdata节区 - 整体保护层次:
- 第一层:UPX壳
- 第二层:Base64内嵌PE
- 第三层:RC4加密节区
解密.hello和.mydata后,发现程序核心是AES输入验证逻辑。但题目目标并非破解输入,而是分析样本中隐藏的UUID标识符。
最终flag:dart{c3d4f5cc-8aab-46ce-a188-2fc453f3b288}
题目3:Python打包程序与自定义块加密
3.1 程序解包
- 目标:PyInstaller打包的Python可执行文件
- 工具:使用在线工具(如pyinstxtractor-web)或本地工具解包,获取内部的pyc文件
3.2 反编译分析
反编译client.pyc,发现核心加密模块为crypt_core.so,以及自定义的Base64编码表和密钥处理逻辑。
- 自定义Base64:码表被替换
- 密钥推导:原始Base85编码的密钥材料,处理后取前16字节作为最终密钥
3.3 分析crypt_core.so
.so文件的反编译代码混乱,需从汇编和常量特征入手。
- 核心函数:
encode_data(plaintext, key) - 算法特征:
- 分组大小16字节
- PKCS#7填充
- 轮密钥扩展
- 轮函数中包含
x ^ rol(x, 2) ^ rol(x, 10) ^ rol(x, 18) ^ rol(x, 24)等线性变换,类似SM4但非标准(为24轮变体)
3.4 解密流程
由于不是标准SM4,需逆向encode_data函数,实现对应的解密算法:
- 密文按16字节分组
- 轮密钥逆序应用
- 移除PKCS#7填充
对提供的三段密文(readme.txt,flag.txt,config.txt)使用密钥passvkcDKWLAA45o解密。
最终flag:dart{f4b547fc-b3d0-44c3-bf21-8f3fb5ad3220}
第二部分:密码学(Cryptography)
题目:多层RSA与秘密共享
1. 题目结构
提供level1/目录和加密的level2.zip。
level1/包含:- 加密脚本
encrypt.py - 明文生成脚本
generate-plaintexts.py - 多个RSA公钥(
key-*.pem) - 多个密文(
ciphertext-*.bin)
- 加密脚本
- 目标:解密
ciphertext,恢复message,获得level2.zip密码。
2. 加密逻辑分析(encrypt.py)
根据RSA模数n的位数选择两种模式:
- n_bits >= 2048:使用RSA-OAEP加密一个32字节的随机AES-GCM密钥,再用该密钥加密消息。
- n_bits < 2048:使用裸RSA(
pow(key_int, e, n))加密一个16字节的随机AES-GCM密钥。
3. 明文生成逻辑(generate-plaintexts.py)
- 将10个
message分别进行简化的Asmuth-Bloom秘密共享。 - 每个
message的共享数据(份额)被拼接,形成10个plaintext文件。 - 每个
plaintext-j.txt的第一行是message1的内容,后续9行分别是message2~message10的第j个份额。
4. 攻击步骤
4.1 恢复RSA私钥
- 检查公钥间的共性:发现
key-1与key-2、key-15与key-4存在共因子,可通过计算GCD恢复私钥。 - 对其他密钥尝试Wiener攻击、Fermat分解等,共恢复11个私钥。
4.2 解密密文
使用恢复的私钥解密对应的ciphertext-*.bin。解密后明文格式为固定头+多行份额数据。每行格式:modulus : remainder : bitlen。
4.3 重构秘密(中国剩余定理)
对每个message(2~10),收集其足够的份额(di, ki),其中ki = S mod di。使用中国剩余定理(CRT)求解原始秘密S,即message内容。
关键message7的内容包含level2.zip的密码:9Zr4M1ThwVCHe4nHnmOcilJ8
5. 第二层:小私钥指数攻击
解压level2.zip得到task.py和level3.zip。
- 关键参数:
d为180-bit素数,e = d^{-1} mod lam,其中lam = lcm(p-1, q-1)。 - 攻击思路:由于
d很小,可尝试推广的Wiener攻击。枚举g = gcd(p-1, q-1)的可能小值,对(e * g) / n进行连分数逼近,恢复d。 - 成功找到
g=4,恢复p和q。 - 下一层密码为
sha256(str(p+q).encode()).hexdigest(),即:2aa9c360df99cbb4209e4dbab5a9f9ffd86d34906e3206fecfdabf0bb7aeb5ac
6. 第三层:基于泄露信息的RSA私钥恢复
解压level3.zip得到新的task.py,提供n, e, c和一个复杂的leak表达式。
- 攻击思路:利用
n = p * q和leak表达式的特性,从低位到高位逐位恢复p和q的比特。 - 实现算法:对于每一位
k,枚举p和q当前位的可能值(0,1),检查(p*q) mod 2^k是否匹配n mod 2^k,同时检查leak mod 2^k是否匹配。由于每一步候选很少,可唯一确定。 - 恢复
p和q后,标准RSA解密得到flag。
最终flag:dart{379c9308-e9a8-45a1-bd55-45bbd822e86d}
第三部分:网络流量分析(Traffic Hunt)
1. 流量概览
- 文件:一个网络流量pcapng文件。
- 主要内容:HTTP流量,其中存在大量带有长
rememberMeCookie的请求,这是Apache Shiro框架反序列化漏洞的典型特征。
2. Shiro RememberMe 反序列化分析
- 攻击者通过构造恶意的
rememberMe值,利用Shiro的反序列化漏洞执行任意命令。 - 从流量中提取
rememberMe的Base64值,解码后得到Java序列化对象,可分析出利用链(如commons-collections)。 - 攻击者执行了
whoami、pwd、ls等命令,并上传了一个Webshell。
3. Webshell通信分析
- 上传的Webshell路径:
/favicondemo.ico,并给出了连接密码和密钥。 - 后续流量中出现大量与该Webshell的加密通信(POST请求,请求体/响应体为Base64字符串)。
- 攻击者通过Webshell下载并执行了一个二进制程序
/var/tmp/out,该程序携带AES密钥参数,并连接C2服务器10.1.243.155:7788。
4. C2自定义协议解密
- 过滤出目标IP端口
7788的TCP流量。 - 协议格式:4字节小端长度 + AES-GCM加密数据。
- 密钥来自命令行参数:
IhbJfHI98nuSvs5JweD5qsNvSQ/HHcE/SNLyEBU9Phs=(Base64解码为32字节AES密钥)。 - 编写解密脚本,按长度字段分割数据流,使用AES-GCM解密(nonce为前12字节,tag为后16字节)。
5. 获取Flag
解密后的通信明文显示攻击者执行了echo命令,输出一串长字符串:3SoX7GyGU1KBVYS3DYFbfqQ2CHqH2aPGwpfeyvv5MPY5Dm1Wt9VYRumoUvzdmoLw6FUm4AMqR5zoi。
- 此字符串经Base58解码,再Base64解码后,得到最终flag。
最终flag:dart{d9850b27-85cb-4777-85e0-df0b78fdb722}
第四部分:隐写术(Steganography)
1. 文件格式修复
- 目标文件末端魔数被篡改(
FFFFFFFF)。 - 将其修复为正确的7z归档头部魔数:
37 7A BC AF 27 1C。
2. 图片隐写分析
修复后解压得到一张图片。使用隐写分析工具(如Stegsolve、zsteg)检查。
- 发现LSB(最低有效位)隐写。
- 在Stegsolve中,提取RGB通道最低位(RGB 0,0,0)的数据,得到一个加密的ZIP压缩包。
3. CRC32爆破攻击
- 该ZIP包内包含多个
pass*.zip文件,每个子ZIP内只有一个4字节的文本文件,并已知其CRC32值。 - 攻击原理:CRC32是公开算法,已知CRC32值和文件长度(4字节),可爆破出原始内容。
- 编写脚本,遍历所有4字节可打印字符组合,计算CRC32并与目标值比对。
- 将所有爆破出的4字节字符串拼接,得到完整密码短语:
c1!xxtLf%fXYPkaA。
4. 零宽字符隐写
使用上述密码解压flag.zip,得到flag.txt。但内容非明文,包含大量零宽字符。
- 零宽字符类型:
- 零宽空格 (
U+200B) 代表比特0 - 零宽非连接符 (
U+200C) 代表比特1
- 零宽空格 (
- 解码脚本:遍历文本中的每个字符,识别零宽字符并转换为比特流,每8位转换为一字节ASCII字符,得到最终flag。
最终flag:(从解码后的零宽隐写信息中获得)
第五部分:Web安全(Auth - 综合渗透)
1. 目标与入口
- 目标Web应用,具备注册、登录、头像上传、管理员查看在线用户等功能。
- 初始状态:普通用户权限。
2. 漏洞挖掘与利用链
2.1 任意文件读取/SSRF(漏洞点:头像URL下载)
- 功能:
/profile/avatar允许用户通过URL上传头像。 - 底层使用
urllib.request.urlopen(),未对协议和路径做限制。 - 利用:通过
file://协议读取服务器敏感文件。file:///etc/passwdfile:///app/app.py(获取源码)file:///etc/redis/redis.conf(获取Redis密码redispass123)file:///proc/self/environ及/proc/<pid>/cmdline(获取进程信息,定位高权限本地服务)
2.2 源码分析与Redis交互逻辑
从app.py得知:
- 登录后,用户对象被
pickle.dumps()并存入Redis键online_user:{username}。 - 管理员端点
/admin/online-users会读取所有online_user:*键,并使用一个“受限”的RestrictedUnpickler进行反序列化。 - 该Unpickler允许
__main__.OnlineUser和builtins.getattr/setattr等,存在被利用的风险。
2.3 CRLF注入攻击Redis(漏洞点:头像URL下载的SSRF)
- 利用
urllib发送请求时,可在URL中插入\r\n(CRLF)来注入额外的协议命令。 - 已知Redis运行在本地
6379,密码从配置文件中获得。 - Payload示例:
http://127.0.0.1:6379/\r\nAUTH redispass123\r\nHSET user:<当前用户名> role admin\r\nQUIT\r\n - 效果:将当前用户在Redis中的角色改为
admin,重新登录后获得管理员会话。
2.4 定位高权限本地服务
- 通过读取
/proc/<pid>/cmdline,发现一个监听在高权限端口的Python XML-RPC服务(mcp_server_secure.py)。 - 读取该脚本,获取认证token和端口号。该服务以root权限运行,可执行任意命令。
2.5 构造恶意Pickle对象触发RCE
- 目标:在管理员访问
/admin/online-users时触发反序列化,执行命令。 - 虽然Unpickler受限,但允许
getattr。可构造调用链,最终获取os.system。 - 最终Payload思路:让反序列化执行的命令,调用上述高权限XML-RPC服务,执行
cat /flag,并将结果写入/tmp/flag_root。
2.6 写入恶意Pickle到Redis
再次利用CRLF注入SSRF,将构造好的恶意Pickle字节码写入Redis键online_user:{当前用户名}。
2.7 触发与获取Flag
- 以管理员身份访问
/admin/online-users,触发反序列化,执行恶意命令。 - 命令调用本地root XML-RPC服务读取
/flag并写入/tmp/flag_root。 - 再次利用头像下载的任意文件读取功能,读取
file:///tmp/flag_root,从返回的Base64图片数据中提取flag。
3. 利用总结
这是一个经典的“SSRF -> Redis未授权访问/注入 -> 篡改数据/写入恶意数据 -> 不安全反序列化 -> RCE -> 信息泄露”的综合利用链。关键点在于将文件读取、协议注入、反序列化漏洞与内网高权限服务相结合,实现权限提升和敏感信息窃取。
总结
本Writeup详细解析了软件系统安全赛中涉及的多种安全技术场景。从逆向工程中的文件格式分析、加壳脱壳,到密码学的复杂RSA场景与共享秘密恢复;从网络流量中的协议分析、加密通信解密,到隐写术的多层隐藏与Web安全的纵深渗透利用链,涵盖了CTF竞赛和实战中常见的技术要点。掌握这些分析方法与工具的使用,对于提升软件安全分析与漏洞挖掘能力至关重要。