<reponame>procter-gamble-tech/pentest-report
#!/usr/bin/python3
from StateAction import StateAction
import paramiko
import socket
import argparse

class SSHExec(StateAction):
    """ Runs an ssh command on all user/hosts """

    def __init__(self, cmd_list, cmd_name, mode='foreach_host', users=None):
        """ cmd list - these commands will be run over SSH """
        """ cmd_name - under this alias the joint result of all commands will be stored in db (e.g. "shadow search"). You'll use it for search later. Two command lists of identical name will not be repeated."""
        """ mode - 'foreach_userhost': run once per host, 'foreach_host': run once per user/host """

        if(mode != 'foreach_userhost' and mode != 'foreach_host'):
            raise ValueError()

        if(mode == 'foreach_host'):
            super().__init__('ssh_exec', ['host', 'port', 'username', 'password', 'cmd_name'], ['host', 'cmd_name'])
        if(mode == 'foreach_userhost'):
            super().__init__('ssh_exec', ['host', 'port', 'username', 'password', 'cmd_name'], ['host', 'username', 'cmd_name'])

        self.cmd_list = cmd_list
        self.cmd_name = cmd_name
        self.users = users

    def emit(self):
        userhosts = list(self.utils.knowledge.find({'type': 'state_action', 'subtype': 'result', 'result.status': 1, 'pentest_id': self.utils.pentest_id, 'name': 'ssh_scanner'}))
        userhosts = self.strip_list(userhosts,['input.host', 'input.port', 'input.username', 'input.password'])

        userhostcommand = [{**uh, **{'cmd_list':self.cmd_list, 'cmd_name': self.cmd_name}} for uh in userhosts if (self.users==None or uh['username'] in self.users)]

        # print(str(userhostcommand))
        return userhostcommand

    def work(self, params):

        target_ssh=paramiko.SSHClient()
        # tell the ssh client to automatically add any missing keys
        target_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        try:
            # connect to the target box via ssh
            print("Connecting to {} as {}/{}".format(params['host'], params['username'], params['password']))
            target_ssh.connect(params['host'],username=params['username'],password=params['password'])
            # chan = target_ssh.get_transport().open_session()

            commands = params['cmd_list']
            results = []
            #if no errors, execute commands on the target
            for command in commands:
                try:
                    # if target_ssh.get_transport().is_active():
                        # NOTE THE TIMEOUT !!!
                        stdin, stdout, stderr = target_ssh.exec_command(command, timeout=60.0)
                        print("Executing `{}`".format( command ))

                        stdoutstr = stdout.read().strip().decode()
                        stderrstr = stderr.read().strip().decode()
                        print("Result: ")
                        print(stdoutstr)
                        print(stderrstr)
                        results.append({'cmd': command, 'stdout': stdoutstr, 'stderr': stderrstr, 'exit_status': stdout.channel.recv_exit_status()})

                except (Exception) as g:
                    print(g)
                    return {'status':2, 'exception': str(g)}
                    pass

            # Close the target ssh session - this would be faster if you looped before closing
            target_ssh.close()

            last_exit_status = stdout.channel.recv_exit_status()
            return {'status': 1 if last_exit_status == 0 else 0, 'cmd_results': results, 'last_exit_status': last_exit_status}

        except (paramiko.BadHostKeyException, paramiko.AuthenticationException, paramiko.SSHException, socket.error) as e:
            print("Failed: {}".format(str(e)))
            return {'status':0, 'error': str(e)}
            pass

parser = argparse.ArgumentParser(description='Executes ssh commands against all known hosts / credentials')
parser.add_argument('-m', '--mode', dest='mode', type=str, default='foreach_host', choices=['foreach_host', 'foreach_userhost'], help="determines if you are interested in successful execution by any user or all users. E.g. 'id' is interesting for every user (foreach_userhost). 'uname -a' for any user (foreach_host). Default: foreach_host.")
parser.add_argument('-U', '--user', type=str, nargs='*', help='Connect only as a given username. Can provide many usernames (e.g. -U john tom alice)' )
parser.add_argument('name', type=str, help='command label. Used to check if identical command was not executed before' )
parser.add_argument('cmd', type=str, nargs='+', help='list of shell commands to be executed' )
parser.add_argument('-r', '--retry',  action='store_true', default=False, help='Rerun all, regardles of prior run or prior success.' )
parser.add_argument('-rr', '--remove-and-retry',  action='store_true', default=False, help='--retry, with additional removal of successful results from prior runs' )
args = parser.parse_args()
# print(args)

ssh = SSHExec(args.cmd, args.name, users=args.user)
ssh.run(retry=(args.retry or args.remove_and_retry) , retry_successful=(args.retry or args.remove_and_retry), remove_previous=args.remove_and_retry)

#!/usr/bin/python3
from StateAction import StateAction
import paramiko
import socket
import argparse

