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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2022-37969PoC — CVE-2022-37969のチュートリアル。CVEの内部原因ではなく、カーネルエクスプロイトの方法論に焦点を当てています。 | Kitploit
ツール/GitHubGitHub/emilc3978/cve-2022-37969poc
特権昇格メモリフォレンジック脆弱性分析エクスプロイトリバースエンジニアリング学習と教育バイナリエクスプロイト
GitHubemilc3978/cve-2022-37969poc

CVE-2022-37969PoC

CVE-2022-37969のチュートリアル。CVEの内部原因ではなく、カーネルエクスプロイトの方法論に焦点を当てています。

リポジトリを見る
2810ヶ月前未レビュー

人気

すべて見る →

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

すべてのツールを探索

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

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

目次

はじめに

これは Windows エクスプロイトに関する一般的な側面を明確にするために作られました。CVE-2022-37969 に適用される基本概念を説明します。最終結果は動作する PoC です。CVE のすべての側面を明確にするものではありませんが、再利用可能なコード片を提供し、多くの一般的なエクスプロイトに見られるメカニズムを説明します。

対象ユーザーは、テストして Windows 内部の基本を理解するための動作する概念実証ソースコードを求める、初心者のリバースエンジニア、エクスプロイト開発者です。さらなる学習のための参照点を提供します。

要件: 基本的なカーネルデバッグ、基本的なリバースエンジニアリング、基本的な Windows 内部構造、c/c++ プログラミングスキル

背景

プログラムとは、マシン上で実行されるコードの断片です。一般にプログラムはデータ(入力)を受け取り、入力を使って計算を行い、データ(出力)を生成します。ほとんどのプログラムは人間によって書かれるため、バグが存在します。バグは、正しく書かれなかったソースコード(プログラマが入力に対して何かをしようとしたが、結果のコードが意図した結果と異なる)によって発生します。ほとんどのバグは製品リリース前に修正されますが、中には残ってしまうものもあります。これは、バグにはさまざまな種類があり、発見が難しいものもあるためです。

Windows もコンピュータープログラムであり、人間によって書かれたため、バグが存在します。なぜそれが重要なのでしょうか? Windows システムは、銀行口座、医療データベースなどの機密データを扱うプログラムを実行できるからです。一部のバグは、制限されたデータへの不正アクセスに利用される可能性があります(これはエクスプロイトの良いユースケースです)。

バグにはさまざまな種類があり、役に立つものもあれば、そうでないものもあります。一般に、バグはプログラムへの入力によって引き起こされます。その入力が、誤って書かれたコード行と組み合わさることで、不正な出力や動作を生成します。その入力を発見するのがセキュリティ専門家(またはハッカー)の仕事です。次のステップは、発生した不正な出力/動作を評価し、「これは有用に使えるか?」という問いに答えることです。ここでバグはさまざまなカテゴリに分類されます。例えば、あるバグはデータ構造を破壊し、対象のコンピューターを再起動させるような動作を引き起こすかもしれません。その有用性は限られています。 別のバグは、制限されたファイルへのアクセス許可を制御するメモリゾーンに入力を書き込ませるかもしれません。この種のバグはより有用です。

したがって、ハッカーは考えられるすべてのバグの中から、自分の目的に最も有用なサブセットを探します。一般的に言えば、問題は「システムを壊さずに、標的のプログラムに特別に細工した入力を与えて、アクセスレベルを昇格させて利益を得ることはできるか?」です。

この技術的でない導入の後、チュートリアルの範囲を定式化できます: 不正な入力を受け入れ、開発者の誤ったコードの結果として、通常ユーザーから管理者への権限を不正に昇格させることができる Windows プログラムを見つけられるか?

対象プログラム: Windows CLFS(Common Log File System Driver)

エクスプロイト名: CVE-2022-37969

種類: ローカル権限昇格

脆弱な ISO のダウンロード: ここからダウンロード

Windows の権限昇格に関する一般理論

Windows のアドレス空間は、ユーザー空間(一般的なプログラムを実行)とカーネル空間(オペレーティングシステム自体とハードウェアコンポーネントソフトウェア、つまりドライバーを実行)に大まかに分割されています。通常ユーザーはカーネル空間にアクセスしてはなりません。ただし、通常ユーザーのプログラムがカーネルコードの一部(システムコール、ドライバープロシージャ)にアクセスできるメカニズムは存在します。なぜアクセスが必要なのでしょうか? OS 設計者が提供する、安全で制御された方法で OS と対話するためです。

