Author：SungLin@Knownsec 404 Team
Time: April 2, 2020
On March 12, 2020, Microsoft confirmed that a critical vulnerability affecting the SMBv3 protocol exists in the latest version of Windows 10, and assigned it with CVE-2020-0796, which could allow an attacker to remotely execute the code on the SMB server or client. On March 13 they announced the poc that can cause BSOD, and on March 30, the poc that can promote local privileges was released . Here we analyze the poc that promotes local privileges.
0x01 Exploit principle
The vulnerability exists in the srv2.sys driver. Because SMB does not properly handle compressed data packets, the function
Srv2DecompressData is called when processing the decompressed data packets. The compressed data size of the compressed data header,
Offset, is not checked for legality, which results in the addition of a small amount of memory.
SmbCompressionDecompress can be used later for data processing. Using this smaller piece of memory can cause copy overflow or out-of-bounds access. When executing a local program, you can obtain the current offset address of the
token + 0x40 of the local program that is sent to the SMB server by compressing the data. After that, the offset address is in the kernel memory that is copied when the data is decompressed, and the token is modified in the kernel through a carefully constructed memory layout to enhance the permissions.
0x02 Get Token
Let's analyze the code first. After the POC program establishes a connection with smb, it will first obtain the Token of this program by calling the function
OpenProcessToken. The obtained Token offset address will be sent to the SMB server through compressed data to be modified in the kernel driver. Token is the offset address of the handle of the process in the kernel. TOKEN is a kernel memory structure used to describe the security context of the process, including process token privilege, login ID, session ID, token type, etc.
Following is the Token offset address obtained by my test.
0x03 Compressed Data
Next, poc will call
RtCompressBuffer to compress a piece of data. By sending this compressed data to the SMB server, the SMB server will use this token offset in the kernel, and this piece of data is
'A' * 0x1108 + (ktoken + 0x40).
The length of the compressed data is 0x13. After this compressed data is removed except for the header of the compressed data segment, the compressed data will be connected with two identical values
0x1FF2FF00BC, and these two values will be the key to elevation.
Let's debug it first, because here is an integer overflow vulnerability. In the function srv2!
Srv2DecompressData, an integer overflow will be caused by the multiplication
0xffff ffff * 0x10 = 0xf, and a smaller memory will be allocated in
srvnet! SmbCompressionDecompress and
nt! RtlDecompressBufferEx2 to continue decompression, then entering the function
nt! PoSetHiberRange, and then starting the decompression operation, adding
OriginalMemory = 0xffff ffff to the memory address of the
UnCompressBuffer storage data allocated by the integer overflow just started Get an address far larger than the limit, it will cause copy overflow.
But the size of the data we need to copy at the end is 0x1108, so there is still no overflow, because the real allocated data size is 0x1278, when entering the pool memory allocation through
srvnet! SrvNetAllocateBuffer, finally enter
srvnet! SrvNetAllocateBufferFromPool to call
nt! ExAllocatePoolWithTag to allocate pool memory.
Although the copy did not overflow, it did overwrite other variables in this memory, including the return value of
srv2! Srv2DecompressDatade. The
UnCompressBuffer_addressis fixed at 0x60, and the return value relative to the
UnCompressBuffer_address offset is fixed at 0x1150, which means that the offset to store the address of the
UnCompressBuffer relative to the return value is
0x10f0, and the address to store the offset data is
0x1168, relative to the storage decompression Data address offset is
There is a question why it is a fixed value, because the
OriginalSize = 0xffff ffff, offset = 0x10 passed in this time, the multiplication integer overflow is
0xf, and in
srvnet! SrvNetAllocateBuffer, the size of the passed in 0xf is judged, which is less At
0x1100, a fixed value of
0x1100 will be passed in as the memory allocation value of the subsequent structure space for the corresponding operation, and when the value is greater than
0x1100, the size passed in will be used.
Then return to the decompressed data. The size of the decompressed data is
0x13. The decompression will be performed normally. Copy
0x1108of "A", the offset address of the 8-byte
token + 0x40 will be copied to the back of "A".
After decompression and copying the decompressed data to the address that was initially allocated, exit the decompression function normally, and then call memcpy for the next data copy. The key point is that rcx now becomes the address of
token + 0x40of the local program!!!
After the decompression, the distribution of memory data is
0x1100 ('A') + Token = 0x1108, and then the function
srvnet! SrvNetAllocateBuffer is called to return the memory address we need, and the address of v8 is just the initial memory offset
v8 + 0x18 = 0x1108, the size of the copy is controllable, and the offset size passed in is 0x10. Finally, memcpy is called to copy the source address to the compressed data
0x1FF2FF00BC to the destination address
0xffff9b893fdc46f0 (token + 0x40), the last 16 Bytes will be overwritten, the value of the token is successfully modified.
The value that is overwritten is two identical
0x1FF2FF00BC. Why use two identical values to overwrite the offset of
token + 0x40? This is one of the methods for operating the token in the windows kernel to enhance the authority. Generally, there are two methods.
The first method is to directly overwrite the Token. The second method is to modify the Token. Here, the Token is modified.
In windbg, you can run the
kd> dt _token command to view its structure.
So modify the value of
_SEP_TOKEN_PRIVILEGES to enable or disable it, and change the values of Present and Enabled to all privileges of the SYSTEM process token
0x1FF2FF00BC, and then set the permission to:
This successfully elevated the permissions in the kernel, and then execute any code by injecting regular shellcode into the windows process "winlogon.exe":
Then it performed the action of the calculator as follows:
本文由 Seebug Paper 发布，如需转载请注明来源。本文地址：https://paper.seebug.org/1165/