PEANUT996

React2Shell攻击防护

· Peanuts

背景

漏洞概述

2025 年 12 月 3 日,React Server Components 中一个严重的未认证远程代码执行(RCE)漏洞被公开披露,编号为 CVE-2025-55182(又名 “React2Shell”),CVSS v3.x 评分 10.0,CVSS v4 评分 9.3

该漏洞允许未认证的攻击者通过发送单个 HTTP 请求,以运行 Web 服务器进程的用户权限执行任意代码。由于 React Server Components(RSC)被 Next.js 等主流框架广泛使用,暴露在互联网上的易受攻击系统数量巨大。

受影响的 RSC 包版本为 19.0、19.1.0、19.1.1 和 19.2.0:

  • react-server-dom-webpack
  • react-server-dom-parcel
  • react-server-dom-turbopack

已观测到的攻击活动

据 Google 威胁情报组(GTIG)报告,漏洞披露后迅速出现了大规模利用活动,涉及从机会型网络犯罪到国家级间谍组织的多个威胁集群:

威胁组织部署的恶意软件目标
UNC6600(中国关联)MINOCAT 隧道工具全球
UNC6586(疑似中国关联)SNOWLIGHT 下载器 / VSHELL 后门全球
UNC6588(中国关联)COMPOOD 后门未知
UNC6603(中国关联)HISONIC 后门亚太地区云基础设施
UNC6595(中国关联)ANGRYREBEL.LINUXVPS 基础设施
经济利益驱动XMRIG 加密货币挖矿广泛

此外,GTIG 还观察到伊朗关联的攻击者利用该漏洞。

我们观察到的攻击行为

Next.js Server Actions 通过 Next-Action HTTP 请求头来标识要调用的服务端函数。该请求头的值是构建时生成的 40 位十六进制哈希(如 a1b2c3d4e5f6...)。

攻击者利用这一机制,发送携带极短或任意 Next-Action的 POST 请求(如 "x""r""dontcare")来探测服务器。这会触发如下错误:

Failed to find Server Action "x". This request might be from an older or newer deployment.

这类探测请求会造成以下影响:

  • 产生大量服务端错误日志
  • 消耗服务器资源处理无效请求
  • 作为进一步攻击的侦察手段(侦察成功后可能部署后门、挖矿程序等)
  • 与 CVE-2025-55182(React2Shell)直接相关

修复建议

  • 立即升级 React Server Components 至 19.0.1、19.1.2 或 19.2.1 以上(推荐升级至 19.2.3 以同时修复后续的 CVE-2025-55183、CVE-2025-55184、CVE-2025-67779)
  • 部署 WAF 规则作为升级前的临时缓解措施
  • 审计依赖:检查项目中是否包含受影响的 RSC 包
  • 监控网络流量:检查由 Web 服务器进程发起的 wget/cURL 出站连接
  • 入侵排查:检查 $HOME/.systemd-utils 等隐藏目录、异常 cron 任务、shell 配置文件(如 .bashrc)中的恶意注入

参考来源:Google Threat Intelligence - Multiple Threat Actors Exploit React2Shell (CVE-2025-55182)

请求特征对比

合法的 Server Action 请求:

POST / HTTP/2
Content-Type: text/x-component
Next-Action: 9a3b7c8d2e1f0a4b5c6d7e8f9a0b1c2d3e4f5a6b

恶意探测请求:

POST / HTTP/2
Content-Type: text/x-component
Next-Action: x

核心区别在于 Next-Action 值的长度和格式。合法值始终是 40 位十六进制字符串。

通用解决方案

拦截 Next-Action 请求头存在但值长度小于 20 个字符的 POST 请求。这个阈值是安全的,因为:

  • 合法的 action ID 是 40 位十六进制哈希
  • 20 字符远低于合法长度
  • 仅在请求头存在时触发,不影响普通 POST 请求(表单提交、API 调用等)

各层防护方案对比

层级方案优点缺点
CDN/WAF基于请求头长度的防火墙规则在边缘拦截,不消耗源站资源可能需要付费功能
边缘计算程序化检查请求头灵活,免费套餐可用配置稍复杂
应用层中间件校验无外部依赖浪费服务器资源
反向代理Nginx/Caddy 请求头过滤完全可控需要自建基础设施

Nginx 示例

location / {
    if ($request_method = POST) {
        set $block_action "";
    }
    if ($http_next_action ~ "^.{1,19}$") {
        set $block_action "${block_action}_short";
    }
    if ($block_action = "_short") {
        return 403;
    }
    proxy_pass http://upstream;
}

Next.js 应用中间件示例

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  if (request.method === 'POST') {
    const nextAction = request.headers.get('next-action');
    if (nextAction && nextAction.length < 20) {
      return new NextResponse('Forbidden', { status: 403 });
    }
  }
  return NextResponse.next();
}

Cloudflare 解决方案

方案一:WAF 自定义规则(推荐)

路径: Cloudflare Dashboard → Security → WAF → Custom Rules

使用 matches 正则(需要 Business/Enterprise 套餐)

(http.request.method eq "POST" and any(http.request.headers["next-action"][*] matches "^.{0,19}$"))

使用 len() 函数(需要 Business/Enterprise 套餐)

(http.request.method eq "POST" and any(len(http.request.headers["next-action"][*]) < 20))

严格格式校验(需要 Business/Enterprise 套餐)

仅允许合法的 40 位十六进制哈希通过:

(http.request.method eq "POST" and any(http.request.headers["next-action"][*] ne "") and not any(http.request.headers["next-action"][*] matches "^[a-f0-9]{40}$"))

Free/Pro 套餐替代方案

matcheslen() 运算符需要 Business 套餐。Free/Pro 套餐可以使用 or 枚举已知的攻击值:

(any(http.request.headers["next-action"][*] eq "x")) or
(any(http.request.headers["next-action"][*] eq "dontcare")) or
(any(http.request.headers["next-action"][*] eq "r"))

注意: 此方案只能拦截已知的攻击模式。需要持续观察日志,发现新的攻击 payload 后手动添加。

操作建议: 先将 Action 设为 Log 观察,确认无误杀后再切换为 Block

方案二:Cloudflare Workers(所有套餐可用)

对于 Free/Pro 套餐需要通用长度检查的场景,可以使用 Workers 在边缘执行:

export default {
  async fetch(request, env) {
    const action = request.headers.get('Next-Action');
    if (request.method === 'POST' && action && action.length < 20) {
      return new Response('Forbidden', { status: 403 });
    }
    return fetch(request);
  }
};

Workers 在边缘运行,无套餐限制,提供与 WAF 正则规则相同的防护效果。

注意事项

  • Cloudflare 在 WAF 表达式中会将所有请求头名称转为小写。始终使用 next-action,而非 Next-Action
  • 规则仅在 Next-Action 请求头存在时触发,不影响正常的 POST 流量。
  • 部署后在 Security → Events 中监控规则命中情况,确认拦截效果且无误杀。