Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

フィードお問い合わせプライバシー© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2020-1206 — CVE-2020-1206 (SMBleed) の Windows SMBv3 におけるカーネル情報漏洩脆弱性に関する技術的分析。未認証のメモリリークオラクルや、SMBGhost と組み合わせた RCE のための悪用技術を含む。 | Kitploit
ツール/GitHubGitHub/datntsec/cve-2020-1206
メモリフォレンジック脆弱性分析エクスプロイト情報収集ペネトレーションテストバイナリエクスプロイト
GitHubdatntsec/cve-2020-1206

CVE-2020-1206

CVE-2020-1206 (SMBleed) の Windows SMBv3 におけるカーネル情報漏洩脆弱性に関する技術的分析。未認証のメモリリークオラクルや、SMBGhost と組み合わせた RCE のための悪用技術を含む。

リポジトリを見る
565年前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

SMBGhost脆弱性(CVE-2020-0796)では、整数オーバーフローバグを利用してAlloc.Userbufferポインタを任意のアドレスに変更し、そこに任意のデータを書き込むwrite-what-whereプリミティブの手法について述べました。SMB Ghostと同様に、この脆弱性もsrv2.sysのSrv2DecompressData関数に存在します。SMBGhost脆弱性(CVE-2020-0796)に関連するSrv2DecompressData関数を、Zecopsによって簡略化されたものと共に確認してみましょう。``` c typedef struct _COMPRESSION_TRANSFORM_HEADER { ULONG ProtocolId; ULONG OriginalCompressedSegmentSize; USHORT CompressionAlgorithm; USHORT Flags; ULONG Offset; } COMPRESSION_TRANSFORM_HEADER, *PCOMPRESSION_TRANSFORM_HEADER;

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関数は、クライアントから送信された圧縮メッセージを受け取り、必要なメモリ領域を割り当て、その中にメッセージを展開します。その後、Offsetフィールドが0以外の場合、圧縮データの前にあるデータ(RawData)を割り当てられたメモリ領域の先頭にコピーします。

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

SMBGhostの脆弱性は、関数が整数オーバーフローをチェックしないことに起因し、誤ったサイズの割り当てを引き起こしてバッファオーバーフローを発生させます。MicrosoftがSMBGhostにパッチを適用してから3ヶ月後、CVE-2020-1206([Zecops Blog](https://blog.zecops.com/)による呼称でSMBleed)という脆弱性が発見されました。この脆弱性により、他方のマシンのアドレスを漏洩させることが可能になり、SMBGhostと組み合わせることでRCEを達成できます。Srv2DecompressData関数をより単純に理解するために、この関数をSMBGhostのパッチ適用前の状態で再利用し、パッチが適用されていると仮定します。

# OriginalCompressedSegmentSizeの偽装
SMBGhostと同様に、今回も送信する展開データよりわずかに大きな値でOriginalCompressedSegmentSizeを偽装します。例えば、サイズがxバイトのデータを圧縮する場合、OriginalCompressedSegmentSizeフィールドにxを設定する代わりに、x + 0x1000を設定します。次の図で明確になります:

![](https://assets.kitploit.com/production/public/readmes/24502/687d3bdc67e4b2f5bb3cecbe41ea52be98a5c904a8688b325a69acb0a854ca75.png)

初期化されていないカーネルデータは、メッセージの一部として扱われます。

[CVE-2020-0796の分析](https://github.com/datntsec/CVE-2020-0796)で述べたように、Srv2DecompressDataは、展開が成功した場合、SmbCompressionDecompress関数後のチェック段階をスキップします。``` c
if (Status < 0 || FinalCompressedSize != Header->OriginalCompressedSegmentSize) {
    SrvNetFreeBuffer(Alloc);
    return STATUS_BAD_DATA;
}

