Python скрипт за SSH през PuTTY

Мога да дам следната команда в командния ред

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

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

Това ми помага да отворя SSH сесията чрез PuTTY.

Като има предвид, че не мога да ги възпроизведа в скрипта на Python.

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

Грешката, която виждам е

"putty.exe -ssh"' не се разпознава като вътрешна или външна команда, работеща програма или пакетен файл


person Nitin    schedule 16.09.2015    source източник


Отговори (3)


В страницата за изтегляне на putty изтеглете и инсталирайте plink и уверете се, че е в пътя на Windows ($PATH променлива)

Тогава този фрагмент на Python трябва да работи:

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 са командите, въведени от потребителя в терминала, stdout и stderr са изходът на сървъра.

Попълнете идентификационните си данни в user="root", server="172.20.0.102 22" и може би password за ssh връзката

person Uri Goren    schedule 16.09.2015
comment
Много по-добре е да настроите SSH ключове, отколкото да дадете парола като команда на изпълним файл. - person robert; 16.09.2015
comment
Съгласен съм. Тъй като plink поддържа и удостоверяване на парола от командния ред, добавих тази опция към кодовия фрагмент. - person Uri Goren; 16.09.2015
comment
Вашият код може да блокира, ако каналите на Windows имат ограничен буфер (като на Unix). Ако искате да подадете вход като низ или да получите stdout, stderr като низ, тогава трябва да използвате метода .communicate() вместо това. - person jfs; 17.09.2015

Трябва да предадете cwd като параметър cwd на Popen:

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

И трябва да използвате Plink, а не PuTTY, за автоматизиране дистанционното изпълнение на командата. Plink приема командата от своя команден ред (PuTTY не):

Popen(['plink.exe -ssh [email protected] ls'], shell=True, stdout=f, stderr=f, cwd=cwd)
person Martin Prikryl    schedule 16.09.2015
comment
не използвайте аргумент списък и shell=True; това е подвеждащо. shell=True тук не е необходимо, можете вместо това да подадете пълния път към plink.exe. - person jfs; 16.09.2015

Знам, че е малко извън въпроса, но това е най-затворената тема, която намерих (бих искал да намеря този код преди седмица в тази публикация)

Търсих код за масова проверка дали дадена парола е активна и да я променя, ако е възможно

Putty има няколко cli инструмента като plink и pscp, които са полезни за много неща.

Ето функцията на python 3 за свързване към ssh сървър и приемане на ssh ключ. използването на pscp позволява автоматично приемане на ключ... може да бъде полезно за първи път

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

Разбира се, това просто Проверете връзката (и приемете ssh ключ)

И така, ето код за стартиране на скрипт на хоста (точно промяна на парола). За да направите това, не можете да използвате синтаксис на един ред (дори трябва да работи, няма да стане, опитах) Трябва да преминете през скрипт файл и да го натиснете с 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

Така че сега имате две функции за масова промяна на паролата на вашите системи.

Бонус: функция за получаване на /etc/passwd и /etc/shadow. Защо? за образователна употреба на вашия ИТ администратор като „хей, прецакате се и използвайте една и съща парола навсякъде и сега целият този акаунт може да бъде грубо форсиран. Така че почистете бъркотията си

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

Още бележки:

ако не използвате shell=True, не получавате изхода и той не работи, не знам защо.

Опитах и ​​асинхронна комуникация, за да изпращам команда ред по ред, не работи.

Опитах също командата ssh (да, вече съществува в windows \o/), но тя не работи за моята цел.

Надявам се това да помогне на някой един ден, на мен щеше да ми помогне много преди седмица :)

person Physaphae    schedule 23.03.2020
comment
Не предлагайте на други да заобикалят сляпо проверка на ключ на хост, без да обяснявате последиците за сигурността. - person Martin Prikryl; 23.03.2020
comment
Ако проблемът е putty.exe -ssh' не се разпознава като вътрешна или външна команда, значи сте дали грешен отговор. Проблемът използва putty.exe (вероятно dosbatch), но вашият отговор е python??? Мисля, че има 2 възможни отговора: 1. Потребителят може да е забравил интервала между putty.exe и -ssh. тогава програмата 'putty.exe-ssh не може да бъде намерена, разбира се... или по-вероятно потребителят трябва да инсталира putty или да постави връзка в списъка с директории на Windows. - person Bart Mensfort; 23.03.2020