浅析SSRF与文件读取的一些小特性
字数 1417 2025-08-25 22:59:02
SSRF与文件读取特性深度分析
0x00 前言
本文深入分析SSRF(Server-Side Request Forgery)与文件读取中的一些特殊行为特性,特别是file_get_contents与curl在处理URL时的差异,这些差异可能导致安全漏洞或绕过防御机制。
0x01 问题现象
当使用不同函数处理URL时,会出现以下差异:
- 请求
http://127.0.0.1/1.php?.jpg:- 使用
curl:访问的是1.php的内容 - 使用
file_get_contents:尝试访问名为1.php?.jpg的文件
- 使用
这种差异源于URL解析方式的不同,下面将从PHP底层和libcurl实现角度分析原因。
0x02 file_get_contents底层分析
2.1 实现原理
file_get_contents在PHP中的实现位于/ext/standard/file.c,关键流程:
- 解析参数后调用
php_stream_open_wrapper_ex - 通过
php_stream_locate_url_wrapper解析协议类型 - 根据协议找到对应的wrapper(包装器)
2.2 关键特性
-
对于
file://协议:- 需要绝对路径,格式为
file:///path/to/file - 不会特殊处理
?或#后面的内容 - 例如
file:///flag.php?#123会尝试打开名为flag.php?#123的文件
- 需要绝对路径,格式为
-
对于HTTP协议:
- 会完整保留URL中的查询参数和片段标识符
- 行为更符合标准URL规范
0x03 curl底层分析
3.1 libcurl实现
PHP的curl扩展基于libcurl实现,关键函数调用链:
curl_init()初始化curl_easy_setopt()设置选项(包括URL)curl_easy_perform()执行请求
3.2 URL解析特性
libcurl在解析URL时:
-
对于
file://协议:- 会忽略查询参数(
?后内容)和片段标识符(#后内容) - 例如
file:///flag.php?123实际访问的是flag.php - 实现位于
lib/urlapi.c的curl_url_get函数
- 会忽略查询参数(
-
对于HTTP协议:
- 保留完整URL路径但可能在某些情况下规范化处理
0x04 安全影响与利用场景
4.1 文件读取绕过
当应用程序同时使用两种函数进行文件读取时,可能产生不一致行为:
$url = $_GET['url'];
$file = $url . '.jpg';
// 第一种情况:使用file_get_contents
file_get_contents($url); // 尝试读取"url?.jpg"
file_get_contents($file); // 尝试读取"url.jpg"
// 第二种情况:使用curl
curl_exec($url); // 读取"url"内容
curl_exec($file); // 读取"url.jpg"内容
4.2 SSRF利用差异
-
file_get_contents:- 严格遵循URL规范
- 可能被用于读取带特殊字符的文件名
-
curl:- 自动去除某些特殊部分
- 可能绕过某些文件名过滤
0x05 防御建议
- 统一处理函数:避免混用不同函数处理相同URL
- 严格过滤:对用户输入的URL进行严格校验和规范化
- 协议限制:明确允许或禁止的协议列表
- 路径检查:确保文件路径不包含特殊字符
- 错误处理:统一错误处理逻辑,避免信息泄露
0x06 总结
file_get_contents和curl对URL解析存在本质差异- libcurl对
file://协议的处理会忽略查询参数和片段 - PHP的流处理更接近原始URL规范
- 这些差异可能导致安全边界被绕过,需要特别注意
理解这些底层实现细节有助于开发更安全的代码和设计更有效的防御措施。