diff --git a/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md b/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md index 69769be2b..e20e2f9f1 100644 --- a/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md +++ b/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md @@ -1,15 +1,27 @@ +# Basic Java Deserialization with ObjectInputStream readObject + {{#include ../../banners/hacktricks-training.md}} -このPOSTでは、`java.io.Serializable`を使用した例が説明されます。 +このPOSTでは、`java.io.Serializable`を使用した例と、**攻撃者が制御するストリームがある場合、`readObject()`をオーバーライドすることが非常に危険である理由**について説明します。 -# Serializable +## Serializable -Javaの`Serializable`インターフェース(`java.io.Serializable`は、**シリアライズ**および**デシリアライズ**を行うクラスが実装しなければならないマーカーインターフェースです。Javaオブジェクトのシリアライズ(書き込み)は[ObjectOutputStream](http://tutorials.jenkov.com/java-io/objectoutputstream.html)を使用して行われ、デシリアライズ(読み込み)は[ObjectInputStream](http://tutorials.jenkov.com/java-io/objectinputstream.html)を使用して行われます。 +Javaの`Serializable`インターフェース(`java.io.Serializable`)は、クラスが**シリアライズ**および**デシリアライズ**されるために実装しなければならないマーカーインターフェースです。Javaオブジェクトのシリアライズ(書き込み)は[`ObjectOutputStream`](http://tutorials.jenkov.com/java-io/objectoutputstream.html)を使用して行われ、デシリアライズ(読み込み)は[`ObjectInputStream`](http://tutorials.jenkov.com/java-io/objectinputstream.html)を使用して行われます。 + +### リマインダー: デシリアライズ中に暗黙的に呼び出されるメソッドはどれですか? + +1. `readObject()` – クラス固有の読み取りロジック(実装されていて*private*の場合)。 +2. `readResolve()` – デシリアライズされたオブジェクトを別のものに置き換えることができます。 +3. `validateObject()` – `ObjectInputValidation`コールバックを介して。 +4. `readExternal()` – `Externalizable`を実装するクラス用。 +5. コンストラクタは**実行されません** – したがって、ガジェットチェーンは前のコールバックのみに依存します。 + +そのチェーン内のいずれかのメソッドが攻撃者が制御するデータ(コマンド実行、JNDIルックアップ、リフレクションなど)を呼び出すと、デシリアライズルーチンはRCEガジェットに変わります。 **シリアライズ可能な**クラス**Person**の例を見てみましょう。このクラスは**readObject**関数を**オーバーライド**しているため、この**クラス**の**任意のオブジェクト**が**デシリアライズ**されると、この**関数**が**実行**されます。\ -この例では、クラスPersonの**readObject関数**が彼のペットの`eat()`関数を呼び出し、犬の`eat()`関数が(何らかの理由で)**calc.exe**を呼び出します。**この計算機を実行するために、Personオブジェクトをシリアライズおよびデシリアライズする方法を見ていきましょう:** +この例では、クラスPersonの**readObject**関数がペットの`eat()`関数を呼び出し、犬の`eat()`関数が(何らかの理由で)**calc.exe**を呼び出します。**この計算機を実行するためにPersonオブジェクトをシリアライズおよびデシリアライズする方法を見ていきます:** -**以下の例は[https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649](https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649)からのものです。** +**以下の例はからのものです** ```java import java.io.Serializable; import java.io.*; @@ -80,8 +92,63 @@ payloadTest("test.ser"); } } ``` -## 結論 +### 結論 (クラシックシナリオ) -この非常に基本的な例からわかるように、ここでの「脆弱性」は**readObject**関数が**他の脆弱な関数を呼び出している**ために発生します。 +この非常に基本的な例からわかるように、ここでの「脆弱性」は、**readObject()** メソッドが **他の攻撃者制御コードを呼び出している** ために発生します。実際のガジェットチェーンでは、外部ライブラリ(Commons-Collections、Spring、Groovy、Rome、SnakeYAMLなど)に含まれる数千のクラスが悪用される可能性があり、攻撃者はコード実行を得るために *1つの* 到達可能なガジェットが必要です。 + +--- + +## 2023-2025: Javaデシリアライズ攻撃の新しい動向 + +* 2023 – CVE-2023-34040: `checkDeserExWhen*` フラグが有効な場合、Spring-Kafkaのエラーレコードヘッダーのデシリアライズにより、攻撃者が公開したトピックから任意のガジェット構築が可能になりました。3.0.10 / 2.9.11で修正済み。¹ +* 2023 – CVE-2023-36480: Aerospike Javaクライアントの信頼されたサーバー仮定が破られました – 悪意のあるサーバーの応答には、クライアントによってデシリアライズされたシリアライズされたペイロードが含まれていました → RCE。² +* 2023 – CVE-2023-25581: `pac4j-core` ユーザープロファイル属性の解析が `{#sb64}` プレフィックス付きのBase64ブロブを受け入れ、`RestrictedObjectInputStream` にもかかわらずデシリアライズされました。4.0.0以上にアップグレードしてください。 +* 2023 – CVE-2023-4528: JSCAPE MFT Manager Service (ポート10880) がXMLエンコードされたJavaオブジェクトを受け入れ、root/SYSTEMとしてRCEを引き起こしました。 +* 2024 – Hibernate5、TomcatEmbed、SnakeYAML 2.xクラスを含む新しいガジェットチェーンがysoserial-plus(mod)に追加され、いくつかの古いフィルターをバイパスしました。 + +## 現代の緩和策 + +1. **JEP 290 / シリアライズフィルタリング (Java 9+)** +*クラスの許可リストまたは拒否リストを追加:* +```bash +# あなたのDTOとjava.baseのみを受け入れ、他はすべて拒否 +-Djdk.serialFilter="com.example.dto.*;java.base/*;!*" +``` +プログラム例: +```java +var filter = ObjectInputFilter.Config.createFilter("com.example.dto.*;java.base/*;!*" ); +ObjectInputFilter.Config.setSerialFilter(filter); +``` +2. **JEP 415 (Java 17+) コンテキスト固有のフィルタファクトリ** – `BinaryOperator` を使用して、実行コンテキストごとに異なるフィルタを適用します(例: RMI呼び出しごと、メッセージキュー消費者ごと)。 +3. **生の `ObjectInputStream` をネットワーク越しに公開しない** – コード実行セマンティクスのないJSON/バイナリエンコーディングを好む(`DefaultTyping`を無効にしたJackson、Protobuf、Avroなど)。 +4. **防御の深さの制限** – 最大配列長、深さ、参照を設定: +```bash +-Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000" +``` +5. **継続的なガジェットスキャン** – `gadget-inspector` や `serialpwn-cli` などのツールをCIで実行し、危険なガジェットが到達可能になるとビルドを失敗させます。 + +## 更新されたツールチートシート (2024) + +* `ysoserial-plus.jar` – 130以上のガジェットチェーンを持つコミュニティフォーク: +```bash +java -jar ysoserial-plus.jar CommonsCollections6 'calc' | base64 -w0 +``` +* `marshalsec` – JNDIガジェット生成のリファレンス(LDAP/RMI)として依然として有用。 +* `gadget-probe` – ネットワークサービスに対する高速なブラックボックスガジェット発見。 +* `SerialSniffer` – `ObjectInputStream` によって読み取られるすべてのクラスを印刷するJVMTIエージェント(フィルタを作成するのに便利)。 +* **検出のヒント** – `-Djdk.serialDebug=true` (JDK 22+) を有効にして、フィルタの決定と拒否されたクラスをログに記録します。 + +## セキュアな `readObject()` 実装のためのクイックチェックリスト + +1. メソッドを `private` にし、`@Serial` アノテーションを追加します(静的解析に役立ちます)。 +2. ユーザー提供のメソッドを呼び出したり、メソッド内でI/Oを行ったりしない – フィールドのみを読み取ります。 +3. 検証が必要な場合は、デシリアライズ後に `readObject()` の外で行います。 +4. `Externalizable` を実装し、デフォルトのシリアライズの代わりに明示的なフィールド読み取りを好みます。 +5. 内部サービスに対しても強化された `ObjectInputFilter` を登録します(妥協耐性のある設計)。 + +## 参考文献 + +1. Spring Security Advisory – CVE-2023-34040 Java Deserialization in Spring-Kafka (2023年8月) +2. GitHub Security Lab – GHSL-2023-044: Unsafe Deserialization in Aerospike Java Client (2023年7月) {{#include ../../banners/hacktricks-training.md}}