CodeReview/backend/app/services/agent/knowledge/vulnerabilities/path_traversal.py

130 lines
2.7 KiB
Python
Raw Permalink Normal View History

"""
路径遍历漏洞知识
"""
from ..base import KnowledgeDocument, KnowledgeCategory
PATH_TRAVERSAL = KnowledgeDocument(
id="vuln_path_traversal",
title="Path Traversal",
category=KnowledgeCategory.VULNERABILITY,
tags=["path", "traversal", "file", "directory", "lfi", "rfi"],
severity="high",
cwe_ids=["CWE-22", "CWE-23"],
owasp_ids=["A01:2021"],
content="""
路径遍历允许攻击者访问应用程序根目录之外的文件可能导致敏感信息泄露或代码执行
## 危险模式
### Python
```python
# 危险 - 直接拼接路径
file_path = "/uploads/" + user_filename
open(base_dir + request.args['file'])
os.path.join(base_dir, user_input) # 仍然危险!
# 危险 - 文件下载
@app.route('/download')
def download():
filename = request.args.get('file')
return send_file(f'/files/{filename}')
# 危险 - 模板包含
render_template(user_template)
```
### Node.js
```javascript
// 危险
const filePath = path.join(__dirname, req.query.file);
fs.readFile('./uploads/' + filename);
res.sendFile(req.params.path);
```
### PHP
```php
// 危险
include($_GET['page']);
require($user_input);
file_get_contents($filename);
```
## 攻击载荷
```
../../../etc/passwd
..\\..\\..\\windows\\system32\\config\\sam
....//....//....//etc/passwd
..%2f..%2f..%2fetc/passwd
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
..%252f..%252f..%252fetc/passwd (双重编码)
```
## 敏感文件目标
```
# Linux
/etc/passwd
/etc/shadow
/etc/hosts
/proc/self/environ
/var/log/apache2/access.log
# Windows
C:\\Windows\\System32\\config\\SAM
C:\\Windows\\win.ini
C:\\inetpub\\logs\\LogFiles
# 应用配置
.env
config.php
settings.py
application.yml
```
## 检测要点
1. 所有文件操作函数
2. 用户输入是否用于构建路径
3. 是否有路径规范化
4. 是否验证最终路径在允许范围内
## 安全实践
1. 验证和规范化路径
2. 使用白名单
3. 检查路径是否在允许目录内
4. 使用安全的文件ID映射
## 修复示例
```python
import os
def safe_join(base_dir, user_path):
# 规范化路径
base_dir = os.path.abspath(base_dir)
full_path = os.path.abspath(os.path.join(base_dir, user_path))
# 验证路径在基础目录内
if not full_path.startswith(base_dir + os.sep):
raise ValueError("Path traversal detected")
return full_path
# 使用
try:
safe_path = safe_join('/uploads', user_filename)
with open(safe_path) as f:
content = f.read()
except ValueError:
abort(403)
# 更安全 - 使用文件ID映射
@app.route('/download/<file_id>')
def download(file_id):
file_record = File.query.get(file_id)
if file_record and file_record.user_id == current_user.id:
return send_file(file_record.path)
abort(404)
```
""",
)