
CVE-2026-41940 (cPanel & WHM 認証バイパス) 向け高忠実度スキャナ
CVE-2026-41940 として追跡されている cPanel/WHM 認証バイパス用の高精度スキャナです。公開されている概念実証や検出にありがちな偽陰性を発生させず、またアカウントロックアウトや root IP 許可リスト機構(ナイーブなスキャンを妨害する)を引き起こさずに脆弱なホストを識別します。
このツールには、cpdavd(ポート 2079 平文/2080 TLS)上の同一系統の CalDAV パストラバーサルバグ(CVE-2026-29205)に対する、オプトインの独立したエクスプロイトチェーンもバンドルされています。このバグにより、リモートの攻撃者は小さな SMTP 駆動のセットアップ手順が成功した後、root として任意のファイルを読み取ることができます。cPanel 11.134.0.26 では、基礎となる RAII のライフタイムバグが修正され、読み取りは非特権のアカウント所有者として実行されます。トラバーサル自体は依然として cpdavd に到達しますが、そのアカウントが既に読み取れるものを超えてエスカレーションすることはできません。CalDAV チェーンは --exploit で有効になり、実際のメールを送信し、確認されたターゲットからファイルを読み取るためデフォルトではオフになっています。エクスプロイトモード(アクティブ)のセクションを参照してください。
CVE-2026-41940 に対する公開検出のほとんどには 3 つの問題があります。このスキャナはそれぞれに対処します。
この検出手法に関するブログ記事はこちらで読めます: https://slcyber.io/research-center/high-fidelity-check-for-the-cpanel-authentication-bypass-cve-2026-41940/
cPanel の vhost ごとの Apache 設定は、リクエストの Host ヘッダに関係なく、/___proxy_subdomain_whm を 127.0.0.1:2086 に、/___proxy_subdomain_cpanel を 127.0.0.1:2080 に転送する ProxyPass をインストールします。RewriteCond は管理サブドメインをプロキシパスにマッピングするリライトのみを制約します。ProxyPass 自体は無条件です。cPanel 管理下の Apache によって提供される任意の vhost でこれらのパスにアクセスすると、管理ポートと同じ脆弱なバックエンドに到達します。
ポート 2082/2083/2086/2087 のみをプローブするスキャナは、これらのポートがファイアウォールで保護されている場合、バグが 443 経由で完全に到達可能であるにもかかわらず、ホストを脆弱ではないと報告します。このスキャナは、デフォルトで 2087、2083、および 443 の 2 つのプロキシパスをプローブします。
cPanel には cphulkd(少数のパスワード試行失敗後にアカウントをロックアウト)と authorized_whm_root_ips(root ログインを設定された送信元アドレスリストに制限)が付属しています。バイパスを悪用して root のセッションを注入しようとするスキャナは次のようになります:
このスキャナは、ランダムに生成されたユーザー名でセッションペイロードに expired=1 を注入することで、WHM 側でこれらの問題を回避します。セッションの注入は、結果の cpsessXXXX URL にアクセスし、レスポンスボディ内の msg_code:[expired_session] を照合することで確認されます。これは注入が成功した場合にのみ存在します。実際のアカウントは対象とならないため、実際のアカウントがロックアウトされることはなく、root ログインは試行されないため root 許可リストは無関係です。
cPanel デーモン(cpaneld、ポート 2083 および /___proxy_subdomain_cpanel パス)では、指定されたユーザー名がディスク上の既存の cPanel アカウントに対応している必要があります(-f /var/cpanel/users/$user)。root はシステムユーザーであり cPanel ユーザーではないため、このチェックを満たすことは決してありません。root のみを試す検出では、この面で偽陰性が発生します。このスキャナは、cPanel 面では一般的な cPanel ユーザー名の設定可能なワードリストを使用し、WHM 面ではそのような制限がないためランダムユーザー名のパスにフォールバックします。
ターゲットごとに、スキャナは面ごとに次の手順を実行します。
GET /login を発行し、Set-Cookie ヘッダーから whostmgrsession(WHM)または cpsession(cPanel)を読み取ります。Cookie にはカンマ区切りのセッション名コンポーネントが含まれています。<user>:\xff\nexpired=1 である Authorization: Basic ヘッダーを使用して GET / を発行します。末尾の \nexpired=1 がセッション注入ペイロードです。ステップ 1 のセッション Cookie は変更せずに再送信されます。Location ヘッダーを読み取り、cpsessXXXX トークンを抽出します。GET /<cpsessXXXX>/ を発行し、ボディ内で msg_code:[expired_session] を探します。これが存在すれば、セッション注入が成功し、ホストが脆弱であることが証明されます。WHM(ポート 2087 および 443 の /___proxy_subdomain_whm パス)では、ユーザー名はランダムな u の後に 10 文字の 16 進文字が続きます。cPanel(ポート 2083 および 443 の /___proxy_subdomain_cpanel パス)では、スキャナはユーザー名ワードリストを走査し、最初に一致したところで停止します。
デフォルトでは、スキャナは 2087、2083、443 の順にプローブし、いずれかの面が脆弱性を確認した時点で停止します。
--exploit)CVE-2026-29205 — cPanel/WHM WP2 セキュリティアップデート、2026 年 5 月 13 日。cPanel 11.134.0.26 で修正。この勧告は、このエクスプロイトチェーンが悪用するのと同じ
cpdavd特権降格の後退を追跡しています。
バグとエクスプロイトチェーンの完全な解説: https://slcyber.io/research-center/new-age-of-collisions-reading-arbitrary-files-pre-auth-as-root-in-cpanel-cve-2026-29205
cpdavd はポート 2079(平文 HTTP)および 2080(TLS)で、CalDAV/CardDAV リソースを提供する際に構築する <principal>/<collection>/... パスを信頼します。パスコンポーネントに .. セグメントをエンコードし、ディスク上の名前もトラバーサルをエンコードする maildir フォルダ(x-attachment-1-y)を指すリクエストを作成することで、cpdavd はディスク上の任意のファイルを root として、所有権やパーミッションに関係なく読み取るように強制できます。これには /etc/shadow、/etc/passwd、およびユーザーごとのメールスプールが含まれます。
読み取りの前にアカウント所有者に特権を降格するはずだった多層防御は静かに失敗しました。Cpanel::AccessIds::ReducedPrivileges オブジェクトが void コンテキストで構築されたため、そのデストラクタは読み取りが実行される前に root 権限を復元しました。cPanel 11.134.0.26 では、オブジェクトを my $privs レキシカル変数にバインドすることで、-f / stat / open / read チェーンを通じて生存させます。修正されたホストでは、読み取りは root ではなく非特権のアカウント所有者として実行されます。
読み取りが機能するには、脆弱なフォルダがディスク上に存在している必要があります。cPanel は、受信者 <user>+x-attachment-1-y@<domain> に初めてメールが届いたときに、.x-attachment-1-y という名前のフォルダを自動的に作成します。したがって、チェーンは次のようになります。
info、admin、webmaster などの一般的なメールボックスプレフィックスの小さなワードリスト)を導出します。<prefix>+x-attachment-1-y@<domain> を送信します。受け入れられた RCPT TO 応答が追跡されます。cpdavd のポート 2080(TLS)および 2079(平文)に対して、/calendar/ と /addressbook/ の両方のコレクションプレフィックスでパストラバーサル GET を送信します。成功するとファイルのバイトが返されます。検出結果には、使用されたメール、コレクション、バイト数、および最初の 200 バイトのプレビューが記録されます。
このチェックは --exploit が渡されない限り無効です。有効にすると、フォルダ作成ステップをスキップできないため、動作するアウトバウンド SMTP リレーが必要です(下記の設定ファイルを参照)。
このエクスプロイトは、cPanel の メールアカウント 機能で設定された実際の仮想メールアカウントに対してのみ機能します。キャッチオールアドレスは機能しません。キャッチオールは Exim の system_aliases ルーターを経由し、dovecot_virtual_delivery トランスポートに到達しないため、.x-attachment-1-y/ フォルダを生成する lda_mailbox_autocreate パスをトリガーしません。
ターゲット上の有効な仮想メールを既に知っている場合は、--email を使用して渡します。
python scanner.py --config scanner.ini --email [email protected] target.com
--email は証明書の SAN 列挙とプレフィックスワードリストを完全にスキップし、指定したアドレスに正確に 1 通のメッセージを送信します。既知の複数のアカウントを対象とするために繰り返すことができます。ターゲット型パスはスプレー型パスよりもはるかに信頼性が高いです。
--email がない場合、スキャナはホストの TLS 証明書から抽出されたドメインごとに約 15 の一般的なプレフィックス(info、admin、webmaster など)をスプレーすることにフォールバックします。200 の cpdavd 露出ホストのサンプルに対する Assetnote の測定では、スプレーのヒット率は約 10% でした。スプレーモードのクリーンな結果は、ホストが修正されているという弱い証拠に過ぎず、実際のアカウントに対して --email を再実行することが確認する唯一の信頼できる方法です。
エクスプロイトモードは --config 経由で INI ファイルを読み取ります。
python scanner.py --config scanner.ini --exploit example.com
scanner.ini.example を scanner.ini にコピーし、SMTP 認証情報を入力し、必要に応じて CalDAV のデフォルトを調整します。scanner.ini は .gitignore に含まれているため、入力済みのコピーはローカルに残ります。SMTP パスワードは SCANNER_SMTP_PASSWORD 環境変数でも指定でき、ファイル内の password フィールドが空の場合にのみ優先されます。
pip install -r requirements.txt
Python 3.8 以降が必要です。
単一ターゲット:
python scanner.py example.com
位置引数による複数ターゲット:
python scanner.py host-a.example.com host-b.example.com:2083
ターゲットのファイル(1 行に 1 つ)。# で始まる行は無視されます:
python scanner.py -f targets.txt
標準入力からの読み取り:
cat targets.txt | python scanner.py
ターゲットはホスト名または host:port のいずれかです。ポートが指定された場合、スキャナはそのポートのみをプローブします。それ以外の場合は 2087、2083、443 をプローブします。
-u, --users — cPanel 面で試す cPanel ユーザー名のカンマ区切りリスト。デフォルトは小さな組み込みリストです。-U, --users-file — 1 行に 1 つの cPanel ユーザー名が記述されたファイル。-p, --ports — ターゲットにポートが指定されていない場合にプローブするポートのカンマ区切りリスト。デフォルトは 2087,2083,443。-t, --threads — cPanel 面でユーザー名リストを走査するために使用されるターゲットごとのスレッド数。デフォルトは 10。-c, --concurrency — 並行してスキャンされるターゲット数。デフォルトは 20。-T, --timeout — リクエストごとのタイムアウト(秒)。デフォルトは 15。-o, --output — 脆弱なターゲットを発見された順に 1 行ずつこのファイルに追記します。--json — ターゲットごとに JSON Lines レコードをこのファイルに書き込みます。-q, --quiet — stdout に脆弱なターゲットのみを出力します。接続失敗とクリーンなターゲットは --json に記録され、サマリーでカウントされます。--no-progress — プログレスバーを無効にします。検出 ごとに 1 行が stdout に書き込まれるため、両方のチェックを実行するターゲットは 2 回出力されます。
[!] host cve-2026-41940 VULNERABLE (port 443)
[!] host caldav-traversal VULNERABLE via admin@host (read 1842b from /etc/passwd)
[+] host cve-2026-41940 NOT VULNERABLE
[?] host cve-2026-41940 CONNECTION FAILED
--json 出力は、findings 配列を持つターゲットごとの 1 レコードです。
{"target": "host", "status": "VULNERABLE", "findings": [
{"check": "cve-2026-41940", "status": "VULNERABLE", "detail": {"port": 443}},
{"check": "caldav-traversal", "status": "VULNERABLE",
"detail": {"email": "admin@host", "domain": "host", "collection": "calendar",
"file": "/etc/shadow", "bytes": 1218, "preview": "root:$6$..."}}
]}
トップレベルの status はすべての検出結果の中で最も悪いケースです。
合計を示すサマリー行が最後に stderr に書き込まれます。プログレスバーは stderr に表示され、stderr が端末でない場合は自動的に抑制されます。
終了コードは、いずれかのターゲットが脆弱な場合は 0、到達可能なすべてのターゲットがクリーンな場合は 1、どのターゲットにも到達できなかった場合は 2 です。
ターゲットのリストをスキャンし、ヒットをファイルに書き込み、stdout は静かに:
python scanner.py -f targets.txt -o vulnerable.txt -q
カスタムユーザー名リストを使用して cPanel 面をスキャン、並列性を高め、ダウンストリーム処理用に JSON 出力:
python scanner.py -f targets.txt -U cpanel-users.txt -c 100 --json results.jsonl
非デフォルトのポートセットをプローブ:
python scanner.py -p 2083,2087,8443 -f targets.txt
単一ターゲットに対して CalDAV チェーンをエンドツーエンドで実行、メールスプレーフォールバック付き(入力済みの scanner.ini が必要):
python scanner.py --config scanner.ini --exploit example.com
既知の仮想メールに対するターゲット型エクスプロイト — スプレーよりもはるかに高いヒット率:
python scanner.py --config scanner.ini --email [email protected] example.com
確認済みの cpdavd ホストリストに対して CalDAV チェーンのみを実行し、/etc/passwd のプレビューを JSON にダンプ:
python scanner.py --config scanner.ini --caldav-only \
-f cpdavd-hosts.txt --json caldav-results.jsonl
デフォルトの scanner.py <target> 呼び出しは、CVE-2026-41940 検出器のみを実行します。セッション注入を確認するために必要なリクエストのみを送信し、それ以上は行いません。実際のユーザーとしてログインせず、root アカウントをターゲットにせず、シェルにエスカレーションせず、ターゲットシステム上の有効なアカウントに対して失敗したパスワードイベントを累積しません。照合するマーカー(msg_code:[expired_session])は、注入された expired=1 セッションフィールドに応答してアプリケーション自体によって生成され、cPanel ログインページが正当に期限切れになったセッションを再生したときに使用するのと同じインジケータです。
--exploit(または --caldav-only)を渡すと、CalDAV パストラバーサルチェーンが有効になります。これはもはや検出器ではありません — 動作するエクスプロイトです。有効にすると、スキャナはドメインの列挙が成功したすべてのターゲットに対して次のことを行います。
scanner.ini で設定されたリレーに対して実際の SMTP セッションを開き、候補の受信者ごとに 1 通の短いメッセージを送信します(通常、ドメインあたり 10~15、ターゲットあたり 3 ドメイン)。--read-file の読み取りを試みます。デフォルトのファイルは /etc/shadow です。読み取りが成功するとファイルのバイトが返されます。空のボディは、ターゲットに到達できないか、特権降格の修正(cPanel 11.134.0.26、my $privs = …)が適用されているホストを示します。検出は、受信したボディの長さをゼロと比較します(応答のアドバタイズされた Content-Length ではありません。これは攻撃者が選択したパスの stat() から派生し、後続の open() が拒否された場合でも値が設定されます)。
トラバーサルの到達可能性を特権降格の修正とは独立してテストするには(例:パッチが適用されたホストで cpdavd に到達可能かどうか、および maildir の前提条件が満たされているかどうかを知りたい場合)、--read-file /etc/passwd を指定して再実行します。/etc/passwd は誰でも読み取り可能なため、パッチ前とパッチ後の両方のホストでバイトが返されます。2 つのシグナルを組み合わせる(/etc/shadow ボディあり = パッチ前の root 読み取り、/etc/shadow 空 + /etc/passwd あり = トラバーサル到達可能だが特権降格修正適用済み)ことで、ホストを曖昧さなく分類できます。
内容と 200 バイトのプレビューは JSONL 出力に書き込まれ、stdout に表示されます。ドメインごとの CalDAV エクスプロイトには 1 分以上かかる場合があります。これはメール配信を待つリトライラダーであり、ハングではありません。
--exploit は、所有しているアセット、またはテストする明示的な書面による許可があるアセットに対してのみ実行してください。SMTP トラフィックは設定されたリレーとすべての受信者メールシステムによってログに記録され、ファイル読み取りは cpdavd によってログに記録されます。
--exploit--config — SMTP リレーの認証情報と CalDAV チューナブルを含む INI ファイル。scanner.ini.example を参照。--read-file — CalDAV チェーンが成功した場合に流出させるファイル。設定ファイルの値を上書きします。デフォルトは /etc/shadow — root 専用ファイルのため、読み取りが成功するとパッチ前(シャドウ内容を返す)とパッチ後(open が拒否、ボディ空 → NOT VULNERABLE と報告)を区別できます。トラバーサルの到達可能性をパッチの有無に関係なくテストするには --read-file /etc/passwd を使用します。--caldav-only — 41940 チェックをスキップし、CalDAV チェーンのみを実行します。--exploit を暗黙的に含みます。CalDAV に到達可能であることが既にわかっているターゲットリストに対してチェーンを再実行する場合に便利です。--email ADDR — ターゲット上の既知の仮想メールアカウント。証明書の SAN 列挙とスプレーワードリストをスキップし、ADDR に正確に 1 通のメッセージを送信して、そのプリンシパルに対して読み取りを行います。繰り返し指定可能。--exploit を暗黙的に含みます。ターゲット型 vs スプレー型エクスプロイトを参照。-v, --verbose — CalDAV チェーンのドメインごとの進行状況(証明書 SAN リスト、スプレー数、リトライラダー)を出力します。