I am automating some tasks with python, but have hit a bit of a roadblock. One of the tasks I am automating requires user input in the shell.
The requirement is that you to run the command with an email address as a parameter (simple enough), and then you are asked to authenticate with the password for that email address. How can you simulate user input to provide the password?
There are also some menus afterwards which ask options, for which the input need just be to repeatedly hit enter. How is this simulated? Keeping in mind that this window will not always have focus..
I'm not sure what you're asking in the second part, but subprocesses can be controlled with the pexpect module. For example:
#!/usr/bin/env python
import pexpect
import sys
# Get email and password somehow
#email = ...
#password = ...
# Start the subprocess
child = pexpect.spawn('mycommand %s' % email)
# redirect output to stdout
child.logfile_read = sys.stdout
# Assumes the prompt is "password:"
child.expect('password:')
child.sendline(password)
# Wait for the process to close its output
child.expect(pexpect.EOF)
Looks like you are thinking in a wrong way. You just need to send some bytes via pipe to recipient (shell script in your case) and this can be done with subprocess.
I guess you can use expect for this.
Related
I've been trying to automate ssh'ing into my server however cannot find a way to fully automate the process. To be specific, getting around this input has been the struggle: root#example's password:
My code:
import subprocess
import time
server_ip = 'server'
pwd = b'password'
p = subprocess.Popen(['ssh', 'root#{}'.format(server_ip)],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
if p == "root#example's password: ":
p.communicate(input= "{}".format(pwd))
else:
time.sleep(2)
if p == "root#example's password: ":
p.communicate(input= "{}".format(pwd))
else:
pass
What it returns:
Pseudo-terminal will not be allocated because stdin is not a terminal.
root#example's password:
user#computer ~ % Permission denied, please try again.
root#example's password:
Permission denied, please try again.
root#example's password:
root#example: Permission denied (publickey,password).
I know my code is very scuffed but it is the furthest I've got to getting in and submitting the password entry request.
Any help is appreciated!
if p == "root#example's password: ": can never be true; p is a subprocess.Popen object, not a string.
You can get a string by reading from the object's standard output, but of course, ssh prints the prompt message on the tty, so you can't easily capture it from Python.
Notice also that without an encoding keyword argument or text=True, you can't send or receive strings; the output you receive will be a b'...' byte string which cannot be compared to a regular string.
... But even if you managed to sort out these problems, taking it from there to a fully working interactive SSH session is still quite some distance to go. I would definitely recommend that you try pexpect or Paramiko instead of rolling your own, especially if you are new to Python.
Tangentially, else: pass is completely unnecessary; there is no reason to add an else: block in the first place if you don't have anything useful to put in it.
And
As "{}".format(pwd) is a really hairy way to write what can be more easily expressed as pwd, or str(pwd) if it's not already a string.
I've managed to get the cmd being opened by python. However, using runas administrator comes with a password check before cmd.exe is executed.
I'm using this to open cmd...
import subprocess
subprocess.call(["runas", "/user:Administrator", "cmd.exe"])
I'm looking for a way to automatically enter the password into the runas.exe prompt which opens when i run the code. Say if i were to create var = "test" and add it after import subprocess how would i make it so that this variable is passed to and seen as an input to the runas.exe?
The solution would require only python modules which are in version 3.4 or higher.
Update
I have found some code which appears to input straight into runas.exe. However, the apparent input is \x00\r\n when in the code the input is supposed to be test I am fairly certain that if i can get the input to be test then the code will be successful.
The code is as follows :
import subprocess
args = ['runas', '/user:Administrator', 'cmd.exe']
proc = subprocess.Popen(args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
proc.stdin.write(b'test\n')
proc.stdin.flush()
stdout, stderr = proc.communicate()
print (stdout)
print (stderr)
Although not an answer to your question, this can be a solution to your problem. Use psexec instead of runas. You can run it like this:
psexec -u user -p password cmd
(or run it from Python using subprocess.Popen or something else)
This piece of code actually works (tested on a Windows 2008 server). I've used it to call runas for a different user and pass his password. A new command prompt opened with new user context, without needing to enter password.
Note that you have to install pywin32 to have access to the win32 API.
The idea is:
to Popen the runas command, without any input redirection, redirecting output
read char by char until we encounter ":" (last char of the password prompt).
send key events to the console using win32 packages, with the final \r to end the password input.
(adapted from this code):
import win32console, win32con, time
import subprocess
username = "me"
domain = "my_domain"
password ="xxx"
free_console=True
try:
win32console.AllocConsole()
except win32console.error as exc:
if exc.winerror!=5:
raise
## only free console if one was created successfully
free_console=False
stdin=win32console.GetStdHandle(win32console.STD_INPUT_HANDLE)
p = subprocess.Popen(["runas",r"/user:{}\{}".format(domain,username),"cmd.exe"],stdout=subprocess.PIPE)
while True:
if p.stdout.read(1)==b":":
for c in "{}\r".format(password): # end by CR to send "RETURN"
## write some records to the input queue
x=win32console.PyINPUT_RECORDType(win32console.KEY_EVENT)
x.Char=unicode(c) # remove unicode for python 3
x.KeyDown=True
x.RepeatCount=1
x.VirtualKeyCode=0x0
x.ControlKeyState=win32con.SHIFT_PRESSED
stdin.WriteConsoleInput([x])
p.wait()
break
I'm trying to run a code which will trigger a script.
The script evaluates something and uploads the results to a site for which it prompts password from user. Need to automate this with a generic user.
I have
import subprocess
p=subprocess.Popen(cmd,cwd=path)
p.wait()
When this runs, it evaluates something and prompts for password.
How to give this password using pexpect?
Is there any other solution to it?
By using the spawn class
p = ['cmd','to','run']
child = pexpect.spawn(' '.join(p), cwd='/path/to/dir')
# Now you give a regex of the expected password prompt
# usually use 'pass.*'
# but for a general case use '.*'
child.expect('.*')
child.sendline('abc123') # your secure password
child.wait()
I'm trying to write a python script that start a process and do some operations atferward.
The commands that I want to automate by script are circled as red in the picture.
The problem is that after performing first command, qemu environment will be run and the other commands should be executed on the qemu environment. So I want to know how can I do these commands by an script in python? Because as I know I can do the first command but I do not know how can I do those commands when I am going to qemu environment.
Could you help me how can I do this process?
First thing that came to mind was pexpect, a quick search on google turned up this blog post automatically-testing-vms-using-pexpect-and-qemu which seems to be pretty much along the lines of what you are doing:
import pexpect
image = "fedora-20.img"
user = "root"
password = "changeme"
# Define the qemu cmd to run
# The important bit is to redirect the serial to stdio
cmd = "qemu-kvm"
cmd += " -m 1024 -serial stdio -net user -net nic"
cmd += " -snapshot -hda %s" % image
cmd += " -watchdog-action poweroff"
# Spawn the qemu process and log to stdout
child = pexpect.spawn(cmd)
child.logfile = sys.stdout
# Now wait for the login
child.expect('(?i)login:')
# And login with the credentials from above
child.sendline(user)
child.expect('(?i)password:')
child.sendline(password)
child.expect('# ')
# Now shutdown the machine and end the process
if child.isalive():
child.sendline('init 0')
child.close()
if child.isalive():
print('Child did not exit gracefully.')
else:
print('Child exited gracefully.')
You could do it with subprocess.Popen also, checking the stdout for the (qemu) lines and writing to stdin. Something roughly like this:
from subprocess import Popen,PIPE
# pass initial command as list of individual args
p = Popen(["./tracecap/temu","-monitor",.....],stdout=PIPE, stdin=PIPE)
# store all the next arguments to pass
args = iter([arg1,arg2,arg3])
# iterate over stdout so we can check where we are
for line in iter(p.stdout.readline,""):
# if (qemu) is at the prompt, enter a command
if line.startswith("(qemu)"):
arg = next(args,"")
# if we have used all args break
if not arg:
break
# else we write the arg with a newline
p.stdin.write(arg+"\n")
print(line)# just use to see the output
Where args contains all the next commands.
Don't forget that Python has batteries included. Take a look of the Suprocess module in the standard lib. There a lot of pitfalls managing processes, and the module take care of them all.
You probably want to start a qemu process and send the next commands writing to its standard input (stdin). Subprocess module will allow you to do it. See that qemu has command line options to connect to stdi: -chardev stdio ,id=id
I'm trying to do a login script using python that will attempt to login with the shell command login -q MyUsername and try multiple passwords. I can already generate the passwords needed but when I try to login using the code below, the login command responds that I entered the wrong username although I know I'm writing it correctly. To clarify: I'm creating a script to login using the shell command login when I already know the username but not the password. The code below shows what I'm doing (iterating over the passwords).
for password in passwordList:
p = Popen(["login","-q","MyUsername"], stdin=PIPE, stdout=PIPE) #The username MyUsername is correct, 100% sure
print repr(p)
stdout_value = p.communicate(password)[0] #
print(str(stdout_value))
if repr(stdout_value).startswith('Login incorrect\nlogin: '):
print "ERROR"
else:
print "GOOD"
break
If I type in the command login -q MyUsername directly into the terminal, I get prompted to write my password whereas using the script returns 'Login Incorrect'. I'm also confused as how Popen works and how to write to stdout.
Thanks in advance!
(Other question: Is there an easier way to do this? (Attempt to login using multiple passwords) I'm using login because it has no lockdown and the user data can't be accessed if it is not by the superuser).
login might read/write directly from/to terminal (tty) outside of process' stdin/stdout. You could use pexpect instead, read the first reason in its docs Q: Why not just use a pipe (popen())?:
import pexpect
output, rc = pexpect.run("login -q MyUsername",
events={"(?i)password: ": "password"},
withexitstatus=True)
Is there an easier way to do this?
Read the hashes from /etc/passwd, /etc/shadow and check those using crypt.crypt(). Or use a specialized tool to test for weak passwords such as "John the Reaper".