Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ブラックボックス観測に基づくAI支援のプロトコルのリバースエンジニアリングと再現 ~AIを用い...

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for chibiegg chibiegg
March 02, 2026

ブラックボックス観測に基づくAI支援のプロトコルのリバースエンジニアリングと再現 ~AIを用いたリバースエンジニアリング~ @ SECCON 14 電脳会議 / Reverse Engineering and Reproduction of an AI-Assisted Protocol Based on Black-Box Observation @ SECCON 14 DENNO-KAIGI

Avatar for chibiegg

chibiegg

March 02, 2026
Tweet

More Decks by chibiegg

Other Decks in Technology

Transcript

  1. 2 自己紹介 @chibiegg 江草 陽太 【所属】 • さくらインターネット (株) 執行役員

    技術推進統括担当 兼 CISO 兼 CIO • BBSakura Networks (株) 取締役 【経歴】 • ヴィアトール学園 洛星中学・高等学校 • 大阪大学工学部電子情報工学科情報通信工学専攻 • 個人事業主 (大学生時代に開業) • 大阪大学大学院工学研究科中退 【外部】 • U-22プログラミングコンテスト実行委員長 など 【発見したCVE】CVE-2023-28727 【趣味】 旅行/温泉/写真/電子工作/プログラミング/かわいい服
  2. © SAKURA internet Inc. そのままAIに読ませてみる 両方のファイルは同じサイズ(7336バイト)で、バイナリデータです。16進ダンプを見ると、パターンが見えてきます。 各エントリは16バイトのようです: - 最初の4バイト: 何らかの識別子/タイプ

    - 次の4バイト: 値1 - 次の4バイト: 値2 - 次の4バイト: 値3 パターンを分析すると: - 位置0-3: `0d 9f 09 00` - ヘッダー? - 位置4-7: `ca f4 5f b4` - 値1 - 位置8-11: `5c e0 1f 16` - 値2 - 位置12-15: `a8 e3 2a 3b` - 値3 各エントリの最初のバイト(位置0, 16, 32...)を見ると: - 0x0d, 0xf8, 0xd0, 0x9f, 0x86, 0x87, 0xc3, 0xd0, 0x96, 0xd0, 0x9c, 0x97, 0x82, 0xff, 0xcf, 0xad... これは何らかの構造化されたデータのようです。Pythonスクリプトを作成して解析してみましょう。</think>両方の ファイルは7336バイトで同じサイズです。16進ダンプから16バイト単位の構造が見えてきます。Pythonスクリプトを 作成して詳細に解析します。
  3. © SAKURA internet Inc. そのままAIに読ませてみる # IPTRX Config File Analysis

    Report ## 概要 WiFiトランシーバ機の設定ファイル(`.cfg2`)の解析結果。 ## ファイル情報 - **ファイル名**: `iptrxconfig_21.cfg2`, `iptrxconfig_22.cfg2` - **サイズ**: 7,336 バイト - **エントリ数**: 458 エントリ(16バイト単位) ## ファイル構造 設定ファイルは16バイト単位のエントリで構成されています。 ### エントリ構造 | オフセット | サイズ | フィールド名 | データ型 | 説明 | |-----------|--------|-------------|----------|------| | 0-1 | 2バイト | Field1 | uint16 (LE) | 識別子/インデックス | | 2-3 | 2バイト | Type | uint16 (LE) | エントリタイプ | | 4-9 | 6バイト | MAC Prefix | bytes | MACアドレス(下位6バイト) | | 8-9 | 2バイト | Port | uint16 (LE) | ポート番号(MACの一部と重複) | | 10-11 | 2バイト | Field3 | uint16 (LE) | 未確認の値 | | 12-15 | 4バイト | Field4 | uint32 (LE) | 未確認の値 |
  4. © SAKURA internet Inc. 難読化をヒントとして複数のパターンのファイルをAIに読ませてみる GLM-4.7 WiFiトランシーバ機の解析をしています TFTPで設定ファイルが無線機にダウンロードされるのですが、その設定ファイルの中身を解析してください ファイルは research/config

    にあります このファイルはテキストファイルですが、パスワードで難読化されています。 パスワードが"9370"と"9371"と空文字の3つのパターンで同一の設定ファイルを作成したものもあります。 難読化方式を解析して、元に戻してください ユーザーはWiFiトランシーバ機の設定ファイルを解析したいと考えています。research/configディレクトリに以下の ファイルがあります: - iptrxconfig_21.cfg2 - iptrxconfig_22.cfg2 - iptrxconfig_22.cfg2_password_9370 - iptrxconfig_22.cfg2_password_9371 - iptrxconfig_22.cfg2_password_nullstring これらはパスワードで難読化されたテキストファイルで、パスワードが"9370"、"9371"、空文字の3つのパターンで作 成されたものがあります。 まず、これらのファイルを読み込んで内容を確認し、難読化方式を解析する必要があります。 タスクを分解します: 1. 各設定ファイルを読み込む 2. ファイルの内容を比較して難読化パターンを分析する 3. 難読化方式を特定する 4. 復号スクリプトを作成する 5. 元の設定ファイルを復元する
  5. © SAKURA internet Inc. 難読化をヒントとして複数のパターンのファイルをAIに読ませてみる ファイルがバイナリとして認識されています。hexdumpやxxdコマンドを使ってバイナリ内容を確認する必要がありま す。</think>ファイルがバイナリとして認識されました。hexdumpで内容を確認します。 パスワードの違いによるバイト値の変化を詳しく調べる必要があります。各パスワードで暗号化されたファイルのバイ トパターンを比較し、暗号化アルゴリズムの特性を分析します。特に、パスワードがどのようにバイト値に影響を与え ているかを確認します。</think>4つのファイルのhexdumpを取得しました。パターンを分析するため、Pythonスクリ

    プトを作成して比較します。 ============================================================ XOR差分分析: ============================================================ original XOR pwd_9371 (first 32 bytes): 6e1bdfe152407a041d7e72c529b65c8d6e1bdfe152407a041d7e72c529b65c8d original XOR pwd_null (first 32 bytes): 267cf1d92bf4d0b09760278e661b6545267cf1d92bf4d0b09760278e661b6545 pwd_9370 XOR pwd_9371 (first 32 bytes): 6e1bdfe152407a041d7e72c529b65c8d6e1bdfe152407a041d7e72c529b65c8d pwd_9370 XOR pwd_null (first 32 bytes): 267cf1d92bf4d0b09760278e661b6545267cf1d92bf4d0b09760278e661b6545
  6. © SAKURA internet Inc. 難読化をヒントとして複数のパターンのファイルをAIに読ませてみる キー生成方式が特定できました!MD5ハッシュを使用しています。 復号結果を見ると、UTF-16LEエンコーディングのようです(各文字の間にnullバイトが入っています)。 復号結果を確認してみましょう。</think>キー生成方式が特定できました!**MD5ハッシュ**を使用しています。復号 結果を見るとUTF-16LEエンコーディングのようです。復号ファイルを確認します。 UTF-16LEエンコーディングで復号できていることがわかりました。先頭のBOM(Byte

    Order Mark)が正しく処理さ れていないようですが、内容は読めそうです。UTF-16LEで正しくデコードして保存するスクリプトを作成します。 </think>UTF-16LEエンコーディングで正しくデコードします。 復号に成功しました!設定ファイルの中身が読めるようになりました。復号されたファイルの完全な内容を確認して、 タスクリストを更新します。</think>復号に成功しました!完全な設定ファイルを確認します。 [Tool Use: execute_command] Command: cat research/config/decrypted_22.txt Cwd: /Users/chibiegg/Develop/iptrx-seccon Timeout: 10 ついに難読化方式を特定する 平文がUTF-16LEであることも特定
  7. decrypted_22. txt(抜粋) tn="l" ip_trx="22" name=" H inata-03" uid="0022" serv_i pad

    dr _01=''10.169.1.3'' s e rv _con n_po rt_ 01="32000" s i g_p o rt=''3 0 04 2'' s e rv _po rt= 113004211 codec_type="g71 lu+signal" g7 ll_size= "20" g726_size= "40" g7 26_rate=" 4" • 9SAKURA internet 一 (以下省略) © SAKURA internet Inc.
  8. © SAKURA internet Inc. 難読化をヒントとして複数のパターンのファイルをAIに読ませてみる (省略) ## 解析手法 1. **XOR差分分析**:

    異なるパスワードで作成されたファイル同士のXOR差分を計算し、キーの周期性(16バイト)を 特定 2. **キー生成方式の推測**: パスワードからキーを生成する様々な方法(MD5、SHA1、SHA256など)を試し、XOR差 分と一致するものを特定 3. **エンコーディングの特定**: 復号結果のバイトパターンからUTF-16LEを特定 ## セキュリティ上の注意点 - MD5ハッシュは衝突耐性が低く、推奨されないハッシュアルゴリズムです - XOR暗号は単純な暗号化方式であり、十分なセキュリティを提供しません - パスワードが推測可能な場合、容易に復号できます 解析結果をまとめさせる
  9. © SAKURA internet Inc. 同様の方式で CSV も読めるか確認 GLM-4.7 同様の方式で research/config/iptrxidlist_22.csv

    が復号できるか確認してください。 iptrxidlist_22.csvファイルのhexdumpを見ると、設定ファイルと同様のパターンが見られます。同じ方式で復号できる か確認します。復号スクリプトを使って試してみます。</think>同じパターンが見られます。復号スクリプトを使って 確認します。 Output: パスワード: 9370 キー (MD5): f2617d00a4f462b47ee02e168ae3273b ✓ UTF-16LEでデコード成功 先頭500文字: 1,1,"Hinata-03","",2,0020,1,bel,cnt3,0,0 2,1,"Hinata-02","",2,0021,1,bel,cnt3,0,0 3,1,"Hinata-03","",2,0022,1,bel,cnt3,0,0 4,1,"Hinata-04","",2,0023,1,bel,cnt3,0,0 5,1,"Hinata-05","",2,0024,1,bel,cnt3,0,0 6,1,"奇数グループ","",1,0001,1,bel,cnt3,0,0 7,1,"偶数グループ","",1,0002,1,bel,cnt3,0,0 (省略) ✓ research/config/decrypted_idlist_22.csv に保存
  10. © SAKURA internet Inc. 末尾にあるチェックサムは解析できるか GLM-4.7 WiFiトランシーバ機の解析をしています TFTPで設定ファイルが無線機にダウンロードされるのですが、その設定ファイルのチェックサム方式を 解析してください research/config/checksum

    に中のデータを変更した同様のファイルをたくさんおいてあります またこのファイルは難読化されており、その方式は research/config.md に書いてあるので、復号してか らチェックサムの解析をしてください。 パスワードは "9370" です。 チェックサムは復号した平文の末尾にあります。 checksumディレクトリ内のファイルを確認しました。ファイル名から、Hinata-01, Hinata-02, Hinata-03, Hinata-04, Hinata-05, Hinata-010, Hinata-011, Hinata-0100, Hinata-0101, Hinata-01000, Hinata-010000, Hinata-0100000, Hinata-01000000, Hinata- 010000000, Hinata-0100000000, Hinata-01000000000 という名前のファイルがあります。 これらはおそらくnameパラメータの値が異なるファイルで、チェックサムの解析に使用されるものです。 まず、checksumディレクトリ内のファイルを復号して、チェックサム部分を抽出し、パターンを分析するスクリプトを作成します。 スクリプトの要件: 1. checksumディレクトリ内のすべてのファイルを復号する(パスワード: "9370") 2. 復号した平文の末尾にあるチェックサムを抽出 3. 各ファイルのチェックサムと内容を比較してパターンを分析 4. チェックサム計算方式を特定 まず、1つのファイルを復号して内容を確認してみましょう。</think>チェックサム解析用のスクリプトを作成します。まず、 checksumディレクトリ内のファイルを復号して内容を確認します。 [Tool Use: write_to_file] Path: research/analyze_checksum.py
  11. © SAKURA internet Inc. 末尾にあるチェックサムは解析できるか 出力を見ると、各ファイルの末尾に奇妙な文字が表示されています。例えば: - Hinata-01: `㏧\ue9eb` -

    Hinata-010: `༙ 螪` - Hinata-05: `㳩좱` これらがチェックサムの可能性があります。UTF-16LEでデコードすると、これらは2バイトずつの文字として表示されていますが、実際に はバイナリデータとしてチェックサムが埋め込まれている可能性があります。 末尾のバイナリデータを16進数で確認する必要があります。スクリプトを修正して、末尾のバイナリデータを16進数で表示するようにしま す。</think>末尾に奇妙な文字が表示されています。これらがチェックサムの可能性があります。バイナリデータを16進数で確認するため にスクリプトを修正します。 スクリプトを修正して、末尾のバイナリデータを16進数で表示するようにしました。実行して結果を確認します。</think>
  12. © SAKURA internet Inc. 末尾にあるチェックサムは解析できるか チェックサムの計算方式を特定するために、本文の内容とチェックサムの関係を分析するスクリプトを作成します。 末尾の共通部分 `2c0030002c0030000d000a00` は `,0,0\r\n`

    (UTF-16LE) で、その後に4バイトのチェックサムが続いています。 チェックサムの計算方式を特定するために、以下の可能性を検証します: 1. CRC32 2. MD5の一部 3. 単純な合計 4. XOR 5. その他のハッシュ関数 まず、本文(チェックサムを除いた部分)のバイト列に対して様々なチェックサム計算を試してみます。</think>
  13. © SAKURA internet Inc. 末尾にあるチェックサムは解析できるか (Claude編) Opus 4.5 · Claude

    Pro WiFiトランシーバ機の解析をしています TFTPで設定ファイルが無線機にダウンロードされるのですが、その設定ファイルのチェックサム方式を 解析してください research/config/checksum に中のデータを変更した同様のファイルをたくさんおいてあります またこのファイルは難読化されており、その方式は research/config.md に書いてあるので、復号してか らチェックサムの解析をしてください。 パスワードは "9370" です。 チェックサムは復号した平文の末尾にあります。 まず、難読化方式の説明とチェックサムファイルの内容を確認します。 難読化方式を理解しました: 1. パスワード"9370"のMD5ハッシュがキー (`f2617d00a4f462b47ee02e168ae3273b`) 2. XOR暗号で16バイトキーを繰り返し適用 3. 平文はUTF-16LE 次に、チェックサムファイルを復号して解析します。まずいくつかのファイルを読んで復号してみましょう。 チェックサムが4バイトのようです。UTF-16LEで扱うので、2つの16ビット値として見るべきかもしれません。 平文はCSVファイルで、末尾の4バイトがチェックサムのようです。`\r\n`の後にチェックサムがあります。チェックサムを除いた本 文に対してどのようなチェックサム方式が使われているか解析する必要があります。 複数のファイルで本文とチェックサムを分離し、チェックサム方式を特定しましょう: 1. CRC32 2. Sum of bytes 3. XOR of bytes 4. Fletcher 5. Adler32 などを試してみます。
  14. © SAKURA internet Inc. 末尾にあるチェックサムは解析できるか (Claude編) Inverted CRC32とチェックサムの関係を詳しく分析します。 XOR値が一定ではないので、checksum ≠

    ~CRC32 ^ constant です。ただし、XOR値が各ファイルで異なるというこ とは、チェックサムがCRC32とは別の何かとの組み合わせであるか、全く異なるアルゴリズムである可能性があります。 もう一つ試してみたいのは、チェックサムが本文の長さに依存しているかどうかです。また、チェックサムの計算が16 ビット単位のCRCを使っている可能性もあります。ファイルサイズが異なるファイルで、サイズとチェックサムの関係 を見てみましょう。 ファイルサイズとチェックサムの関係を分析します。 サイズが同じでもチェックサムが大きく異なります。これはチェックサムがサイズだけでなく、内容に依存しているこ とを示しています(予想通り)。もう一度基本に戻って、UTF-16LEの文字列として考えてみましょう。組込み機器で はwchar_t単位(2バイト)でCRCや合計を計算することがあります。UTF-16LEの文字コードに対してCRC32を計算し ている可能性があります。 UTF-16文字コード列に対してCRC32を計算する方法を試します。 まだ一致しません。組み込み機器特有のカスタムアルゴリズムの可能性が非常に高いです。より網羅的にCRC32の多項 式を試してみましょう。また、CRC32のテーブルが異なるものを使っている可能性があります。CRC32の計算で使用さ れる標準多項式は 0xEDB88320 (reversed) または 0x04C11DB7 (normal) ですが、他の多項式が使用されている可能性 があります。網羅的に多くの多項式を試してみましょう。 多くのCRC32多項式を網羅的に試します。 標準的なCRC32多項式では一致しませんでした。これは独自のアルゴリズムか、完全にカスタムの実装である可能性が 高いです。次のアプローチとして、2つのファイル間で変更されたバイトと、チェックサムの変化の関係をより詳しく 分析し、アルゴリズムを逆解析してみましょう。複数の変更パターンを観察することで、アルゴリズムの特性を推測で きるかもしれません。
  15. © SAKURA internet Inc. 末尾にあるチェックサムは解析できるか (Claude編) 同じ長さのファイル間での比較を詳しく分析します。 素晴らしい発見!同じ長さ(1749文字)のファイル間での比較を見ると:- 02 vs

    03: xor_diff=0x0001, cs_xor=0x8a360d18- 04 vs 05: xor_diff=0x0001, cs_xor=0x8a360d18 同じxor_diffで同じcs_xor!これは、同じ長さのファイル間では、チェックサムがXORだけに依存していることを示して います。さらに:- 02 vs 04: xor_diff=0x0006, cs_xor=0x31f70889- 03 vs 05: xor_diff=0x0006, cs_xor=0x31f70889同 じxor_diffで同じcs_xor!- 02 vs 05: xor_diff=0x0007, cs_xor=0xbbc10591- 03 vs 04: xor_diff=0x0007, cs_xor=0xbbc10591同じxor_diffで同じcs_xor! これは、同じ長さのファイル間では checksum = transform(xor) の形式が成り立つことを確認しています。transform 関数は長さに依存しているか、または別の要因で異なる長さのファイル間では異なる動作をします。 次に、長さが異なるファイル間でのチェックサムの差を分析して、長さの影響を特定しましょう。 素晴らしい発見!定数は長さごとに異なりますが、同じ長さのファイルでは同じ定数が使われています。これは、 チェックサムの計算が以下の形式であることを示しています:checksum = transform(xor_of_chars) XOR length_constant[len]各長さに対する定数 - 1749: 0xe38a162e - 1750: 0x3b27e38a - 1751: 0x61f23b27 - 1752: 0x007d61f2 - 1753: 0xf4a4007d - 1754: 0xb462f4a4 - 1755: 0xe07eb462 - 1756: 0x162ee07e - 1757: 0xe38a162e - 1758: 0x3b27e38a これらの定数の間にもパターンがあるか確認しましょう。おそらく、長さに依存したCRC32の計算が含まれています。
  16. © SAKURA internet Inc. 末尾にあるチェックサムは解析できるか (Claude編) Opus 4.5 · Claude

    Pro 長さごとにXORの定数を探しておく方式ではなく、長さが変わっても計算できる様にした いです、長さによって変わるXORの値と長さの関係を分析して ユーザーは、長さ定数をテーブルとして持つのではなく、任意の長さに対して計算できる方式を望んでいます。長さと長さ定数の関 係を分析して、計算式を導き出す必要があります。 現在わかっている長さ定数: - 1749: 0xe38a162e - 1750: 0x3b27e38a - 1751: 0x61f23b27 - 1752: 0x007d61f2 - 1753: 0xf4a4007d - 1754: 0xb462f4a4 - 1755: 0xe07eb462 - 1756: 0x162ee07e - 1757: 0xe38a162e - 1758: 0x3b27e38a 連続する長さの定数のXOR差分を見て、パターンを探します。また、CRC32の特性として、データの末尾にバイトを追加すると、 CRC値が特定のパターンで更新されることを利用できるかもしれません。
  17. © SAKURA internet Inc. 末尾にあるチェックサムは解析できるか (Claude編) I found the formula!

    `XorOut[length % 8] = (key_words[(length % 8 + 1) % 8] << 16) | key_words[length % 8]` Where key_words are the MD5 key interpreted as 8 little-endian 16-bit values. So the complete checksum algorithm is: 1. CRC-32/MPEG-2 of the body (poly=0x04C11DB7, init=0xFFFFFFFF, refin=False, refout=False) 2. XOR with a value derived from the MD5 key based on (character_count % 8)Now let me verify this works for all files and then update the documentation. パターンを発見しました。完全なチェックサムアルゴリズムを検証します。 All 16 files pass verification. The algorithm is: 1. CRC-32/MPEG-2 of the body 2. XOR with a value derived from MD5(password) based on (character_count % 8) The XorOut is constructed by taking two consecutive 16-bit words from the MD5 key (interpreted as little-endian 16- bit values) and combining them into a 32-bit value. Now let me update the documentation file with this complete algorithm. 全ファイルの検証に成功しました。ドキュメントを完全なアルゴリズムで更新します。
  18. © SAKURA internet Inc. 参考:生成されたチェックサムの実装 46 import hashlib import struct

    def calculate_checksum(body, password="9370"): """ iptrxidlistファイルのチェックサムを計算 Args: body: UTF-16LEエンコードされた本文(チェックサム部分を除く) password: 暗号化パスワード(デフォルト: "9370") Returns: 32ビットチェックサム値 """ # MD5キー生成 key = hashlib.md5(password.encode('utf-8')).digest() # キーを8個の16ビットLE値として解釈 key_words = [] for i in range(0, 16, 2): word = key[i] | (key[i+1] << 8) key_words.append(word) # CRC-32/MPEG-2 パラメータ POLY = 0x04C11DB7 INIT = 0xFFFFFFFF # CRC計算 crc = INIT for byte in body: crc ^= (byte << 24) for _ in range(8): if crc & 0x80000000: crc = ((crc << 1) ^ POLY) & 0xFFFFFFFF else: crc = (crc << 1) & 0xFFFFFFFF # XorOut計算 char_count = len(body) // 2 mod = char_count % 8 xorout = (key_words[(mod + 1) % 8] << 16) | key_words[mod] # 最終チェックサム return crc ^ xorout def decrypt_file(filepath, password="9370"): """ファイルを復号""" key = hashlib.md5(password.encode('utf-8')).digest() with open(filepath, 'rb') as f: data = f.read() decrypted = bytearray() for i, b in enumerate(data): decrypted.append(b ^ key[i % 16]) return bytes(decrypted) def verify_checksum(filepath, password="9370"): """ファイルのチェックサムを検証""" decrypted = decrypt_file(filepath, password) stored_checksum = struct.unpack('<I', decrypted[-4:])[0] body = decrypted[:-4] calculated = calculate_checksum(body, password) return calculated == stored_checksum, stored_checksum, calculated
  19. © SAKURA internet Inc. 通信上の機能の解析スコープ 以下の機能に絞って解析 • 全体通話 (全員に対して話す) •

    個別通話 (相手を選んで話す) • グループ通話 (グループを選んで話す) • メッセージ送信 (文字列を送信する) • プレゼンス通知 (既定のステータス10種類から送信)