Need little assistance with pexpect module - python

Need assistance with the pexpect module
I have written a simple code which would clone a git repository from a server using ssh.
I'm facing couple of problems.
The password is shown in plain text.
I dont know a proper way to exit the program after the download. it throws out the following error...
Traceback (most recent call last):
File "ToDelete3.py", line 65, in <module>
# # if i == 1:
File "ToDelete3.py", line 36, in getRepository
i = p.expect([ssh_key,'password:',pexpect.EOF])
File "/usr/lib/python2.7/dist-packages/pexpect.py", line 1492, in interact
self.__interact_copy(escape_character, input_filter, output_filter)
File "/usr/lib/python2.7/dist-packages/pexpect.py", line 1520, in __interact_copy
data = self.__interact_read(self.child_fd)
File "/usr/lib/python2.7/dist-packages/pexpect.py", line 1510, in __interact_read
return os.read(fd, 1000)
OSError: [Errno 5] Input/output error
the code that I have written so far is :
command = 'git clone ssh://username#someserver/something.git'
ssh_key = 'Are you sure you want to continue connecting'
def gracefulExit():
print 'Password Incorrect !!!'
os._exit(1)
def getRepository():
p = pexpect.spawn(command,maxread=10000,timeout = 100)
p.logfile = sys.stdout # logs out the command
i = p.expect([ssh_key,'password:',pexpect.EOF])
if i == 0:
print 'Inside sshkey'
p.sendline('yes')
i = p.expect([ssh_key,'password:',pexpect.EOF])
if i == 1:
try:
p.sendline('mypassword') # this mypassword is shown in clear text on the console
p.interact()
p.logfile = sys.stdout
p.expect(pexpect.EOF)
except Exception,e:
print str(e)
gracefulExit()
if i == 2:
print 'Inside EOF block'
if p.isalive():
print '******************************************************'
print ' Closing the process of Download !!! '
print '******************************************************\n\n'
p.close()
Any inputs is highly appreciated..
Thanks.
-Vijay

There are few errors in the program:
p.interact()
This is used when we want to get back the control after having automatically supplied the password using pexpect module. You don't need to use that since you are automating the whole repository check out.
Also a few things can be improved, after passing the password, set a infinite timeout since it may take a while to copy a git repository.
p.expect(pexpect.EOF, timeout=None)
After that you can read all the execution output with the following command
output_lines = p.before
output_lines_list = output_lines.split('\r\n')
for line in output_lines: print line
you can also use the above to log the output to a file by directly writing to it
Using p.logifile = sys.stdout is not good since it will record pexpect operation from start including passing of password.
After this there is no need to close, you are not running a interactive program. Remove all these lines:
if i == 2:
print 'Inside EOF block'
if p.isalive():
print '******************************************************'
print ' Closing the process of Download !!! '
print '******************************************************\n\n'
p.close()
The issue is that some where you have to store the password and use it with p.sendline. How ever, you store password, it is going to be insecure. You can also take the input at the start for the password, this way you will not be storing the password within your program but that defeats automation. I don't see a way out but for taking password input, you can do:
import getpass
getpass.getpass("please provide your password")

To get rid of the password being echo'd to stdout, use the following when redirecting output -
p.logfile_read = sys.stdout # logs out the command
I have tried this myself and seems to be working. Here is the reference for this revelation.

Related

multiple commands by logging into SSH

I am trying to log in to the server and give multiple commands from the input file. Here input file is web.txt (contains 'bash', 'df-g' as examples). I am sucessfully able to login to server, but not able to run the commands. I don't know what I am doing wrong here. Can anyone help me please.
import paramiko
web_list = []
def create_web_list():
file = open("web.txt", "r", encoding='utf-8')
for value in file.readlines():
web_list.append(value.strip( ))
return web_list
ip = 'x.x.x.x'
username = 'username'
password = 'password'
def web_device(web_list):
SESSION = paramiko.SSHClient()
SESSION.set_missing_host_key_policy(paramiko.AutoAddPolicy)
SESSION.connect(ip,port=22,username=username,password=password,look_for_keys=False,allow_agent=False)
print("Connection Sucessful")
for cmd in web_list:
stdin,stdout,stderr=SESSION.exec_command(cmd)
outlines=stdout.readlines()
resp=''.join(outlines)
print(resp)
SESSION.close()
if __name__ == "__main__":
web_device(create_web_list())
Please specify either you want output in one go or you want output for each command separately? if you want with one go then please find below:
Executing multiple commands on paramiko SSHClient, you can place all commands in one line with ; separator like:
client.exec_command('ls -l; cwd; whoiam') etc
so please read line from file accordingly and execute commands with one go instead using a loop.
For Individual command execution case use below:
with open("web.txt", "r", encoding='utf-8') as f:
return web_list.append(f.strip( ))
and print output in utf format like '\n'.join(outlines)

