Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
ds3-nrssr-rce — CVE-2022-24125 および CVE-2022-24126 向けのドキュメントと概念実証コード | Kitploit
ツール/GitHubGitHub/tremwil/ds3-nrssr-rce
エクスプロイトフレームワーク脆弱性分析エクスプロイトリバースエンジニアリングシェルコードペネトレーションテスト学習と教育レッドチーミングシェルコード生成ペイロード開発バイナリエクスプロイト
GitHub
169854年前Kitploit レビュー済み
tremwil/ds3-nrssr-rce

ds3-nrssr-rce

CVE-2022-24125 および CVE-2022-24126 向けのドキュメントと概念実証コード

リポジトリを見る

人気

すべて見る →

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

すべてのツールを探索

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

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

アップデート: Dark Souls III 1.15.1

2022年8月25日、Dark Souls IIIの新たなゲームアップデート1.15.1が、オンラインサービスの復旧とともにリリースされました。このアップデートでは、CVE-2022-24125とCVE-2022-24126の両方が修正され、さらにゲームのP2Pネットワーキングに存在する多種多様なその他の潜在的なセキュリティ脆弱性(OOB読み取り/書き込み)も修正されました。さらに、他のプレイヤーのセーブデータを破損させる既知のエクスプロイトもすべて修正されています。オンラインマルチプレイ中によく遭遇する「呪いのナイフ」などの一般的なチートもパッチされています。

ds3-nrssr-rce

このリポジトリには、FROM SOFTWAREのゲームに影響を与える最新のRCEエクスプロイトCVE-2022-24126の概念実証コードとドキュメントが含まれています。理論上は他のゲームでも可能ですが、この研究はDark Souls IIIで行われたため、焦点はそちらに当てられています。現時点では概念実証コードはDark Souls IIIにのみ存在しますが、脆弱性は以下のゲームに存在することが確認されています:

  • Dark Souls 1 PTDE(クレジット:LukeYui)
  • Dark Souls Remastered(クレジット:metal-crow)
  • Dark Souls 2(Scholarを含む)(クレジット:LukeYui)
  • Dark Souls 3(1.15.0まで)(クレジット:tremwil)

脆弱性のあるコードはSEKIROにも存在します(クレジット:LukeYui)が、トリガーする方法はありません。Demon's Soulsでの存在は確認されていませんが、非常に可能性が高いです。クローズドネットワークテストは影響を受けましたが、リリース版のELDEN RINGは影響を受けていません。 実際、Dark Souls IIIに存在していたネットワーククラッシュ、範囲外読み取り/書き込み、およびピアのゲームデータを変更できるエクスプロイトの膨大なリストは、ELDEN RINGではパッチされています。LukeYui によるこのリストの作成と、迅速に対応したFROM SOFTWAREに称賛を送ります!ELDEN RINGは、ハッカーが引き起こせる被害の範囲に関して、疑いなく最も安全なFROM SOFTWAREのタイトルであることを嬉しく思います。

誤解を解く

一般に信じられているのとは反対に、これはピアツーピアネットワーキングのエクスプロイトではありません。マッチメイキングサーバーに関連しており、別のマッチメイキングサーバーの脆弱性(CVE-2022-24125)のため、脆弱性を引き起こすためにマルチプレイヤーアクティビティに参加する必要がないという点で、はるかに深刻です。

Dark Souls III において、これを悪用する悪意ある攻撃者は、数秒以内にすべてのオンラインプレイヤーのマシン上で最大 1.3MiB のシェルコードを確実に実行できたでしょう。

1

サーバー停止前の数ヶ月間、平均同時プレイヤー数が約20,000人であったことを考えると、これは即座に修正が必要な問題であることは明らかでした。特にELDEN RINGにも存在する可能性があったからです。FROM SOFTWAREが、概念実証ビデオと詳細なエクスプロイトドキュメント(このREADMEの大部分はこれに基づいています)を含む私の最初の報告から40日以上経っても行動を起こさなかったため、私はエクスプロイトの存在を無害な方法で公に示し、開発者に対応を促す注意を喚起することを決意しました。そしてそれは功を奏しました。