一部のドライバーは、ユーザーが提供するデータ入力を使用して、カーネル空間のデータ構造を操作します。入力がバグを引き起こす場合、カーネルが破損する可能性があります。その一例が Common Log File System Driver です。特別な入力を使うことで、ユーザーの特権アクセスレベルを保持するカーネルデータ構造をドライバーに変更させ、通常ユーザー を 管理者 で上書きさせることができます。

管理者に特権を昇格させるためには何を変更する必要があるか?

まず最終目標を念頭に置きます。Windows は、システム上で実行中の各プロセスの情報を、_EPROCESS という名前のカーネルデータ構造内に格納します。_EPROCESS の例

重要なフィールドの1つは struct _EX_FAST_REF Token です。これは別のデータ構造であり、そのプロセスの特権レベルを参照するデータをさらに指し示します。次の図では、System プロセスがシステムトークンを持ち、Explorer プロセスが通常ユーザートークンを持っています。

Tokens

したがって、Explorer.exe の特権を昇格させるには、System の _EPROCESS-->Token の値を Explorer の _EPROCESS-->Token にコピーする必要があります。System トークンを自分たちのプログラムのトークンにコピーし、昇格したプロセスからコマンドプロンプトを起動することで(子プロセスは親プロセスのトークンを継承します)、同様のことを達成します。

これらのアクションを完了するには、以下のメカニズムが必要です:

  1. カーネル内の _EPROCESS データ構造のアドレスを取得する
  2. System プロセスの Token フィールドの値を読み取る
  3. Explorer の _EPROCESS データ構造のアドレスを取得する
  4. Explorer の _EPROCESS 構造内の Token オフセットに System のトークンの値を書き込む

対象プロセスの PID による _EPROCESS データ構造の特定

はじめに: 長年にわたる Windows の性質: 新しい脆弱性が発見されるにつれて、Windows はそれらを緩和するためのパッチが必要でした。また、新しいテクノロジーの出現に伴い、Windows は競争力を維持するためにアップデートが必要でした。重要な要件の1つは、以前のバージョンとの後方互換性でした。そして時には、セキュリティは隠蔽によって達成されました。データ構造や関数定義はマニュアルから削除されましたが、機能は残っていました。リバースエンジニアリングにより、研究者はそれらの機能をさまざまな目的に利用できました。

