为什么 Wazuh 错过了 React2Shell
Source: Dev.to
请提供您希望翻译的完整文本内容,我将为您翻译成简体中文并保留原有的格式、Markdown 语法以及代码块和链接。谢谢!
介绍
安全社区最近被 React2Shell 震动,这是一种严重的未认证远程代码执行(RCE)漏洞。它最初被记录在两个 CVE 中:
CVE-2025-55182– ReactCVE-2025-66478– Next.js
该漏洞的 CVSS 评分为 10.0,影响 Next.js 15/16(App Router) 以及任何依赖 React 19 的 RSC 实现 的框架。
Wazuh 发布了一篇很棒的博客,解释了如何检测此漏洞:
👉
然而,经过更深入的研究,我发现了一个关键限制,这不仅适用于此 CVE,也适用于大多数现代应用栈。
检测盲区:为什么 SIEM 对本地项目视而不见
标准的漏洞检测器(包括 Wazuh 的默认模块)擅长查找通过系统管理器(如 apt 或 npm install -g)安装的包。现代开发却在别处进行:
| 技术 | 依赖项的典型位置 |
|---|---|
| Node.js | 每个项目内部的本地 node_modules 文件夹 |
| Python | 虚拟环境(venv、uv)将包与系统隔离 |
| Docker | 包埋在容器层中(/var/lib/docker/...) |
如果你的 SIEM 没有检查这些本地路径,你就像在盲目飞行。因此,项目目录中的 Next.js 或 React 的易受攻击版本会被 Wazuh 漏掉。
我之前在这里解释过这个问题:
👉
Wazuh 提供了若干功能来帮助,但没有一个能完全解决此问题。
IT 卫生 / 漏洞检测
- 文档:
- 文档:
它的作用: 仅检测全局安装的包。
它的盲点:
- 本地 Node.js 项目
- Python 虚拟环境
- Docker 容器
文件完整性监控 (FIM)
- 文档:
它的作用: 检测文件变更。
它不提取的内容:
- 包名
- 版本
- 漏洞状态
命令监控
- 文档:
优点: 可以从 Wazuh 管理器运行脚本。
缺点:
- 风险高——如果管理器被攻破,所有代理都会受影响。
- 不建议用于频繁扫描。
因此,我需要一种 更安全、更精准的方法。
解决方案:自定义清单工作流
仅靠静态扫描器是不够的。我们需要一个主动脚本来:
- 在文件系统中爬取
package.json文件。 - 提取特定高风险库(
react、next)的版本信息。 - 将发现记录到 JSON 文件中。
- 将该文件导入 Wazuh,实现实时告警。
步骤 1:清单脚本
下面是一个轻量级的 Python 脚本,不会排除 /var/lib/docker,从而能够在容器镜像内部找到易受攻击的库。
将其保存为 /usr/local/bin/scan_react2shell.py 并赋予可执行权限(chmod +x /usr/local/bin/scan_react2shell.py)。
#!/usr/bin/env python3
import json
import os
# --- CONFIGURATION -------------------------------------------------
LOG_FILE = "/var/log/react2shell_scan.json"
SEARCH_PATHS = ["/"] # Roots to scan
EXCLUDE_DIRS = {"/proc", "/sys", "/dev", "/run", "/tmp", "/snap", "/boot"}
# ------------------------------------------------------------------
def scan_system():
print(f"[*] Starting inventory scan on: {SEARCH_PATHS}")
# Ensure log file exists
if not os.path.exists(LOG_FILE):
try:
open(LOG_FILE, "w").close()
print(f"[*] Created new log file at {LOG_FILE}")
except IOError as e:
print(f"[!] Could not create log file: {e}")
return
inspected = 0
for root_dir in SEARCH_PATHS:
for dirpath, dirnames, filenames in os.walk(root_dir, followlinks=True):
# Skip excluded directories
if any(excl in dirpath for excl in EXCLUDE_DIRS):
dirnames[:] = [] # Prevent walk into sub‑dirs
continue
if "package.json" not in filenames:
continue
# Identify if the package is a top‑level react/next module
parent_dir = os.path.basename(dirpath)
grandparent_dir = os.path.basename(os.path.dirname(dirpath))
pkg_name = None
if grandparent_dir == "node_modules":
if parent_dir == "react":
pkg_name = "react"
elif parent_dir == "next":
pkg_name = "next"
if not pkg_name:
continue
pkg_path = os.path.join(dirpath, "package.json")
try:
with open(pkg_path, "r", encoding="utf-8", errors="ignore") as f:
data = json.load(f)
version = data.get("version", "0.0.0")
print(f"[+] Found {pkg_name} v{version} at {pkg_path}")
inspected += 1
# Tag Docker locations for easier downstream processing
display_path = pkg_path
if "/var/lib/docker" in pkg_path or "/var/lib/containerd" in pkg_path:
display_path = f"[DOCKER] {pkg_path}"
# Append entry to log file
entry = {
"package": pkg_name,
"version": version,
"path": display_path,
"timestamp": int(time.time())
}
with open(LOG_FILE, "a", encoding="utf-8") as log_f:
log_f.write(json.dumps(entry) + "\n")
except (IOError, json.JSONDecodeError) as e:
print(f"[!] Error reading {pkg_path}: {e}")
print(f"[*] Scan complete – inspected {inspected} vulnerable packages.")
return
if __name__ == "__main__":
scan_system()
脚本功能说明
- 从根目录
/开始遍历整个文件系统。 - 跳过已知的系统目录,这些目录不可能包含项目代码。
- 在
node_modules/react或node_modules/next中查找package.json文件。 - 提取
version字段,并将一行 JSON 写入/var/log/react2shell_scan.json。 - 对位于 Docker 存储路径(
/var/lib/docker或/var/lib/containerd)下的发现进行标记,以便后续处理。
rd`).
您可以使用 cron 或 systemd 定时器来调度此脚本,并配置 Wazuh 读取生成的日志文件以触发告警。
后续步骤
- 创建 Wazuh localfile 规则,监控
/var/log/react2shell_scan.json并解析其中的 JSON 条目。 - 定义告警规则,当版本匹配已知的漏洞范围时触发(例如 React 和 Next.js 的受影响版本区间)。
注意: 此脚本会扫描 package.json 文件,标记 react 和 next 等包,并检测它们是否位于 Docker 路径中。
示例输出
{"timestamp":"2025-12-11T13:15:07","scan_type":"react_inventory","package":"react","version":"19.2.1","path":"[DOCKER]/var/lib/docker/.../node_modules/react/package.json"}
{"timestamp":"2025-12-11T13:15:08","scan_type":"react_inventory","package":"next","version":"15.4.5","path":"/home/user/app/node_modules/next/package.json"}
Step 2 – Wazuh 集成
一旦脚本生成了 /var/log/react2shell_scan.json,请配置 Wazuh 以读取该文件。
1. 配置 Agent(localfile)
在 Wazuh Agent 配置文件 (ossec.conf) 或 通过集中配置,添加以下块:
<localfile>
<log_format>json</log_format>
<location>/var/log/react2shell_scan.json</location>
</localfile>
2. 集中推送配置
为避免在每台服务器上手动编辑 ossec.conf,请使用 Wazuh 的 集中配置 功能。
在 Wazuh Manager 上,编辑默认组的共享配置:
vim /var/ossec/etc/shared/default/agent.conf
将块插入 <agent_config> 标签内:
<agent_config>
<localfile>
<log_format>json</log_format>
<location>/var/log/react2shell_scan.json</location>
</localfile>
</agent_config>
工作原理
- 同步化: 在 Manager 上保存文件会生成新的 MD5 校验和。
- 传播: 下一次心跳时,Agent 检测到变化,下载更新后的
agent.conf并重启日志收集器。 - 可见性: 每当 Python 脚本(通过 cron 运行)更新
/var/log/react2shell_scan.json,数据就会被流式传输到 Wazuh Manager 进行规则评估。
3. 创建检测规则
将以下规则添加到 Manager 的本地规则文件 (/var/ossec/etc/rules/local_rules.xml):
<rule id="100500" level="12">
<if_sid>100500</if_sid>
<field name="type">json</field>
<field name="program_name">react_inventory</field>
<description>Inventory: Found $(package) version $(version) at $(path).</description>
</rule>
<rule id="100501" level="12">
<if_sid>100500</if_sid>
<field name="package">react</field>
<field name="version">^19\.0\.0$|^19\.1\.[0-1]$|^19\.2\.0$</field>
<cve>CVE-2025-55182</cve>
<reference>https://nvd.nist.gov/vuln/detail/CVE-2025-55182</reference>
<description>Vulnerable React2Shell detected: React $(version) at $(path)</description>
<mitre> T1190 </mitre>
</rule>
<rule id="100502" level="12">
<if_sid>100500</if_sid>
<field name="package">next</field>
<field name="version">^15\.0\.[0-4]$|^15\.1\.[0-8]$|^15\.4\.[0-7]$|^16\.0\.[0-6]$</field>
<cve>CVE-2025-66478</cve>
<reference>https://nvd.nist.gov/vuln/detail/CVE-2025-66478</reference>
<description>Vulnerable React2Shell detected: Next.js $(version) at $(path)</description>
<mitre> T1190 </mitre>
</rule>
第3步 – 使用 Ansible 部署
将脚本、cron 任务和权限部署到多台服务器 而不 使用 Wazuh 的 “Command Monitoring”。
---
- name: Deploy React2Shell inventory scanner
hosts: all
become: true
vars:
script_src: files/react2shell_scan.py
script_dest: /usr/local/bin/react2shell_scan.py
log_file: /var/log/react2shell_scan.json
cron_job: "0 2 * * * /usr/bin/python3 {{ script_dest }}"
tasks:
- name: Copy Python scanner script
copy:
src: "{{ script_src }}"
dest: "{{ script_dest }}"
mode: '0755'
- name: Ensure log file exists with correct permissions
file:
path: "{{ log_file }}"
state: touch
owner: wazuh
group: wazuh
mode: '0640'
- name: Install daily cron job
cron:
name: "React2Shell inventory scan"
minute: "0"
hour: "2"
job: "{{ cron_job }}"
user: root
运行 playbook:
ansible-playbook -i inventory.yml deploy-react2shell.yml
通知 / 消息集成
在您偏好的聊天平台上通过社区集成接收实时警报。

- Slack:
- Telegram:
Microsoft Teams 集成
- Microsoft Teams: https://github.com/0xdolan/wazuh-teams-integration
结论
通过将 “System Inventory” 转换为 “Application Inventory”, 我们捕获了一个 CVSS 10.0 漏洞,否则它会隐藏在本地 node_modules 文件夹中。