1. 赛事背景与参赛体验
2025年长城杯线上赛作为国内网络安全领域的重要赛事,今年吸引了超过3000支队伍参与角逐。作为连续三年参赛的老兵,我想分享这次比赛中几个典型题目的解题思路和技术要点。不同于官方Writeup的标准化描述,这里会着重还原解题过程中的真实思考路径和那些"灵光一现"的关键突破点。
比赛采用传统的Jeopardy赛制,涵盖Web安全、逆向工程、密码学、二进制漏洞和杂项五大类题目。今年的题目设置有个明显特点:不再考察单一知识点,而是要求选手在复杂场景中串联多项技术。比如一道看似简单的Web题,可能需要结合流量分析、密码破解和自定义解码器才能拿到flag。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Web安全类题目解析
2.1 题目"Secret Gallery"的突破过程
这道题首先呈现为一个图片分享网站,表面功能极其简单:
- 用户注册/登录系统
- 图片上传/查看功能
- 基础的搜索框
常规测试路径:
- 尝试SQL注入:搜索框和登录表单均存在WAF防护
- 测试文件上传:限制严格,仅允许jpg/png且校验文件头
- 检查Cookie:发现JWT令牌,但签名强度足够
转折点出现在分析前端代码时,发现一个隐藏的API端点:
javascript复制// 前端打包代码中发现的线索
const fetchGallery = async (id) => {
try {
const res = await fetch(`/api/gallery/${id}?debug=true`, {
headers: { 'X-Admin': 'false' }
});
return await res.json();
}...
}
关键突破步骤:
- 修改
debug=true参数触发详细错误信息 - 发现后端使用MongoDB的
$where操作符 - 构造特殊的ID参数实现JS注入:
code复制/api/gallery/1%27%2B(()=%3E{return%20process.env.FLAG})()%2B%27
重要教训:现代Web应用往往会隐藏调试接口,这些接口通常缺乏生产环境级别的安全防护。打包后的前端代码和sourcemap文件是重要情报来源。
2.2 题目"Old School Blog"的链式利用
这道题模拟了一个老式PHP博客系统,解题过程展示了漏洞链的构建:
第一阶段:信息收集
- 通过
robots.txt发现/adminer-4.8.1.php - 目录扫描找到
/backups/20240501.sql.gz
第二阶段:突破点
- 利用Adminer的SSRF特性连接mysql://127.0.0.1:3306
- 从备份文件获取到默认凭证admin/p@ssw0rd123
- 登录后发现SQLi过滤存在缺陷:
sql复制SELECT * FROM posts WHERE id=1 AND 1=IF(MID(@@version,1,1)=5,BENCHMARK(10000000,SHA1(1)),1)
第三阶段:提权操作
- 通过
into outfile写入PHP webshell - 利用
LOAD_FILE读取/etc/passwd发现www-data用户 - 最终在
/var/backups找到包含flag的数据库备份
3. 逆向工程类题目详解
3.1 题目"Baby RE"的反混淆技巧
这道看似简单的逆向题实际上考察了多层代码混淆的应对能力。提供的二进制文件challenge在IDA中显示为:
c复制int main() {
char s[100];
puts("Input:");
fgets(s, 100, stdin);
if ( check(s) ) puts("Correct!");
else puts("Wrong!");
}
实际分析难点:
check函数被ollvm混淆,控制流平坦化- 关键比较操作被替换为动态计算的函数指针
- 部分校验逻辑通过
SIGTRAP信号处理程序实现
解题关键步骤:
- 使用
angr符号执行绕过控制流混淆:
python复制import angr
p = angr.Project("challenge")
state = p.factory.entry_state()
simgr = p.factory.simulation_manager(state)
simgr.explore(find=0x4012A3, avoid=0x4012B0)
print(simgr.found[0].posix.dumps(0))
- 动态调试发现反调试陷阱:
bash复制gdb -q ./challenge
(gdb) catch signal SIGTRAP
(gdb) commands
>silent
>set $rax = 0
>continue
>end
- 最终识别出核心算法是变种的TEA加密,密钥隐藏在
.rodata段的伪随机数中
3.2 题目"ARM Challenge"的架构适配
这道题提供了一个ARMv8架构的二进制文件,在x86环境中运行需要特殊处理:
环境准备:
bash复制# 安装qemu和交叉编译工具链
sudo apt install qemu-user-static gcc-aarch64-linux-gnu
# 运行动态链接版本
qemu-aarch64 -L /usr/aarch64-linux-gnu/ ./challenge
# 静态分析推荐
apt install ghidra
分析中发现的关键点:
- 使用
strncmp比较时故意错位输入:
armasm复制ldr x0, [sp, 0x18] ; 用户输入
ldr x1, [sp, 0x20] ; 比较目标
add x1, x1, 1 ; 故意偏移比较位置
bl strncmp
- 关键校验逻辑被分割到
.init_array和.fini_array段 - 通过
mprotect动态修改代码段权限
解决方案:
- 使用
strace跟踪系统调用 - 通过
qemu的-g参数配合gdb-multiarch调试 - 最终发现需要输入字符串的SHA256值满足特定格式
4. 密码学题目精讲
4.1 题目"RSA Paradox"的陷门利用
这道题给出了以下参数:
code复制n = 0xb8af3d3afb8935...
e = 0x10001
c = 0x4f8ae3e1d6c2b9...
看似标准的RSA加密,但实际暗藏玄机:
-
常规分解n失败(300位大整数)
-
发现n可以表示为:
python复制p = 2**1024 - 2**512 + 1 q = 2**1024 + 2**512 + 1 assert n == p * q -
利用特殊结构快速计算φ(n):
python复制phi = (p-1)*(q-1) d = pow(e, -1, phi) -
解密时发现flag被分割成多段加密,需要中国剩余定理组合:
python复制from Crypto.Util.number import long_to_bytes m1 = pow(c1, d, p) m2 = pow(c2, d, q) flag = (m1 * q * pow(q, -1, p) + m2 * p * pow(p, -1, q)) % n
4.2 题目"Lattice Attack"的格基规约
这道题给出了ECDSA签名系统的部分信息:
- 使用secp256k1曲线
- 泄露了256个签名对应的k值最高位
- 需要恢复私钥d
解题采用经典的HNP(Hidden Number Problem)攻击:
- 构建格基矩阵:
python复制B = 2^252 # 已知bit数
m = 256 # 签名数量
M = matrix(ZZ, m+2, m+2)
for i in range(m):
M[i,i] = q
M[m,i] = (r[i]*inverse_mod(s[i],q)) % q
M[m+1,i] = (inverse_mod(s[i],q)*(B*t[i])) % q
M[m,m] = 1
M[m+1,m+1] = B/q
- 使用LLL算法规约:
python复制L = M.LLL()
for row in L:
if abs(row[-1]) == B//q:
d = (row[-2] * q//B) % q
if verify_d(d):
break
- 最终恢复出的私钥可以解密给出的flag密文
5. 实战经验总结
5.1 比赛策略优化建议
-
时间分配矩阵:
题目类型 初始评估时间 最长投入时间 放弃阈值 Web 15分钟 2小时 3次尝试 Reverse 30分钟 3小时 IDA卡顿 Crypto 20分钟 1.5小时 数学复杂 Pwn 25分钟 2小时 环境问题 -
团队协作模式:
- 一人负责监控新题发布
- 两人专攻各自擅长领域
- 最后1小时集中解高分题
5.2 工具链配置技巧
高效比赛环境搭建:
bash复制# 使用tmux分屏布局
tmux new-session -s ctf
tmux split-window -h
tmux split-window -v
tmux select-pane -t 0
tmux split-window -v
# 常用工具快速启动脚本
#!/bin/bash
case $1 in
"web") docker run -p 8080:8080 --rm -ti web_audit ;;
"rev") r2 -d ./challenge ;;
"crypto") sage ;;
*) echo "Usage: $0 {web|rev|crypto}" ;;
esac
5.3 常见失误警示
-
Web类:
- 忽略HTTP头中的线索(如JWT弱密钥)
- 过度依赖自动化工具漏掉手动测试点
-
Reverse类:
- 没有识别出反调试陷阱
- 忽略动态链接库中的关键函数
-
Crypto类:
- 错误实现数学公式
- 没有验证中间计算结果
这次比赛最深的体会是:现代CTF题目越来越注重"贴近实战"的设计理念。那些看似简单的题目往往隐藏着需要多维度思考的突破点。建议新手从基础题目入手,逐步培养"攻击面思维"——不仅要看到明面的功能,更要思考开发者可能忽略的安全边界。
