The below code fails to exit after 3/3 even though the stderr text
[ERROR] ssh target does not support password auth
fprintf(stderr, "[ERROR] ssh target..
output
#!/usr/bin/env python
import subprocess
import sys
if len(sys.argv) != 3:
print "Usage: sshrecon.py <ip address> <port>"
sys.exit(0)
ip_address = sys.argv[1].strip()
port = sys.argv[2].strip()
print "INFO: Performing <<TEST>> hydra ssh scan against " + ip_address
#3 steps for test phase:
#1 Run Hydra
#2 Gather std_err std_out output into a var
#3 analyze for String. Exit if found, else continue with full scan.
#[1/3] TEST if target allows PW auth
HYDRA_TEST_COMMAND = "hydra -l test -p test -f -o /var/www/html/recon_scan/results/labs/%s_test.txt -u %s -s %s ssh" % (ip_address, ip_address, port)
results_Test = subprocess.Popen(HYDRA_TEST_COMMAND, stdout=subprocess.PIPE, shell=True)
#[2/3]Gather stderr, stdout output into var
output = results_Test.stdout.read()
print output
#[3/3]analyze std_out for string. Exit if found.
if "ssh target does not support password auth" in output:
sys.exit()
This does not capture the result of stderr
.
results_Test = subprocess.Popen(
HYDRA_TEST_COMMAND,
stdout=subprocess.PIPE,
shell=True)
Because stderr
is not redirected, only stdout
, your program will not be able to read it. Your two choices are to mix stderr
and stdout
into one single stream, or to capture them separately.
If you want to combine both stderr
and stdout
into one stream,
results_Test = subprocess.Popen(
HYDRA_TEST_COMMAND,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
shell=True)
If you want separate streams,
results_Test = subprocess.Popen(
HYDRA_TEST_COMMAND,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
Using shell=True
is not recommended in general, because it can lead to potential unexpected behavior or attack vectors. Alternatively, you can pass the arguments as a list instead of a string, and then you can use the default (safer, faster) shell=False
.
HYDRA_TEST_COMMAND = [
'hydra', '-l', 'test', '-p', 'test', '-f',
'-o', '/var/www/html/recon_scan/results/labs/%s_test.txt' % ip_address,
'-u', ip_address, '-s', port, 'ssh']
If port
is an int
you will need to use str(port)
instead.
There are cases where shell=True
is more convenient but they are rare in practice.
This might not affect how your program works, but it eliminates problems with quoting or weird characters in filenames. If you don't like how verbose it is you can make it a bit shorter with .split()
.
Instead of proc.stdout.read()
, use proc.communicate()
.
# instead of results_Test.stdout.read()
stdout, stderr = results_Test.communicate()
If you used PIPE
for both stdout
and stderr
, this gives you the contents of both in separate variables. If you use .stdout.read()
instead, the process can become blocked waiting for you to read from .stderr.read()
. That's the primary job of .communicate()
-- it reads from both stderr
and stdout
at the same time so the process doesn't block.
If you use stderr=subprocess.STDOUT
, then stderr
will be None
because the contents are mixed into stdout
.
In either case, it is recommended to use .communicate()
.