目录
[(1)分号 ;](#(1)分号 ;)
[(2)"与"符号 &&](#(2)“与”符号 &&)
[(3)"或"符号 ||](#(3)“或”符号 ||)
[(4)管道符 |](#(4)管道符 |)
本文讲解CTFHub的RCE-命令注入关卡的原理和渗透实战的全过程。命令注入是由于应用程序未对用户输入充分过滤,导致攻击者可拼接恶意命令执行。文章详细解析了分号、与/或符号、管道符等常见命令分隔符的原理及跨平台差异,并提出了输入过滤、安全函数、最小权限等防范措施。实战部分通过分析靶场PHP源码,发现其直接将用户输入拼接至系统命令,存在严重安全风险。利用命令分隔符注入;ls和;cat命令查看目录及文件内容,最终通过查看网页源码成功获取flag。案例展示了未过滤用户输入直接拼接系统命令的高风险性。

一、命令注入
1、定义
命令执行指的是由于应用程序对用户输入过滤不严,攻击者可以通过提交恶意构造的参数破坏命令语句结构,从而让服务器执行任意操作系统命令。
2、产生原因
- 用户输入未做充分校验 :程序直接将用户输入的数据拼接到系统命令中,没有对输入内容进行合法性检查和过滤。例如,在一个用于 ping 测试的功能模块中,代码直接将用户输入的 IP 地址拼接到系统的
ping
命令后执行,若用户输入127.0.0.1; rm -rf /
(在类 Unix 系统中,;
用于分隔多条命令 ),就可能导致服务器上的所有文件被删除。 - 使用危险函数且缺乏防护 :编程语言中一些能执行系统命令的函数(如 PHP 中的
system()
、exec()
、shell_exec()
,Python 中的os.system()
、subprocess.Popen()
等 ),如果使用不当且未对传入参数严格过滤,就容易引发命令执行风险。
3、命令分隔符
(1)分号 ;
-
含义 : "然后"
-
工作方式: 按顺序执行命令,无论前一个命令是成功还是失败,都会继续执行下一个。
-
Linux/Unix : ✅ 可以使用。这是最常用的顺序执行分隔符。
-
例子 :
ping example.com ; whoami
-
效果 : 先尝试 ping 网站,然后 不管是否 ping 通,都会执行
whoami
来查看当前用户名。
-
-
Windows : ❌ 不能使用。Windows 命令行默认不识别分号作为命令分隔符。
(2)"与"符号 &&
-
含义 : "成功了才"
-
工作方式 : 逻辑"与"。只有当前一个命令成功执行(返回退出码为0)后,才执行下一个命令。如果前一个命令失败,后面的命令就不会运行。
-
Linux/Unix : ✅ 可以使用。
-
例子 :
ping -c 1 example.com && cat /etc/passwd
-
效果 : 只有能成功 ping 通 example.com,才 会去执行
cat /etc/passwd
(读取系统敏感文件)。
-
-
Windows : ✅ 可以使用。行为与 Linux 完全一致。
-
例子 :
ping example.com && ipconfig
-
效果 : 只有能成功 ping 通,才 会执行
ipconfig
来显示网络信息。
-
(3)"或"符号 ||
-
含义 : "失败了就"
-
工作方式 : 逻辑"或"。只有当前一个命令执行失败(返回非零退出码)后,才执行下一个命令。如果前一个命令成功,后面的命令就不会运行。
-
Linux/Unix : ✅ 可以使用。
-
例子 :
ping -c 1 invalid_hostname || whoami
-
效果 : ping 一个不存在的主机肯定会失败,于是 就执行
whoami
来查看当前用户名。
-
-
Windows : ✅ 可以使用。行为与 Linux 完全一致。
-
例子 :
dir C:\nonexistent_folder || net user
-
效果 : 列出一个不存在的目录会失败,于是 就执行
net user
来查看系统用户列表。
-
(4)管道符 |
-
含义 : "把它的结果给"
-
工作方式 : 将第一个命令的标准输出 ,作为第二个命令的标准输入。它关注的是数据流的传递,而不是命令的成功与失败。
-
Linux/Unix : ✅ 可以使用。这是非常核心和强大的功能。
-
例子 :
ps aux | grep mysql
-
效果 : 列出所有进程信息,然后把结果传递给
grep
命令,筛选出包含 "mysql" 的行。
-
-
Windows : ✅ 可以使用。行为与 Linux 一致。
-
例子 :
dir | find ".txt"
-
效果 : 列出当前目录文件,然后把结果传递给
find
命令,只显示包含 ".txt" 的文件名。
-
4、防范措施
-
严格过滤用户输入:对用户输入的数据进行严格校验,只允许符合特定格式和范围的数据通过。比如,对于 IP 地址输入,使用正则表达式校验其格式是否正确,禁止输入特殊字符和命令分隔符。
-
使用安全的函数和方法 :在执行外部命令时,优先使用安全的函数或方法。例如,在 PHP 中使用
escapeshellcmd()
和escapeshellarg()
函数对用户输入进行转义处理,在 Python 中使用subprocess
模块的安全调用方式(如subprocess.run()
),并明确指定参数,避免命令注入。 -
最小权限原则:运行应用程序的用户账户应只拥有执行必要操作的最小权限,即使存在命令执行风险,攻击者也无法执行高权限的恶意命令,降低危害程度。
-
及时更新和修补:及时更新操作系统、应用程序以及相关组件的版本。
二、渗透实战
1、访问靶场
打开关卡如下所示,提示信息为"这是一个在线测试网络延迟的平台,路由器中经常会见到。无任何安全措施,尝试获取 flag",提示本关卡的功能是测试网络延迟。点击打开题目,此时系统自动创建Docker环境,下图蓝色部分的URL地址就是靶场环境。

开启burpsuite,firefox浏览器开启代理指向burpsuite。在浏览器中地址栏输入靶场的URL地址。访问URL进入到靶场首页。
http://challenge-038bb805f8d4d830.sandbox.ctfhub.com:10800/
如下所示这是一个显示靶场源码的页面。这段PHP 代码的核心逻辑这是一个简单的网络诊断工具,通过 Web 接口提供 ping 功能。

2、源码分析
接下来我们分析页面的源码信息,如下所示代码并没有对GET方式传入的参数ip进行过滤。

很明显这段代码存在严重的安全隐患,它直接将用户输入的ip
参数拼接到系统命令中,可能导致命令注入攻击 。攻击者可以通过构造特殊的ip
参数执行任意系统命令,例如:127.0.0.1; ls /
。在实际开发中,需要对用户输入进行严格验证和过滤,避免直接将用户输入用于系统命令。详细注释后的源代码如下所示。
<?php
// 初始化结果变量为FALSE
// 用于存储ping命令的执行结果,初始值为FALSE表示尚未执行命令
$res = FALSE;
// 检查是否通过GET请求传递了'ip'参数,并且该参数不为空
// isset($_GET['ip']) 检查参数是否存在
// $_GET['ip'] 检查参数值是否不为空(非空字符串被视为TRUE)
if (isset($_GET['ip']) && $_GET['ip']) {
// 构建ping命令:在类Unix系统中ping 4次目标IP
// $_GET['ip'] 是用户传递的IP地址参数
$cmd = "ping -c 4 {$_GET['ip']}";
// 执行构建好的系统命令,并将输出结果存储到$res数组中
// exec()函数用于执行外部命令
// 第一个参数是要执行的命令
// 第二个参数是用于存储命令输出结果的数组(每行输出作为数组的一个元素)
exec($cmd, $res);
}
?>
这段 PHP 代码的功能是接收用户通过 GET 请求传递的 IP 地址,然后在服务器上执行 ping 命令测试与该 IP 的连接情况,并存储执行结果。
- 首先初始化了一个
$res
变量为FALSE
,用于后续存储 ping 命令的执行结果。 - 通过
isset($_GET['ip']) && $_GET['ip']
判断用户是否通过 URL 传递了有效的ip
参数。 - 当存在有效
ip
参数时,构建 ping 命令字符串,其中-c 4
表示在类 Unix 系统中 ping 目标 IP 4 次。 - 使用
exec()
函数执行构建好的 ping 命令,并将命令的输出结果存储到$res
数组中。 - 如果没有有效的
ip
参数,$res
将保持初始值FALSE
。
3、安全分析
这段代码存在严重的命令注入(Command Injection)安全隐患,具体分析如下所示。
(1)核心风险:未过滤的用户输入直接拼接进系统命令
代码中通过 $_GET['ip']
获取用户输入的 IP 地址,并直接拼接到 ping
命令中:
$cmd = "ping -c 4 {$_GET['ip']}"; // 危险!直接拼接用户输入
exec($cmd, $res);
假设攻击者在 URL 中传入这样的参数:
?ip=127.0.0.1; ls /
这相当于在服务器上执行了两个命令:
ping -c 4 127.0.0.1
(正常的 ping 操作)ls /
(列出服务器根目录文件,攻击者可获取系统信息)
(2)为什么会产生这个问题?
- 缺乏输入验证 :没有检查
$_GET['ip']
是否为合法的 IP 地址(如是否包含特殊字符;
&
|
等)。 - 直接拼接命令:将用户输入直接作为命令的一部分,而非参数处理。
- 权限风险:如果 PHP 进程以高权限(如 root)运行,攻击者可能通过注入命令获取服务器完全控制权。
4、执行查看当前目录命令
在IP输入框内输入"127.0.0.1&ls",如下所示显示了当前目录下的文件列表,关注下图红框中的文件"14011643814.php"。
127.0.0.1&ls

5、执行查看flag命令
接下来使用cat查看当前目录下的14011643814.php文件,在IP输入框内输入"127.0.0.1&cat 14011643814.php",点击ping,如下所示页面并没有直接显示flag的内容。
127.0.0.1&cat 14011643814.php

(1)右键源码法
在当前页面右键-查看源代码,如下所示,发现flag值,渗透成功。

(2)burpsuite法
用bp找到该报文并查看其响应内容,如下图红框所示,成功获取到flag值。
