Back to Articles

Inside o365spray: How Attackers Enumerate and Spray Microsoft 365 Tenants

[ View on GitHub ]

Inside o365spray: How Attackers Enumerate and Spray Microsoft 365 Tenants

Hook

Microsoft has patched the most popular O365 user enumeration technique at least four times—and each time, tools like o365spray simply switch to one of their backup modules. The cat-and-mouse game continues, with attackers maintaining the upper hand through endpoint diversity.

Context

Microsoft 365 environments present a unique challenge for security assessments. Unlike traditional on-premise Active Directory where you need internal network access to enumerate users and test passwords, O365 exposes authentication endpoints directly to the internet. This architectural reality creates an asymmetric advantage: while defenders must monitor thousands of authentication sources worldwide, attackers can methodically probe these endpoints to validate usernames and spray passwords from anywhere.

The security testing problem becomes more complex when organizations implement hybrid deployments with federated authentication, password hash synchronization, or ADFS. Each configuration exposes different attack surfaces across OAuth2, ActiveSync, Autodiscover, and legacy protocols. Traditional spraying tools targeted single endpoints, making them fragile when Microsoft applied patches or implemented rate limiting. o365spray emerged as a framework-style tool that consolidates multiple enumeration and spraying techniques, providing redundancy when specific vectors get blocked. For penetration testers and red teams conducting authorized assessments, this multi-module approach reflects how real adversaries maintain persistence in their techniques despite defensive improvements.

Technical Insight

Infrastructure

Password Spray

Enumeration

usernames/passwords

enum mode

spray mode

HTTP requests

auth attempts

controlled spray

delayed requests

optional proxy

rotated IPs

direct

IfExistsResult

auth response

CLI Interface

Module Selector

Enum Modules

Office/OAuth2/RST/etc

User Validator

Spray Modules

OAuth2/ADFS/ActiveSync/etc

Lockout Protection

Per-User Attempt Counter

Rate Limiter + Jitter

FireProx IP Rotation

Concurrent HTTP Engine

O365 Auth Endpoints

login.microsoftonline.com

System architecture — auto-generated

At its core, o365spray implements a module-based architecture where each enumeration and spraying technique targets different O365 authentication endpoints. The tool currently includes five enumeration modules (Office, OneDrive, Autologon, OAuth2, RST) and seven spraying modules (OAuth2, ADFS, Autodiscover, ReportingWebService, ActiveSync, RST, OneDrive). This diversity exists because Microsoft frequently patches specific endpoints, and having multiple options ensures at least one technique remains viable.

The enumeration workflow demonstrates the architectural philosophy. A basic username enumeration using the Office module looks like this:

python3 o365spray.py --enum -U usernames.txt --domain targetcorp.com

Under the hood, this sends HTTP requests to https://login.microsoftonline.com/common/GetCredentialType with JSON payloads containing each username. The response structure differs for valid versus invalid accounts—valid accounts return IfExistsResult: 0 while invalid ones return IfExistsResult: 1. The Office module is considered passive because it doesn’t submit authentication attempts, but here’s the critical gotcha: modules like Autologon, OAuth2, and RST actually perform authentication attempts, which increment lockout counters even during enumeration.

The spraying engine implements sophisticated lockout protection through a per-user attempt tracking system. When you execute a password spray, the tool maintains state about how many attempts each account has consumed:

python3 o365spray.py --spray -U valid_users.txt -P passwords.txt \
  --count 1 --lockout 3 --domain targetcorp.com --sleep 30

The --count parameter specifies attempts per lockout period, while --lockout defines the total lockout threshold (typically 3-6 for O365 tenants). The tool enforces a cooldown after each spray cycle using --sleep, and critically, it automatically waits for the authentication attempt counter to reset (default: 30 minutes for O365) between enumeration and spraying if you chain operations. This prevents the common mistake where testers enumerate users with OAuth2 (consuming one attempt per user), then immediately spray passwords without accounting for those consumed attempts.

