pypsrp

repository·master·Indexed 18 days ago

https://github.com/jborean93/pypsrp

A Python client library for the PowerShell Remoting Protocol (PSRP) and Windows Remote Management (WinRM). It enables Python applications to execute commands, run PowerShell scripts, and manage remote Windows hosts via WSMan transport. The library provides four API layers: a Simple Client API for common tasks, a WSMan Interface for raw calls, a Windows Remote Shell (WinRS) layer for cmd commands, and a PSRP layer for managing PowerShell pipelines and Runspace Pools.

Tokens
18K
Snippets
52
Records
79
Agent score
63%

What's inside pypsrp

  1. Overview of pypsrp APIs and capabilities

    master

    pypsrp is a Python client for the PowerShell Remoting Protocol (PSRP) and Windows Remote Management (WinRM) service. It allows executing commands on remote Windows hosts from any machine running Python.

    The library provides four distinct API layers:

    1. Simple Client API: For copying files (to/from remote), executing processes, and running PowerShell scripts.
    2. WSMan Interface: For executing WSMan calls such as Send, Create, Connect, and Disconnect.
    3. Windows Remote Shell (WinRS) Layer: For executing cmd commands and executables using the WinRM protocol.
    4. PowerShell Remoting Protocol (PSRP) Layer: For creating remote Runspace Pools and managing PowerShell pipelines.

    Core capabilities include executing cmd commands, running executables, running PowerShell scripts, file transfers, and creating asynchronous Runspace Pools containing one or multiple PowerShell pipelines.

  2. How pypsrp components work together

    master

    The library is organized into three main layers that handle the lifecycle of a remote command:

    1. Transport: Manages the raw message exchange between the client and the server.
    2. Shell: Implements the protocol details (WSMan or PSRP) to establish a remote session. It uses a Connection to transmit instructions.
    3. Process: The execution layer that runs specific scripts or executables within the established shell.

    Depending on your needs, you can use the high-level Client API for simplicity, or manually compose WSMan connections with WinRS (for cmd/executables) or RunspacePool (for PowerShell/PSRP) shells.

  3. Configure logging for pypsrp

    master

    The library uses standard Python logging. Messages are sent to the pypsrp named logger and pypsrp.* loggers for individual scripts.

    To enable easy logging for the entire library, create a JSON configuration file (e.g., log.json) and run your script with the PYPSRP_LOG_CFG environment variable set to the path of that file.

    Warning: Setting the log level to DEBUG will output all messages sent to and from the client, which may leak sensitive information. Use DEBUG only for troubleshooting.

    PYPSRP_LOG_CFG=log.json python script.py

    Example log.json configuration:

    {
        "version": 1,
        "disable_existing_loggers": false,
        "formatters": {
            "simple": {
                "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
            }
        },
        "handlers": {
            "console": {
                "class": "logging.StreamHandler",
                "level": "DEBUG",
                "formatter": "simple",
                "stream": "ext://sys.stdout"
            }
        },
        "loggers": {
            "pypsrp": {
                "level": "DEBUG",
                "handlers": ["console"],
                "propagate": "no"
            }
        }
    }
  4. Execute commands using WinRS and Process

    master

    To run standard command-line executables (like cmd.exe or powershell.exe as a process), use the WinRS shell and the Process object.

    Workflow:

    1. Create a WSMan connection.
    2. Initialize a WinRS shell using the connection.
    3. Create a Process object with the desired executable and arguments.
    4. Call .invoke() to run synchronously, or use .begin_invoke(), .poll_invoke(), and .end_invoke() for asynchronous execution.

    Process properties:

    • stdout, stderr: Command output.
    • rc: Return code.
    from pypsrp.shell import Process, SignalCode, WinRS
    from pypsrp.wsman import WSMan
    
    wsman = WSMan("server", ssl=False, auth="basic", encryption="never", username="vagrant", password="vagrant")
    
    with wsman, WinRS(wsman) as shell:
        # Synchronous execution
        process = Process(shell, "dir")
        process.invoke()
    
        # Asynchronous execution
        process = Process(shell, "powershell", ["gci", "$pwd"])
        process.begin_invoke()
        process.poll_invoke()
        process.end_invoke()
  5. Set up a Vagrant environment for integration testing

    master

    Integration tests require a specific host setup. You can use Vagrant to automate this.

    1. Start the Vagrant box:
      vagrant up
    2. SSH into the box:
       ```bash
    vagrant ssh
    1. Inside the Vagrant box, run the following PowerShell commands to configure the session and certificates:
    Register-PSSessionConfiguration -Path "C:\Users\vagrant\Documents\JEARoleSettings.pssc" -Name JEARole -Force
    
    $sec_pass = ConvertTo-SecureString -String "vagrant" -AsPlainText -Force
    $credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "vagrant", $sec_pass
    $thumbprint = (Get-ChildItem -Path Cert:\LocalMachine\TrustedPeople)[0].Thumbprint
    
    New-Item -Path WSMan:\localhost\ClientCertificate `
        -Subject "vagrant@localhost" `
        -URI * `
        -Issuer $thumbprint `
        -Credential $credential `
        -Force

    After the environment is set up, use the following environment variables to run the integration tests:

    • PYPSRP_RUN_INTEGRATION: Set to any value to enable integration tests
    • PYPSRP_SERVER: 127.0.0.1
    • PYPSRP_USERNAME: vagrant
    • PYPSRP_PASSWORD: vagrant
    • PYPSRP_HTTP_PORT: 55985
    • PYPSRP_HTTPS_PORT: 55986
    • PYPSRP_CERT_DIR: The full path to the project directory
  6. Run tests against a real Windows host

    master

    You can run the test suite against a live Windows host by setting the following environment variables before execution:

    • PYPSRP_SERVER: The hostname or IP of the remote host
    • PYPSRP_USERNAME: The username to connect with
    • PYPSRP_PASSWORD: The password to connect with
    • PYPSRR_PORT: The port to connect with (default: 5986)
    • PYPSRP_AUTH: The authentication protocol to use (default: negotiate)
  7. Execute PowerShell scripts using RunspacePool and PowerShell

    master

    For full PowerShell functionality (PSRP protocol), use the RunspacePool shell and the PowerShell process object. This allows you to build complex pipelines using cmdlets, parameters, and scripts.

    Workflow:

    1. Create a WSMan connection.
    2. Initialize a RunspacePool shell.
    3. Initialize a PowerShell object using the pool.
    4. Build the command using methods like add_cmdlet(), add_argument(), add_parameter(), or add_script().
    5. Call .invoke() to execute.

    PowerShell methods for building commands:

    • add_script(script_text): Adds a raw script.
    • add_cmdlet(name): Adds a cmdlet to the pipeline.
    • add_parameter(key, value): Adds a parameter to the last added cmdlet.
    • add_argument(value): Adds a positional argument to the last added cmdlet.
    • add_statement(): Ends the current pipeline (like a newline) so the next command starts a new one.

    PowerShell properties:

    • output: The result of the execution.
    • streams: A dictionary containing different output streams (e.g., debug, error, warning).
    • had_errors: Boolean indicating if errors occurred.

    To reuse a PowerShell object, use .close(), .clear_streams(), or .clear_commands().

    from pypsrp.powershell import PowerShell, RunspacePool
    from pypsrp.wsman import WSMan
    
    wsman = WSMan("server", auth="kerberos", cert_validation=False)
    
    with wsman, RunspacePool(wsman) as pool, PowerShell(pool) as ps:
        # Building a pipeline: Get-Process | Select-Object -Property Name
        ps.add_cmdlet("Get-Process")
        ps.add_cmdlet("Select-Object")
        ps.add_parameter("Property", "Name")
        output = ps.invoke()
    
        # Adding a new statement (new pipeline)
        ps.add_statement()
        ps.add_cmdlet("Get-Service")
        ps.add_argument("audiosrc")
        ps.invoke()
  8. Install pypsrp with CredSSP authentication support

    master

    To enable CredSSP authentication, install the credssp extra:

    pip install pypsrp[credssp]

    If the installation fails, you may need to update your build tools:

    pip install -U pip setuptools

    Additionally, some system development packages might be required:

    • Debian/Ubuntu: apt-get install gcc python-dev
    • RHEL/CentOS: yum install gcc python-devel
    • Fedora: dnf install gcc python-devel
  9. Install pypsrp with basic features

    master

    To install the base version of pypsrp with standard features (supporting Basic, Certificate, and NTLM authentication via WSMan), use pip:

    pip install pypsrp

    Core Requirements:

    • CPython 3.10+
    • cryptography
    • pyspnego
    • requests
  10. Install pypsrp with Kerberos authentication support

    master

    Kerberos authentication is supported but requires additional system packages and Python libraries, especially on Linux.

    1. Install System Dependencies

    Depending on your Linux distribution, run the appropriate command:

    Debian/Ubuntu:

    # For Python 3
    apt-get install gcc python3-dev libkrb5-dev
    # To add NTLM support to GSSAPI SPNEGO
    apt-get install gss-ntlmssp

    RHEL/CentOS:

    yum install gcc python-devel krb5-devel
    # To add NTLM support to GSSAPI SPNEGO
    yum install gssntlmssp

    Fedora:

    dnf install gcc python-devel krb5-devel
    # To add NTLM support to GSSAPI SPNEGO
    dnf install gssntlmssp

    Arch Linux:

    pacman -S gcc krb5

    2. Install Python Package

    Once system dependencies are met, install the Kerberos extra:

    pip install pypsrp[kerberos]

    Note: Kerberos must be configured to communicate with your domain separately.

  11. Run the pypsrp test suite

    master

    To run the existing test suite, install the package in development mode with the [dev] extra and use pytest.

    pip install -e .[dev]
    
    python -m pytest \
        tests/tests_pypsrp \
        --verbose \
        --junitxml junit/test-results.xml \
        --cov pypsrp \
        --cov-report xml \
        --cov-report term-missing
  12. Understand PSRP Message types and destinations

    master

    The PSRP protocol uses specific identifiers to categorize messages and define their intended destination.

    Destinations

    • Destination.CLIENT (0x00000001): The message is intended for the client.
    • Destination.SERVER (0x00000002): The message is intended for the server.

    Message Types Messages are categorized by their function in the protocol lifecycle, such as session establishment (SESSION_CAPABILITY), runspace management (CREATE_PIPELINE, RUNSPACEPOOL_STATE), and data streaming (PIPELINE_INPUT, PIPELINE_OUTPUT, ERROR_RECORD).