361 Views
June 05, 26
スライド概要
GMO IERAE HackNight #4 「AI時代のセキュリティ攻防戦」
https://ierae.connpass.com/event/391105/
GMOサイバーセキュリティ byイエラエ株式会社
生成AIを活用した脆弱性調査 川根 健太郎
川根 健太郎 所属 オフェンシブセキュリティ部 高度診断課 発見した脆弱性 CVE-2025-25257 CVSS Fortinet FortiWeb 9.8 認証前 RCE CVE-2025-20337 保有資格 OSCP / OSEP / OSWE Cisco ISE CVSS 10.0 認証前 RCE CVE-2025-33217 CVSS NVIDIA GPUディスプレイドライバ 7.8 Use-After-Free
Pwn2Own Berlin 2026 Windows11権限昇格に成功! UAFを2つ組み合わせ低権限からSystemへ昇格 ZDI経由でMicrosoftへ報告 賞金 $15000 獲得 https://x.com/thezdi/status/2054990435899125974
Pwn2Own Berlin 2026 Windows11権限昇格に成功! UAFを2つ組み合わせ低権限からSystemへ昇格 ZDI経由でMicrosoftへ報告 賞金 $15000 獲得 実はこれもLLMを活用して調査! https://x.com/thezdi/status/2054990435899125974
LLMを使って バイナリの脆弱性を探すには?
バイナリ解析のための MCP サーバ デコンパイルや逆アセンブルなどを行うツールを LLM に提供する。 IDA Pro MCP github.com/mrexodia/ida-pro-mcp Binary Ninja MCP github.com/fosdickio/binary_ninja_mcp ghidraMCP github.com/LaurieWired/GhidraMCP
実例 ①:接続中のバイナリを確認
実例 ②:関数をデコンパイル
LLM に丸投げするだけでは限界がある 自明な脆弱性は LLM に投げるだけである程度見つかる。ただし … ・誤検知が多い ⇒ 脆弱性の精査に時間が奪われる ・同じ脆弱性ばかり見つかる ⇒ LLMは特徴的なパターンに引っ張られやすい ・主要なターゲットだと脆弱性が見つけられない ⇒ Kernel, Hypervisor, etc…
プロンプトの投げ方で結果は大きく変わる 曖昧な指示は「広く浅く」、対象を絞ると「具体的に深く」探索される。 プロンプト② プロンプト① 「脆弱性を探して」 種別を絞らず浅く広く列挙 $ grep -rn "innerHTML" Grep で SQL 文の使用箇所を抽出 # XSS? # CSRF? # SQLi? ... 10 matches report.py:55 db.execute(stmt) order.py:103 cursor.execute(s) ... 31 matches $ grep -rn "eval(" search.py:88 cursor.execute(q) admin.py:17 raw_sql(stmt) ... 114 matches $ grep -rn "execute" $ grep -rn -E "execute|raw_sql" user_api.py:42 raw_sql(query) ... 78 matches $ grep -rn "csrf_token" 「SQL インジェクションの脆弱性を探して」 # RCE? billing.py:71 raw_sql(q)
プロンプトの投げ方で結果は大きく変わる
対象をさらにファイル単位まで絞ると、コードの中身まで読み込む。
プロンプト②
プロンプト③
「SQL インジェクションの脆弱性を探して」
「login.py で SQL インジェクションを探して」
Grep で SQL 文の使用箇所を抽出
login.py を直接読んで SQLi 発見
$ grep -rn -E "execute|raw_sql"
runner = QueryRunner(db)
user_api.py:42 raw_sql(query)
def authenticate (user, pw):
search.py:88 cursor.execute(q)
sql = f"SELECT ... name='{user}’”
admin.py:17 raw_sql(stmt)
return runner.run_query(sql)
report.py:55 db.execute(stmt)
order.py:103 cursor.execute(s)
billing.py:71 raw_sql(q)
プロンプトの組み方 モデルが既に知っていることを改めてプロンプトに書かない。 書かない 脆弱性の発生原因の一般論 memcpy のコピー長がユーザ入力で未検証な × ら BOF 書く 脆弱性調査の観点 ✓ × Use-After-Free や Double Fetch の定義 など ✓ 関数を意図的に失敗させると、初期化が走らず 未初期化メモリがユーザモードに返らないか ユーザーモードコールバック前後で、オブジェ クトの状態や所有権が変わっていないか
安易に検索ツールを与えない 検索ツールがあると LLM が思考を放棄する。 バッファオーバーフローを探したい ⇒「コード検索ツールで memcpy を使っているところを探そう!」 関数ポインタが指す関数がわからない ⇒「関数検索ツールでそれっぽい関数を探そう!」 与えるならTaint解析など高級なツールを与えるべき
仮想的にパッチを当てる 実バイナリに仮想的にパッチをあてて AI にはパッチ後を見せる ことでノイズを減らす バイナリ alloc_and_copy: mov eax, [rbp+len] 整数オーバーフロー 仮想パッチ alloc_and_copy: imul eax, 4 mov eax, [rbp+len] mov edi, eax imul eax , 4 call malloc jo mov rdi, rax mov edi, eax mov rsi, [rbp+src] call malloc mov ecx, [rbp+len] mov rdi, rax rep movsd mov rsi, [rbp+src] .fail mov ecx, [rbp+len] rep movsd 。
仮想的にパッチを当てる 脆弱性の調査 脆弱性の検証 再現へ パッチの開発を検討 デコンパイル 逆アセンブル パッチ後 デコンパイル 逆アセンブル 元データ パッチ開発 ⇄ パッチレビュー 提出 Binary Ninja MCP
脆弱性の検証 — バイアスを避ける 検証を同じセッションでやるとバイアスがかかって検証が甘くなる。 ✕ 同セッションで検証 ✓ セッションを分ける Session A Session A 1. 脆弱性を発見 1. 脆弱性を発見 2. 見つけた脆弱性を検証 2. レポートを出力 ⇒ バイアスがかかる・FP 増 Session B 3. レポートを検証 ⇒ バイアスがかかりづらい・FP 減
脆弱性の検証 — 観点毎に検証する 観点を混ぜると判定が曖昧になり精度が落ちる。 1. コードが脆弱であるか 2. セキュリティ境界を超えるか ● ロックや検証は本当に抜けているか ● 非特権ユーザから到達可能か ● 検証に本当に不備があるか ● リモートから到達可能か ⇒ レポートの通りに欠陥が存在するかで判断 ⇒ 悪用した際にセキュリティ境界を超えるかで判断
脆弱性の再現 — 環境 Hyper -V Binary Ninja 解析 JSON RPC Claude Code Claude Code Claude Code Binary Ninja MCP server Claude Code HTTP レポート Binary Ninja 検証 Claude Code 検証VM Claude Code VM 1 再現確認 検証済 SSH 再現 Claude Code Claude Code VM 2 再現確認
脆弱性の再現 PoC開発 原因分析・修正 ✓ 再現成功 クラッシュダンプ取得 ✕ 脆弱でない 理由をレポート化 クラッシュが脆弱性に 対応するか 脆弱 脆弱でない理由が妥当か 脆弱でない 環境/設定の問題か 人間に渡す 再現 PoC実行・観測 原因分析 環境/設定起因 理由をレポート化 ループ
まとめ LLMは上手く使えば主要な製品で脆弱性リサーチに活用できる ⇒ LLMの動きを理解して脆弱性を探させる工夫や 誤検知を排除するための仕組み作りが大事!