CVE-2024-21762 Bishop Fox Vulnerability Scanner for FortiGate Firewalls

Loading

Summary

In February, Fortinet released a security advisory for CVE-2024-21762. Bishop Fox analyzed the patch and developed a scanner to quickly determine if an appliance is affected by this vulnerability.

FIGURE 1 CVE-2024-21762

Overview

CVE-2024-21762 is identified as a severe security issue involving an out-of-bounds write in the SSL VPN sector of FortiOS. The team dissecting the patching process observed several adjustments in the processing of HTTP requests with chunked transfer encoding. Besides creating a proof-of-concept that can induce a crash tied to this vulnerability, they have also developed a technique to detect, via specific behavioral indicators, whether a system has been updated with the patched firmware.

What is Chunked Transfer Encoding?

HTTP/1.1 saw the introduction of the Transfer-Encoding header, designed to define encoding mechanisms at the transport level of HTTP requests. It enables the transmission or redirecting of HTTP data when the payload size is indeterminable by employing a series of chunks, each with a specified length. These lengths are encoded in hexadecimal and are separated by a carriage return (CR) followed by a line feed (LF). A zero byte length signals the conclusion of the chunked transfer.

Patch Diffing

We observed that part of the patch introduces validation to ensure some value is less than 0x10. When this condition is not met, the string “invalid chunk length string” is logged.

FIGURE TWO CVE-2024-21762

FIGURE 1 – BinDiff Control Flow Graph – From Bishop Fox

The control flow graph in BinDiff introduces two fresh basic blocks. If a register’s value surpasses 0x10, the following string is populated into a different register: ”%s: %d invalid chunk length string.”

From a closer examination, it was determined that the code checks to ensure the chunk size field does not exceed 16 characters in length.

Triggering the Check

The task of pinpointing the activation process for this function through static examination proved to be a formidable challenge. Fortinet has intricately woven a complete Apache2 server into its monolithic init executable, introducing a multifaceted web of request handling and signal connections. The journey from when a request is received to its final resolution by specific code segments is elaborate. Consequently, we opted to insert a breakpoint at the beginning of the function in question and proceeded to transmit segmented POST submissions across all known paths. This approach quickly yielded numerous responses within the /remote/ directory. Astonishingly, it became evident that even erroneous page requests to anything under /remote/ would activate the function in question. We learned that the easiest way to reach the function was through specific error-handling mechanisms, for example, the ap_die function.

However, the drawback of this method is that by the time the function is engaged, the server is already in the process of generating an error response. Hence, we cannot directly observe the error caused by submitting an overly lengthy size field. This necessitates the exploration of an alternate means to determine the presence of the validation process.

Introducing an Observable Effect

While our initial direct testing method was unfeasible, we can still discern variances in behavior when the function ceases operation prematurely. The server’s reliance on the declared chunk size to decide the amount of data to read allows us to impede its process indefinitely by withholding the expected amount of data. Take, for instance, sending a request body like this: FF abcd.

This causes the session to linger and eventually expire due to a timeout.

Introducing a disproportionately extended size field modifies the situation to where the timeout is contingent on whether the size field’s excessive length is recognized by FortiOS. This leads us to develop a payload that appears as: 0000000000000000FF abcd.

When this payload encounters vulnerable systems, the size field is interpreted as a request for 255 bytes, resulting in a suspended connection until the timeout is reached. Conversely, systems that have been updated will cease processing the request sooner and issue an HTTP response without the need to await the entirety of the message.

A script to automate this technique along with usage instructions is available on GitHub.

Leave a Reply

Your email address will not be published. Required fields are marked *

Press ESC to close