目次

  • エクスプロイトの概要 (CVE-2022-24126)
  • 配布経路 (CVE-2022-24125)
  • 全ゲームに共通する一般的なエクスプロイト戦術
    • バグ #1: エントリリストパーサーに境界チェックがない
    • バグ #2: NRSessionSearchResult パーサーでのバッファオーバーラン
    • ROPチェーンへの道を開く
  • Dark Souls III 概念実証コード
    • PoCコードの実行
    • 攻撃ベクトル
    • 仮想呼び出しリダイレクションチェーン
    • 追加情報

エクスプロイトの概要 (CVE-2022-24126)

NRSessionSearchResult マッチメイキングデータの解析中に、スタックバッファとデータサイズフィールドに対する不適切な境界チェックにより、攻撃者は任意のコードを実行できます。スタックオーバーフローにより、ストリームリーダーが内部で使用する DLMemoryInputStream オブジェクトの vftable_ptr の下位2バイトを上書きでき、実行を慎重に選択された隣接コードにリダイレクトできます。DLMemoryInputStream オブジェクトの構造とデータサイズフィールドを巧妙に悪用することで、任意のコードリダイレクトを達成でき、RCX はパケットのアドレスを指すようになります。そこから、異なるオフセットでの仮想呼び出し(パケットバッファに書き込んだ任意のアドレスにジャンプするようになる)を介した一連のコードリダイレクトを使用して、任意のコード実行を達成できます。

配布経路 (CVE-2022-24125)

配布経路こそが、この特定のRCEを(すでにRCEであること以上に)特に深刻なものにしています。エクスプロイトは、NRSessionSearchResult 情報を含むマッチメイキングプッシュリクエストを介して送信されます。つまり、攻撃者は自分のオンラインセッションに参加する誰でもターゲットにできます。特にDS3の場合:

  • 召喚 (PushRequestSummonSign)
  • ダークスピリットの侵入 (PushRequestAllowBreakInTarget)
  • 誓約による参加 (PushRequestVisit)
  • アリーナの戦闘者 (PushRequestAcceptQuickMatch)

これでも十分に悪質ですが、本当の潜在能力は RequestSendMessageToPlayers リクエストによって解放されます:

root@kitploit:~
message RequestSendMessageToPlayers { 
    repeated uint32 player_ids = 1; 
    required bytes push_message = 2;
}

ホストはこのリクエストを使用して、侵入者に PushRequestAllowBreakInTarget プッシュメッセージを直接送信し、彼らがスポーン座標を取得してP2Pセッションに参加できるようにします。それだけです。ゲームがこのリクエストを使用するのはこれだけです。

しかし、それにより任意のクライアントが、数十万人もの特定のプレイヤーに任意のプッシュメッセージを送信できるようになります。

これがいかにひどく安全でないか、強調してもしすぎることはありません。任意のプレイヤーは、実質的にマッチメイキングサーバーになりすますことができます。このリクエストを使用して PushRequestVisit を介してエクスプロイトを送信することにより、攻撃者はプレイヤーIDがわかっていれば、任意のオンラインプレイヤーをリモートでターゲットにできます。また、攻撃者は、それぞれが多数の可能性のあるプレイヤーIDを含む複数のリクエストを送信することで、非常に迅速にオンラインプレイヤーベース全体にエクスプロイトを拡散させることもできます。

全ゲームに共通する一般的なエクスプロイト戦術

RCEがすべてのゲームに完全に移植できるわけではありませんが、攻撃者に任意のコードリダイレクトを与えるエクスプロイトの核となるアイデアは同じです。これが達成できれば、ゲーム固有の仮想呼び出しチェーンまたはROPチェーンを見つけられる可能性が非常に高くなります。この「最初のステップ」では、以下の脆弱性を使用します:

バグ #1: エントリリストパーサーに境界チェックがない

セッション参加情報を含むマッチメイキングプッシュリクエストは、長さで区切られたデータエントリのチェーンで構成されるカスタムバイナリ形式でその情報を格納します。各エントリは以下の形式です:

