Skip to content

Latest commit

 

History

History
176 lines (129 loc) · 6.97 KB

File metadata and controls

176 lines (129 loc) · 6.97 KB

Paramiko

A pure-Python implementation of the SSHv2 protocol for scripting remote command execution, SFTP file transfer, and tunnelling.

Overview

Paramiko lets you open SSH sessions, run commands, and move files programmatically without shelling out to the ssh binary. It underpins tools like Fabric and Ansible's connection layer. In security and administration work it is used to automate post-exploitation actions on authorized hosts, mass-manage servers, transfer tooling, and — carefully — test SSH authentication controls.

Installation

pip install paramiko

Basic Usage

import os

import paramiko

client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.RejectPolicy())    # never AutoAddPolicy

try:
    client.connect(
        hostname="127.0.0.1",
        username=os.environ["LAB_SSH_USER"],
        key_filename=os.environ["LAB_SSH_KEY"],
        timeout=10,
    )
    stdin, stdout, stderr = client.exec_command("id")
    print(stdout.read().decode().strip())
    print("exit status:", stdout.channel.recv_exit_status())
finally:
    client.close()

Credentials come from the environment, and unknown host keys are rejected rather than silently trusted.

Important APIs

API Purpose
paramiko.SSHClient() High-level client
client.load_system_host_keys() Load ~/.ssh/known_hosts
client.set_missing_host_key_policy(policy) RejectPolicy (safe), WarningPolicy, AutoAddPolicy (unsafe)
client.connect(hostname, username, key_filename=, password=, timeout=) Establish the session
client.exec_command(cmd) Returns (stdin, stdout, stderr)
stdout.channel.recv_exit_status() The command's exit code
client.open_sftp() SFTP client for file transfer
sftp.get(remote, local) / sftp.put(local, remote) Transfer files
paramiko.RSAKey.from_private_key_file(path, password=) Load a key explicitly
paramiko.AuthenticationException / SSHException Error types to catch
client.close() Release the connection

Example

Run a command over SSH and capture output:

import paramiko

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
client.connect("192.168.56.10", username="tester", password="Passw0rd!", timeout=10)

stdin, stdout, stderr = client.exec_command("uname -a && id")
print(stdout.read().decode())
client.close()

Output

Linux target 6.1.0-amd64 #1 SMP x86_64 GNU/Linux
uid=1000(tester) gid=1000(tester) groups=1000(tester)

Transfer a file with SFTP:

import paramiko

transport = paramiko.Transport(("192.168.56.10", 22))
transport.connect(username="tester", password="Passw0rd!")
sftp = paramiko.SFTPClient.from_transport(transport)

sftp.put("enum.sh", "/tmp/enum.sh")          # upload a tool
sftp.get("/etc/hostname", "remote_hostname") # download evidence
print("files on /tmp:", sftp.listdir("/tmp"))

sftp.close()
transport.close()

Output

files on /tmp: ['enum.sh', 'systemd-private-...']

Authenticate with a private key instead of a password:

import paramiko

key = paramiko.RSAKey.from_private_key_file("id_rsa")
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
client.connect("192.168.56.10", username="tester", pkey=key)

_, stdout, _ = client.exec_command("hostname")
print("connected to:", stdout.read().decode().strip())
client.close()

Output

connected to: target

Security Use Cases

  • SSH automation — run enumeration or configuration commands across many authorized hosts from one script.
  • Post-exploitation tasking — after gaining valid credentials, script cleanup, evidence collection, or lateral movement on in-scope systems.
  • Secure file transfer — push tooling and pull loot/evidence via SFTP without extra binaries on the target.
  • Credential-control testing — validate key-vs-password policy and account lockout behaviour against systems you are authorized to test.
  • Tunnelling / pivoting — build port forwards through a compromised jump host for reaching internal segments.

Warning

Use valid, authorized credentials only. Automated login attempts against systems you don't control can constitute unauthorized access.

Common Mistakes

  • Using AutoAddPolicy() — this accepts any host key, silently defeating the protection against man-in-the-middle attacks.
  • Ignoring the exit statusexec_command succeeds even when the remote command fails; check recv_exit_status().
  • Not reading stderr, so remote errors vanish.
  • Deadlocking on large output — read stdout before waiting on the exit status.
  • Hardcoding passwords or key passphrases in the source.
  • Forgetting client.close(), leaking connections.
  • Omitting timeout=, so an unresponsive host hangs the script.
  • Building remote commands by string interpolation — the remote shell interprets metacharacters, so this is command injection.

Security Considerations

[!warning] Authorized use only Connect only to hosts you own or are explicitly authorized to administer or test.

  • AutoAddPolicy is the critical mistake here. It trusts whatever key the server presents, so an attacker who can intercept the connection can transparently proxy your session and capture credentials. Use RejectPolicy and manage known_hosts deliberately.
  • Never hardcode credentials. Read usernames, passwords, and key paths from environment variables or a secrets manager; a key committed to a repository must be treated as compromised.
  • Prefer key authentication over passwords, and protect private keys with a passphrase and 0600 permissions.
  • Remote command construction is injection-prone. Anything interpolated into exec_command() reaches a shell — validate against an allowlist, or use SFTP and structured operations instead.
  • Sessions are privileged. A compromised automation host with stored keys is a path into every system it can reach; scope keys narrowly and use command= restrictions in authorized_keys.
  • Log connections and commands so automated administration remains auditable.

Best Practices

  • Avoid AutoAddPolicy in real assessments — use WarningPolicy() or pin known host keys to detect MITM.
  • Prefer key-based auth (RSAKey/Ed25519Key) over embedding passwords in scripts.
  • Always set timeout= and close clients/transports in a try/finally.
  • Read stderr as well as stdout; exit status is in stdout.channel.recv_exit_status().
  • Store credentials in environment variables or a secrets manager, never hard-coded.

References

Related Topics

  • [[pwntools]] — its ssh tubes cover exploit-oriented SSH work
  • [[psutil]] — inventory the hosts you manage over SSH
  • [[Readme|Python for Security Professionals]] — course home