1

I am able to give the following command in the command-line

C:\>cd "C:\Program Files\ExtraPuTTY\Bin"

C:\Program Files\ExtraPuTTY\Bin>putty.exe -ssh [email protected] 22

This helps me open the SSH session through PuTTY.

Whereas I am not able to reproduce them in the Python script.

cwd="C://Program Files//ExtraPuTTY//Bin"
COMMAND="ls"
ssh = Popen(['putty.exe -ssh','%s'%HOST, COMMAND,cwd],shell=True,stdout=f,stderr=f)

The error that I see is

"putty.exe -ssh"' is not recognized as an internal or external command,operable program or batch file

3 Answers 3

3

In the putty download page, download and install plink, and make sure its in the windows path ($PATH variable)

Then, this python snippet should work:

import subprocess
cmd='plink -ssh {}@{} -pw {}'.format(user,server,password)
sp = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True)
sp.stdin.write(stdin)
sp.stdin.close()
stdout= sp.stdout.read()
stderr=sp.stderr.read()
sp.wait()

stdin is the commands typed by the user in the terminal, stdout and stderr are the server output.

Fill in your credentials in the user="root", server="172.20.0.102 22" and maybe password for the ssh connection

Sign up to request clarification or add additional context in comments.

3 Comments

It's much better to set up SSH keys than to give a password as a command to an executable.
I agree. Since plink supports also command-line password auth, I added this option to the code snippet.
Your code may deadlock if pipes on Windows have a limited buffer (like on Unix). If you want to pass input as a string or get stdout, stderr as a string then you should use .communicate() method instead.
1

You have to pass the cwd as the cwd parameter of the Popen:

Popen(['putty.exe -ssh'...], shell=True, stdout=f, stderr=f, cwd=cwd)

And you should use Plink, not PuTTY, for automating the remote command execution. The Plink accepts the command on its command-line (PuTTY does not):

Popen(['plink.exe -ssh [email protected] ls'], shell=True, stdout=f, stderr=f, cwd=cwd)

Even better, use a native Python SSH library, like Paramiko:
Python Paramiko - Run command

1 Comment

don't use a list argument and shell=True; it is misleading. shell=True is unnecessary here, you could pass the full path to plink.exe instead.
-1

I know it' a bit beside the question, but that the most closed topic I found (I'd like to found that code a week ago on that post)

I was looking for a code to massively check if a password is active, and change it if possible

Putty have several cli tool like plink and pscp whch are useful for a lot of stuff.

Here is python 3 function to connect to a ssh server and accept ssh key. using pscp allow a auto accept key... can be useful for first time

def TestSSHConnection(IP_Addr,User,Password,verbosity=0, force_plink=False):
#Some infos about returned code
# 0 = Error Or crash
# 1 = Connection ok
# 2 = No connect Password Error
# 3 = SSH key trouble (shit append)
# 4 = Timeout
# 5 = Host Unreachable
# 6 = Connection Crash

out=""
err=""
try:
    if force_plink:
        print("echo y | plink -l "+str(User)+" -pw "+str(Password)+" -batch "+str(IP_Addr)+" exit",)
        ssh=subprocess.Popen("echo y | plink -l "+str(User)+" -pw "+str(Password)+" -batch "+str(IP_Addr)+" exit",shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,encoding='utf8')#,stdin=subprocess.PIPE)
    else:
        print("echo y | pscp -l "+str(User)+" -pw "+str(Password)+" -ls "+str(IP_Addr)+":/",)
        ssh=subprocess.Popen("echo y | pscp -l "+str(User)+" -pw "+str(Password)+" -ls "+str(IP_Addr)+":/",shell=True,stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    out,err = ssh.communicate()
    try:
        out = out.decode('utf-8')
    except AttributeError as inst:
        pass
    except Exception as inst:
        if verbosity>1:
            print("While decoding stdout: "+str(type(inst)))
    try:
        err = err.decode('utf-8')
    except AttributeError as inst:
        pass
    except Exception as inst:
       print("While decoding stderr: "+str(type(inst)))
    ssh.kill()
    del ssh
except Exception as inst:
    print("Crash"+str(inst))
    return 0

if len(err)>0:
    if 'Unable to open connection' in err or 'Host does not exist' in err:
        if verbosity>0: print("Unreachable")
        result = 5
        if verbosity>1:
            print()
            print("-"*30)
            print(err)
            print("-"*30)

    elif 'Connection timed out' in err:
        result = 4

    elif 'The server\'s host key is not cached in the registry' in err:
        result = 3
        if verbosity>1:
            print()
            print("SSH key Err".center(30,"-"))
            print(err)
            print("-"*30)

    elif 'Access denied' in err:
        result = 2
        if verbosity>2:
            print()
            print("Denied".center(30,"-"))
            print(err)
            print("-"*30)
    else:
        result = 6
        if verbosity>0: print("ConnCrash")
        print("Oups".center(30,"-"))
        print(err)
        print("-"*30)
else:
    if verbosity>0: print("Conn ok")
    result = 1

del out,err
return result

Of cource, this juste Check connection (and accept ssh key)

So here is a code to run a script on the host (precisely a password change). To do so, you can't use one line syntax (even it must work, it won't, i tried) You have to pass through a script file and push it with plink.