root@kitploit:~
struct Entry
{
    uint32_t type_or_id; // 確実ではないが、おそらくタイプ(固定長=2、可変長=1?)
    uint32_t size;
    uint8_t data[size];
}

これらのエントリのデータをコピーするゲーム関数は、サイズフィールドを盲目的に信頼するため、範囲外読み取りが発生します。悪意のあるクライアントは、サイズフィールドに 0x7FFFFFFF などの値を設定することでこれを悪用し、メモリ割り当てを失敗させ、被害者のゲームをクラッシュさせることができます。その後、このサイズは DLMemoryInputStream のコンストラクタにも渡され、これがエクスプロイトの重要な部分になります。

バグ #2: NRSessionSearchResult パーサーでのバッファオーバーラン

上記のデータ構造内のエントリの1つは、シリアル化された NRSessionSearchResult オブジェクトです。このデータのパーサーは、最初にプロパティのリストを解析します。これらのプロパティは、4バイト整数、8バイト整数、またはnull終端のワイド文字列にすることができます。このプロパティリストの後には、ホストのSteam persona名(null終端ワイド文字列)と、エクスプロイトには重要ではない追加データが続きます。この関数とプロパティリストパーサーの両方は、文字列を読み取るために固定サイズのスタックバッファを使用しますが、どちらの場合もバッファに対する境界チェックは実行されません。以下は、ホスト名をコピーするゲームコードです(Ghidraデコンパイラを使用して生成し、その後クリーンアップしたもの):

root@kitploit:~
size_t idx = 0;
wchar_t wchr = 0;
do {
  // DLEndianStreamReaderのvftableインデックス17のread_wchar()関数
  wchr = stream_reader->read_wchar();
  player_name_buff[idx] = wchr;
  idx++;
} while (wchr != 0);

これによりバッファオーバーランエクスプロイトが発生し、攻撃者はスタックを破損させることができます。

仮想呼び出し / ROPチェーンへの道を開く

任意のコードリダイレクトを達成するために、これと、パーサーを呼び出す関数によってスタック上にインスタンス化される DLMemoryInputStream オブジェクトのメモリレイアウト(ストリームリーダーが内部で使用するもの)を利用します:

root@kitploit:~
struct DLMemoryInputStream {
    uintptr_t* vftable_ptr; // オフセット 0
    size_t data_size;       // オフセット 4 (32bit) / 8 (64bit)
    uint8_t* data_buffer;   // オフセット 8 (32bit) / 16 (64bit)
    // バッファ以降のエントリはエクスプロイトにとって重要ではない
}

