
CVE-2020-0796 (SMBGhost) के लिए तकनीकी विश्लेषण और प्रूफ-ऑफ-कॉन्सेप्ट, SMBv3 संपीड़न में एक पूर्णांक अतिप्रवाह भेद्यता जो Windows 10/Server पर स्थानीय विशेषाधिकार वृद्धि की ओर ले जाती है।
SMBv3 में Windows 10/Server version 1903 से जोड़ी गई compression सुविधा में integer overflow दोष है, जिसे Microsoft ने 12/03/2020 को पुष्टि की। यह attacker को Local Privilege Escalation (LPE) और Remote Code Execution (RCE) करने की अनुमति देता है। यहाँ केवल LPE दोष के बारे में बात की जाएगी।
प्रभावित संस्करण:
srv2.sys फ़ाइल का विश्लेषण करने पर, Decompress से संबंधित निम्नलिखित फ़ंक्शन कॉल होते हुए पाए गए:``` js
Srv2ReceiveHandler
|
|
v
Srv2DecompressMessageAsync
|
|
v
Srv2DecompressData -------> SrvNetAllocateBuffer
|
|
v
SmbCompressionDecompress
|
|
v
memcpy
सबसे पहले, एक smb डेटा पैकेट प्राप्त करने के लिए `Srv2ReceiveHandler` फ़ंक्शन को कॉल किया जाता है, और यह `ProtocolId` प्रोटोकॉल के अनुरूप एक फ़ंक्शन को कॉल करता है। यदि `PrococolId` = 0x424D53FC है, तो यह `Srv2DecompressMessageAsync` फ़ंक्शन को कॉल करेगा, जो डेटा पैकेट को डीकंप्रेस करने के लिए `Srv2DecompressData` फ़ंक्शन को कॉल करता है। `Srv2DecompressData` फ़ंक्शन, डीकंप्रेसन के बाद डेटा संग्रहीत करने के लिए एक `Alloc` आवंटित करने हेतु `SrvNetAllocateBuffer` फ़ंक्शन को कॉल करेगा, फिर यह डेटा पैकेट को डीकंप्रेस करने के लिए `SmbCompressionDecompress` फ़ंक्शन को कॉल करेगा, और अंत में `memcpy` फ़ंक्शन को कॉल करेगा। इस प्रकार, संपूर्ण डीकंप्रेसन प्रक्रिया में निम्नलिखित मुख्य चरण होंगे:
- 1. Allocate
- 2. Decompress
- 3. Copy
Microsoft द्वारा प्रदान किए गए दस्तावेज़ के अनुसार, `COMPRESSION_TRANSFORM_HEADER` संरचना का उपयोग क्लाइंट और सर्वर के बीच संपीड़ित डेटा भेजने और प्राप्त करने के लिए किया जाता है। इसकी संरचना इस प्रकार है:``` c
typedef struct _COMPRESSION_TRANSFORM_HEADER
{
ULONG ProtocolId;
ULONG OriginalCompressedSegmentSize;
USHORT CompressionAlgorithm;
USHORT Flags;
ULONG Offset;
} ;
यहाँ हम केवल ऊपर के 2 मुख्य फ़ील्ड पर ध्यान केंद्रित करते हैं:
OriginalCompressedSegmentSize असंपीड़ित डेटा सेगमेंट का आकार है, जो बाइट में मापा जाता है।Offset संपीड़ित डेटा की शुरुआत और _COMPRESSION_TRANSFORM_HEADER संरचना के अंत के बीच बाइट में विचलन है।इस प्रकार संपीड़ित डेटा पैकेट का रूप इस प्रकार होगा:
``` c
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;
}
`Srv2DecompressData` फ़ंक्शन का विश्लेषण करने पर पता चलता है कि यह फ़ंक्शन एक संपीड़ित डेटा पैकेट `COMPRESSION_TRANSFORM_HEADER` (Header) प्राप्त करता है, फिर `SrvNetAllocateBuffer` फ़ंक्शन के माध्यम से `Header->OriginalCompressedSegmentSize` + `Header->Offset` के योग को पैरामीटर के रूप में उपयोग करके एक मेमोरी क्षेत्र (Alloc) आवंटित करता है, उसके बाद संपीड़ित डेटा को डिकंप्रेस करता है और बिना संपीड़ित डेटा को `Alloc->Buffer` में कॉपी करता है।

Integer overflow त्रुटि तब होती है जब `Srv2DecompressData` `SrvNetAllocateBuffer` फ़ंक्शन को कॉल करता है। वास्तव में `SrvNetAllocateBuffer` फ़ंक्शन 2 64-बिट मान प्राप्त करता है, लेकिन `SrvNetAllocateBuffer` को कॉल करते समय, `Srv2DecompressData` इसमें केवल 2 32-बिट मान (ULONG) पास करता है। जबकि `OriginalCompressedSegmentSize` और `Offset` दोनों ULONG हैं, इन्हें एक साथ जोड़ने पर परिणाम 32-बिट से बड़ा हो सकता है। इसीलिए integer overflow त्रुटि होती है (सीधे शब्दों में समझें तो जब 0xffffffff (`OriginalCompressedSegmentSize`) को 0x10 (`Offset`) के साथ जोड़ा जाता है, तो परिणाम 0xf0000000f होता है, लेकिन `SrvNetAllocateBuffer` फ़ंक्शन को केवल 0x0000000f मान प्राप्त होता है)।

Integer overflow त्रुटि के कारण Alloc मेमोरी क्षेत्र गलत तरीके से आवंटित होगा (आवंटित किया जाने वाला आकार वास्तविक आकार से छोटा होगा), जिससे buffer overflow त्रुटि हो सकती है:
