1

I am trying to write a Python 3 script to pragmatically ssh into a Linux server and change the password. I have put a script together using the Paramiko module.

I am running into issues when trying to run multiple shell commands. My script attempts to execute the commands but Paramiko times out after one shell command.

This is the script I am currently working on. Any insight would be greatly appreciated.

import paramiko

def change_pw():
    hostname = "IP" #IP Address of Linux Server
    username = "root" #username
    password = "oldpw!" #password for Linux Server

#NOTE - This variable is suppose to define 3 shell commands. I do not believe the script is sending these commands as listed because the password does not update.
    commands = [
        "passwd",
        "newpw!",
        "newpw!"
    ]

#NOTE - Attempted to utilize '\n' to execute multiple commands and failed
    # commands = [
    #     "passwd \n newpw! \n newpw!"
    # ]

    # initialize the SSH clientp0-
    client = paramiko.SSHClient()
    # add to known hosts
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
        client.connect(hostname=hostname, username=username, password=password)
    except:
        print("[!] Cannot connect to the SSH Server")
        exit()

    # execute the commands
    for command in commands:
        print("="*50, command, "="*50)
        stdin, stdout, stderr = client.exec_command(command)
        print(stdout.read().decode())
        err = stderr.read().decode()
        if err:
            print(err)

change_pw()
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992

2 Answers2

1

You do not have three commands. You have one command, the passwd, which takes two lines of input.

These two questions show how to provide an input to commands using Paramiko:

So specifically for passwd, you need to use:

stdin, stdout, stderr = client.exec_command('passwd')
# answer the new password prompts
stdin.write('newpw\n')
stdin.write('newpw\n')
stdin.flush()
# wait for the command to complete a print the output
stdout.channel.set_combine_stderr(True)
print(stdout.read().decode())

For the purpose of the Channel.set_combine_stderr, see Paramiko ssh die/hang with big output.


Obligatory warning: Do not use AutoAddPolicy – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
-1

The issue is that I was trying to utilize 3 input commands to change the password for root. I only needed to call the passwd command and then pass two input variables for "Enter new PW" and "Confirm new PW"

import paramiko
import time

hostname = 'IP'
username = 'root'
password = 'oldpw'


commands = ['passwd']



# initialize the SSH clientp
client = paramiko.SSHClient()
# add to known hosts
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
    client.connect(hostname=hostname, username=username, password=password)
except:
    print("[!] Cannot connect to the SSH Server")
    exit()

# execute the commands
for command in commands:
    print("="*50, 'PW change executed', "="*50)
    stdin, stdout, stderr = client.exec_command(command)
    stdin.write('newpw' '\n' 'newpw' '\n') #input varuables for "Enter new PW" and "re-enter new PW"
    stdin.flush()
    print(stdout.read().decode())
    err = stderr.read().decode()
    if err:
        print(err)
  • What's the point of `for command in commands`, if you call only one command? The loop is not designed to ever work for multiple commands, as the code is tailored to `passwd` only. + Do not use `AutoAddPolicy` this way, it's a security flaw. – Martin Prikryl Mar 23 '21 at 06:49