Скрипт 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)


На странице загрузки шпатлевки загрузите и установите 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, конечно, не может быть найдена... или, что более вероятно, пользователь должен установить шпатлевку или поместить ссылку в список каталогов Windows. - person Bart Mensfort; 23.03.2020