The FireProx integration showcases advanced evasion architecture. FireProx creates AWS API Gateway endpoints that proxy requests to O365, rotating source IPs with each request:

python3 o365spray.py --spray -U users.txt -p 'Winter2024!' \
  --fireprox https://abc123.execute-api.us-east-1.amazonaws.com/fireprox \
  --rate 10 --jitter 2

When FireProx is enabled, each authentication request originates from different AWS IP ranges, defeating IP-based rate limiting. The --rate parameter controls concurrent connections (threads), while --jitter adds random delays between requests (0-2 seconds in this example). This combination makes traffic patterns appear less automated. The tool also rotates through 4,800+ user-agent strings to avoid fingerprinting.

The codebase uses Python’s concurrent.futures.ThreadPoolExecutor for parallelization, with custom rate limiting logic that tracks requests per second across all threads. Each module inherits from a base class that implements shared functionality for HTTP client configuration, proxy rotation, and response parsing. The modular design means when Microsoft patches one endpoint, developers can quickly add new modules targeting alternative authentication flows without refactoring the core spraying logic.

One particularly clever implementation detail is the automatic detection of federated domains. When you spray passwords against a federated tenant without password synchronization enabled, o365spray detects the federated authentication responses and can automatically switch from OAuth2 spraying to ADFS spraying, targeting the on-premise federation server instead of the cloud endpoint.

Gotcha

The most dangerous misunderstanding about o365spray involves the enumeration modules. Not all enumeration is passive reconnaissance. The Autologon, OAuth2, and RST modules submit actual authentication attempts with blank or test passwords, meaning they consume one lockout attempt per user. If you enumerate 5,000 users with the OAuth2 module (which performs an authentication attempt to differentiate valid from invalid accounts), then immediately spray passwords, you’re actually on attempt number two for each user—not attempt one. With O365’s typical three-attempt lockout threshold, you only get one real password spray before triggering lockouts. The tool’s automatic 30-minute wait between operations mitigates this when running enumeration and spraying in a single command, but if you run them separately, you must manually wait for the counter reset or risk locking out the entire organization.

The OneDrive enumeration module has a significant false negative rate. It checks whether a user’s OneDrive URL (https://targetcorp-my.sharepoint.com/personal/username_targetcorp_com) is accessible, which only works for users who have logged into OneDrive at least once. New accounts, accounts that exclusively use other O365 services, or users who haven’t accessed OneDrive will show as invalid even though they’re legitimate usernames. Similarly, the OAuth2 federated spraying module only succeeds when password hash synchronization is enabled on the tenant—if the organization uses pure federated authentication without sync, all password attempts fail regardless of validity because authentication gets redirected to the on-premise ADFS server. The tool doesn’t always clearly indicate why attempts are failing in these edge cases, potentially leading to incorrect conclusions about credential validity.

Verdict

Use if you’re conducting authorized penetration tests or red team engagements against Microsoft 365 environments and need robust username enumeration or password spraying capabilities with built-in lockout protection. The multi-module architecture provides resilience when Microsoft patches specific endpoints, and the FireProx integration offers genuine IP rotation for evasion. The tool excels when you understand O365 lockout mechanics and can carefully orchestrate enumeration-to-spraying workflows. Skip if you lack explicit authorization (this tool generates detectable authentication traffic and can lock out thousands of accounts), need completely passive reconnaissance (several modules trigger authentication attempts), or are assessing non-O365 platforms. Also skip if you want a point-and-click experience—o365spray requires understanding lockout thresholds, authentication attempt counting, and federation configurations to use safely. Consider the successor project Omnispray if you need to spray passwords across multiple platforms (AWS, Okta, etc.) beyond just O365, or use MSOLSpray if you’re already working from a Windows environment and want PowerShell-native tooling.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/cybersecurity/0xzdh-o365spray.svg)](https://starlog.is/api/badge-click/cybersecurity/0xzdh-o365spray)