def ChangeMyPassword(IP_Addr,User,Old_Password,New_Password,verbosity=0):
#Some infos about returned code
# 0 = Error Or crash
# 1 = Change Ok
# 2 = Old Password Error
# 3 = SSH key trouble (shit append)
# 4 = Timeout
# 5 = Host Unreachable
# 6 = Connection Crash

out=""
err=""

try:
    path_script = "."+os.sep+"Script_chmdp_"+str(IP_Addr)+".sh"
    if os.path.exists(path_script):os.remove(path_script)
    fic_script = codecs.open(path_script,'w', encoding='utf8')
    fic_script.write('echo -e \"'+str(Old_Password)+'\\n'+str(New_Password)+'\\n'+str(New_Password)+'\" | passwd')
    fic_script.flush()
    fic_script.close()

    cmd = "plink -l "+str(User)+" -pw "+str(Old_Password)+" -batch "+str(IP_Addr)+ " "
    cmd += "-m "+path_script

    print(str(cmd))

    ssh=subprocess.Popen(cmd,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,encoding='utf8')#,stdin=subprocess.PIPE)

    out,err = ssh.communicate()
    try:
        out = out.decode('utf-8')
    except AttributeError as inst:
        pass
    except Exception as inst:
        if verbosity>1:
            print("While decoding stdout: "+str(type(inst)))
    try:
        err = err.decode('utf-8')
    except AttributeError as inst:
        pass
    except Exception as inst:
       print("While decoding stderr: "+str(type(inst)))
    ssh.kill()
    del ssh
except Exception as inst:
    print("Crash"+str(inst))
    return 0

if 'all authentication tokens updated successfully' in out:
    if verbosity>0: print("Conn ok")
    result = 1
else:
    if verbosity>0: print("Something goes wrong, hope we do not crash your server :)")
    result = 0
del out,err
return result

So now you have two function to massively change password on your systems.

Bonus: a function to get /etc/passwd and /etc/shadow. Why? for educationnal use on your IT admin like 'hey you f*** up and use the same password everywhere, and now all this account can be Bruteforced. So clean up your mess

def GetPass(IP_Addr,User,Password,verbosity=0, force_plink=False):
#Some infos about returned code
# 0 = Error Or crash
# 1 = Connection ok
# 2 = No connect Password Error
# 3 = SSH key trouble (shit append)
# 4 = Timeout
# 5 = Host Unreachable
# 6 = Connection Crash

out=""
err=""
try:

    ssh=subprocess.Popen("echo "+str(Password)+" | plink -l "+str(User)+" -pw "+str(Password)+" -batch "+str(IP_Addr)+" sudo cat /etc/passwd;sudo cat /etc/shadow",shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,encoding='utf8')#,stdin=subprocess.PIPE)

    out,err = ssh.communicate()
    try:
        out = out.decode('utf-8')
    except AttributeError as inst:
        pass
    except Exception as inst:
        if verbosity>1:
            print("While decoding stdout: "+str(type(inst)))
    try:
        err = err.decode('utf-8')
    except AttributeError as inst:
        pass
    except Exception as inst:
       print("While decoding stderr: "+str(type(inst)))
    ssh.kill()
    del ssh
except Exception as inst:
    print("Crash"+str(inst))
    return 0

if len(err)>0:
    if 'Unable to open connection' in err or 'Host does not exist' in err:
        if verbosity>0: print("Unreachable")
        result = 5
        if verbosity>1:
            print()
            print("-"*30)
            print(err)
            print("-"*30)

    elif 'Connection timed out' in err:
        result = 4

    elif 'The server\'s host key is not cached in the registry' in err:
        result = 3
        if verbosity>1:
            print()
            print("SSH key Err".center(30,"-"))
            print(err)
            print("-"*30)

    elif 'Access denied' in err:
        result = 2
        if verbosity>2:
            print()
            print("Denied".center(30,"-"))
            print(err)
            print("-"*30)
    else:
        result = 6
        if verbosity>0: print("ConnCrash")
        print("Oups".center(30,"-"))
        print(err)
        print("-"*30)
else:
    if verbosity>0: print("Conn ok")
    result = out

del out,err
return result

Some more notes:

if you don't use shell=True, you don't get the output, and it does not work, I don't know why.

I also tried a asynchronous communication to send comand line by line, it does not work.

I also tried the ssh command (yes it now exist on windows \o/) but it does not work for my purpose.

Hope this help someone one day, it would have helped me a lot a week ago :)

2 Comments

Do not suggest others to blindly bypass a host key verification, without explaining the security consequences.
If the problem is ""putty.exe -ssh"' is not recognized as an internal or external command", then you gave the wrong answer. The problem uses "putty.exe" (probably dosbatch), but your answer is python??? I think there are 2 possible answers: 1. The user may have forgotten the space between putty.exe and -ssh. then the program 'putty.exe-ssh" cannot be found of course... or more likely the user should install putty or put a link in the directory list of Windows.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.