data_size フィールド(バグ #1)を制御できるため、それを data_buffer フィールドのスタックメモリアドレスに設定できます。アドレスが一定で大きすぎない場合(DS3はこれらの要件を満たします)、これが成功します。コンパイラはスタックバッファをフレームの先頭に配置するため、攻撃者はバグ #2 を使用して DLMemoryInputStream の vftable_ptr の下位2バイトを上書きできます。そのため、次の文字が DLEndianStreamReader によって読み取られると、内部で DLMemoryInputStream が呼び出され、コードがリダイレクトされます。2バイトで十分な余地があり、DLEndianStreamReader vftable の22番目の関数にジャンプできます。この関数は、その最初のフィールドが指すオブジェクトの6番目の仮想メソッドを呼び出します。64ビットプロセス(すなわちDark Souls III)では、以下の命令が実行されます:

root@kitploit:~
MOV       RCX,qword ptr [RCX + 0x8]
MOV       RAX,qword ptr [RCX]
JMP       qword ptr [RAX + 0x40]

RCX は DLMemoryInputStream オブジェクトへのポインタであるため、最初の命令は、攻撃者がバグ #1 を使用して data_buffer フィールドを指すスタックアドレスに設定した data_size フィールドを RCX に書き込みます。次の2つの命令は、データバッファのオフセット 0x40 に攻撃者が書き込んだメモリアドレスに実行をリダイレクトします。これで任意のコードリダイレクトが達成されました!そこから攻撃者は、バッファが仮想メソッドテーブルとして機能するようになるため、異なるオフセットでの仮想呼び出しに近いコードを選択することで、ペイロードを適切なメモリ領域にコピーして実行するコードリダイレクションチェーンを設定できます。Dark Souls IIIの概念実証では、RCEを達成するためにわずか3つのガジェットしか必要としないセットアップを見つけました:

  • 0x18: 140e97700
  • 0x40: 1422be020
  • 0x68: 140e40f15

これらの3つのガジェットの詳細についてはこちらを参照してください。他のゲームでこの仮想呼び出し方式が実現可能でない場合、任意のコードリダイレクトは、より伝統的なROPエクスプロイトをセットアップするためにも使用できます。

Dark Souls III 概念実証コード

PoCコードの実行

概念実証コードを実行するには、まず接続先のサーバーが必要です。公式サーバーはエクスプロイトのために無効化されていますが、ds3os を使用してプライベートサーバーをセットアップできます。ds3os は小売サーバーの動作を可能な限り模倣するように設計されていますが、このエクスプロイトを修正するためのセキュリティパッチがすでにこのプロジェクトに適用されています。ただし、BuildConfig.h で SEND_MESSAGE_TO_PLAYERS_SANITY_CHECKS と NRSSR_SANITY_CHECKS の定数を false に設定して自分でプロジェクトをビルドすることで、テスト環境をセットアップすることもできます。これにより、安全でない小売サーバーの動作が模倣されます。ds3os が提供する手順に従ってゲームを起動し、サーバーに接続します。

これが完了し、ゲームがサーバーに接続されたら、PoCコードをビルドして Injector.exe 実行可能ファイルを起動します。これにより、エクスプロイトコードを含むDLLがDark Souls IIIプロセスに注入されます。このDLLは、FRPGメッセージをサーバーに送信するゲーム関数を使用して、自分のクライアントにエクスプロイトを配信します。

攻撃ベクトル

概念実証では、RequestSendMessageToPlayers を使用して送信される PushRequestVisit メッセージを使用することにしました。これは、ターゲットのゲームが受信後すぐに脆弱なデータを解析する(メインメニューでも同様)という意味で、エクスプロイトの最も強力なバージョンです。

仮想呼び出しリダイレクションチェーン

オフセット 0x18: 140e97700

root@kitploit:~
LEA       RAX,[DAT_144786150]
RET

このガジェットは 0x68 のガジェットで使用されます。RAX に 144786998 より低いがかなり近いアドレスを置く必要があります。これが最も近いものです。

オフセット 0x40: 1422be020

root@kitploit:~
MOV       RDX,RAX
MOV       R8,qword ptr [RCX]
CALL      qword ptr [R8 + 0x68]

オフセット 0x68 のガジェットを使用するには、データバッファアドレスを RDX に格納し、RCX を同じままにする必要があります。これによりそれが正確に達成されます。

オフセット 0x68: 140e40f15

root@kitploit:~
; オフセット 0x40 のガジェットからここにジャンプ
MOV       RBX,RDX
CMP       R9,R8

 ; 決してジャンプしない、R9 != R8
JZ        LAB_140e40f7a
MOV       RAX,qword ptr [RCX]
MOV       R8,qword ptr [RSP + 0x50]
MOV       RDX,R9
MOV       qword ptr [RSP + 0x30],RSI

; オフセット 18 (140e97700) のガジェットを呼び出す。144786150 を RAX にロード
CALL      qword ptr [RAX + 0x18]
MOV       RSI,RAX
TEST      RAX,RAX

; 決してジャンプしない、RAX はデータバッファアドレス
JZ        LAB_140e40f4d 
CMP       RBP,RDI
MOV       RDX,RBX
MOV       RCX,RAX
CMOVC     RDI,RBP
MOV       R8,RDI ; RDI は 14F3B0 に近いスタックアドレスなので、memcpy は成功する
CALL      memcpy

LAB_140e40f4d:
TEST      RBX,RBX
; RBX == RDX == データバッファアドレス、非ゼロなので決してジャンプしない
JZ        LAB_140e40f62 

; memcpy により 144786150 の RWE メモリ領域を完全に制御できるようになった。RCE 達成!
MOV       RCX,qword ptr [DAT_144786998]
MOV       RDX,RBX
MOV       RAX,qword ptr [RCX]
CALL      qword ptr [RAX + 0x68]

このガジェットはほぼすべてを行います。オフセット 0x18 を呼び出して memcpy の宛先ポインタを取得し、パケットをそこにコピーしてから、静的オブジェクト 144786998 のオフセット 0x68 の仮想関数を呼び出します。このオブジェクトは memcpy 呼び出しにより完全に制御できるようになりました。memcpy によって破損するメモリの量が大きく、一部の領域は他のゲームスレッドによって常に書き込まれているため、エクスプロイトはまず安全な場所にコピーされる「セットアップ」ペイロードをロードし、他のすべてのスレッドを一時停止してから実際のペイロードを再コピーしてからジャンプします。詳細については rce.h を参照してください。

追加情報

概念実証コードのソースコードを確認することをお勧めします。パケットの構造を詳述した多くのコメントがあります。各ステップで何が起こっているかをリアルタイムで確認したい場合(ぜひ確認すべきです。とてもクールです!)、ゲームをデバッガの下で実行しながら、以下の注目アドレスにブレークポイントを設定して概念実証DLLを注入できます:

140ca5960

基本的にエクスプロイトが始まる場所。この関数は、PushRequestVisit メッセージのサイズ区切りエントリリストデータの解析を担当します。最初にリストの各エントリを異なるベクターに抽出します:

root@kitploit:~
0x140ca59f8:
    player_data_cpy_ptr = (std_vector *)VectorCopy2_140ca4ef0(&player_data_cpy,player_data);
    FUN_140ca5010(player_data_cpy_ptr,&spawn_data,0x1c);
    FUN_140ca5010(player_data_cpy_ptr,&unk,4);
    FUN_140ca4fa0(player_data_cpy_ptr,&nrssr_data);

関数 140ca5010 はエントリサイズをチェックしますが、140ca4fa0 は可変サイズのエントリ用であり、サイズフィールドに対する健全性チェックを実行しません(バグ #1)。上記の任意のコードリダイレクトエクスプロイトを達成するには、これを 14F3B0 に設定する必要があります。これにより約1.3MiBの範囲外読み取りが発生しますが、メモリページはアクセス違反を回避するのに十分な大きさであるはずです。

140ca56b0

前の関数によって nrssr_data を引数として呼び出されます。スタック上に DLMemoryInputStream オブジェクトを作成し、それがNRSSRパーサーに引数として渡されます。

141955f50: ParseNRSessionSeachResult

NRSessionSearchResult パーサー。NRSSRの署名とバージョン番号を検証し(14196a0f0)、プロパティリスト(14196a260)、ホスト名(14195603a)、およびその他の情報(rce.hを参照)を解析します。

14195603a

上記の関数内のループで、ホスト名を安全でない方法でコピーします(バグ #2)。バッファオーバーフロー中に何が起こっているかを追跡するのに役立つアドレスをいくつか示します:

  • パーサースタックバッファアドレス:14F128
  • DLMemoryInputStream スタックアドレス:14F3A0
  • 上書き後の DLMemoryInputStream vtable ポインタ:1439e8b30
  • DLInputStreamReader が使用する DLMemoryInputStream の仮想関数のオフセット:0x18

1439e8b48

root@kitploit:~
MOV       RCX,qword ptr [RCX + 0x8]
MOV       RAX,qword ptr [RCX]
JMP       qword ptr [RAX + 0x40]

上書きされたメモリストリームvftableによって引き起こされた最初のコードリダイレクトの後に辿り着く場所です。ここから仮想呼び出しリダイレクションチェーンが始まります。

Footnotes

  1. Dark Souls III Ver. 1.15 の場合。理論上の最大ペイロードサイズはスタックレイアウトに依存するため、ゲームとバージョンによって異なります。 ↩

ツールをダウンロード