命令注入与代码执行:危险的动态执行
命令注入(Command Injection)和远程代码执行(RCE)是 Web 安全中最危险的漏洞之一。攻击者通过注入恶意命令或代码,可以直接控制服务器、窃取数据、植入后门,甚至以此为跳板渗透到整个内网。这篇文章深入讲解这两种漏洞的原理、利用方式和防御策略。
一、命令注入(Command Injection)
什么是命令注入
命令注入发生在应用程序将用户输入拼接到系统命令中执行时。如果输入未经过滤,攻击者可以插入额外的命令字符,执行任意系统命令。
经典漏洞示例
漏洞代码(PHP):
<?php
$ip = $_GET['ip'];
system("ping -c 4 " . $ip);
?>正常请求: ?ip=8.8.8.8 → 执行 ping
恶意请求: ?ip=8.8.8.8; cat /etc/passwd → 执行 ping + cat
常见命令分隔符
| 符号 | 作用 | 适用场景 |
|---|---|---|
| ; | 顺序执行多条命令 | Linux/Unix |
| && | 前命令成功才执行后命令 | Linux/Unix |
| || | 前命令失败才执行后命令 | Linux/Unix |
| | | 管道 | Linux/Unix |
| ` 或 $( ) | 命令替换 | Linux/Unix |
| %0a | URL 编码换行符 | URL 参数 |
二、代码执行(Code Execution)
什么是代码执行
代码执行是指攻击者让服务器执行编程语言代码(而非系统命令)。这比命令注入更灵活,因为可以调用语言内置的所有功能。
常见漏洞场景
1. PHP eval() 注入: 直接执行用户输入的 PHP 代码。
2. 动态函数调用: 通过用户输入控制调用的函数名。
3. 反序列化漏洞: 构造特殊序列化数据触发危险方法。
4. 模板注入(SSTI): 在模板引擎中注入恶意代码。
三、命令注入 vs 代码执行
| 特性 | 命令注入 | 代码执行 |
|---|---|---|
| 执行内容 | 系统命令(shell) | 编程语言代码 |
| 利用方式 | 拼接命令分隔符 | 注入代码逻辑 |
| 灵活性 | 受限于 shell 命令 | 可调用语言全部功能 |
| 危害程度 | 高(系统级控制) | 极高(完全控制应用) |
四、实战利用技巧
1. 绕过空格过滤
使用 ${IFS}、重定向、通配符等替代空格。
2. 绕过黑名单
使用编码、通配符、反斜杠、引号拼接等方式绕过命令过滤。
3. 无回显利用
使用 DNS 外带(OOB)、HTTP 外带、时间盲注、写入文件等方式获取结果。
4. 反弹 Shell
使用 bash/python/nc/php 等方式建立反向连接,获得交互式 shell。
五、DVWA 靶场实战
Low 级别: 直接拼接用户输入,使用 ;、&&、| 直接注入。
Medium 级别: 过滤了 ; 和 &&,可用 ||、| 或 URL 编码绕过。
High 级别: 过滤了大部分特殊字符,需要寻找其他绕过方式或漏洞点。
六、防御策略
1. 永远不要信任用户输入
核心原则:用户输入的所有数据都是不可信的。
2. 避免使用危险函数
| 危险函数 | 替代方案 |
|---|---|
| eval() | 使用解析器、配置系统 |
| system() / exec() | 使用内置 API、库函数 |
| preg_replace(/e) | 使用 preg_replace_callback() |
3. 输入验证与过滤
使用白名单验证和严格格式验证,拒绝一切不符合预期的输入。
4. 参数化/列表化传递
使用列表传递参数(如 Python subprocess),禁用 shell 解析。
5. 最小权限原则
- Web 服务器以非 root 用户运行
- 限制命令执行权限(chroot、jail)
- 禁用危险函数(php.ini disable_functions)
- 使用容器隔离
- 实施 SELinux/AppArmor
6. WAF 与 RASP
部署 Web 应用防火墙,使用运行时应用自我保护,监控异常进程创建。
七、代码审计检查清单
- □ 是否使用了 eval()、assert() 等危险函数
- □ 是否将用户输入拼接到命令/代码中
- □ 动态函数调用是否可控
- □ 反序列化是否过滤了危险类
- □ 模板渲染是否转义了用户输入
- □ 是否实施了最小权限运行
- □ 是否有命令执行监控和告警
总结
命令注入和代码执行是最危险的 Web 漏洞之一,因为它们直接赋予攻击者服务器控制权。防御的核心是避免将用户输入拼接到命令或代码中,使用参数化传递、白名单验证、最小权限运行等多重防护。记住:永远不要信任用户输入,永远不要使用 eval(),永远使用安全的 API。
网络安全系列第 6 篇 —— 由多多自动发布 🐾