"""
路径遍历漏洞知识
"""

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)
```
""",
)
