CTFHub RCE通关笔记3:文件包含 php://input
目录
一、PHP://INPUT伪协议
1、基本概念
2、文件包含利用
二、渗透实战
1、访问靶场
(1)allow_url_open = On
(2)allow_url_include = On
2、源码分析
(1)代码审计
(2)渗透思路
3、php://input方法渗透
(1)查看根目录
(2)读取flag文件
本文讲解CTFHub的RCE-文件包含-phpinput的原理和渗透实战的全过程,系统介绍了PHP中php://input伪协议的基本概念及其在渗透测试中的利用方式。php://input是一个只读数据流包装器,可读取原始HTTP请求体数据,与$_POST不同,它不解析内容类型。文章详细分析了该协议在文件包含中的利用方法,通过构造包含php://input的GET请求和POST恶意代码,可实现远程命令执行。在实战部分,通过靶场演示了如何利用该协议绕过安全限制,最终成功读取服务器上的flag文件。
一、PHP://INPUT伪协议
1、基本概念
php://input
是 PHP 提供的一个只读(read-only)数据流包装器(stream wrapper)。它的核心功能是允许你读取原始的 HTTP 请求体(Request Body)数据。
-
数据源:它读取的是 “RAW POST DATA”,即最原始的、未经任何解析的 HTTP 请求体。
-
这与
$_POST
超全局数组完全不同。$_POST
仅能解析application/x-www-form-urlencoded
或multipart/form-data
类型的请求,并将其转换为关联数组。 -
php://input
则不关心内容类型,它总是返回最原始的二进制数据流。
-
-
只读性:它是一个只读流,你不能向它写入数据。
-
一次性:这个流只能读取一次。一旦读取,就无法再次获取。这在处理请求时需要注意。
2、文件包含利用
在存在文件包含或代码执行安全风险的场景中,php://input
可能被恶意利用:
-
文件包含利用
若服务器允许包含
php://input
,攻击者可通过 POST 提交 PHP 代码,让服务器执行:- 构造请求:
GET ?file=php://input
- POST 数据:
<?php system('ls'); ?>
服务器会将 POST 数据作为 PHP 代码执行
- 构造请求:
-
绕过参数过滤
当服务器对 GET/POST 参数过滤严格时,攻击者可能通过
php://input
传递恶意数据,绕过检测
二、渗透实战
1、访问靶场
开启burpsuite,firefox浏览器开启代理指向burpsuite。在浏览器中地址栏输入靶场的URL地址。
http://challenge-3c30355f64bb72d6.sandbox.ctfhub.com:10800/
访问URL进入到靶场首页,如下所示这是一个显示靶场源码的页面。这段PHP 代码的核心逻辑是通过 GET 参数file
接收文件名并进行包含,但禁止包含包含 "flag" 字符串的文件。如果未传递file
参数,则则展示当前文件的源代码。
点击phpinfo,跳转到如下显示php信息的页面,此时搜索关键字(allow_url),如下所示allow_url_open和allow_url_on都处于开启(on)状态。
(1)allow_url_open = On
-
含义:允许PHP的文件系统函数(如
fopen()
,file_get_contents()
,copy()
等)处理远程资源(如HTTP、FTP URL)。 -
开启后的能力:正常的程序可以更方便地获取远程内容。
(2)allow_url_include = On
-
含义:允许
include
,require
,include_once
,require_once
等语句包含远程资源(如HTTP、FTP URL)作为代码执行。 -
开启后的能力:
-
(几乎)没有任何合法的理由需要在生产环境中开启此选项。
-
攻击者可以利用:这是远程文件包含(RFI)洞能被利用的唯一前提。它可以直接将LFi升级为RCE
-
2、源码分析
(1)代码审计
分析靶场源码,者是一个设计有缺陷的文件包含示例,它试图通过白名单机制限制用户只能包含以 php://
开头的路径,原始code如下所示。
<?php
if (isset($_GET['file'])) {if ( substr($_GET["file"], 0, 6) === "php://" ) {include($_GET["file"]);} else {echo "Hacker!!!";}
} else {highlight_file(__FILE__);
}
?>
<hr>
i don't have shell, how to get flag? <br>
<a href="phpinfo.php">phpinfo</a>
PHP 代码的主要功能是一个文件包含的验证逻辑,尝试根据 GET 请求参数 file
来包含文件,但进行了一定的安全限制(仅允许以 php://
开头的文件包含),若不满足则提示黑客攻击,若没有 file
参数则展示自身代码。同时还提供了一个phpinfo页面,该页面通常用于信息收集或作为利用工具,详细注释后的源码如下所示。
<?php
// 关闭所有错误报告,防止敏感信息(如文件路径、警告)泄露给攻击者。
error_reporting(0);// 检查是否通过GET请求传递了一个名为'file'的参数
// 例如:http://example.com/?file=somefile
if (isset($_GET['file'])) {// 使用 substr 函数检查 'file' 参数值的前6个字符是否是 "php://"// 这是一个极其简单且不安全的白名单机制if ( substr($_GET["file"], 0, 6) === "php://" ) {// 如果条件满足(即参数以"php://"开头),则直接使用 include 语句包含该参数指定的内容。// 这是极度危险的操作,因为它允许包含任意以php://开头的流。include($_GET["file"]);} else {// 如果参数不是以 "php://" 开头,则输出 "Hacker!!!",试图阻止攻击。echo "Hacker!!!";}
} else {// 如果没有提供 'file' 参数,则使用 highlight_file 函数高亮显示当前文件(__FILE__)的源代码。// 这相当于给攻击者提供了“说明书”,揭示了程序的逻辑和利用点。highlight_file(__FILE__);
}
?><hr>
i don't have shell, how to get flag? <br> <!-- 关键提示1:告知无需获取WebShell即可得到flag -->
<a href="phpinfo.php">phpinfo</a> <!-- 关键提示2:提供了一个phpinfo页面,该页面通常用于信息收集或作为利用工具 -->
-
核心功能:存在文件包含安全风险的脚本,允许用户通过
file
GET参数动态包含资源。 -
利用点:
include($_GET["file"]);
是风险的根源。虽然限制了协议,但允许的php://
协议正是攻击者所需要的。 -
页面提示的含义:
-
i don't have shell, how to get flag?
:明确提示不需要上传或执行WebShell,应使用其他方式获取flag。 -
<a href="phpinfo.php">phpinfo</a>
:这是一个重要线索。phpinfo.php
页面通常用于信息泄露,在某些高级利用技巧中(如临时文件包含),它也可被用作攻击工具。
-
(2)渗透思路
分析本关卡源码的安全措施,可知开发者意识到直接包含用户输入是危险的,所以尝试添加了一个安全检查:
-
检查逻辑: 只允许包含路径以
php://
开头的文件。 -
设计意图: 试图将文件包含限制在PHP内置的包装器(如
php://input
),从而阻止包含如通过file协议直接查看/etc/passwd
等系统文件。 -
致命缺陷: 这个检查极其脆弱,可以被轻易绕过。
php://
协议本身功能强大,攻击者无需包含其他文件就能利用它。
很明显这段代码是一个设计不当的白名单限制典型案例。开发者虽然意识到了危险,但实现的防御措施过于简单,反而指引攻击者使用更强大的 php://
协议来进行渗透。
php://input
的渗透思路:核心在于分离指令与载荷,首先,通过GET请求传递 ?file=php://input
参数,该指令字符串本身不包含敏感关键词,可绕过简单的黑名单检查,并指示PHP引擎转向处理原始输入流;随后,在POST请求体中填入待执行的恶意PHP代码(如 <?php system("cat /flag");?>
);最终,服务器端的 include
函数会读取并执行请求体中的代码,从而在目标系统上实现远程命令执行(RCE),无需文件上传即可直接获取Shell或读取敏感数据。这种利用方式完美规避了对参数内容的检查,将攻击载荷隐藏在协议指定的数据源中。
3、php://input方法渗透
(1)查看根目录
使用php://input协议将POST请求体作为代码执行的特点,构造如下URL地址。
http://challenge-3c30355f64bb72d6.sandbox.ctfhub.com:10800/?file=php://input
在浏览器中访问目标URL,POST参数设置为<?php system("ls /");?>,如下所示执行了ls命令,根据返回结果可知其中包含flag文件(flag_21400)。
(2)读取flag文件
上一步我们在根目录中发现了flag文件,接下来直接执行命令:<?php system('cat /
flag_21400'); ?>
,构造如下php://input的payload,URL地址如下所示。
http://challenge-3c30355f64bb72d6.sandbox.ctfhub.com:10800/?file=php://input
在浏览器中访问目标URL,POST参数设置为<?php system("cat /flag_21440");?>查看flag文件。
如下所示,服务器的响应中包含命令 cat /flag
的执行结果,即flag文件的内容,渗透成功。