
UniFi Network ApplicationコントローラがCVE-2026-22557に対して脆弱かどうかを安全に検出する
UniFi Network Application コントローラが CVE-2026-22557 に対して脆弱かどうかを、混乱を引き起こさずに安全に検出します。 Bishop Fox ブログの詳細な解説記事もご覧ください。
CVE-2026-22557 は、UniFi Network Application のゲストキャプティブポータルにおける認証不要のパストラバーサル脆弱性であり、リモートの攻撃者がコントローラプロセスユーザーとして任意のファイルを読み取ることを可能にします(CVSS 10.0)。この脆弱性は、UniFi Network Application 10.1.x ブランチの 10.1.85 以前、および 10.2.x および 9.0.x ブランチの対応する以前のリリースに影響します。Ubiquiti は 10.1.89、10.2.97、9.0.118 で修正を出荷しました(SAB-062)。
ゲストポータルのエラーページレンダラーは、page_error リクエストパラメータを読み取り、それをポータルリソースローダーへの相対パスとしてそのまま使用し、検証を行いません。クエリ対象のサイトで portal_customized: true が設定されている場合(ホテル、小売店、カフェの展開など、ブランド化されたキャプティブポータルの設定はすべてこの状態になります)、ローダーはそのパスをディスク上のポータルディレクトリに対して解決し、パスがそこからエスケープされる可能性があります。
このツールは、以下の手順で非破壊的な脆弱性テストを実施します:
/status からコントローラの報告されたバージョンを読み取り、SAB-062 の修正ラインと比較する/guest/<site>/wechat/sign の page_error パラメータを ../ の深さ 1~8 で、二重ブランチのファイル名に対してプローブし、トラバーサルが発生するかどうかを判定するfirmware.json) に対して追加の読み取りを 1 回実行し、カスタマイズされたポータルのファイルシステムブランチがアクティブかどうかを判定するこのツールは、ブランチアクティブのオラクルとしてランタイムカタログファイルのみを要求します。認証情報、TLS 素材、データベース状態、バックアップは読み取りません。また、ファイルの内容を stdout やディスクに書き出すこともありません。判定結果のみが出力されます。
portal_customized: true がある場合、キャリブレーションされた深さでカタログファイルが返され、VULNERABLE と確認されます。portal_customized: false の場合、キャリブレーション手順ではトラバーサルがトリガーされますが、確認手順ではディスクコンテンツが返されません → PARTIALLY EXPOSED。アプリケーションバイナリは依然として脆弱です。このサイトが悪用可能な状態でなくても、パッチ適用が必要です。NOT VULNERABLE。NOT EXPOSED になります。git clone https://github.com/BishopFox/CVE-2026-22557-check
cd CVE-2026-22557-check
Python 3.9+ が必要です。このツールは Python 標準ライブラリのみを使用するため、pip install は不要です。
<TARGET> の UniFi Network Application コントローラをテストします。コントローラの Web UI に到達する任意の URL をツールに指定します。脆弱なハンドラは管理ポート(デフォルト 8443/TCP)だけでなく、専用のゲストポータルポート(8843、8880)でもディスパッチされます。
python3 cve_2026_22557_check.py <BASE_URL> [--site NAME]
デフォルトのサイトスラッグは default です。複数のサイトが設定されている UniFi デプロイメントでは、各サイトに対して --site <name> を指定してツールを再実行する必要があります。コントローラは、そのサイトのいずれかに portal_customized: true があれば悪用可能です。
以下の例では、ホストごとに 1 行で結果を表示する --brief を使用しています。--brief なしで実行すると、完全なバナー、ステップバイステップの進行状況、および推奨される修復アクションを含む結果ブロックが表示されます。
コントローラは脆弱なビルド上にあり、クエリ対象のサイトでカスタマイズポータルの前提条件がアクティブなため、認証なしの読み取りパスに到達可能です。
$ python3 cve_2026_22557_check.py https://192.168.1.100:8443 --brief
[VULNERABLE] https://192.168.1.100:8443 site=default
コントローラは脆弱なビルド上にありますが、クエリ対象のサイトで portal_customized: true が有効になっていないため、このサイトではディスク読み取りの前提条件が満たされていません。アプリケーションバイナリはまだパッチが必要です。同じコントローラ上の別のサイトが悪用可能な状態である可能性があります。
$ python3 cve_2026_22557_check.py https://192.168.1.100:8443 --brief
[PARTIAL] https://192.168.1.100:8443 site=default
コントローラは修正済みビルド(10.1.89、10.2.97、9.0.118 以降)上にあるため、クエリされたどの深さでもトラバーサルは発生しません。
$ python3 cve_2026_22557_check.py https://192.168.1.200:8443 --brief
[NOT VULNERABLE] https://192.168.1.200:8443 site=default
--site NAME プローブする UniFi サイトスラッグ(デフォルト: "default")
--max-depth N 試行する最大 ../ トラバーサル深度(デフォルト: 8)
--no-tls-recon TLS 証明書の subject/SAN 表示をスキップ
--no-color ANSI カラー出力を無効化(NO_COLOR 環境変数でも有効)
--timeout N リクエストごとのタイムアウト秒数(デフォルト: 20)
--brief バナーや手順なしで単一行の結果を出力
終了コード: 0 VULNERABLE、1 partially exposed / not vulnerable / not exposed、2 transport error。
このツールが VULNERABLE の判定を返すには、以下の条件がすべて満たされている必要があります:
/guest/* ハンドラは管理ポート(8443)と専用ゲストポータルポート(8843、8880)の両方でディスパッチされます。ツールは指定された URL のみをプローブします。guest_access 設定で portal_customized: true が設定されている。これがディスク読み取りコードパスの前提条件です。複数のサイトがあるコントローラは、そのサイトのいずれかでこれが有効になっていれば悪用可能です。いずれかの条件が満たされない場合、ツールはより保守的な判定にフォールスルーします。PARTIALLY EXPOSED の結果でも、アプリケーションは脆弱でありパッチが必要であることを意味します。クエリ対象のサイトがたまたまディスク読み取りパスを公開していないだけです。
脆弱性のあるリクエストパターンは次のとおりです:
GET /guest/s/<site>/wechat/sign?page_error=<value>
正当なクライアントは /guest/s/<site>/wechat/sign に POST でのみアクセスします(ディスパッチャーはそれを受け入れ、エラーページレンダラーを起動しません)。page_error= クエリパラメータを伴うこのエンドポイントへの GET リクエスト、特に ../、%2e%2e、または先頭の / を含むものは異常であり、悪用試行として扱う必要があります。Tomcat の標準アクセスログには、クエリ文字列を含む完全なリクエスト行が記録されます。
このコードは MIT ライセンス の下で配布されています。
事前の相互同意なしにターゲットを攻撃する目的でこのツールを使用することは違法です。該当するすべての地域、州、連邦法を遵守するのはエンドユーザーの責任です。開発者は一切の責任を負わず、このプログラムの誤用または損害について責任を負いません。