Pikachu靶场通关笔记(44) — SSRF漏洞 (curl篇)

23次阅读
没有评论

1. 漏洞概述

SSRF (Server-Side Request Forgery,服务端请求伪造) 是一种由攻击者构造形成,由服务端发起请求的安全漏洞。

简单来说,当 Web 应用提供了从其他服务器获取数据的功能,但却没有对目标地址做严格过滤与限制时,攻击者就可以 把这台存在漏洞的服务器当作“跳板”

这有什么危害呢?
因为请求是由目标服务器自己发出的,它 绕过了外网的防火墙限制。攻击者借此可以:

  1. 内网探测:扫描内网的主机存活状态和端口开放情况(通常外网是访问不到内网的,但服务器自己可以)。
  2. 攻击内网应用:向内网的 Redis、数据库等服务发送攻击 Payload。
  3. 读取本地文件 :利用强大的 伪协议(如 file://, dict://, gopher://读取服务器上的敏感文件或执行复杂操作。

本关卡演示的是 PHP 中利用 curl 函数配置不当造成的 SSRF 漏洞。


2. 闯关实操 (Exploitation)

2.1 基础利用:HTTP/HTTPS 代理请求

打开关卡,点击页面上的超链接。观察浏览器地址栏,URL 为:
http://localhost:8899/vul/ssrf/ssrf_curl.php?url=http://127.0.0.1/.../info1.php

页面展示了一首诗。这说明 ssrf_curl.php 通过 url 参数,去请求了 info1.php
我们尝试让服务器去访问外网,将参数修改为百度:
http://localhost:8899/vul/ssrf/ssrf_curl.php?url=https://www.baidu.com
回车后,页面显示了百度首页!此时,Pikachu 服务器变成了一个代理。

Pikachu 靶场通关笔记(44)— SSRF 漏洞 (curl 篇)

2.2 进阶利用:利用 file:// 协议读取本地文件

SSRF 最可怕的地方在于 PHP 的 cURL 支持多种伪协议。除了 http://,我们还可以利用 file:// 协议来读取服务器内部的本地磁盘文件。

因为我们知道靶场搭建在 Linux (Docker) 环境下,尝试构造读取 /etc/passwd 文件的 Payload:
http://localhost:8899/vul/ssrf/ssrf_curl.php?url=file:///etc/passwd
发送请求后,成功读取到了服务器系统的底层账号信息!证明 SSRF 不仅能打网络,还能读本地。

Pikachu 靶场通关笔记(44)— SSRF 漏洞 (curl 篇)

3.【实战排错实录】Docker 环境下的 SSRF 深坑

在本次测试中,我尝试利用 SSRF 去访问本地自己写的一个包含 <?php phpinfo(); ?>1.php 文件,却接连遭遇了两个大坑。如果你也是用 Docker 搭建的靶场,这段排错记录绝对能救命。

🔴 请求 8899 端口报错 Connection refused (拒绝连接)

现象
由于我的靶场在外部浏览器是通过 localhost:8899 访问的,于是我理所当然地构造了如下 SSRF 链接:
.../ssrf_curl.php?url=http://127.0.0.1:8899/vul/ssrf/upload/1.php
结果后台 cURL 报错:Failed to connect to 127.0.0.1 port 8899: Connection refused

Pikachu 靶场通关笔记(44)— SSRF 漏洞 (curl 篇)

原理解析(Docker 网络视角偏差):
要理解这个报错,必须搞懂 Docker 的端口映射原理。
启动容器时,我们用了 -p 8899:80,意思是将 宿主机(你的真实电脑)8899 端口,映射到 Docker 容器内部80 端口。

  • 你的浏览器视角(外部):你访问 8899 端口,Docker 截获并转发给容器,一切正常。
  • PHP cURL 视角(内部):SSRF 的请求是由 容器内部的 PHP 代码发出的 。当 PHP 去请求 127.0.0.1:8899 时,它是在找 容器自己网卡 上的 8899 端口。但是容器内部的 Web 服务器(Apache)只监听了默认的 80 端口,根本没有 8899 端口!所以直接被操作系统拒绝。

✅ 解决办法:换位思考
SSRF 是站在目标服务器内部发起的请求。在容器内部,Web 服务就在 80 端口。所以去掉 8899 即可成功访问:
.../ssrf_curl.php?url=http://127.0.0.1/vul/ssrf/upload/1.php

Pikachu 靶场通关笔记(44)— SSRF 漏洞 (curl 篇)

4. 源码分析 (Code Review)

后端 ssrf_curl.php 的代码非常短,但由于配置疏忽,导致了严重漏洞:

if(isset($_GET['url']) && $_GET['url'] != null){$URL = $_GET['url'];
    $CH = curl_init($URL); // 初始化 cURL 会话
    curl_setopt($CH, CURLOPT_HEADER, FALSE);
    curl_setopt($CH, CURLOPT_SSL_VERIFYPEER, FALSE);
    $RES = curl_exec($CH); // 核心:无条件执行请求
    curl_close($CH) ;

    // 直接将请求抓取到的结果输出到前端
    echo $RES;
}

漏洞成因:
程序获取到了客户端传入的 $URL 变量后,直接将其传入了 curl_init()curl_exec() 执行网络请求。
全过程 没有验证请求的协议 (允许了危险的 file:// 等)、 没有验证请求的域名 /IP(允许了访问 127.0.0.1 和内网网段)。盲目信任用户输入,将服务器变成了黑客的提线木偶。


5. 修复建议

防御 SSRF 漏洞,需要对向外发起的请求进行极其严格的限制:

  1. 限制请求的协议(白名单)
    通常业务只需要 HTTP/HTTPS 协议,必须在代码层面明确禁用 file://, gopher://, dict:// 等危险协议。
    php // cURL 限制仅允许 HTTP 和 HTTPS curl_setopt($CH, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
  2. 限制请求的 IP 地址(防止内网探测)
    在发起请求前,解析目标 URL 的 IP 地址,如果发现 IP 属于内网保留地址(如 127.0.0.0/8, 192.168.0.0/16, 10.0.0.0/8),则直接拦截请求。
  3. 使用白名单域名限制
    如果业务明确知道需要请求的外部接口域名,建立一个严格的域名白名单,非白名单内的请求一律拒绝。
正文完
 0
评论(没有评论)