GithubHelp home page GithubHelp logo

0xzdh / o365spray Goto Github PK

View Code? Open in Web Editor NEW
677.0 8.0 93.0 362 KB

Username enumeration and password spraying tool aimed at Microsoft O365.

License: MIT License

Python 100.00%
python python3 security security-tools enumeration pentest pentesting-tools password-spray

o365spray's Introduction

o365spray

o365spray is a username enumeration and password spraying tool aimed at Microsoft Office 365 (O365). This tool reimplements a collection of enumeration and spray techniques researched and identified by those mentioned in Acknowledgments.

For educational, authorized and/or research purposes only.

WARNING: The Autologon, oAuth2, and RST user enumeration modules work by submitting a single authentication attempt per user. If the modules are run in conjunction with password spraying in a single execution, o365spray will automatically reset the lockout timer prior to performing the password spray -- if enumeration is run alone, the user should be aware of how many and when each authentication attempt was made and manually reset the lockout timer before performing any password spraying.

Table of Contents

Usage

o365spray

Validate a domain is using O365:
o365spray --validate --domain test.com

Perform username enumeration against a given domain:
o365spray --enum -U usernames.txt --domain test.com

Perform password spraying against a given domain:
o365spray --spray -U usernames.txt -P passwords.txt --count 2 --lockout 5 --domain test.com

usage: o365spray [flags]

o365spray | Microsoft O365 User Enumerator and Password Sprayer -- v3.0.4

options:
  -h, --help            show this help message and exit

Target:
  -d DOMAIN, --domain DOMAIN
                        Target domain for validation, user enumeration, and/or
                        password spraying.

Actions:
  --validate            Run domain validation only.

  --enum                Run username enumeration.

  --spray               Run password spraying.

Credentials:
  -u USERNAME, --username USERNAME
                        Username(s) delimited using commas.

  -p PASSWORD, --password PASSWORD
                        Password(s) delimited using commas.

  -U USERFILE, --userfile USERFILE
                        File containing list of usernames.

  -P PASSFILE, --passfile PASSFILE
                        File containing list of passwords.

  --paired PAIRED       File containing list of credentials in username:password
                        format.

Password Spraying Configuration:
  -c COUNT, --count COUNT
                        Number of password attempts to run per user before resetting
                        the lockout account timer.
                        Default: 1

  -l LOCKOUT, --lockout LOCKOUT
                        Lockout policy's reset time (in minutes).
                        Default: 15 minutes

Module Configuration:
  --validate-module VALIDATE_MODULE
                        Specify which valiadtion module to run.
                        Default: getuserrealm

  --enum-module ENUM_MODULE
                        Specify which enumeration module to run.
                        Default: office

  --spray-module SPRAY_MODULE
                        Specify which password spraying module to run.
                        Default: oauth2

  --adfs-url ADFS_URL   AuthURL of the target domain's ADFS login page for password
                        spraying.

Scan Configuration:
  --sleep [-1, 0-120]   Throttle HTTP requests every `N` seconds. This can be randomized
                        by passing the value `-1` (between 1 sec and 2 mins).
                        Default: 0

  --jitter [0-100]      Jitter extends --sleep period by percentage given (0-100).
                        Default: 0

  --rate RATE           Number of concurrent connections (attempts) during
                        enumeration and spraying.
                        Default: 10

  --poolsize POOLSIZE   Maximum size of the ThreadPoolExecutor.
                        Default: 10000

  --safe SAFE           Terminate password spraying run if `N` locked accounts
                        are observed.
                        Default: 10