OriginalCompressedSegmentSizeフィールドはxではなくx + 0x1000に設定されていますが、解凍が成功した後、FinalCompressedSize変数には値xは含まれず、代わりにx + 0x1000が含まれます:```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;

}

Bởi vì sau khi giải nén thành công, FinalCompressedSize được cập nhật để giữ giá trị CompressedBufferSize (tương ứng với OriginalCompressedSegmentSize được truyền vào hàm SmbCompressionDecompress). Việc cập nhật và kiểm tra sau đó là gần như không cần thiết, có thể dẫn đến một số lỗi không mong muốn.

解凍が成功した後、FinalCompressedSizeはCompressedBufferSize(SmbCompressionDecompress関数に渡されるOriginalCompressedSegmentSizeに対応)を保持するように更新されるためです。その後の更新とチェックはほとんど不要であり、予期しないエラーを引き起こす可能性があります。

# Khai thác ở mức cơ bản
# 基本的な悪用

Cấu trúc message mà Zecops sử dụng để chứng minh lỗ hỏng là [SMB2 WRITE message](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e7046961-3318-4350-be2a-a8d69bb59ce8). Cấu trúc này chứa các trường như số byte có thể write, flag,..., theo sau là một buffer có độ dài tùy ý. Điều này khá hoàn hảo để khai thác lỗi, vì ta có thể tạo một message và chỉ định header, với một buffer chứa data chưa được khởi tạo.

Zecopsが脆弱性を実証するために使用するメッセージ構造は、[SMB2 WRITEメッセージ](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e7046961-3318-4350-be2a-a8d69bb59ce8)です。この構造には、書き込み可能なバイト数、フラグなどのフィールドが含まれ、その後に可変長のバッファが続きます。これは脆弱性の悪用にほぼ完璧であり、ヘッダを指定し、未初期化データを含むバッファを持つメッセージを作成できるからです。

Dựa trên POC của [Zecops](https://blog.zecops.com/) trên kho lưu trữ WindowsProtocolTestSuites của Microsoft, để để có cái nhìn rõ hơn về về điều này, ta sẽ thêm phần bổ sung nhỏ này cho hàm compression:

MicrosoftのWindowsProtocolTestSuitesリポジトリにおける[Zecops](https://blog.zecops.com/)のPOCに基づき、これをより明確に理解するために、圧縮関数に次の小さな追加を行います。``` c
// HACK: fake size
if (((Smb2SinglePacket)packet).Header.Command == Smb2Command.WRITE)
{
    ((Smb2WriteRequestPacket)packet).PayLoad.Length += 0x1000;
    compressedPacket.Header.OriginalCompressedSegmentSize += 0x1000;
}

Lưu ý rằng POC này yêu cầu thông tin xác thực và chia sẻ quyền write, thường có sẵn trong nhiều trường hợp. Tuy nhiên, lỗi trả về sẽ áp dụng cho mọi message (bao gồm cả message có hoặc không có thông tin xác thực), nên có khả năng ta sẽ có thể khai thác mà không cần phải xác thực. Một điều nữa, là bộ nhớ mà chúng ta sẽ leak là từ các lần phân bổ trước trong NonPagedPoolNx và vì chúng ta có thể kiểm soát kích thước phân bổ, chúng ta sẽ kiểm soát được dữ liệu mà chúng ta sẽ leak ở một mức độ nào đó.

SMBleed POC Source Code

Vậy nếu không có thông tin xác thực thì có thể leak được địa chỉ kernel không? Để trả lời cho câu hỏi này, ta hãy phân tích SMB sâu hơn nữa.

Đi sâu vào SMB

Khi xác thực thông tin, client sẽ gửi các message sau:

SMB2 NEGOTIATE → SMB2 SESSION_SETUP → SMB2 SESSION_SETUP

Nếu thông tin xác thực sai, phiên kết nối sẽ bị hủy sau gói tin SMB2 SESSION_SETUP thứ 2:

Giả sử rằng ta không có thông tin xác thực, chúng ta sẽ kiểm tra xem liệu có một lệnh nào có thể gửi mà không cần phải xác thực hay không. Qua việc tìm kiếm, ta nhận thấy:

  • Lệnh đầu tiền phải gửi là SMB2 NEGOTIATE và nó cũng là lệnh SMB2 NEGOTIATE duy nhất trong suốt một phiên.
  • Các lệnh tiếp theo, cho đến khi xác thực thành công phải là SMB2 SESSION_SETUP.

Trong đó SMB2 NEGOTIATE message sẽ không được nén. Bug nằm ở hàm giải nén, vì vậy ta sẽ không xem xét nó mà chỉ xét các SMB2 SESSION_SETUP message.

SMB2 SESSION_SETUP

Như đã nói ở trên, một phiên thông thường sẽ có 2 lệnh SMB2 SESSION_SETUP được gửi. Các gói tin trả về sẽ không chứa dữ liệu nào cần thiết để ta có thể khai thác, và ta cũng không có cách nào làm ảnh hưởng đến gói tin trả về. Tuy nhiên gói trả về thứ hai sẽ có body trống với status 0xC000006D (STATUS_LOGON_FAILURE) trong packet header. Nhận thấy, gói SMB2 SESSION_SETUP đầu tiên sẽ chứa request NTLM Negotiate message và gói thứ 2 sẽ chứa NTLM Authenticate message. NTLM Negotiate message khá đơn giản, và có thể không có gì thú vị, nên ta sẽ đi sâu vào NTLM Authenticate message.

ツールをダウンロード