I'm fairly new to how Paramiko works, but my main objective is to be able to run automated commands over SSH using Python.
I have the following code and I am trying to run a simple ls command to start off with but for some odd reason the code seems to get stuck and no output or error messages are produced.
import sys
import paramiko as pm
sys.stderr = sys.__stderr__
import os
class AllowAllKeys(pm.MissingHostKeyPolicy):
def missing_host_key(self, client, hostname, key):
return
HOST = '192.168.31.1'
USER = 'admin'
PASSWORD = 'admin'
client = pm.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(pm.AutoAddPolicy())
client.connect(HOST, username=USER, password=PASSWORD)
channel = client.invoke_shell()
stdin = channel.makefile('wb')
stdout = channel.makefile('rb')
stdin.write('''
ls
exit
''')
print stdout.read()
stdout.close()
stdin.close()
Any help would be much appreciated :)
I attempted the same route you were going, and didn't have much luck either. What I then opted for were the send() and recv() methods of the paramiko Channel class. Here is what I used:
>>> s = paramiko.SSHClient()
>>> s.load_system_host_keys()
>>> s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
>>> s.connect(HOST,USER,PASS)
>>> c = s.invoke_shell()
>>> c.send('ls')
>>> c.recv(1024)
ls
bin etc usr home
proc var lib tmp
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
target_host = 'x.x.x.x'
target_port = 22
target_port = 22
pwd = ':)'
un = 'root'
ssh.connect( hostname = target_host , username = un, password = pwd )
stdin, stdout, stderr = ssh.exec_command('ls;exit')
#mrpopo,try this code which uses pecpect,
import pexpect
import pxssh
import time
import os
def tc(ipaddr,password):
try:
ss = pexpect.spawn(ipaddr)
ss.logfile = sys.stdout
print "SSH connecting"
print
except:
print "connection refused"
print
#sys.exit()
try:
ss.expect (':')
ss.sendline (password +"\n")
print "connected"
time.sleep(30)
ss.expect (">")
print "connection established"
print
except:
print "Permission denied, please try again."
print
sys.exit()
try:
ss.sendline ('ls\n')
ss.expect ('>')
tc("ssh admin#192.168.31.1,admin")
Related
Testing sending commands to IoT devices that drops the user into a python script instead of a bash shell.
i.e. in /etc/passwd - admin:x:1000:0:admin:/home/admin:/home/admin/IoT.py
So cant use the normal bash exec_commands to talk to the python script. Basically once it connects it needs the send a command string and receive the output. Below the script reads IP addresses from a text file, whats the correct way to send and receive commands
#!/usr/bin/env python
import paramiko
import sys
def LogonSSH(ipAddress) :
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
for line in open(ipAddress, "r").readlines() :
ipAddr = line.strip()
username='admin'
password='admin'
try :
print "[+] Trying %s with username: %s password: %s " % (ipAddr, username, password)
ssh.connect(ipAddr, username=username, password=password)
except paramiko.AuthenticationException:
print "[x] %s - could not log in" % (ipAddr)
continue
stdin, stdout, stderr = ssh.exec_command('help')
stdin.flush()
stdin.write('help\n')
out = stdout.read()
stdin.flush()
print out
ssh.close()
break
if __name__ == "__main__" :
LogonSSH(sys.argv[1])
Below changes might help you. Just make send and recv, recv only takes the last commands output, but you need to consider:
Put some sleep after sending command (just trial and error)
Some tricks on output data, because it has invisible string parts such as (<pre>..</pre>)
Some output data might be too big to handle > 65100 bytes of recv, just check Paramiko Docs for recv method.
#!/usr/bin/env python
import paramiko
import sys
def LogonSSH(ipAddress) :
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
for line in open(ipAddress, "r").readlines() :
ipAddr = line.strip()
username='admin'
password='admin'
try:
print "[+] Trying %s with username: %s password: %s " % (ipAddr, username, password)
ssh.connect(ipAddr, port=22, username=uname, password=pin, timeout=240,banner_timeout=250, auth_timeout=500)
my_ssh_shell = ssh.invoke_shell()
except Exception as ex:
print("Some exception occured:" + str(ex))
continue
my_ssh_shell.send(bytes("help" + "\x0D", 'utf-8'))
result_screen = my_ssh_shell.recv(65100).decode('ascii')
print("Your SSH -help- command returns:" + str(result_screen))
my_ssh_shell.close()
break
if __name__ == "__main__" :
LogonSSH(sys.argv[1])
Edit: Just change it to any exception for connection, and also some additional paramters on connection string.
The following code will get the MOTD, but send still not working
my_ssh_shell = ssh.invoke_shell()
my_ssh_shell.settimeout(2)
while True :
data = my_ssh_shell.recv(1024).decode('ascii')
if len(data) < 1 :break
print(data)
return
#### DOESNT SEND HERE OR GET RECEIVE RESULTS#########
# my_ssh_shell.send('help\n')
# while True :
# data = my_ssh_shell.recv(1024).decode('ascii')
# if len(data) < 1 :break
# print(data)
# return
my_ssh_shell.close()
I use Python flask and paramiko to execute command on my remote ssh server from my html form.
It should to display the message back to my html file:
(result from the executed file in ssh server)
Any Idea or Website Link are welcoming
Thank you.
You can use something like this within a function. Once the function is called return the "output" to the html.
import sys, paramiko
if len(sys.argv) < 4:
print "args missing"
sys.exit(1)
hostname = sys.argv[1]
password = sys.argv[2]
command = sys.argv[3]
username = "admin"
port = 22
try:
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
client.connect(hostname, port=port, username=username, password=password)
stdin, stdout, stderr = client.exec_command(command)
output = stdout.read(),
finally:
client.close()
The following code fetches IP address (Cisco Router) from a text file and executes the mentioned command and prints the resultant output on to a file. Here am trying to first test the reach-ability of the device by using PING, on successful ping response commands should be executed else should print an error and move to the next host. Please help me on how to achieve this. I am a newbie.
Here is my code,
import paramiko
import sys
import os
import subprocess
with open('C:\Python27\Testing\Fetch.txt') as f:
for line in f:
line = line.strip()
dssh = paramiko.SSHClient()
dssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
dssh.connect(line, username='cisco', password='cisco')
stdin, stdout, stderr = dssh.exec_command('sh ip ssh')
mystring = stdout.read()
print mystring
f = open('C:\Python27\Testing\output.txt', 'a+')
f.write(mystring)
f.close()
dssh.close()
Input file Fetch.txt looks like this,
10.0.0.1
10.0.0.2
10.0.0.3
10.0.0.4
10.0.0.5
I scoured through the forum and achieved just about what I am looking for.. If all the IP addresses are reachable in that list, the script works just fine. But if any one of the IP address is unreachable then the script ends abruptly without proceeding to the next IP address. I realize that am doing something wrong here, I just need that little bit of help to get this working..... Please help out.
import paramiko
import sys
import os
import subprocess
dssh = paramiko.SSHClient()
dssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
with open('C:\Python27\Testing\Fetch.txt') as f:
for line in f:
line = line.strip()
with open(os.devnull, "wb") as limbo:
ip = line
result = subprocess.Popen(["ping", "-n", "1", "-w", "200", ip],
stdout=limbo, stderr=limbo).wait()
if result:
print ip, "Down"
else:
print ip, "Reachable"
dssh.connect(line, username='cisco', password='cisco')
stdin, stdout, stderr = dssh.exec_command('sh ip ssh')
mystring = stdout.read()
print mystring
f = open('C:\Python27\Testing\output.txt', 'a+')
f.write('\n' + ip + '\n' + mystring)
f.close()
dssh.close()
You ideally don't have to test if a host is pingable first using a separate if statement..paramiko comes inbuilt with a lot of exception checking ..using this along the socket module..your program can be written in a cleaner fashion without having to use subprocesses..
import paramiko
import socket
dssh = paramiko.SSHClient()
dssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ips = [i.strip() for i in open("C:\Python27\Testing\Fetch.txt")] # creates a list from input file
for ip in ips:
try:
dssh.connect(ip, username='cisco', password='cisco', timeout=4)
stdin, stdout, stderr = ssh.exec_command('sh ip ssh')
print ip + '===' + stdout.read()
ssh.close()
except paramiko.AuthenticationException:
print ip + '=== Bad credentials'
except paramiko.SSHException:
print ip + '=== Issues with ssh service'
except socket.error:
print ip + '=== Device unreachable'
this will catch other exceptions like bad credentials and other issues with ssh service
You could try using fabric which is made for executing SSH commands on multiple machines.
This is just a snippet i threw together but it should show you the way to go.
from fabric.api import run, execute ,env
class Fetcher:
def __init__(self,hosts=[]):
env.hosts= hosts
env.warn_only = True # needed to not abort on pingtimout or other errs
def getclock(self)
run('sh clock')
def fetch(self):
results = execute(self.getclock,hosts=env.hosts)
if __name__ == '__main__':
hosts = loadfromtxt(hosts.txt)
f = Fetcher(hosts=hosts)
f.fetch()
I recall an example of python threading, either in the docs or in a book I read (don't remember the source) that does something like what you're trying to do. Something like this should work:
import sys
import os
import subprocess
from threading import Thread
class Pinger(Thread):
def __init__ (self, ip):
Thread.__init__(self)
self.ip = ip
self.status = False
def __repr__(self):
return "Pinger for '%s' status '%s'" % (self.ip, self.status)
def run(self):
with open(os.devnull, "wb") as limbo:
# Changed the arguments because I don't have a windows ping.exe to test it on
result = subprocess.Popen(["ping", "-c", "2", "-q", self.ip],
stdout=limbo, stderr=limbo).wait()
if result:
# print self.ip, "Down"
self.status = False
else:
# print self.ip, "Reachable"
self.status = True
hosts = []
with open('Fetch.txt') as f:
for line in f:
host = Pinger(line.rstrip())
# print host
hosts.append(host)
host.start()
for host in hosts:
host.join()
if host.status:
print "Host '%s' is up" % host.ip
#### Insert your ssh exec code here ####
# dssh.connect(host.ip, username='cisco', password='cisco')
# etc.
else:
print "Host '%s' is down" % host.ip
Why do you need Paramiko module or to create an input if python can do itself ?
#!/usr/bin/python
import os
hostname = raw_input('Enter the Router Name: ')
routers = hostname.split(',')
print routers
for hostname in routers:
response = os.system("ping -c5 " + hostname)
if response == 0:
print(hostname, 'is up!')
else:
print(hostname, 'is down!')
I have the following script to connect to an custom ssh shell.
When I execute the script it just hangs. It doesnt execute the command. I suspect problems with the shell because it does not have any prompt. Do you have any idea?
import sys
import os
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('10.115.130.22', username='admin', password='xxx', timeout = 30)
stdin, stdout, stderr = ssh.exec_command('xconfiguration SystemUnit Name: devicename')
print stdout.readlines()
ssh.close()`
I spent way too much time on this problem. I found that I needed to use the invoke_shell() to be able to get anything past the greeting banner on the Tandberg C/E series video endpoints. Here's my working code, FWIW:
import time
import paramiko
command = 'help'
host = 'x.x.x.x'
port = 22
user = 'admin'
passwd = 'TANDBERG'
def tbgShell(host,port,username,password,cmd):
"""send an arbitrary command to a Cisco/TBG gizmo's ssh and
get the result"""
transport = paramiko.Transport((host, port))
transport.connect(username = user, password = passwd)
chan = transport.open_channel("session")
chan.setblocking(0)
chan.invoke_shell()
out = ''
chan.send(cmd+'\n')
tCheck = 0
while not chan.recv_ready():
time.sleep(1)
tCheck+=1
if tCheck >= 6:
print 'time out'#TODO: add exeption here
return False
out = chan.recv(1024)
return out
output = tbgShell(host, port, user, passwd, command)
print output
This is a custom shell. It is a cisco ex90 video conferencing system.
But I tried different commands like xconfig which show you the config.
# sshpy v1 by s0urd
# simple ssh client
# irc.gonullyourself.org 6667 #code
import paramiko
import os
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
privatekey = os.path.expanduser('/home/rabia/private')
mkey = paramiko.RSAKey.from_private_key_file(privatekey)
ssh.connect('78.46.172.47', port=22, username='s0urd', password=None, pkey=mkey)
while True:
pick = raw_input("sshpy: ")
stdin, stdout, stderr = ssh.exec_command(pick)
print stdout.readlines()
ssh.close()
When I try to run more then 1 command I get this error:
AttributeError: 'NoneType' object has no attribute 'open_session'
Looks like it's because at the end of the while loop you do ssh.close() (thus closing the session).