How do I SSH to machine through a middle host using Paramiko? - python

Essentially, I need to access a computer, say machine A, which is only accessible via the internal network of my company. I used to be able to set up tcprelay port forwarding to accomplish this but that pipeline has been disabled due to some potential security flaws.
Let’s say my company general network is at
company#10.0.0.1
and the specific machine i want to work with is at
machine#10.0.0.3
Both accounts have password ‘password’
Via terminal and shell commands, I can just hop there using one single command:
https://askubuntu.com/a/311457
or, in steps, it would be:
[on my account] ssh company#10.0.0.1
[on my account] enter password
[on company network] ssh machine #10.0.0.3
[on company network] enter password again
And I’d be logged into the machine I need to communicate with.
However, after hacking away all afternoon I could not get this working with Paramiko. I tried setting up the connection then issuing a client.exec_command() but just cannot get a handle for the specific machine. The rest of my scripts relies on having a paramiko client that can receive commands and return responses, so it would be a very heavy overhead for me to go propagate all changes were I to switch to say fabric or subprocess.
The closest I got to was:
ssh.connect(’10.0.0.1', username=‘company', password=‘password’)
chan = ssh.get_transport().open_session()
chan.get_pty()
chan.exec_command(‘ssh machine#10.0.0.3’)
print chan.recv(1024)
which returned the ‘enter password’ prompt, but running chan.send(‘password’) just ends with a hang.
I’m pulling my hair out at this point and am just reading through the documentation hoping to find what concept I’m missing.
If anyone can give some advice I’d really appreciate it.
Thanks!

Alternative way is to avoid entering password when login to another machine.
This can be done by using ssh-keygen.
Login to first machine (A) with user 'first':
$ ssh-keygen -t rsa
--> Don't enter any passphrase when requested
--> Note down the line "Your public key has been saved in /home/first/.ssh/"
--> This file is the public key of machine 'A'
Now login to second machine(B) using ssh.
Then check for ~/.ssh folder. If no folder, create one.
Create a file with name 'authorized_keys' under ~/.ssh/authorized_keys
Copy the content of file from 'first' user to the file 'authorized_keys'.
is a file with 'id_rsa.pub' from 'first' user login (under /home/first/.ssh/id_rsa.pub)
Now you can login to second machine from first without entering password thru your script.

I worked on a project where it had to log in using username/password over SSH then do the same thing again to another host. I had no control over networks ACLs and SSH keys were not allowed for some reason. You'll need to add paramiko_expect. Here's how I got it to work:
import paramiko
from paramiko_expect import SSHClientInteraction
user1 = 'admin'
pass1 = 'admin'
user2 = 'root'
pass2 = 'root'
# not needed for this example, but included for reference
user_prompt = '.*\$ '
# will match root user prompt
root_prompt = '.*$ '
# will match Password: or password:
pass_prompt = '.*assword: '
# SSH to host1
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(
paramiko.AutoAddPolicy())
ssh_client.connect(hostname='host1', username=user1, password=pass1)
# Interact with SSH client
with SSHClientInteraction(ssh_client, display=True) as interact:
# Send the command to SSH as root to the final host
interact.send('ssh {}#host2'.format(user2)
# Expect the password prompt
interact.expect(pass_prompt)
# Send the root password
interact.send(pass2)
# Expect the root prompt
interact.expect(root_prompt)
ssh_client.close()
One caveat: if host1 has never connected to host2 using SSH it'll get a warning about host key checking and timeout. You can change the configuration on host1 or just SSH to host1 then from host1 SSH to host2 and type yes and press enter.

Related

fabric ask for password for ssh user on Redhat8 even though I could ssh via terminal successfully(no issue on centos)

On terminal, I could ssh to the target server without password successfully.
The target server is redhat8.
But using fabric(I tried fabric==1.14.0 and fabric==2.6.0), both failed on waiting for password.
This is my test codes:
host = 'fake_host'
access_account = 'fake_user'
def test_connection():
with settings(user=access_account, host_string=host):
run('ls -la')
test_connection()
This is the result:
run: ls -la
/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/getpass.py:83: GetPassWarning: Can not control echo on the terminal.
passwd = fallback_getpass(prompt, stream)
Warning: Password input may be echoed.
[fake_host] Login password for '<fake_user>':
There is no difference if I explicitly set the key file.
We have another server which OS is centOS7, with the same settings, we can ssh to the server without password successfully and can use the same fabric codes run the command successfully.
What is the possible reason?
We found the reason is because of high security settings on the target server.
Fix:
edit /etc/crypto-policies/back-ends/opensshserver.config -> add "ssh-rsa" to "-oPubkeyAcceptedKeyTypes".
Example: " -oPubkeyAcceptedKeyTypes=ssh-rsa"

SecureCRT - Python script, automated ssh2 tab not responding to commands being sent

I'm modifying a script in python to run in securecrt 8.5.2 in order to backup the running-config of some cisco ASR9K equipment I have in charge, but the script seems to end abruptly after the second sucessful ssh2 hop (2nd tab) and does not send the commands I scripted (the exit in this specifical example), here's the code I have, as I'd said it's a modified version of the one's in vandyke page for opening ssh2.
One important thing is that I have to tab each session of each individual routers, because it doesn't permit doing an ssh direct from the active cli, so I had to improvise and implement this "connect in TAB", I'm suspecting that the secureCRT doesn't know if it is in the new tab I've opened so, it doesn't know where to send the commands.
I was playing with the line 30, but it doesn't seem to have any effect. I was changing the expected text, but it doesn't seem to recognize the correct tab or doesn't read the correct one.
Personal Background: A complete beginner in the python language.
# $language = "python"
# $interface = "1.0"
# Connect to an SSH server using the SSH2 protocol. Specify the
# username and password and hostname on the command line as well as
# some SSH2 protocol specific options.
host = "X.X.X.a"
host2 = "X.X.X.b"
def main():
crt.Screen.Synchronous = True
# Prompt for a username and password instead of embedding it in a script...
#
usr = crt.Dialog.Prompt("Enter the user name for" + host, "Username", "", True)
passwd = crt.Dialog.Prompt("Enter TACACS+ for" + host, "Login", "", True)
# Build a command-line string to pass to the Connect method.
cmd = "/SSH2 /L %s /PASSWORD %s /C AES-128-CTR /M SHA1 %s" % (usr, passwd, host)
crt.Session.Connect(cmd)
crt.Screen.WaitForString("X.X.X.a#")
crt.Screen.Send("copy running-config tftp:\r")
crt.Screen.WaitForString("Host name or IP address (control-c to abort): []?")
crt.Screen.Send("tftpserver.com\r")
crt.Screen.WaitForString("Destination file name (control-c to abort): [running-config]?")
crt.Screen.Send("X.X.X.a_running_config\r")
crt.Screen.WaitForString("X.X.X.a")
cmd2 = "/SSH2 /L %s /PASSWORD %s /C AES-128 /M SHA1 %s" % (usr, passwd, host2)
crt.Session.ConnectInTab(cmd2)
crt.Screen.WaitForString("X.X.X.b#")
crt.Screen.Send("exit\r")
main()
crt.Session.ConnectInTab(cmd2)
It connects to the equipment in a new tab, but what I expect is that the script will keep doing the same it did for the host1 (X.X.X.a) and send the same boring stuff to the host2 (X.X.X.b) via ssh2 tab, and continue the itterative process until I do this for all the equipments I need.
Thanks for reading me.
Well it's not even funny easy was to solve this very sub-optimal code or script but it was not much of a problem, the only thing is that I had to dissconect to the previous session when I inyected all the commands, so in order to put the cursor on the new tab, the previous session must be dissconected first.
The solution?
crt.Session.Disconnect()

Trying to connect to ftp server with a firewall proxy using ftplib python

Right now, I'm connecting to the ftp in bash using
echo "
user $USER1 $PASS1
user $USER2 $PASS2
user $USER3 $PASS3"|ftp -n $FTPSERVER
I tried to handle this in python using
ftp = ftplib.FTP(SERVER)
ftp.sendcmd("user {} {}".format(USER1, PASS1))
ftp.sendcmd("user {} {}".format(USER2, PASS2))
...
When I connect using bash, the output is
However, when I try using python, the first line only gives output "331 Password: " and if I send anymore commands, it gives the error Please supply password with PASS command.
Also, I'm not sure if it's relevant but $USER2 and $PASS2 have # in them with $PASS2 beginning with it.

How to keep paramiko ssh session open after loggin in using python?

I am trying to ssh to a test cisco router in a test environment using python paramiko, and run cisco commands in that test router.
Everything works great except for 1 small detail.
After running the script I want the ssh session to remain open. (so I can run other commands manually).
I want to keep the ssh session open until I type "exit"
I found another link with a similar issue but I cant understand the solution.
(See here Python ssh - keep connection open after script terminates)
I would appreciate if someone can help me out here
My code
import paramiko
import time
def ssh_session(ip):
try:
session = paramiko.SSHClient() #Open the session
session.set_missing_host_key_policy(paramiko.AutoAddPolicy())
session.connect(ip, username = "ciscouser1", password = "password")
connection = session.invoke_shell()
####Running Cisco IOS commands###
connection.send("enable\n")
connection.send("password1") #sending
connection.send("\n")
connection.send("configure terminal\n\n")
time.sleep(1)
connection.send("do show ip int brief\n")
time.sleep(1)
except paramiko.AuthenticationException:
print "wrong credentials"
ssh_session("10.10.10.1")
The session timeout would be controlled by the SSH server. To the best of my knowledge, the only way to keep your session alive on the client side is to not be inactive, which can be accomplished by sending null packets. As to how to do this specifically with paramiko I am not certain. Perhaps you could send some kind of dummy command (or maybe even an empty string?) every so often?

How to auto answer prompts via SSH connection in python

I want to call an application on a remote machine using python paramiko; this application waits till you enter a specific string and then succeeds. How can I send requested string over SSH connection to it?
The application call is like:
./app --init
This option will delete the database and recreate all files.
OLD DATA (IF ANY) WILL BE LOST!
This option must be used just on one of your servers.
Running it on any one of the servers will delete the other server's data, too.
If you are sure, type the following sentence and press ENTER:
I KNOW THAT THIS OPTION DESTROYS EVERYTHING; DO IT ANYWAY.
Then I should type I KNOW THAT THIS OPTION DESTROYS EVERYTHING; DO IT ANYWAY. and press ENTER to continue.
I have this code to connect to the remote host:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip, username=usrname, password=passwd, compress=True)
I tried self.sshlink.exec_command('cd app_addr;./app --init'); it performed nothing.
I found the solution in one of the un-accepted answers in this question.
This is what I've finally tried and succeeded:
cmd = 'cd app_address;./app --init'
answer = 'I KNOW THAT THIS OPTION DESTROYS EVERYTHING; DO IT ANYWAY.'
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname=ip, username=username, password=password)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(cmd)
ssh_stdin.write(answer + '\n')
ssh_stdin.flush()
time.sleep(5)
ssh_stdout.read()

Categories

Resources