PHP filter是PHP定义的一个伪协议,用于在数据流打开时进行筛选过滤,在数据读取或者写入的时候通过过滤器对数据进行处理。PHP filter 可以使用多个过滤器进行处理。
php://filter/过滤器|过滤器/resource=待过滤的数据流
require_once和require的参数是一个文件路径,指明要包含的文件,而PHP filter 提供了接口,使得可以通过这个接口访问到指定的文件内容,require在包含文件时,只关心文件内容,而不关心文件内容来自于何处,所以可以给require 传PHP filter参数,
如果有如下代码
<?php
$file = $_GET['page'];
require($file);
则可以通过如下请求泄露敏感信息
curl "http://localhost/test.php?page=php://filter/convert.base64-encode/resource=/etc/passwd"
PHP的base64decode函数在处理base64编码的数据时,会自动规范化:去除字符串中不合法的字符并且忽略,而后尝试解码。
但PHP filter的base64解码行为和base64decode行为略有不同,PHP filter的base64-decode不能处理随即插入的等号,此时可以使用UTF-7编码规避,UTF-7编码会把等号转化为其他的base64字符。
根据官网链接的
reference
根据文档,如果开启了iconv支持,则可以通过伪协议php://convert.iconv.*.*调用iconv函数。
convert.iconv.<input-encoding>.<output-encoding>orconvert.iconv.<input-encoding>/<output-encoding>
linux中可以使用iconv函数将字符串从一个编码转为另外一个编码,在PHP://filter中可以使用iconv过滤器调用到这个函数
php -r "echo file_get_contents(\"php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7/res
ource=php://temp\");"
GyQpQw+AD0APQ-#
某些编码规定该编码会在数据之前预置一些字节,相当于签名,标识这段数据是该编码 在 RFC 2781中就说明该编码会预置0XFEFF
The Unicode Standard and ISO 10646 define the character “ZERO WIDTH NON-BREAKING SPACE” (0xFEFF), which is also known informally as “BYTE ORDER MARK” (abbreviated “BOM”).This usage, suggested by Unicode and ISO 10646 Annex F (informative), is to prepend a 0xFEFF character to a stream of Unicode characters as a “signature”; a receiver of such a serialized stream may then use the initial character both as a hint that the stream consists of Unicode characters and as a way to recognize the serialization order. In serialized UTF-16 prepended with such a signature, the order is big-endian if the first two octets are 0xFE followed by 0xFF; if they are 0xFF followed by 0xFE, the order is little-endian. Note that 0xFFFE is not a Unicode character, precisely to preserve the usefulness of 0xFEFF as a byte-order mark.
下图给出了如何在字符串前面预置8
ĸĸ在UNICODE表中对应于0x0138,而后逐个打印,0x38变成了8

LANTIN6表如下:
| x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0x | ||||||||||||||||
| 1x | ||||||||||||||||
| 2x | SP | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / |
| 3x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
| 4x | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
| 5x | P | Q | R | S | T | U | V | W | X | Y | Z | [ | |] | ^ | _ | |
| 6x | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
| 7x | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | |
| 8x | ||||||||||||||||
| 9x | ||||||||||||||||
| Ax | NBSP | Ą | Ē | Ģ | Ī | Ĩ | Ķ | § | Ļ | Đ | Š | Ŧ | Ž | SHY | Ū | Ŋ |
| Bx | ° | ą | ē | ģ | ī | ĩ | ķ | · | ļ | đ | š | ŧ | ž | ― | ū | ŋ |
| Cx | Ā | Á | Â | Ã | Ä | Å | Æ | Į | Č | É | Ę | Ë | Ė | Í | Î | Ï |
| Dx | Ð | Ņ | Ō | Ó | Ô | Õ | Ö | Ũ | Ø | Ų | Ú | Û | Ü | Ý | Þ | ß |
| Ex | ā | á | â | ã | ä | å | æ | į | č | é | ę | ë | ė | í | î | ï |
| Fx | ð | ņ | ō | ó | ô | õ | ö | ũ | ø | ų | ú | û | ü | ý | þ | ĸ |
UNICODE如下:

通过将恶意代码转化为base64形式,而后通过编码预置字符,最后使用convert.base64-decode尝试解码预置的数据,就可以使得PHP filter最后解码出恶意代码。
当使用require时,且路径可控,就可以利用PHP filter执行任意代码。
参考链接
https://gynvael.coldwind.pl/?id=671 https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d https://www.synacktiv.com/en/publications/php-filters-chain-what-is-it-and-how-to-use-it
Created at 2023-12-29T18:32:43+08:00