
Check Point CPM RCE CVE-2026-93616 向けの安全な未認証パッチ状態チェッカー。エクスプロイトを行わずに TCP 19009 上の UpgradeSvcRemote SOAP ログインをプローブします。
CVE-2026-93616 に対する未認証のパッチ状態チェックです。これは Check Point Security Management (CPM) サーバーにおける未認証のディレクトリトラバーサルであり、Runtime.exec() に到達するもので、2026-09-22 に sk1000171 で修正されました。CWE-22、CVSS 9.8 Critical (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)、実環境で悪用されています。Check Point が CNA であり、この問題は外部からの報告ではなく、実環境での悪用から特定されました。
CPM サーバーは TCP 19009 で SOAP Web サービスを公開しています。UpgradeSvcRemote のログインメソッド loginAsApplicationReadOnlyPublicSession は、その targetVersion パラメータを検証なしに Runtime.exec に渡されるファイルシステムパスへ転送するため、未認証の呼び出し元が実行を攻撃者の選んだスクリプトへリダイレクトできます。修正では targetVersion に Bean Validation パターンを追加し、パス区切り文字を拒否します。
このスクリプトは、各ターゲットにその修正が存在するかどうかを報告します。targetVersion に不正な文字を 1 つ送信するだけで、トラバーサルシーケンスは決して送信せず、認証も、ファイルのアップロードも、ターゲット上での何かの実行も行いません。VULNERABLE 以外の結果は、それ自体ではターゲットがパッチ済みであることを示しません。脆弱でない結果の解釈を参照してください。
サポート終了ビルドは明示的に処理されます。R81.10 より古いトレインでは、ログインメソッドが受け取るパラメータが少ないため、パッチ状態を読み取る前に XML アンマーシャリングによってプライマリプローブが拒否されます。Check Point サーバーがそのようにプローブを拒否した場合、スクリプトは古いパラメータ形状でフォローアップ呼び出しを 1 回送信します。その後ログインメソッドがディスパッチすれば、そのターゲットは Check Point が修正を公開しなかった影響を受けるビルドであり、判定は VULNERABLE、理由は affected-eos-no-fix となります。フォローアップ呼び出しには mode も targetVersion も含まれないため、これも検証すべきもの、トラバースすべきものを何も送信しません。これにより、レガシーサーバーが識別不能と読み取られてしまうギャップが埋められます。
# single target (port defaults to 19009)
./cve_2026_93616_check.py mgmt.example.com
# explicit port
./cve_2026_93616_check.py mgmt.example.com:19009
# several targets
./cve_2026_93616_check.py mds-a.example.com mds-b.example.com
# scan a list, one target per line ('#' comments allowed), compact output
./cve_2026_93616_check.py -f targets.txt --brief
# machine-readable output for pipelines
./cve_2026_93616_check.py -f targets.txt --json > results.json
Python 3.8+、標準ライブラリのみ — サードパーティパッケージは不要です。
このツールはゲートウェイではなく、管理サーバー (Security Management、Multi-Domain Management、Log、Multi-Domain Log、SmartEvent) に対して実行してください。このチェックは TCP 19009 の CPM SOAP リスナーを対象としており、ゲートウェイはこれを実行していません。
| Flag | Description |
|---|---|
TARGET | 1 つ以上の HOST[:PORT] ターゲット。ポートはデフォルトで 19009 |
-f, --targets-file FILE | ファイルからターゲットを読み取る (1 行に 1 つ、# コメント可) |
-p, --port PORT | ターゲットがポートを省略した場合のデフォルトポート (デフォルト: 19009) |
--timeout SECS | プローブごとのタイムアウト (デフォルト: 15) |
--workers N | 同時実行するターゲット数 (デフォルト: 16)。出力は入力順のまま |
-b, --brief | ターゲットごとに整列された 1 行。多数のホストのスキャン向け |
--json | 構造化 JSON を出力。ターゲットごとのプローブマーカーを含む |
--no-color | 色付き出力を無効化 (NO_COLOR および非 TTY も尊重) |
脆弱なサーバー (デフォルト出力。TTY では [!] マーカーと VULNERABLE が赤で表示されます):
$ ./cve_2026_93616_check.py mgmt.example.com
[!] mgmt.example.com:19009: VULNERABLE [dispatched-without-validation]
loginAsApplicationReadOnlyPublicSession accepted an illegal targetVersion and dispatched it; the fix's input validation is absent
パッチ済みサーバー:
$ ./cve_2026_93616_check.py mgmt-dr.example.com
[+] mgmt-dr.example.com:19009: PATCHED [validation-constraint-present]
the server rejected an illegal targetVersion with the input-validation constraint added by the fix (Jumbo Hotfix R82.10 Take 45 or equivalent)
応答はあったもののログインメソッドをディスパッチしなかったため、パッチ状態を読み取れなかった Check Point 管理サーバー:
$ ./cve_2026_93616_check.py log.example.com
[?] log.example.com:19009: INCONCLUSIVE [cpm-no-dispatch]
a Check Point management fault came back, but the UpgradeSvcRemote login method did not dispatch, so patch state could not be read
--brief を使った複数ターゲット:
$ ./cve_2026_93616_check.py -f targets.txt --brief; echo "exit: $?"
VULNERABLE mgmt.example.com:19009 dispatched-without-validation
PATCHED mgmt-dr.example.com:19009 validation-constraint-present
INCONCLUSIVE log.example.com:19009 cpm-no-dispatch
UNAFFECTED web.example.com:19009 not-cpm
ERROR offline.example.com:19009 unreachable
exit: 1
--json を使った JSON 出力。判定を実際のレスポンス内容と照合できるよう、プローブマーカーが含まれます:
$ ./cve_2026_93616_check.py mgmt.example.com mgmt-dr.example.com --json
[
{
"target": "mgmt.example.com:19009",
"verdict": "VULNERABLE",
"reason": "dispatched-without-validation",
"detail": "loginAsApplicationReadOnlyPublicSession accepted an illegal targetVersion and dispatched it; the fix's input validation is absent",
"http_status": 500,
"probe": {
"http_status": 500,
"saw_validation": false,
"saw_dispatch": true,
"saw_cpm": true,
"note": ""
}
},
{
"target": "mgmt-dr.example.com:19009",
"verdict": "PATCHED",
"reason": "validation-constraint-present",
"detail": "the server rejected an illegal targetVersion with the input-validation constraint added by the fix (Jumbo Hotfix R82.10 Take 45 or equivalent)",
"http_status": 500,
"probe": {
"http_status": 500,
"saw_validation": true,
"saw_dispatch": true,
"saw_cpm": true,
"note": ""
}
}
]
このチェックは本番システムに対して使用することを意図しています:
targetVersion に不正な文字 (!) を 1 つ入れるだけです。この 1 文字でパッチ済みビルドの検証を引っかけるのに十分であり、パス区切り文字のようにディレクトリを脱出することはできません。レガシーのフォローアッププローブは targetVersion をまったく含みません。domainId 要素を省略するため、未パッチのサーバーではメソッドがパラメータを構築する際に NullPointerException を発生させ、ReflectionUtils が Runtime.exec に到達する前に終わります。仮にそうでなくても、プローブ値は存在しないディレクトリに解決されるため、実行するスクリプトはありません。レガシープローブはアプリケーション名とタイムアウトのみを送信するため、パスを構築する材料がありません。| # | Call | When | Purpose |
|---|---|---|---|
| 1 | UpgradeSvcRemote.loginAsApplicationReadOnlyPublicSession (current shape) | 常に | パッチ状態プローブ |
| 2 | UpgradeSvcRemote.loginAsApplicationReadOnlyPublicSession (legacy shape) | Check Point サーバーによって呼び出し 1 がアンマーシャリングで拒否された場合のみ | サポート終了ビルドの確認 |
プローブは $MDS_FWDIR/log/cpm.elg に記録されます。パッチ済みサーバーは検証拒否をログに記録し、未パッチサーバーはディスパッチとその NullPointerException をログに記録し、サポート終了サーバーは呼び出し 1 のアンマーシャリングエラーと呼び出し 2 のディスパッチをログに記録します。両方のプローブはアプリケーション名 bf-check を送信し (呼び出し 1 は値 bf-check! も送信します)、これはログ内で攻撃ではなくこのツールであると識別できます。
修正は、targetVersion を受け取るすべての UpgradeSvcRemote メソッドの targetVersion パラメータに Bean Validation パターン ^[A-Za-z0-9._-]*$ を追加します。このパターンはバージョン文字列を許可しますがパス区切り文字は許可しないため、Runtime.exec へのトラバーサルが塞がれます。このチェックは不正な文字を 1 つ送信し、サーバーがどちら向きに応答するかを読み取ります:
| 不正な文字 1 つに対する応答 | ビルド | 判定 |
|---|---|---|
targetVersion contains illegal characters | 修正済み (Take 45 および同等品) | PATCHED |
| メソッドがディスパッチ、検証メッセージなし | 影響あり (R81.10 以降) | VULNERABLE |
| プローブが XML アンマーシャリングで拒否され、その後レガシー形状がディスパッチ | 影響あり、サポート終了 | VULNERABLE |
| Check Point フォールト、メソッドがディスパッチせず | いずれか | INCONCLUSIVE |
ディスパッチは、レスポンス内の完全なメソッド名 UpgradeSvcRemote.loginAsApplicationReadOnlyPublicSession によって確認されます。裸の文字列 UpgradeSvcRemote は使用できません。Check Point フォールトは名前空間マップ内のすべてのサービスを列挙するため、このメソッドが実行されたかどうかに関係なく、その部分文字列はあらゆる CPM レスポンスに現れます。このチェックは完全なメソッド名のみに一致します。
loginAsApplicationReadOnlyPublicSession のパラメータ形状はリリース間で変更されました。R81.10 以降はプライマリプローブが送信する mode 要素と targetVersion 要素を受け入れますが、R81.10 より古いビルドは受け入れず、パッチ状態のシグナルが生成される前に XML アンマーシャリング (サーバースタックが JAXB/CXF アンマーシャラーで始まる generalRemoteFaultException) でプライマリプローブを拒否します。これらの古いトレインはすべてサポート終了であり、修正が提供されたことがないため、その拒否自体が発見事項です。
スクリプトはこれを認識し (Check Point フォールトとアンマーシャラースタック)、古い形状 (applicationName と timeout のみ) でフォローアップ呼び出しを 1 回送信します。その形状でログインメソッドがディスパッチすれば、ターゲットは影響を受け、パッチ適用不可能なビルドであると確認され、VULNERABLE / affected-eos-no-fix と報告されます。フォローアップはこの場合にのみ送信されるため、現行のサポート対象サーバーは依然として単一のリクエストでチェックされます。
このチェックはパッチ済みコードパスの挙動を観察するものであり、バージョン文字列を読み取りません。パッチ済みサーバーがどの Jumbo Hotfix take を実行しているかは報告しません。