HTTP Configuration:
  --useragents USERAGENTS
                        File containing list of user agents for randomization.

  --timeout TIMEOUT     HTTP request timeout in seconds. Default: 25

  --proxy PROXY         HTTP/S proxy to pass traffic through
                        (e.g. http://127.0.0.1:8080).

  --proxy-url PROXY_URL
                        FireProx API URL.

Output Configuration:
  --output OUTPUT       Output directory for results and test case files.
                        Default: current directory

Debug:
  -v, --version         Print the tool version.

  --debug               Enable debug output.

Modules

Validation

  • getuserrealm (default)

Enumeration

  • autologon
  • oauth2 (default)
  • office
  • onedrive
  • rst

The onedrive module relies on the target user(s) having previously logged into OneDrive. If a valid user has not yet used OneDrive, their account will show as 'invalid'.

Spraying

  • activesync
  • adfs
  • autodiscover
  • autologon
  • oauth2 (default)
  • reporting
  • rst

The oAuth2 module can be used for federated spraying, but it should be noted that this will ONLY work when the target tenant has enabled password synchronization - otherwise authentication will always fail. The default mechanic is to default to the 'adfs' module when federation is identified.

FireProx Base URLs

Microsoft has made it more difficult to perform password spraying, so using tools like FireProx help to bypass rate-limiting based on IP addresses.

To use FireProx with o365spray, create a proxy URL for the given o365spray module based on the base URL tables below. The proxy URL can then be passed in via --proxy-url.

NOTE: Make sure to use the correct --enum-module or --spray-module flag with the base URL used to create the FireProx URL.

Enumeration

The 'tenant' value in the OneDrive URL is the domain name value that is provided via the --domain flag.

Module Base URL
autodiscover https://outlook.office365.com/
autologon https://autologon.microsoftazuread-sso.com/
oauth2 https://login.microsoftonline.com/
office https://login.microsoftonline.com/
rst https://login.microsoftonline.com/
onedrive https://<tenant>-my.sharepoint.com/

Spraying

Module Base URL
activesync https://outlook.office365.com/
adfs Currently not implemented
autodiscover https://autodiscover-s.outlook.com/
autologon https://autologon.microsoftazuread-sso.com/
oauth2 https://login.microsoftonline.com/
reporting https://reports.office365.com/
rst https://login.microsoftonline.com/

User Agent Randomization

User-Agent randomization is now supported and can be accomplished by providing a User-Agent file to the --useragents flag. o365spray includes an example file with 4,800+ agents via resc/user-agents.txt.

The agents in the example data set were collected from the following:

Omnispray

The o365spray framework has been ported to a new tool: Omnispray. This tool is meant to modularize the original enumeration and spraying framework to allow for generic targeting, not just O365. Omnispray includes template modules for enumeration and spraying that can be modified and leveraged for any target.

Acknowledgments

Author Tool/Research Link
gremwell o365enum: User enumeration via office.com without authentication o365enum
grimhacker office365userenum: ActiveSync user enumeration research and discovery. office365userenum / blog post
Raikia UhOh365: User enumeration via Autodiscover without authentication. UhOh365
dafthack MSOLSpray: Password spraying via MSOL MSOLSpray
byt3bl33d3r MSOLSpray: Python reimplementation Gist
nyxgeek onedrive_user_enum: OneDrive user enumeration onedrive_user_enum / blog post
Mr-Un1k0d3r adfs-spray: ADFS password spraying adfs-spray
Nestori Syynimaa AADInternals: oAuth2 and autologon modules AADInternals
Daniel Chronlund / xFreed0m Invoke-AzureAdPasswordSprayAttack / ADFSpray: Office 365 reporting API password spraying Invoke-AzureAdPasswordSprayAttack / ADFSpray
Optiv (Several Authors) Go365: RST user enumeration and password spraying module Go365
byt3bl33d3r SprayingToolkit: Code references SprayingToolkit
sensepost ruler: Code references Ruler

Bugs

If any bugs/errors are encountered, please open an Issue with the details (or a Pull Request with the proposed fix). See the section below for more information about using previous versions.

Using Previous Versions

If issues are encountered, try checking out previous versions prior to code rewrites:

# v1.3.7
git checkout e235abdcebad61dbd2cde80974aca21ddb188704

# v2.0.4
git checkout a585432f269a8f527d61f064822bb08880c887ef

o365spray's People

Contributors

0xzdh avatar macmod avatar verydamptowel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

o365spray's Issues

Problems with running Domain Validation

Whenever I am trying to start a spray it says that the Domains are not using O365 although they are provided in the Description as working. I then tried to validate them manually and the following error came up:

root@UnknownPC:~/o365spray# python3 o365spray -v -d portal.office.com
/usr/bin/python3: can't find 'main' module in '/root/o365spray/o365spray'

When running the spray command I get this error:

root@UnknownPC:~/o365spray# python3 o365spray.py --spray -U names.txt -P 10-million-password-list-top-1000000.txt -c 5 -d https://outlook.office365.com/

        *** O365 Spray ***

----------------------------------------<

version : 1.3.7
domain : https://outlook.office365.com/
spray : True
userfile : names.txt
passfile : 10-million-password-list-top-1000000.txt
count : 5 passwords/spray
lockout : 15.0 minutes
validate_type : getuserrealm
spray_type : activesync
rate : 10 threads
safe : 10 locked accounts
timeout : 25 seconds
output : .
start : 2023-05-27 00:49:30

----------------------------------------<

[*] Performing O365 validation for: https://outlook.office365.com/

[FAILED] The following domain is not using O365: https://outlook.office365.com/

I am running Ubuntu as WLS on my Windows 11 PC and have python 3 as well as o365spray installed.
Thanks for any help!

Run_in_executor pattern over the userlist in enumeration module eats up memory unpredictably with large lists

If you have a large list of likely users to enumerate with --enum, say more than 7 million (common when inferring emails from popular names in a country, for instance), o365spray will use tons of memory, more than 16GB in some cases (regardless of --enum-method).

This is likely due to this pattern of concurrency in o365spray/core/handlers/enumerator/modules/base.py:

        blocking_tasks = [
            self.loop.run_in_executor(
                self.executor,
                partial(
                    self._enumerate,
                    domain=domain,
                    user=user,
                    password=password,
                ),
            )
            for user in userlist
        ]

        if blocking_tasks:
            await asyncio.wait(blocking_tasks)

If there was a concurrency limit of some sort, such as what is suggested here, I suspect this wouldn't happen. This limit could be set to a sufficiently high value like 10000 by default to mitigate this issue for large wordlists and also prevent performance impacts for smaller wordlists. It could also be configurable in an argument for better flexibility.

ModuleNotFoundError: No module named 'o365spray'

o365spray --validate --domain test.com --proxy-url https://127.0.0.1:8080

Traceback (most recent call last):
File "", line 198, in _run_module_as_main
File "", line 88, in _run_code
File "/home/kali/Desktop/tools/o365spray/o365spray/main.py", line 11, in
from o365spray import version
ModuleNotFoundError: No module named 'o365spray'

Issue after running the installation in the following way

git clone https://github.com/0xZDH/o365spray.git
cd o365spray
pip install -r requirements.txt

Setup install broken

When installing the tool via setuptools using: python setup.py install - the installation is broken via: ModuleNotFoundError: No module named 'o365spray.core'.

Object\Attribute Error

Currently trying to test password spraying and having the following error when I run a spray using both the autodiscover and MSOL modules. Activesync module works fine.

Command-line

python o365spray.py --spray -u USER@DOMAIN --domain DOMAIN.onmicrosoft.com -p PASSWDTEST1 --spray-module autodiscover --debug --proxy http://127.0.0.1:8080

OR

python o365spray.py --spray -u USER@DOMAIN --domain DOMAIN.onmicrosoft.com -p PASSWDTEST1 --spray-module msol --debug --proxy http://127.0.0.1:8080

Debug output

[2021-07-30 13:18:19,753] INFO  -       __main__.py:233  - Running O365 validation for: DOMAIN
[2021-07-30 13:18:19,755] DEBUG - connectionpool.py:973  - Starting new HTTPS connection (1): login.microsoftonline.com:443
[2021-07-30 13:18:20,111] DEBUG - connectionpool.py:452  - https://login.microsoftonline.com:443 "GET /getuserrealm.srf?login=user@DOMAIN&xml=1 HTTP/1.1" 200 451
[2021-07-30 13:18:20,112] INFO  -       __main__.py:263  - [VALID] The following domain is using O365: DOMAIN
[2021-07-30 13:18:20,112] DEBUG - selector_events.py:59   - Using selector: EpollSelector
[2021-07-30 13:18:20,113] INFO  -       __main__.py:451  - Running password spray against 1 users.
[2021-07-30 13:18:20,113] INFO  -       __main__.py:497  - Password spraying the following passwords: ['PASSWDTEST1']
[2021-07-30 13:18:20,113] DEBUG -        sprayer.py:375  - 'Sprayer' object has no attribute 'helper'
[2021-07-30 13:18:20,114] INFO  -        sprayer.py:136  - 

This is using the latest version. Any ideas what is causing this or if I am doing something wrong?

Feature Request: Safe Mode

Hey! This tool is awesome. I’ve been using it on engagements and it works great. One feature that I’d love would be a --safe flag that halts spraying if a user-defined number of accounts sequentially return the LOCKED OUT status. Would it be possible to add something like that in?

Ignore comment lines in user file

I apologize in advance, I am not a git pro, I don't know how to pull/branch yet; I will learn, but I need to get back to my pentest first. Below I have a change suggestion to ignore lines in the userlist file that start with a comment (#). Use case: I start with a list, and as I find invalid usernames, etc, I like to keep them in the list, but comment them out with some reason why. I considered it for the password file as well, but a password starting with # is possible. I also considered using some form of line.partition("#")[0] to catch it anyplace in the line, but again it may be potentially valid for a password.

I modified modules/generate/helpers.py as follows (just add the if check):

def get_users(conf: Configuration) -> list[str]:
    user_list: list[str] = []
    for line in conf.user_file:
        line = line.rstrip()
        if line[0] == "#":
            continue
        user_list.append(line)
    return user_list

Thanks for your work, I will attempt to contribute more effectively!

Spraying doesn't start due to UnicodeDecodeError

I have replaced URLs with REDACTED due to privacy concerns. Please tell me if this prevents my issue from being solved.

Command line input and output:

user@pop-os:~/Downloads/o365spray$ python3 o365spray.py --spray -U ../../users.txt -P ../rockyou.txt --count 2 --domain REDACTED

            *** O365 Spray ***            

>----------------------------------------<

   > version        :  3.0.0
   > domain         :  REDACTED
   > spray          :  True
   > userfile       :  ../../users.txt
   > passfile       :  ../rockyou.txt
   > count          :  2 passwords/spray
   > lockout        :  15.0 minutes
   > validate_module:  getuserrealm
   > spray_module   :  oauth2
   > rate           :  10 threads
   > safe           :  10 locked accounts
   > timeout        :  25 seconds
   > start          :  2022-09-29 16:47:37

>----------------------------------------<

[2022-09-29 16:47:37,905] [info] Validating: REDACTED
[2022-09-29 16:47:38,414] [info] [WARNING] The following domain appears to be using O365, but is Federated: REDACTED
	[!] --> ADFS AuthURL: REDACTED
[2022-09-29 16:47:38,414] [info] 

[ ? ]	Switch to the ADFS module for password spraying [Y/n] n
Traceback (most recent call last):
  File "/home/user/Downloads/o365spray/o365spray.py", line 6, in <module>
    main()
  File "/home/user/Downloads/o365spray/o365spray/__main__.py", line 272, in main
    spray(args, output_directory, enum)
  File "/home/user/Downloads/o365spray/o365spray/core/handlers/sprayer/spray.py", line 39, in spray
    passlist += Helper.get_list_from_file(args.passfile)
  File "/home/user/Downloads/o365spray/o365spray/core/utils/helper.py", line 135, in get_list_from_file
    list_ = [line.strip() for line in f if line.strip() not in [None, ""]]
  File "/home/user/Downloads/o365spray/o365spray/core/utils/helper.py", line 135, in <listcomp>
    list_ = [line.strip() for line in f if line.strip() not in [None, ""]]
  File "/usr/lib/python3.10/codecs.py", line 322, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf1 in position 923: invalid continuation byte

Thank you in beforehand!

Doesn't work with Python 3.9+

Hi!

While trying to run o365spray, following bit crashes:

PS C:\o365spray> py .\o365spray.py --help
Traceback (most recent call last):
  File "C:\data\tools\__Azure\o365spray\o365spray.py", line 4, in <module>
    from o365spray.__main__ import main  # type: ignore
  File "C:\data\tools\__Azure\o365spray\o365spray\__main__.py", line 14, in <module>
    from o365spray.core import (  # type: ignore
  File "C:\data\tools\__Azure\o365spray\o365spray\core\__init__.py", line 8, in <module>
    from o365spray.core.handlers import Enumerator  # type: ignore
  File "C:\data\tools\__Azure\o365spray\o365spray\core\handlers\__init__.py", line 1, in <module>
    from o365spray.core.handlers.enumerator import Enumerator  # type: ignore
  File "C:\data\tools\__Azure\o365spray\o365spray\core\handlers\enumerator.py", line 37, in <module>
    class Enumerator(BaseHandler):
  File "C:\data\tools\__Azure\o365spray\o365spray\core\handlers\enumerator.py", line 45, in Enumerator
    loop: asyncio.base_events._UnixSelectorEventLoop,
AttributeError: module 'asyncio.base_events' has no attribute '_UnixSelectorEventLoop'

Could you please look into this?

Regards,
Mariusz

Add additional code indicating Password was fine, but Conditional Access Policy thwarted attempt

Hi,

This issue is similar to MSOLspray's one.

During our tests we've found, that when sprayed User with a correct password - attempt failed due to Conditional Access Policy requirements, following error code will be thrown:

AADSTS53003: Access has been blocked by Conditional Access policies. The access policy does not allow
token issuance.

error_uri: https://login.microsoft.com/error?code=53003
https://login.microsoft.com/error?code=53003%22,%22suberror%22:%22message_only%22%7D

Whereas the same attempt with a wrong password brings no such error.

The conclusion is that AADSTS53003 error code indicates correct password, but CAP getting into way.
I guess it's worth adding corresponding logic to handle that :)

Regards,
Mariusz.

Safe/lockout is not used when using a paired list

In the code:

        if args.paired:
            logging.info("Password spraying using paired usernames:passwords.")

            loop.run_until_complete(spray.run(passlist))
            # Note: Since we are pairing usernames and passwords, we can ignore the
            #       lockout reset wait call as we should only be running a single
            #       cycle

The note is not true in all cases, if the paired list contains multiple passwords for the same user, the lockout policy should still be used. e.g.

alice:qwerty
bob:password123
bob:bobisthebest

AttributeError: module 'o365spray' has no attribute '__version__'

Installing with Python 3.9.2, pipx 1.1.0 and pip 20.3.4 results in the error message AttributeError: module 'o365spray' has no attribute '__version__', additionally the SetuptoolsDeprecationWarning: The license_file parameter is deprecated, use license_files instead. warning is displayed.

Used command pipx install git+https://github.com/0xZDH/o365spray.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.