CVE-2019-9512 – A Microsoft Windows HTTP/2 Ping Flood Denial of Service
December 05, 2019 | Trend Micro Research TeamIn this excerpt of a Trend Micro Vulnerability Research Service vulnerability report, Saran Neti and Dusan Stevanovic of the Trend Micro Research Team detail a recent unauthenticated denial of service in Microsoft Windows Internet Information Server (IIS). The following is a portion of their write-up covering CVE-2019-9512, with a few minimal modifications.
A denial-of-service vulnerability has been recently patched in Microsoft Windows. The vulnerability is due to resource exhaustion when continually sending HTTP/2 Ping frames (not to be confused with an ICMP Ping) to the webserver. This bug was originally reported to Microsoft by Jonathan Looney of Netflix and was addressed by CVE-2019-9512.
A remote unauthenticated attacker can exploit this vulnerability by sending a flood of HTTP/2 Ping frames. Successful exploitation causes a denial-of-service condition on the target system.
The Vulnerability
The Windows Internet Information Server (IIS) is a collection of Internet services packaged with the Windows operating system. IIS includes an HTTP server capable of serving static as well as dynamic content. IIS supports various web technologies including HTML, ASP, ASP.NET, JSP, PHP, and CGI. IIS includes support for a new version of the HTTP protocol: HTTP/2. This functionality is provided by the http.sys
kernel-mode driver.
HTTP/2 is a modern standard for the HyperText Transfer Protocol. It improves upon the widely used HTTP/1.1 standard by providing, among others, the following features: HTTP version negotiation for future expansion, multiplexing of multiple requests using weighted streams, and data compression of HTTP headers. HTTP/2 is a binary protocol that retains much of the use and semantics of HTTP/1.1 including its methods, status codes, and header fields. Modern browsers (e.g., Google Chrome, Mozilla Firefox, and Microsoft Edge) and web servers (e.g., Microsoft IIS, nginx, Apache httpd) include support for HTTP/2. Although HTTP/2 does not mandate a secure TLS-based transport, these implementations permit HTTP/2 only over TLS. The Application-Layer Protocol Negotiation (ALPN) TLS extension is used by endpoints in the TLS handshake to negotiate the application layer protocol, which currently includes the following: HTTP/1.1, SPDY/2, SPDY/3, and various HTTP/2 identifiers (h2, h2-17, h2-14, h2c, h2c-17). Microsoft IIS supports the h2 ALPN extension wherein HTTP/2 data is exchanged immediately after the TLS handshake is completed.
An HTTP/2 connection begins with a 24-byte magic connection preface:
PRI * HTTP/2.0\x0d\x0a\x0d\x0aSM\x0d \x0a\x0d\x0a
This sequence is followed by the exchange of a series of frames, the basic unit of encoding data in HTTP/2, starting with the SETTINGS frame. All frames have a fixed-length 9-byte header followed by a variable-length payload. The structure of a frame is as follows:
All multi-byte integers are in big-endian format.
The HTTP/2 Ping frame (Frame type=0x6) is a mechanism for measuring a minimal round-trip time from the sender, as well as determining whether an idle connection is still functional. Ping frames can be sent from any endpoint. In addition to the frame header, Ping frames must contain 8 bytes of data in the payload. A sender can include any value it chooses. Receivers of a Ping frame that do not include an ACK flag must send a Ping frame with the ACK flag set in response, with an identical payload. Ping responses should be given higher priority than any other frame. Ping frames are not associated with any individual stream and their Stream Identifier should be set to 0.
A denial-of-service vulnerability exists in the Windows kernel-mode HTTP driver http.sys
. When a Windows-based web server such as IIS is configured for HTTPS, it enables support for HTTP/2 by default, and employs http.sys
to process incoming HTTP/2 requests over TLS. For each HTTP/2 connection http.sys
maintains a state. When http.sys receives a Ping frame, function HTTP!UxDuoParsePing()
will be called to build this state and allocate memory. The memory allocation happens in the function HTTP!UxDuoAllocateParcel()
, which is called from HTTP!UxDuoParsePing()
. If a malicious attacker sends a continuous stream of Ping frames, significant resources will be allocated for processing these frames. Additional memory is also allocated in the function HTTP!UxDuoParse()
, which calls HTTP!UxDuoParsePing()
. Since the function HTTP!UxDuoParsePing()
does not allow for rate-limiting the number of Ping frames that can be accepted and processed from a client, significant resource exhaustion can ensue.
Note that in the patched version of the http.sys
, the HTTP!UxDuoParsePing()
function calls a newly introduced function HTTP!UxDuoApplyPingFrameDosPrevention()
. This new function utilizes a registry setting HTTP2MaxPingsPerMinute
, which limits the maximum number of pings per minute a client can send to the server before the connection is closed by the server. This key is located in the registry under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP\Parameters
.
By sending a continuous stream of HTTP/2 frames, the attacker can cause a significant resource exhaustion on an affected target server, and thus lead to a potential denial-of-service condition – especially if a distributed network of source machines is employed.
Source Code Walkthrough
The following code snippet was taken from http.sys
version 10.0.14393.2828. Comments added by Trend Micro Security Research have been highlighted.
To trigger the condition, the attacker initiates a TLS connection with the target server and negotiates HTTP/2 using the 'h2' ALPN extension value. The attacker then sends HTTP/2 magic bytes and multiple Ping frames to the target host. The vulnerability is triggered as the server processes these frames, for the duration during which the attacker remains connected.
The Patch
Microsoft issued a patch for this vulnerability in August and assigned it CVE-2019-9512. In addition to applying the vendor-provided patch, an administrator needs to configure their server to limit the number of HTTP/2 packets accepted. This can vary based on the environment and services running on each server. The administrator must add the "HTTP2MaxPingsPerMinute" setting in the Registry Editor. This key is found under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP\Parameters
. For additional information, see the vendor's advisory. Unfortunately, Microsoft offers no guidance on what values to use.
Special thanks to Saran Neti and Dusan Stevanovic of the Trend Micro Research Team for providing such a thorough analysis of this vulnerability. For an overview of Trend Micro Research services please visit http://go.trendmicro.com/tis/.
The threat research team will be back with other great vulnerability analysis reports in the future. Until then, follow the ZDI team for the latest in exploit techniques and security patches.