_EPROCESS のカーネルアドレスを見つけるために、非公開関数 NtQuerySystemInformation を使用します(パラメーターはリンク参照)。SystemInformationClass パラメーターを使用することで、取得したい情報の種類を指定できます。SystemExtendedHandleInformation 値(#define SystemExtendedHandleInformation 0x40)を指定して、一般的なプロセス情報を取得します。

NtQuerySystemInformation を使用する際の注意点は、返されるデータの長さを事前に知ることができないことですが、NtQuerySystemInformation にはそれを助けるメカニズムがあります。必要なデータに対して誤ったサイズの配列で呼び出すと、ERROR と、要求すべき正しいデータサイズを返します。これを使って、次のようにしてプロセス情報を正しく読み取ることができます。

  1. ダミーの SystemInformationLength パラメーターを指定して NtQuerySystemInformation を呼び出す
  2. 返された ReturnLength パラメーターの値を読み取る
  3. 先ほど返された正しい SystemInformationLength 値を指定して、再度 NtQuerySystemInformation を呼び出す

返されるデータ構造は PSYSTEM_HANDLE_INFORMATION_EX 型です。これは非公開のデータ構造です(リンク参照)。これは SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX データ構造につながり、その Object フィールドには対応するプロセスの _Eprocess データ構造のカーネルアドレスが保持されます。

したがって、ロジックは次のようになります: すべての PSYSTEM_HANDLE_INFORMATION_EX 要素を反復処理し、SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX の UniqueProcessId フィールドを対象のプロセス PID と比較し、対応する Object フィールドを選択して、その _Eprocess アドレスをカーネル内で見つけます。

コードの一部:

proc_1 proc_2

NtQuerySystemInformation は関数へのポインターとして宣言され、そのアドレスは実行時に loadlibrary と getprocaddress を介して動的に取得されます。

  1. typedef NTSTATUS(WINAPI* ptr_NtQuerySystemInformation)(int, PVOID, ULONG, PULONG);
  2. ntdll=LoadLibrary(L"ntdll.dll");
  3. MyNtQuerySystemInformation = (ptr_NtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation");

トークンの読み取りと書き込みには、clfsw32.sys と NamedPipes 内部の脆弱性に依存する必要があります

パイプを使ったカーネル内データの読み書き

これはややブラックボックスであり、他の記事で詳述されていますが、エクスプロイトのプロセスを基本的に理解するために、この機能の最低限の知識を説明します。 パイプはプロセス間通信メカニズムです。プロセスはパイプを使用してお互いに情報を渡すことができます。パイプはカーネルデータ構造として表され、ユーザー空間から値を設定できるフィールドがあります。その例がパイプ属性(Pipe Attributes)です。

(後でこれを CLSF の脆弱性と結び付けて、ユーザー空間からカーネル空間への任意の読み取り/書き込みを実現します)

カーネルでのデータ割り当て

さらに読むには、fengshui-spraying-big-kids-pool を参照してください。メカニズムの簡略化した説明は次のとおりです:

カーネルには、割り当てたいサイズに応じてメモリを割り当てる2つの方法があります: オブジェクト <4KB+ヘッダーの場合はスモールプール、オブジェクト >4KB+ヘッダーの場合はビッグプールです。 ビッグプールページは、ユーザー空間から列挙できるため重要です。これは、通常ユーザーがビッグプールページを含むすべてのカーネル開始アドレスを見つけられることを意味します。

どうやって? 各ビッグプールページには Tag という名前のフィールドがあり(そこに保存されているデータの種類に関する情報を取得するために使用できます)、システム内のすべてのビッグプールページは、SystemInformationClass パラメーターの値として SystemBigPoolInformation を指定した NtQuerySystemInformation を使用して列挙できます。次に、すべてのページから Tag でフィルタリングして、関心のあるビッグプールページのアドレスを取得できます。例えば、CLFS は 'Clfs' タグを持つビッグプールページを使用します。カーネル内で CLFS オブジェクトが割り当てられているすべてのページのアドレスを取得できます。

proc_1

パイプに戻ると、同じ方法で操作できます。ビッグプールメカニズムを使用するのに十分な大きさのパイプを割り当て、ビッグプールページを列挙し、パイプ固有の Tag を検索してそれらのページをフィルタリングします。

これにより、カーネルが私たちのパイプを割り当てた場所をユーザー空間にリークできます。カーネルに入るデータを制御して読み取ることはどうでしょうか?

このためにパイプ属性(Pipe Attributes)に依存します。ビッグプールタグと同様に、パイプ属性はパイプを説明する情報を含む配列です(ユーザーが入力します)。非公開関数 NtFsControlFile を使用して、パイプ属性データ構造に任意の読み取り、書き込みを行うことができます。非公開であるため、PipeAttribute ベクトルを設定してから読み取る概念実証のみが提供されます。読み取り、書き込みのプリミティブに対して許可されている変更は、入出力バッファーの内容とそのサイズを制御することだけです。

カーネル内のパイプ属性からの書き込みと読み取りの例:

ここでは、ビッグプールページ(0x2000)を使用するのに十分な大きさのパイプを割り当て、入力バッファーと出力バッファーを制御された値に設定します。 注意: 入力値の最初の2バイトは、機能するために 0x5a 0x00 でなければなりません。

pipewr

ここでは、先ほどカーネルに書き込んだものを読み戻します。ここでも出力バッファーのみを変更します。

peprd

そして結果:

piperes

パイプのビッグプールページはメモリ上でどのように見えるか、そしてなぜ前述の操作が私たちにとって有用なのか?

カーネル内のパイプのビッグプールページの内容は次のとおりです: ビッグプールページをクエリすることで、カーネル内のパイプデータ構造の先頭を見つけました。アドレス pipe_begin+0x20 には、入力バッファー+0x2 へのポインターがあります。

pipe_kern

パイプ属性読み取り関数を呼び出すと、OS は次のことを行います:

  1. カーネル内のパイプの場所を特定する
  2. 0x20 を加算し、ポインターを逆参照して、カーネル空間の内容をユーザーバッファーにダンプする。
ツールをダウンロード