Script aborts after adding a try block and writing to two log files

I have a text file that is a list of servers which is called solaris_h.txt. Some of the servers on this list, I'm not able to authenticate probably because I don't have an account or the password is incorrect. When authentication fails on a particular server on the list, the script aborts. So, somebody suggested the try and except block. I want the script to complete the list of servers in solaris_h.txt and to write to a log file the successful logins and writing to another log file the servers that failed to authenticate. After adding the try block, when executing the script, it exits immediately without error. And how do I get my script to write to one log file the successful logins and to another log file the unsuccessful logins?
#!/usr/bin/python
import pxssh
import sys
log = open("myprog.log", "a")
sys.stdout = log
s = pxssh.pxssh(timeout=30, maxread=2000000)
s.SSH_OPTS += "-o StrictHostKeyChecking=no"
s.SSH_OPTS += "-o UserKnownHostsFile=/dev/null"
s.SSH_OPTS += "PubkeyAuthentication=no"
f=open('solaris_h.txt','r')
for line in f:
try:
s.login(line,'xxxx','xxxxxx')
z = s.sendline('uname -a')
s.prompt()
y = s.before
print("%s %s" % (line, y))
s.logout()
except pxssh.ExceptionPxssh:
pass
Here is the error when it fails authentication.
Traceback (most recent call last):
File "./z.py", line 17, in <module>
s.login(line,'username','password')
File "/usr/lib/python2.7/site-packages/pxssh.py", line 226, in login
raise ExceptionPxssh ('password refused')
pxssh.ExceptionPxssh: password refused
If you want to ignore an error from a failed login, you can do a try/except block around the login like:
try:
s.login(line, 'username', 'password')
z = s.sendline('uname -a')
s.prompt()
y = s.before
print("%s %s" % (line, y))
s.logout()
except pxssh.ExceptionPxssh:
pass
Use try except blocks for the authentication code alone. so if any errors they will be caught and loop will continue with next server name.

Python Pexpect full output is not saved (How to deal with the "--More--" prompt?)

I am using Pexpect to run a command remotely on a server and saving the output in a file. However, it does not save the whole output as it's truncated due to --More-- . Is there a way to avoid --More--, so that the whole output is saved in the output file?
I have tried using child.setwinsize(1000,1000) but it didn't solve the issue.
Current code:
import pexpect
import time
child = pexpect.spawn('ssh username#ip_address')
time.sleep(1)
child.sendline('password')
time.sleep(1)
child.logfile = open("output.txt", "w")
child.sendline('command')
child.expect(pexpect.EOF)
print child.before, child.after
child.close
Not sure what command you're running but usually you can press SPACE when you see the --More-- prompt. For example:
import pexpect, sys
child = pexpect.spawn('more /etc/services')
child.logfile_read = sys.stdout
patterns = ['--More--', pexpect.EOF]
while True:
ret = child.expect(patterns)
if ret == 0:
child.send(' ')
elif ret == 1:
break
I found one more answer- just execute below command before actual command.
terminal length 0
After that suppose I entered some command like show ip interface. Then, This will show whole output. You don't need to press enter again and again. As,
child.sendline('terminal length 0')
child.expect('# ')
child.sendline('show ip interface') #write your command here
child.expect('# ')

Python 3 - Issues writing to files using the stdout argument of subprocess.call module

