Hi Guys,
I want to share my PoC with some EDR. I found it interesting that all the product cannot detect SMBghost exploitation related to the buffer overflow part.
SMBGhost exploitation consists of two steps. The first step is to gain privilege access from exploiting SMBGhost to exploit buffer overflow CVE-2020-0796. After it can gain control, the next part is to inject malicious DLL into a winlogon process. All EDR will only detect the second stage that is DLL injection into winlogon. Detecting the injection to winlogon is straightforward part as this is not common for an application injecting DLL into this.
The vulnerability CVE-2020-0796

Buffer Overflow sequence below
- 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
SMBGhost is an integer overflow vulnerability that exists in srv2!Srv2DecompressData, the routine that decompresses compressed request packets.

The Problematic Code in Server
typedef struct _COMPRESSION_TRANSFORM_HEADER
{
ULONG ProtocolId;
ULONG OriginalCompressedSegmentSize;
USHORT CompressionAlgorithm;
USHORT Flags;
ULONG Offset;
} COMPRESSION_TRANSFORM_HEADER, *PCOMPRESSION_TRANSFORM_HEADER;
typedef struct _ALLOCATION_HEADER
{
// ...
PVOID UserBuffer;
// ...
} ALLOCATION_HEADER, *PALLOCATION_HEADER;
NTSTATUS Srv2DecompressData(PCOMPRESSION_TRANSFORM_HEADER Header, SIZE_T TotalSize)
{
PALLOCATION_HEADER Alloc = SrvNetAllocateBuffer(
(ULONG)(Header->OriginalCompressedSegmentSize + Header->Offset),
NULL);
If (!Alloc) {
return STATUS_INSUFFICIENT_RESOURCES;
}
ULONG FinalCompressedSize = 0;
NTSTATUS Status = SmbCompressionDecompress(
Header->CompressionAlgorithm,
(PUCHAR)Header + sizeof(COMPRESSION_TRANSFORM_HEADER) + Header->Offset,
(ULONG)(TotalSize - sizeof(COMPRESSION_TRANSFORM_HEADER) - Header->Offset),
(PUCHAR)Alloc->UserBuffer + Header->Offset,
Header->OriginalCompressedSegmentSize,
&FinalCompressedSize);
if (Status < 0 || FinalCompressedSize != Header->OriginalCompressedSegmentSize) {
SrvNetFreeBuffer(Alloc);
return STATUS_BAD_DATA;
}
if (Header->Offset > 0) {
memcpy(
Alloc->UserBuffer,
(PUCHAR)Header + sizeof(COMPRESSION_TRANSFORM_HEADER),
Header->Offset);
}
Srv2ReplaceReceiveBuffer(some_session_handle, Alloc);
return STATUS_SUCCESS;
}
If we look carefully, we can notice that lines 20 and 31 can lead to an integer overflow for certain inputs. For example, most POCs that appeared shortly after the bug publication and crashed the system just used the 0xFFFFFFFF value for the Offset field. Using the value 0xFFFFFFFF triggers an integer overflow on line 20, and as a result less bytes are allocated.
In Assembly

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.
The Problematic Code in Client

Suppose 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 \xfc SMB, which must be present and represents the magic bytes used to indicate the message must be decompressed
Privilege Escalation Process
The technique is about leaking the current process token address using the NtQuerySystemInformation(SystemHandleInformation) API and then overriding it, granting the current process token privileges can then be used for privilege escalation. The Abusing Token Privileges For EoP research by Bryan Alexander (dronesec) and Stephen Breen (breenmachine) (2017) demonstrates several ways of using various token privileges for privilege escalation.
https://github.com/hatRiot/token-priv/blob/master/abusing_token_eop_1.0.txt
https://media.blackhat.com/bh-us-12/Briefings/Cerrudo/BH_US_12_Cerrudo_Windows_Kernel_WP.pdf
https://github.com/ZecOps/CVE-2020-0796-LPE-POC/blob/master/write_what_where.py

I use the exploitation PoC from https://github.com/ZecOps/CVE-2020-0796-LPE-POC that is very easy to understand.
Code that Alexandre Beaulieu kindly shared in his Exploiting an Arbitrary Write to Escalate Privileges writeup. The privilege escalation after modifying the process’ token rights by injecting a DLL into winlogon.exe. The DLL’s whole purpose is to launch a privileged instance of cmd.exe. Complete Local Privilege Escalation Proof of Concept can be found here and is available for research / defensive purposes only. https://segfault.me/2019/05/24/exploiting-an-arbitrary-write-to-escalate-privileges/