以前的CTF中见过这种很神奇的协议,上周墙网杯又见到了,再总结一下,在实际中的应用也是比较多的,算是一个比较实用的技巧。

假设有类似以下的PHP代码段。

<?php
    $file = $_GET['file'];
    include($file.".jpg");
?>

很明显看出来这是个文件包含,但是将传递的文件名后面强制加了一个".jpg"的后缀,导致了无法任意文件包含。但是我们可以通过zip协议绕过这个限制,我们看一下PHP官方文档中对这个协议的描述:http://php.net/manual/zh/wrappers.compression.php

其中有一段用法:zip://archive.zip#dir/file.txt。看到这个之后应该就能明白如何绕过了。
首先我们新建一个test.php文件,内容如下:

<?php
    phpinfo();
?>

并将其改名为test.jpg,因为上面的代码只能包含jpg文件嘛。然后将其压缩成zip包,压缩的时候注意要选择only store之类的选项,防止数据被压缩。然后将这个zip的后缀改为jpg之类的,目的是可以成功上传。之后我们就可以通过:

http://example.com/include/include2.php?file=zip://test.zip%23test

这样的形式getshell了。

对于如下的代码段:

<?php
    $file = $_GET['file'];
    if (isset($file) && strtolower(substr($file, -4)) == ".jpg") {
        include($file)
    }
?>

也可以通过相似的方法getshell,这里就不再赘述了。无非就是%23test.jpg之类的呗。

除了zip协议,还有phar协议也可以做到类似的事情。参考:http://php.net/manual/zh/wrappers.phar.php
基本上和zip差不多,区别就是phar://php.zip/php.jpg中是用/来分隔而不是#