class SSHExec(StateAction):
    """ Runs an ssh command on all user/hosts """

    def __init__(self, cmd_list, cmd_name, mode='foreach_host', users=None):
        """ cmd list - these commands will be run over SSH """
        """ cmd_name - under this alias the joint result of all commands will be stored in db (e.g. "shadow search"). You'll use it for search later. Two command lists of identical name will not be repeated."""
        """ mode - 'foreach_userhost': run once per host, 'foreach_host': run once per user/host """

        if(mode != 'foreach_userhost' and mode != 'foreach_host'):
            raise ValueError()

        if(mode == 'foreach_host'):
            super().__init__('ssh_exec', ['host', 'port', 'username', 'password', 'cmd_name'], ['host', 'cmd_name'])
        if(mode == 'foreach_userhost'):
            super().__init__('ssh_exec', ['host', 'port', 'username', 'password', 'cmd_name'], ['host', 'username', 'cmd_name'])

        self.cmd_list = cmd_list
        self.cmd_name = cmd_name
        self.users = users

    def emit(self):
        userhosts = list(self.utils.knowledge.find({'type': 'state_action', 'subtype': 'result', 'result.status': 1, 'pentest_id': self.utils.pentest_id, 'name': 'ssh_scanner'}))
        userhosts = self.strip_list(userhosts,['input.host', 'input.port', 'input.username', 'input.password'])

        userhostcommand = [{**uh, **{'cmd_list':self.cmd_list, 'cmd_name': self.cmd_name}} for uh in userhosts if (self.users==None or uh['username'] in self.users)]

        # print(str(userhostcommand))
        return userhostcommand

    def work(self, params):

        target_ssh=paramiko.SSHClient()
        # tell the ssh client to automatically add any missing keys
        target_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        try:
            # connect to the target box via ssh
            print("Connecting to {} as {}/{}".format(params['host'], params['username'], params['password']))
            target_ssh.connect(params['host'],username=params['username'],password=params['password'])
            # chan = target_ssh.get_transport().open_session()

            commands = params['cmd_list']
            results = []
            #if no errors, execute commands on the target
            for command in commands:
                try:
                    # if target_ssh.get_transport().is_active():
                        # NOTE THE TIMEOUT !!!
                        stdin, stdout, stderr = target_ssh.exec_command(command, timeout=60.0)
                        print("Executing `{}`".format( command ))

                        stdoutstr = stdout.read().strip().decode()
                        stderrstr = stderr.read().strip().decode()
                        print("Result: ")
                        print(stdoutstr)
                        print(stderrstr)
                        results.append({'cmd': command, 'stdout': stdoutstr, 'stderr': stderrstr, 'exit_status': stdout.channel.recv_exit_status()})

                except (Exception) as g:
                    print(g)
                    return {'status':2, 'exception': str(g)}
                    pass

            # Close the target ssh session - this would be faster if you looped before closing
            target_ssh.close()

            last_exit_status = stdout.channel.recv_exit_status()
            return {'status': 1 if last_exit_status == 0 else 0, 'cmd_results': results, 'last_exit_status': last_exit_status}

        except (paramiko.BadHostKeyException, paramiko.AuthenticationException, paramiko.SSHException, socket.error) as e:
            print("Failed: {}".format(str(e)))
            return {'status':0, 'error': str(e)}
            pass

parser = argparse.ArgumentParser(description='Executes ssh commands against all known hosts / credentials')
parser.add_argument('-m', '--mode', dest='mode', type=str, default='foreach_host', choices=['foreach_host', 'foreach_userhost'], help="determines if you are interested in successful execution by any user or all users. E.g. 'id' is interesting for every user (foreach_userhost). 'uname -a' for any user (foreach_host). Default: foreach_host.")
parser.add_argument('-U', '--user', type=str, nargs='*', help='Connect only as a given username. Can provide many usernames (e.g. -U john tom alice)' )
parser.add_argument('name', type=str, help='command label. Used to check if identical command was not executed before' )
parser.add_argument('cmd', type=str, nargs='+', help='list of shell commands to be executed' )
parser.add_argument('-r', '--retry',  action='store_true', default=False, help='Rerun all, regardles of prior run or prior success.' )
parser.add_argument('-rr', '--remove-and-retry',  action='store_true', default=False, help='--retry, with additional removal of successful results from prior runs' )
args = parser.parse_args()
# print(args)

ssh = SSHExec(args.cmd, args.name, users=args.user)
ssh.run(retry=(args.retry or args.remove_and_retry) , retry_successful=(args.retry or args.remove_and_retry), remove_previous=args.remove_and_retry)
#!/usr/bin/python3 Runs an ssh command on all user/hosts cmd list - these commands will be run over SSH cmd_name - under this alias the joint result of all commands will be stored in db (e.g. "shadow search"). You'll use it for search later. Two command lists of identical name will not be repeated. mode - 'foreach_userhost': run once per host, 'foreach_host': run once per user/host # print(str(userhostcommand)) # tell the ssh client to automatically add any missing keys # connect to the target box via ssh # chan = target_ssh.get_transport().open_session() #if no errors, execute commands on the target # if target_ssh.get_transport().is_active(): # NOTE THE TIMEOUT !!! # Close the target ssh session - this would be faster if you looped before closing # print(args)