The latest vulnerability in SMBv3 is a “wormable” vulnerability given its potential ability to replicate or spread over network shares using the latest version of the protocol (SMB 3.1.1). As of this writing, Microsoft have just released a patch for CVE-2020-0796 on the morning of March 12th. The bug was introduced very recently, in the decompression routines for SMBv3 data payloads. The code implementing this was deployed in April 2019 for Version 1903 and November 2019 for version 1909.
The vulnerability occurs during the processing of a malformed compressed message. The header of the message follows this format: (from [MS-SMB2])
There are two parameters in the header that are of interest: OriginalCompressedSegmentSize and Offset/Length
The Srv2DecompressData (srv2.sys) function allocates a buffer of size OriginalCompressedSegmentSize + Offset/Length
This is not checking the signedness of these values, and as the addition is signed an attacker can allocate a buffer smaller than intended
Data is being decompressed at buffer + offset, using data from packet+0x10+offset
OriginalCompressedSegmentSize is used as the UncompressedBufferSize parameter passed to SmbCompressionDecompression which is a wrapper for RtlDecompressBufferEx2
This routine assumes the uncompressed buffer size to be an unsigned long so a negative value gets cast into a large unsigned number
Because of this, the decompression routine decompresses the buffer and can go well beyond the original size, as it is assuming it has a very large buffer to work with
Here’s an annotated disassembly of the relevant function on the server side:
This flaw can affect both client and server in SMB negotiations in a compressed message sent after the Negotiate Protocol Responses. The server vulnerability is within srv2.sys and the client vulnerability is within mrxsmb.sys which both end up calling the same code in SmbCompressDecompress.
Here’s an annotated disassembly of the relevant function on the client side – unlike the server side the OriginalCompressedSegmentSize is bounds checked but there is no check on offset/length before they are combined and passed to ExAllocatePoolWithtag. We have confirmed the BSOD crash from both client->server AND server-client using this vulnerability.
If a computer allows inbound SMB3 traffic over port 445, by default compression is supported and the client and server will negotiate the “terms” of this compression and then the client will proceed to transfer a compressed payload.
The flaw is present in the SMB Compression Transform Header, prior to any kind of authentication.
We can see the very large OriginalSize used for attacker-controlled data (4294967295 is 0xFFFFFFFF in hex which is also -1 if viewed as a signed long). This is copied into a smaller fixed buffer and results in a classic buffer overflow. Of note is the ProtocolID of \xfcSMB, which must be present and represents the magic bytes used to indicate the message must be decompressed per the spec.
However, it is not just the server-side which is vulnerable to this attack. If a client connects to a malicious SMB server, both sides run the same vulnerable code and a malicious server can respond to client requests in the same way to trigger the overflow on the initiator/client side. In this scenario, the Windows Powershell command referenced here will not be effective in stopping this attack against the SMB client. It will only be useful when implemented on the SMB server/recipient side pre-authentication.
As always, this kind of patch should be applied as soon as possible, subject to organizational policy. While there are currently no known exploits in the wild, as you will see, causing a BSOD (blue screen of death), is quite trivial, and remains a highly effective attack method for disruption if an attacker can gain access to an internal network.
More dangerous yet are any systems exposing port 445 to the Internet, as we have seen the damage possible through similar bugs such as WannaCry. As of the time of this writing and just prior to Microsoft releasing its patch, Shodan.io appears to have just over 35,000 Windows computers reporting the vulnerable versions of software as searched by: port:445 os: “Windows” + os: “18362” for example. Many of these will likely be patched quickly now that a fix is out.
Looking at the patched version, we can see the code is now using RtlULongAdd to add OriginalCompressedSegmentSize and the Offset/Length value. There also seem to be an extra test to make sure the size is not bigger than the whole packet plus 0x134.
Looking a little further, we can also see the usage of RtULongSub for computing the size of the compressed buffer while accounting for the offset field.
Finally, we can also notice the usage of WPP tracing code in case an error occurs (tracing was already occurring throughout the driver, but this specific function was not previously instrumented in such a way).
Getting a Blue Screen of Death or BSOD is a straightforward exercise. Pivoting from that to full remote code execution will likely be more challenging, as additional bugs will likely be required to bypass Windows’ latest mitigation techniques, such as Kernel ASLR or KASLR. For this bug, the attacker will have easy primitives for the allocation of data and can control the size of the data used to trigger the overflow. On the flip side, the objects allocated in memory to store the attacker input are freed relatively quickly, making exploitation more difficult.