Threat Overview
Proofpoint disclosed an active TeamFiltration campaign tracked as UNK_CondorFiltration that targeted more than 5,700 Microsoft 365 accounts across 28 tenants. The campaign used 1,487 unique AWS EC2 source IP addresses. Seven accounts were successfully compromised. All seven were unmanaged functional or service accounts with no prior legitimate login baseline, default or unrotated passwords, and no MFA. Proofpoint observed post-compromise access from a German VPN node, attempted corporate VPN authentication, and access to OfficeHome, Azure Portal, and SharePoint Online.
References
- Proofpoint, September 22, 2026 – https://www.proofpoint.com/us/blog/threat-insight/Spraying-in-the-Andes-TeamFiltration-Returns
- The Hacker News, September 24, 2026 – TeamFiltration Campaign Compromises Seven Microsoft 365 Accounts Using Default Passwords
Impacted Systems
Microsoft 365 and Microsoft Entra ID tenants, especially functional, shared, service, or other non-human accounts that retain default or predictable passwords, have no MFA, or lack a normal interactive sign-in baseline. Proofpoint observed AWS EC2 attack infrastructure and later access from a German VPN node.
Why this matters
The campaign demonstrates a common identity gap: service and functional accounts can remain outside normal MFA and lifecycle controls. Successful password spraying can transition directly into Microsoft 365, Azure Portal, SharePoint, and potentially corporate VPN access without endpoint malware.
Exploitation Status
Confirmed active campaign. Proofpoint observed more than 5,700 targeted accounts across 28 tenants and seven successful compromises. The reported waves occurred from late July through August 2026.
What this hunt looks for
Distributed failed sign-ins, successful authentication after repeated failures, first-ever or rare interactive sign-ins, successful sign-ins without MFA, new source IPs, country changes, and access to Azure Portal, OfficeHome, or SharePoint Online.
Required logs
Microsoft Entra SigninLogs and AADNonInteractiveUserSignInLogs. Identity Protection telemetry can strengthen prioritization where available.
First Pass – Password Spray by IP
SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType != 0
| summarize FailedUsers=dcount(UserPrincipalName),Failures=count(),Users=make_set(UserPrincipalName,50) by IPAddress,bin(TimeGenerated,15m)
| where FailedUsers >= 10 and Failures >= 20
| order by FailedUsers desc,Failures descDistributed Spray Against Individual Accounts
SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType != 0
| summarize SourceIPs=dcount(IPAddress),Failures=count(),IPs=make_set(IPAddress,50) by UserPrincipalName,bin(TimeGenerated,1h)
| where SourceIPs >= 10 and Failures >= 20
| order by SourceIPs desc,Failures descSuccess After Repeated Failures
let Failures=SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType != 0
| summarize FailedAttempts=count(),FailureIPs=dcount(IPAddress),LastFailure=max(TimeGenerated) by UserPrincipalName;
SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType == 0
| join kind=inner Failures on UserPrincipalName
| where FailedAttempts >= 10 and TimeGenerated >= LastFailure
| project TimeGenerated,UserPrincipalName,IPAddress,AppDisplayName,ClientAppUsed,AuthenticationRequirement,ConditionalAccessStatus,FailedAttempts,FailureIPs,LastFailure
| order by TimeGenerated descSuccessful Sign-Ins Without MFA
SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType == 0
| where AuthenticationRequirement !~ "multiFactorAuthentication"
| project TimeGenerated,UserPrincipalName,IPAddress,Location,AppDisplayName,ClientAppUsed,AuthenticationRequirement,ConditionalAccessStatus,UserAgent
| order by TimeGenerated descFirst Seen Interactive Sign-In
let Baseline=SigninLogs
| where TimeGenerated between (ago(30d)..ago(7d))
| where ResultType == 0
| summarize by UserPrincipalName;
SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType == 0
| join kind=leftanti Baseline on UserPrincipalName
| project TimeGenerated,UserPrincipalName,IPAddress,Location,AppDisplayName,ClientAppUsed,AuthenticationRequirement,ConditionalAccessStatus
| order by TimeGenerated descNew Source IP for Account
let Baseline=SigninLogs
| where TimeGenerated between (ago(30d)..ago(7d))
| where ResultType == 0
| summarize by UserPrincipalName,IPAddress;
SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType == 0
| join kind=leftanti Baseline on UserPrincipalName,IPAddress
| project TimeGenerated,UserPrincipalName,IPAddress,Location,AppDisplayName,ClientAppUsed,AuthenticationRequirement
| order by TimeGenerated descAzure Portal OfficeHome and SharePoint Access
SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType == 0
| where AppDisplayName has_any ("Azure Portal","OfficeHome","SharePoint")
| project TimeGenerated,UserPrincipalName,IPAddress,Location,AppDisplayName,ClientAppUsed,AuthenticationRequirement,ConditionalAccessStatus
| order by TimeGenerated descNon-Interactive Service Account Failures
AADNonInteractiveUserSignInLogs
| where TimeGenerated >= ago(7d)
| where ResultType != 0
| summarize FailedIPs=dcount(IPAddress),Failures=count(),Apps=make_set(AppDisplayName,20) by UserPrincipalName,bin(TimeGenerated,1h)
| where FailedIPs >= 10 or Failures >= 20
| order by Failures descCountry Change on Successful Sign-In
SigninLogs
| where TimeGenerated >= ago(14d)
| where ResultType == 0
| extend Country=tostring(LocationDetails.countryOrRegion)
| summarize Countries=make_set(Country,10),CountryCount=dcount(Country),IPs=make_set(IPAddress,20),Apps=make_set(AppDisplayName,20) by UserPrincipalName
| where CountryCount >= 2
| order by CountryCount descDetection Notes
The primary signal is behavioral, not a static IOC list. Proofpoint observed 1,487 AWS EC2 source IPs, so IP blocking alone is insufficient. Functional and service accounts may legitimately use non-interactive flows, making account role and historical baseline important. Correlate no-MFA successes with Conditional Access and the account’s intended authentication model.