I'm trying to automate running snmpwalk against several hosts on my penetration testing lab. Basically what I want to do is to give my python script a list of target IPs (in the form of a text file), have it run snmpwalk against them, and store the results in separate files that I create (one per target IP). Here's a portion of my code that runs the tool against the target IPs contained in the live_list object file:
def run_snmpwalk(selection):
# Rewind file
live_list.seek(0)
if selection == '1':
i = 0
for line in live_list:
tgt_host = line.strip("/\n")
file_obj_array[i].write('[+] SNMPWalk user enumeration for IP: ' + tgt_host + ' \n')
print('[+] Attempting to enumerate users from IP: ' + tgt_host)
exit_code = subprocess.call(['snmpwalk', '-c', 'public', '-v1', tgt_host, '1.3.6.1.4.1.77.1.2.25'], stdout=file_obj_array[i])
i += 1
if exit_code == 0:
print('[+] Success')
else:
print('[+] Something went wrong while executing snmpwalk ')
As crappy as it might be, the code above works as I intended to, except for one little detail that I can't seem to fix.
The line below uses the subprocess.call module with the stdoutparameter set to the file I previously created to contain the output of the command:
subprocess.call(['snmpwalk', '-c', 'public', '-v1', tgt_host, '1.3.6.1.4.1.77.1.2.25'], stdout=file_obj_array[i])
And this next line is supposed to write a header in the file to which the output of the previous command is being dumped to:
file_obj_array[i].write('[+] SNMPWalk user enumeration for IP: ' + tgt_host + ' \n')
However, instead of ending up with a header, the line above ends up at the bottom of the file, despite it being executed before the subprocess.call line. Here's a sample output file of the function above:
iso.3.6.1.4.1.77.1.2.25.1.1.5.71.117.101.115.116 = STRING: "Guest"
iso.3.6.1.4.1.77.1.2.25.1.1.6.97.117.115.116.105.110 = STRING: "austin"
iso.3.6.1.4.1.77.1.2.25.1.1.9.73.85.83.82.95.83.82.86.50 = STRING: "IUSR_SRV2"
iso.3.6.1.4.1.77.1.2.25.1.1.9.73.87.65.77.95.83.82.86.50 = STRING: "IWAM_SRV2"
iso.3.6.1.4.1.77.1.2.25.1.1.13.65.100.109.105.110.105.115.116.114.97.116.111.114 = STRING: "Administrator"
iso.3.6.1.4.1.77.1.2.25.1.1.14.84.115.73.110.116.101.114.110.101.116.85.115.101.114 = STRING: "TsInternetUser"
[+] SNMPWalk user enumeration for IP: 10.11.1.128
I can't figure out why subprocess.call manages to write lines to the file before file_obj_array[i].write, even though it comes after it in the for loop.
Any ideas would help.
Thanks!
You have to flush buffers:
def run_snmpwalk(selection, live_list, file_obj_array):
# Rewind file
live_list.seek(0)
if selection == '1':
for line, file_obj in zip(live_list, file_obj_array):
tgt_host = line.strip("/\n")
file_obj.write('[+] SNMPWalk user enumeration for IP: {}\n'.format(tgt_host))
file_obj.flush()
print('[+] Attempting to enumerate users from IP: {}'.format(tgt_host))
exit_code = subprocess.call(['snmpwalk', '-c', 'public', '-v1', tgt_host, '1.3.6.1.4.1.77.1.2.25'], stdout=file_obj)
if exit_code == 0:
print('[+] Success')
else:
print('[+] Something went wrong while executing snmpwalk ')

scp to a remote server using pexpect

I'm trying to learn a little bit on pexpect: in particular I'm trying to copy a file from my laptop to a remote server.
I'm experiencing a weird behaviour: more or less the same code works if I write it line by line but it won't if I run it as a script.
Here is what I write line-by-line:
child = pexpect.spawn('scp pathdir/file.ext username#hostname:pathdir')
r=child.expect ('assword:')
r
it returns 0 and I finish the job with the password
child.sendline ('password')
When I do ssh to the server I found my file there. So I collect all the steps in a script; it exits without errors, but the file it was not copied... why? But more importantly, how can I fix that?
Here is the script:
child = pexpect.spawn('scp pathdir/file.ext username#hostname:pathdir')
r=child.expect ('assword:')
print r
if r==0:
child.sendline ('password')
child.close()
I'm not sure how pexpect works so I print r to be sure it is 0. And it is.
I faced the "same" problem recently. Here's how I did it. I hope this will definitely help you.
Your question :
I'm not sure how pexpect works so I print r to be sure it is 0. And it is.
Yes it is zero.
Try the code below :
try:
var_password = "<YOUR PASSWORD>" Give your password here
var_command = "scp pathdir/file.ext username#hostname:pathdir"
#make sure in the above command that username and hostname are according to your server
var_child = pexpect.spawn(var_command)
i = var_child.expect(["password:", pexpect.EOF])
if i==0: # send password
var_child.sendline(var_password)
var_child.expect(pexpect.EOF)
elif i==1:
print "Got the key or connection timeout"
pass
except Exception as e:
print "Oops Something went wrong buddy"
print e
child.expect can accept more than one arguments. In such case you have to send those arguments in form of list. In above scenario, if output of pexpect.spawn is "password:" then i will get 0 as output and if EOF is encountered instead of "password" then the value of i will be 1.
I hope this would clear your doubt. If not, then let me know. I will try to enhance the explanation for you.
After sending password i.e
child.sendline('password')
write:
child.expect(pexpect.EOF)
This waits till copying of file finishes
I ran into the same problem. It happened when I specified the home directory (~/) of the client as the destination. This worked fine when manually typing in the scp command but for some reason not when using pexpect. Simply using a relative or absolute destination directory path solved the problem for me.
you have to finish your code with child.interact() then it will run the whole commands that you have written before that.
It will look like this:
child = pexpect.spawn('scp pathdir/file.ext username#hostname:pathdir')
r=child.expect ('assword:')
print r
if r==0:
child.sendline ('password')
child.interact()
child.close()

Categories