CVE-2026-33439(jato.clientSessionのデシリアライゼーションによるOpenAM事前認証RCE)の最初に公開されたエクスプロイト実装。
人間の洞察 + AI 支援による分析 + リバースエンジニアリング + アドバイザリ → エクスプロイト
CVE-2026-33439 の初の公開エクスプロイト実装
ForgeRock OpenAM における未認証の Java デシリアライゼーション脆弱性。細工された JATO セッションオブジェクトを介して完全なリモートコード実行を可能にします。同じ川は二度流れる。彼らは jato.pageSession(CVE-2021-35464)を修正したが、jato.clientSession(CVE-2026-33439)を忘れていた。デシリアライゼーションガジェットチェーンは認証情報を要求しない。
CVE-2026-33439 は、OpenIdentityPlatform OpenAM(16.0.6 より前のバージョン)における事前認証リモートコード実行(RCE)の脆弱性です。この脆弱性は、ClientSession.deserializeAttributes() 内で jato.clientSession HTTP パラメータの安全でない Java デシリアライゼーションが行われることに起因します。ここでは、クラスのホワイトリストが適用されないまま Encoder.deserialize() → ApplicationObjectInputStream.readObject() が呼び出されます。
未認証の攻撃者は、シリアライズされた Java オブジェクトを含む細工された HTTP GET または POST リクエストを、JSP が <jato:form> タグをレンダリングする任意の JATO ViewBean エンドポイントに送信します。サーバーはこれを受信すると、バリデーションなしでオブジェクトをデシリアライズし、OpenAM WAR にバンドルされているクラスだけで完全に構築されたガジェットチェーンをトリガーし(外部ライブラリは不要)、アプリケーションプロセスのユーザーとして任意の OS コマンドを実行します。
CVSS 4.0 ベクタ: AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N → 9.3 緊急
CVSS 3.1 ベクタ: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H → 9.8 緊急
この脆弱性は、CVE-2021-35464 の後に適用された不完全な修正による直接的なリグレッションです。
CVE-2021-35464(ForgeRock AM / OpenAM): jato.pageSession パラメータの安全でないデシリアライゼーションによる事前認証 RCE。実環境で広く悪用され、CISA KEV に掲載されています。修正では、ConsoleViewBeanBase.deserializePageAttributes() 内に WhitelistObjectInputStream が導入されました。これは、クラスをインスタンス化する前に、すべてのクラス名をハードコードされた約 40 個の安全なクラスの許可リストと照合するカスタム ObjectInputStream サブクラスです。
CVE-2026-33439(OpenAM ≤ 16.0.5): 修正は jato.pageSession にのみ適用されました。jato.clientSession パラメータは、ClientSession.deserializeAttributes() 内の完全に別のコードパスで処理されますが、修正されることはなく、現在もフィルタリングされていない Encoder.deserialize() → ApplicationObjectInputStream を使用しており、クラスのホワイトリストなしで ObjectInputStream.readObject() を呼び出します。
攻撃プリミティブは同じです。デシリアライゼーションシンクが異なるだけです。変更されたのはパラメータ名のみです。
JATO は UI ビューの状態を、jato.pageSession および jato.clientSession という名前の HTTP パラメータにシリアライズします。リクエストが到着すると、OpenAM はレスポンスをレンダリングする前に UI 状態を復元するため、これらのパラメータをデシリアライズします。この 2 つのパラメータは、まったく異なるコードパスをたどります。
jato.pageSession の修正済みコードパス(CVE-2021-35464 後):```java // PATCHED - ConsoleViewBeanBase.deserializePageAttributes() ObjectInputStream ois = new WhitelistObjectInputStream(new ByteArrayInputStream(decoded)); // class whitelist enforced - gadget chains blocked Object obj = ois.readObject();
jato.clientSession の未パッチのコードパス (脆弱):```java
// ClientSession.java
protected ClientSession(RequestContext context) {
this.encodedSessionString =
context.getRequest().getParameter("jato.clientSession");
}
protected void deserializeAttributes() {
if (this.encodedSessionString != null
&& this.encodedSessionString.trim().length() > 0) {
this.setAttributes(
(Map) Encoder.deserialize(
// VULNERABLE - URL-safe base64 decode then plain ObjectInputStream
Encoder.decodeHttp64(this.encodedSessionString), false)
);
}
}
Encoder.deserialize() は、クラスフィルタリングを行わないプレーンな ApplicationObjectInputStream(ObjectInputStream のサブクラス)を構築します。JVMクラスパス上の任意のクラスをインスタンス化できます。デシリアライゼーションは、JSPレンダリング中に < jato:form > タグがレンダリングされるたびにトリガーされます:``` getClientSession() → hasAttributes() → getEncodedString() → isValid() → ensureAttributes() → deserializeAttributes()
---
<div id="vulnerability_affected"/>
### ***影響を受けるバージョン***
| 製品 | 脆弱性のあるバージョン | 修正済み |
|-----------------------------|-------------------------------------------------|---------|
| OpenIdentityPlatform OpenAM | ≤ 16.0.5 | 16.0.6 |
| ForgeRock AM (downstream) | パッチの系統によっては影響を受ける可能性があります | - |
---
<div id="vulnerability_attacksurface"/>
### ***攻撃対象領域***
JSP に *< jato:form >* タグを含む JATO ViewBean エンドポイントは、認証前に悪用可能です:
| エンドポイント | 目的 |
|-----------------------------|-----------------------------------------|
| /ui/PWResetUserValidation | パスワードリセット - ユーザーID入力 |
| /ui/PWResetQuestion | パスワードリセット - 秘密の質問 |
パスワードリセットエンドポイントは主要なターゲットです。これらは設計上パブリックにアクセス可能であり、*< jato:form >* タグを確実にレンダリングします。
---
---
---
<div id="gadgetchain"/>
## ***⚙️ ガジェットチェーン***
<div id="gadgetchain_deserialization101"/>
### ***Java デシリアライゼーション 101***
Java がバイトストリームからオブジェクトをデシリアライズするとき、再構築するすべてのクラス(ネストされたオブジェクトを含む)に対して readObject() を呼び出します。攻撃者がバイトストリームを制御し、readObject() がコード実行に至る一連のメソッド呼び出しをトリガーするオブジェクトを注入した場合、ガジェットチェーン RCE が成立します。
CVE-2026-33439 の重要な点は、ガジェットチェーンが外部ライブラリを必要としないことです。チェーン内のすべてのクラスは OpenAM WAR 自体にバンドルされています:`openam-core-16.0.5.jar, xalan-2.7.3.jar, and click-nodeps-2.3.0.jar`。<u>つまり、この脆弱性はデフォルトの OpenAM デプロイメントであればどこでも悪用可能です。</u>
---
<div id="gadgetchain_encoding"/>
### ***Encoder.decodeHttp64***
これがエクスプロイトを機能させる重要な詳細です。`jato-shaded-16.0.5.jar` 内の `Encoder` クラスは、標準の base64 でもカスタムの文字置換スキームでもなく、Java の URL セーフ base64 エンコーダ/デコーダを使用します。
Encoder.class を逆コンパイルして検証済み:```bash
# Extract Encoder.class from the JATO JAR
jar xf /work/jato-shaded-16.0.5.jar com/iplanet/jato/util/Encoder.class
# Decompile and inspect decodeHttp64
javap -p -c com/iplanet/jato/util/Encoder.class | grep -A10 "decodeHttp64"
入力テキスト(チャンク9/73の内容)が提供されていないため、翻訳できる内容がありません。翻訳対象のMarkdownテキストを送信してください。``` public static byte[] decodeHttp64(java.lang.String); Code: 0: invokestatic #8 // Method java/util/Base64.getUrlDecoder:()Ljava/util/Base64$Decoder; 3: aload_0 4: invokevirtual #9 // Method java/util/Base64$Decoder.decode:(Ljava/lang/String;)[B 7: areturn
URLセーフなbase64は、'+' の代わりに '-' を、'/' の代わりに '_' を使用し、パディング '=' はありません。正しいエンコーディングは次のとおりです:```java
Base64.getUrlEncoder().withoutPadding().encodeToString(serializedBytes)
その他のエンコーディング(標準のbase64や手動での文字置換を含む)を使用すると、decodeHttp64() が例外をスローするか、破損したバイト列を生成し、HTTPレスポンスにエラーを返さずにデシリアライゼーションを静かに中断します。