前言

命令注入(Command Injection),是后端直接拼接用户可控参数至系统 shell 命令执行所引发的高危漏洞。区别于 SQL 注入针对数据库、XSS 针对浏览器,命令注入直接操控操作系统底层指令,危害直达服务器本体。

运维人员、安全工程师在护网巡检中经常碰到:接口入参看似做了关键词过滤,仍被攻击者利用特殊字符、编码变形绕过防护,成功执行系统命令。本文从漏洞原理、常见业务场景、全品类绕过技巧、运维落地防御、面试考点完整梳理,兼顾实战挖洞与应急加固。

一、命令注入基础原理

1. 漏洞成因

后端开发直接把用户可控输入拼接入系统命令语句,调用系统接口(Runtime.exec、ProcessBuilder、system ()、exec () 等)执行 shell 指令;未对特殊分隔符、系统关键字做过滤,攻击者插入拼接字符,在原有指令后追加自定义恶意命令。

2. 攻击执行链路

用户提交恶意参数 → 程序拼接至系统命令 → 操作系统 shell 解析复合命令 → 恶意指令被执行 → 读取文件、反弹 shell、篡改系统配置。

3. 高危开发函数

Java:Runtime.getRuntime().exec()ProcessBuilder

PHP:system()、exec()、shell_exec()、passthru()

Python:os.popen、os.system、subprocess.call(shell=True)

错误示例

// 接收前端传入ip参数,直接拼接ping命令
String ip = request.getParameter("ip");
// 漏洞:可控参数直接拼接shell指令
Runtime.getRuntime().exec("ping -c 1 " + ip);

4. 高频出现业务场景

  1. 在线 IP 探测、域名 PING 测速功能;
  2. 后台文件压缩、解压、备份调度功能;
  3. 远程文件同步、服务器磁盘空间查询;
  4. 运维平台自定义脚本参数输入。

二、常用命令分隔符

符号 作用 示例
; 顺序执行,前一条执行完毕执行后一条(Linux 通用) ping 127.0.0.1;id
| 管道符,前一条输出作为后一条输入 ping 127.0.0.1|whoami
|| 逻辑或,前命令失败则执行后续 ping xxx||cat /etc/passwd
&& 逻辑与,前命令执行成功才执行后续 ping 127.0.0.1&&ls -l
& 后台并发执行(Windows/Linux 通用) ping 127.0.0.1 & calc

三、关键字过滤绕过全方案

开发常采用黑名单过滤:拦截cat、ls、id、whoami、netstat等命令关键词、;|& 等符号,攻击者通过变形、编码、分隔、特殊语法绕过,也是护网应急溯源最常见的攻击手法。

1. 空格绕过

系统 shell 支持多种占位符替代空格:

cat${IFS}/etc/passwd

2. 关键词截断拼接绕过

(1)反斜杠 \ 分隔字符

c\at /etc/passwd

(2)单引号 / 双引号拆分字符

c'a't /etc/passwd
c"a"t /etc/passwd

(3)变量截取构造命令

a=c;b=at;$a$b /etc/passwd

3. 环境变量取值绕过

利用系统环境变量截取字符拼接指令,规避关键词黑名单:

# 利用PATH、PS1等内置变量切片取值
${PATH:5:1}${PATH:8:1} /etc/passwd

4. 编码绕过

(1)URL 编码

前端参数 URL 二次编码,后端解码后还原特殊字符与命令; 原始:;id → URL 编码:%3Bid

(2)八进制 / 十六进制编码

echo -e "\x63\x61\x74" /etc/passwd

5. 通配符模糊匹配绕过

利用*、?通配符模糊匹配文件路径,不用完整文件名:

cat /etc/pass?wd
ls /etc/pass*

6. 换行符 %0a 换行注入

部分过滤仅拦截同行分隔符,换行符可另起一行执行新命令:

127.0.0.1%0aid

7. 嵌套命令绕过 ` 反引号、$()

`id`
$(whoami)
ping 127.0.0.1$(cat /etc/passwd)

8. Windows 系统特殊绕过

利用 cmd 特殊语法:^换行转义、% 变量截取,适用于 Windows 服务器命令注入场景。

四、高阶无字母数字命令注入

当系统过滤全部英文字母、数字,仅保留符号,攻击者依托 Linux 内置运算符、环境变量构造命令,护网高危难点漏洞,多用于无过滤白名单场景。

五、企业和运维全维度防御方案

1. 最优方案:禁用字符串拼接,参数列表调用

Java 使用ProcessBuilder多参数构造,参数与指令分离,杜绝拼接,从底层阻断注入。

// 安全写法:指令、参数分开传入,不会拼接注入
List<String> cmd = Arrays.asList("ping","-c","1",ip);
ProcessBuilder pb = new ProcessBuilder(cmd);

禁止任何形式的字符串拼接系统命令。

2. 输入校验:采用白名单,摒弃黑名单

  1. 入参格式强校验:如 PING 功能仅允许 IPv4/IPv6 正则格式,不符合直接拒绝;
  2. 限制输入内容,只允许数字、小数点等业务必需字符,其余特殊符号直接拦截;

3. 特殊字符全局过滤

非业务必需的分隔符:; | & $ \ ' " 、换行符、IFS 相关字符统一拦截。

4. 运行权限最小化

应用运行进程使用低权限普通账号,禁止 root/Administrator 权限运行 Web 服务;即便触发命令注入,攻击者也无法高权限篡改系统、植入后门。

5. 运维兜底防护

  1. 系统启用 bash 审计日志,记录异常系统调用,护网期间快速溯源攻击行为;
  2. WAF 配置命令注入特征规则,拦截含各类绕过字符的异常请求;
  3. 定期代码审计,全局检索 Runtime、ProcessBuilder、system 等危险执行函数。

6. 沙箱隔离

高危运维功能单独部署在隔离沙箱服务器,与核心业务服务器内网隔离,避免漏洞横向扩散。

六、安全面试高频背诵考点

1. 命令注入和 SQL 注入的区别?

命令注入攻击操作系统 shell,执行系统指令;SQL 注入攻击数据库引擎,执行 SQL 语句;二者注入对象、利用函数、危害范围不同。

2. 黑名单过滤为什么防不住命令注入?

攻击者可通过空格替代符、引号拆分、环境变量截取、编码、通配符等几十种变形绕过关键词与符号黑名单,无法穷举所有绕过方式,白名单 + 参数分离才是安全方案。

3. 防止命令注入最有效的编码方案是什么?

不拼接字符串,采用数组形式拆分命令与参数,使用 ProcessBuilder 等参数化调用 API。

4. IFS 是什么,在注入中的作用?

Linux 内置环境变量,代表分隔空格,攻击者用 ${IFS} 替换空格绕过空格过滤,实现命令注入。

七、总结

  • 命令注入核心根源:可控参数直接拼接系统 shell 命令,是护网蓝队应急处置 TOP 级漏洞;
  • 绕过核心思路:替换空格、拆分关键词、编码变形、环境变量取值、换行另起指令;
  • 安全三原则:优先参数化调用不拼接、入参使用白名单强校验、进程权限最小化;
  • 运维侧记住:黑名单永远无法彻底防御注入,只能作为辅助兜底策略。
Logo

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

更多推荐