Memory Exhaustion in Decompressing Compressed Data Due to Large Limit on Message Size in uWebSockets
Denial of Service Due to Large Limit on Message Size
Common Weakness Enumeration: CWE-400 (Uncontrolled Resource Consumption)
Library: uWebSockets (Node.js)
Vulnerability Type: Denial of Service
Affected Versions: >= 0.10.0, <= 0.10.8
Description
Affected versions of uWebSockets (uws) do not properly handle large WebSocket messages when permessage-deflate is enabled, which may result in a denial of service (DoS) condition.
If uWebSockets receives a 256MB WebSocket message with permessage-deflate enabled, the server will compress the message prior to executing the length check, and subsequently decompress the message prior to processing. This can result in a situation where an excessively large WebSocket message passes the length checks, yet still gets cast from a Buffer to a string, which will exceed V8's maximum string size and crash the process.
Attack Scenario
An attacker can exploit this vulnerability by sending a carefully crafted large WebSocket message to the server. The message is initially large (e.g., 256MB) but is compressed down to a size that passes the server's length checks (e.g., less than 16MB). When the server receives and decompresses this message, the resultant data exceeds V8's maximum string size, causing the process to crash.
Exploit Steps
Enable
permessage-deflateon the server: The server must havepermessage-deflateenabled for WebSocket connections. This extension allows WebSocket messages to be compressed, reducing their size during transmission.Craft a Large WebSocket Message: The attacker creates a WebSocket message that is very large, for instance, 256MB. This message should contain data that compresses efficiently, resulting in a much smaller compressed size.
Send the Compressed Message: The attacker sends this compressed message to the server. Due to
permessage-deflate, the message's size is reduced during transmission, allowing it to bypass the server's length checks.Server Decompression and Processing: Upon receiving the message, the server decompresses it. The decompressed size is now back to 256MB, significantly larger than the original compressed size that passed the length checks.
Exceeding V8's Maximum String Size: As the server attempts to cast the Buffer containing the decompressed message to a string, the size of this string exceeds the maximum allowed by V8, resulting in a crash of the Node.js process.
Example Code
Here's an example setup for a uWebSockets SSL application with permessage-deflate enabled:
In this setup:
The WebSocket server is configured with SSL/TLS using
cert.pemandkey.pem.permessage-deflateis enabled by setting.compression = uWS::SHARED_COMPRESSOR.The maximum payload length is set to 16MB.
An attacker would send a large (e.g., 256MB) WebSocket message that compresses to less than 16MB, allowing it to pass the length check. When the server decompresses the message, it expands back to 256MB, causing the server to exceed V8's maximum string size and crash.
Conclusion
This vulnerability demonstrates the importance of careful handling and validation of compressed data. By exploiting the way permessage-deflate processes WebSocket messages, an attacker can send large payloads that cause the server to crash, leading to a denial of service.
Last updated