Moar python3 compat

pull/90/head
lanjelot 7 years ago
parent 9f377357e4
commit 32c6963575

@ -135,7 +135,9 @@ ajpy | AJP | https://github.com/hypn0s/AJPy/
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
openldap | LDAP | http://www.openldap.org/ | 2.4.24 | openldap | LDAP | http://www.openldap.org/ | 2.4.24 |
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
impacket | SMB | https://github.com/CoreSecurity/impacket | 0.9.12 | impacket | SMB, MSSQL | https://github.com/CoreSecurity/impacket | 0.9.12 |
--------------------------------------------------------------------------------------------------
pyOpenSSL | impacket | https://pyopenssl.org/ | 17.5.0 |
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
cx_Oracle | Oracle | http://cx-oracle.sourceforge.net/ | 5.1.1 | cx_Oracle | Oracle | http://cx-oracle.sourceforge.net/ | 5.1.1 |
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
@ -145,7 +147,7 @@ xfreerdp | RDP (NLA) | https://github.com/FreeRDP/FreeRDP/
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
psycopg | PostgreSQL | http://initd.org/psycopg/ | 2.4.5 | psycopg | PostgreSQL | http://initd.org/psycopg/ | 2.4.5 |
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
pycrypto | VNC | http://www.dlitz.net/software/pycrypto/ | 2.3 | pycrypto | VNC, impacket | http://www.dlitz.net/software/pycrypto/ | 2.6.1 |
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
dnspython | DNS | http://www.dnspython.org/ | 1.10.0 | dnspython | DNS | http://www.dnspython.org/ | 1.10.0 |
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
@ -153,7 +155,7 @@ IPy | NET keyword | https://github.com/haypo/python-ipy
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
pysnmp | SNMP | http://pysnmp.sourceforge.net/ | 4.2.1 | pysnmp | SNMP | http://pysnmp.sourceforge.net/ | 4.2.1 |
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
pyasn1 | SNMP | http://sourceforge.net/projects/pyasn1/ | 0.1.2 | pyasn1 | SNMP, impacket | http://sourceforge.net/projects/pyasn1/ | 0.1.2 |
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
ike-scan | IKE | http://www.nta-monitor.com/tools-resources/ | 1.9 | ike-scan | IKE | http://www.nta-monitor.com/tools-resources/ | 1.9 |
-------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------
@ -577,7 +579,7 @@ NB1. SNMPv3 requires passphrases to be at least 8 characters long.
* Brute-force the ZIP file password (cracking older pkzip encryption used to be not supported in JtR). * Brute-force the ZIP file password (cracking older pkzip encryption used to be not supported in JtR).
---------- ----------
unzip_pass zipfile=path/to/file.zip password=FILE0 0=passwords.txt -x ignore:code!=0 unzip_pass zipfile=file.zip password=FILE0 0=passwords.txt -x ignore:code!=0
}}} }}}
@ -676,16 +678,21 @@ class TXTFormatter(logging.Formatter):
def format(self, record): def format(self, record):
if not record.msg or record.msg == 'headers': if not record.msg or record.msg == 'headers':
self._fmt = self.resultfmt fmt = self.resultfmt
if not all(True if 0x20 <= ord(c) < 0x7f else False for c in record.candidate): if not all(True if 0x20 <= ord(c) < 0x7f else False for c in record.candidate):
record.candidate = repr(record.candidate) record.candidate = repr(record.candidate)
else: else:
if record.levelno == logging.DEBUG: if record.levelno == logging.DEBUG:
self._fmt = '%(asctime)s %(name)-7s %(levelname)7s [%(pname)s] %(message)s' fmt = '%(asctime)s %(name)-7s %(levelname)7s [%(pname)s] %(message)s'
else: else:
self._fmt = '%(asctime)s %(name)-7s %(levelname)7s - %(message)s' fmt = '%(asctime)s %(name)-7s %(levelname)7s - %(message)s'
if PY3:
self._style._fmt = fmt
else:
self._fmt = fmt
return logging.Formatter.format(self, record) return logging.Formatter.format(self, record)
@ -714,8 +721,8 @@ class XMLFormatter(logging.Formatter):
def format(self, record): def format(self, record):
for k, v in record.__dict__.iteritems(): for k, v in record.__dict__.items():
if isinstance(v, basestring): if isinstance(v, str):
record.__dict__[k] = xmlescape(v) record.__dict__[k] = xmlescape(v)
return super(XMLFormatter, self).format(record) return super(XMLFormatter, self).format(record)
@ -793,7 +800,7 @@ def process_logs(queue, indicatorsfmt, argv, log_dir):
else: # remove "</results>...</root>" else: # remove "</results>...</root>"
with open(results_xml, 'r+b') as f: with open(results_xml, 'r+b') as f:
offset = f.read().find('</results>') offset = f.read().find(b'</results>')
if offset != -1: if offset != -1:
f.seek(offset) f.seek(offset)
f.truncate(f.tell()) f.truncate(f.tell())
@ -896,6 +903,23 @@ except ImportError:
from cStringIO import StringIO from cStringIO import StringIO
from sys import maxint from sys import maxint
PY3 = sys.version_info >= (3,)
if PY3: # http://python3porting.com/problems.html
def b(x):
return x.encode('ISO-8859-1')
def B(x):
return x.decode()
else:
def b(x):
return x
def B(x):
return x
try:
input = raw_input
except NameError:
pass
notfound = [] notfound = []
try: try:
from IPy import IP from IPy import IP
@ -904,33 +928,40 @@ except ImportError:
has_ipy = False has_ipy = False
notfound.append('IPy') notfound.append('IPy')
import multiprocessing.forking try:
class _Popen(multiprocessing.forking.Popen): # Python 3.4+
if sys.platform.startswith('win'):
import multiprocessing.popen_spawn_win32 as forking
else:
import multiprocessing.popen_fork as forking
except ImportError:
import multiprocessing.forking as forking
if sys.platform.startswith('win'):
# First define a modified version of Popen.
class _Popen(forking.Popen):
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
if hasattr(sys, 'frozen'):
# We have to set original _MEIPASS2 value from sys._MEIPASS
# to get --onefile mode working.
os.putenv('_MEIPASS2', sys._MEIPASS)
try:
super(_Popen, self).__init__(*args, **kw)
finally:
if hasattr(sys, 'frozen'): if hasattr(sys, 'frozen'):
# We have to set original _MEIPASS2 value from sys._MEIPASS # On some platforms (e.g. AIX) 'os.unsetenv()' is not
# to get --onefile mode working. # available. In those cases we cannot delete the variable
os.putenv('_MEIPASS2', sys._MEIPASS) # but only set it to the empty string. The bootloader
try: # can handle this case.
super(_Popen, self).__init__(*args, **kw) if hasattr(os, 'unsetenv'):
finally: os.unsetenv('_MEIPASS2')
if hasattr(sys, 'frozen'): else:
# On some platforms (e.g. AIX) 'os.unsetenv()' is not os.putenv('_MEIPASS2', '')
# available. In those cases we cannot delete the variable
# but only set it to the empty string. The bootloader
# can handle this case.
if hasattr(os, 'unsetenv'):
os.unsetenv('_MEIPASS2')
else:
os.putenv('_MEIPASS2', '')
class Process(multiprocessing.Process): # Second override 'Popen' class with our modified version.
_Popen = _Popen forking.Popen = _Popen
# So BaseManager.start() uses this new Process class
multiprocessing.Process = Process
from multiprocessing.managers import SyncManager from multiprocessing.managers import SyncManager
# imports }}} # imports }}}
# utils {{{ # utils {{{
@ -975,7 +1006,7 @@ def create_dir(top_path):
if os.path.isdir(top_path): if os.path.isdir(top_path):
files = os.listdir(top_path) files = os.listdir(top_path)
if files: if files:
if raw_input("Directory '%s' is not empty, do you want to wipe it ? [Y/n]: " % top_path) != 'n': if input("Directory '%s' is not empty, do you want to wipe it ? [Y/n]: " % top_path) != 'n':
for root, dirs, files in os.walk(top_path): for root, dirs, files in os.walk(top_path):
if dirs: if dirs:
print("Directory '%s' contains sub-directories, safely aborting..." % root) print("Directory '%s' contains sub-directories, safely aborting..." % root)
@ -1400,7 +1431,7 @@ Please read the README inside for more examples and usage information.
log_queue = multiprocessing.Queue() log_queue = multiprocessing.Queue()
logsvc = Process(name='LogSvc', target=process_logs, args=(log_queue, module.Response.indicatorsfmt, argv, build_logdir(opts.log_dir, opts.auto_log))) logsvc = multiprocessing.Process(name='LogSvc', target=process_logs, args=(log_queue, module.Response.indicatorsfmt, argv, build_logdir(opts.log_dir, opts.auto_log)))
logsvc.daemon = True logsvc.daemon = True
logsvc.start() logsvc.start()
@ -1426,6 +1457,7 @@ Please read the README inside for more examples and usage information.
p = expand_path(v[1:]) p = expand_path(v[1:])
with open(p) as f: with open(p) as f:
v = f.read() v = f.read()
kargs.append((k, v)) kargs.append((k, v))
iter_vals = [v for k, v in sorted(wlists.items())] iter_vals = [v for k, v in sorted(wlists.items())]
@ -1619,14 +1651,14 @@ Please read the README inside for more examples and usage information.
# consumers # consumers
for num in range(self.num_threads): for num in range(self.num_threads):
report_queue = multiprocessing.Queue(maxsize=1000) report_queue = multiprocessing.Queue(maxsize=1000)
t = Process(name='Consumer-%d' % num, target=self.consume, args=(task_queues[num], report_queue, logger.queue)) t = multiprocessing.Process(name='Consumer-%d' % num, target=self.consume, args=(task_queues[num], report_queue, logger.queue))
t.daemon = True t.daemon = True
t.start() t.start()
self.thread_report.append(report_queue) self.thread_report.append(report_queue)
self.thread_progress.append(Progress()) self.thread_progress.append(Progress())
# producer # producer
t = Process(name='Producer', target=self.produce, args=(task_queues, logger.queue)) t = multiprocessing.Process(name='Producer', target=self.produce, args=(task_queues, logger.queue))
t.daemon = True t.daemon = True
t.start() t.start()
@ -2130,7 +2162,6 @@ class Timing:
# TCP_Cache {{{ # TCP_Cache {{{
class TCP_Connection: class TCP_Connection:
def __init__(self, fp, banner=None): def __init__(self, fp, banner=None):
self.fp = fp self.fp = fp
self.banner = banner self.banner = banner
@ -2197,16 +2228,16 @@ class TCP_Cache:
# FTP {{{ # FTP {{{
from ftplib import FTP, Error as FTP_Error from ftplib import FTP, Error as FTP_Error
try: try:
from ftplib import FTP_TLS # New in python 2.7 from ftplib import FTP_TLS # only available since python 2.7
except ImportError: except ImportError:
notfound.append('ftp-tls') notfound.append('python')
class FTP_login(TCP_Cache): class FTP_login(TCP_Cache):
'''Brute-force FTP''' '''Brute-force FTP'''
usage_hints = ( usage_hints = (
"""%prog host=10.0.0.1 user=FILE0 password=FILE1 0=logins.txt 1=passwords.txt""" '''%prog host=10.0.0.1 user=FILE0 password=FILE1 0=logins.txt 1=passwords.txt'''
""" -x ignore:mesg='Login incorrect.' -x ignore,reset,retry:code=500""", ''' -x ignore:mesg='Login incorrect.' -x ignore,reset,retry:code=500''',
) )
available_options = ( available_options = (
@ -2237,23 +2268,25 @@ class FTP_login(TCP_Cache):
def execute(self, host, port='21', tls='0', user=None, password=None, timeout='10', persistent='1'): def execute(self, host, port='21', tls='0', user=None, password=None, timeout='10', persistent='1'):
with Timing() as timing:
fp, resp = self.bind(host, port, tls, timeout=timeout)
try: try:
with Timing() as timing:
fp, resp = self.bind(host, port, tls, timeout=timeout)
if user is not None or password is not None: if user is not None or password is not None:
with Timing() as timing: with Timing() as timing:
if user is not None: if user is not None:
resp = fp.sendcmd('USER ' + user) resp = fp.sendcmd('USER ' + user)
if password is not None: if password is not None:
resp = fp.sendcmd('PASS ' + password) resp = fp.sendcmd('PASS ' + password)
logger.debug('No error: %s' % resp) logger.debug('No error: %r' % resp)
self.reset() self.reset()
except FTP_Error as e: except FTP_Error as e:
logger.debug('FTP_Error: %s' % e)
resp = str(e) resp = str(e)
logger.debug('FTP_Error: %s' % resp)
if persistent == '0': if persistent == '0':
self.reset() self.reset()
@ -2264,7 +2297,6 @@ class FTP_login(TCP_Cache):
# }}} # }}}
# SSH {{{ # SSH {{{
try: try:
from logging import NullHandler # only available since python 2.7 from logging import NullHandler # only available since python 2.7
except ImportError: except ImportError:
@ -2314,10 +2346,10 @@ class SSH_login(TCP_Cache):
def execute(self, host, port='22', user=None, password=None, auth_type='password', keyfile=None, persistent='1'): def execute(self, host, port='22', user=None, password=None, auth_type='password', keyfile=None, persistent='1'):
with Timing() as timing:
fp, banner = self.bind(host, port, user)
try: try:
with Timing() as timing:
fp, banner = self.bind(host, port, user)
if user is not None: if user is not None:
if keyfile is not None: if keyfile is not None:
@ -2359,6 +2391,7 @@ class SSH_login(TCP_Cache):
# Telnet {{{ # Telnet {{{
from telnetlib import Telnet from telnetlib import Telnet
class Telnet_login(TCP_Cache): class Telnet_login(TCP_Cache):
'''Brute-force Telnet''' '''Brute-force Telnet'''
@ -2389,7 +2422,8 @@ class Telnet_login(TCP_Cache):
with Timing() as timing: with Timing() as timing:
fp, _ = self.bind(host, port, timeout=timeout) fp, _ = self.bind(host, port, timeout=timeout)
trace = '' trace = b''
prompt_re = b(prompt_re)
timeout = int(timeout) timeout = int(timeout)
if self.prompt_count == 0: if self.prompt_count == 0:
@ -2400,9 +2434,10 @@ class Telnet_login(TCP_Cache):
if inputs is not None: if inputs is not None:
with Timing() as timing: with Timing() as timing:
for val in inputs.split(r'\n'): for val in inputs.split(r'\n'):
logger.debug('input: %s' % val) logger.debug('input: %s' % val)
cmd = val + '\n' #'\r\x00' cmd = b(val + '\n') #'\r\x00'
fp.write(cmd) fp.write(cmd)
trace += cmd trace += cmd
@ -2414,13 +2449,17 @@ class Telnet_login(TCP_Cache):
if persistent == '0': if persistent == '0':
self.reset() self.reset()
raw = B(raw)
trace = B(trace)
mesg = repr(raw)[1:-1] # strip enclosing single quotes mesg = repr(raw)[1:-1] # strip enclosing single quotes
return self.Response(0, mesg, timing, trace) return self.Response(0, mesg, timing, trace)
# }}} # }}}
# SMTP {{{ # SMTP {{{
from smtplib import SMTP, SMTP_SSL, SMTPAuthenticationError, SMTPHeloError, SMTPException from smtplib import SMTP, SMTP_SSL, SMTPException, SMTPResponseException
class SMTP_Base(TCP_Cache): class SMTP_Base(TCP_Cache):
available_options = TCP_Cache.available_options available_options = TCP_Cache.available_options
@ -2482,7 +2521,7 @@ class SMTP_vrfy(SMTP_Base):
self.reset() self.reset()
code, mesg = resp code, mesg = resp
return self.Response(code, mesg, timing) return self.Response(code, B(mesg), timing)
class SMTP_rcpt(SMTP_Base): class SMTP_rcpt(SMTP_Base):
@ -2516,7 +2555,7 @@ class SMTP_rcpt(SMTP_Base):
self.reset() self.reset()
code, mesg = resp code, mesg = resp
return self.Response(code, mesg, timing) return self.Response(code, B(mesg), timing)
class SMTP_login(SMTP_Base): class SMTP_login(SMTP_Base):
@ -2545,14 +2584,19 @@ class SMTP_login(SMTP_Base):
logger.debug('No error: %s' % str(resp)) logger.debug('No error: %s' % str(resp))
self.reset() self.reset()
except (SMTPHeloError,SMTPAuthenticationError,SMTPException) as resp: except SMTPResponseException as e:
logger.debug('SMTPError: %s' % str(resp)) logger.debug('SMTPResponseException: %s' % e)
resp = e.args
except SMTPException as e:
logger.debug('SMTPException: %s' % e)
resp = '1', b(str(e))
if persistent == '0': if persistent == '0':
self.reset() self.reset()
code, mesg = resp code, mesg = resp
return self.Response(code, mesg, timing) return self.Response(code, B(mesg), timing)
# }}} # }}}
@ -2595,10 +2639,10 @@ class Finger_lookup:
s.connect((host, int(port))) s.connect((host, int(port)))
if user: if user:
s.send(user) s.send(b(user))
s.send('\r\n') s.send(b'\r\n')
data = '' data = b''
with Timing() as timing: with Timing() as timing:
while True: while True:
raw = s.recv(1024) raw = s.recv(1024)
@ -2610,7 +2654,7 @@ class Finger_lookup:
logger.debug('recv: %r' % data) logger.debug('recv: %r' % data)
data = data.strip() data = B(data).strip()
mesg = repr(data) mesg = repr(data)
resp = self.Response(0, mesg, timing, data) resp = self.Response(0, mesg, timing, data)
@ -2668,14 +2712,13 @@ class LDAP_login:
try: try:
from impacket.smbconnection import SMBConnection, SessionError from impacket.smbconnection import SMBConnection, SessionError
from impacket import nt_errors from impacket import nt_errors
from impacket.dcerpc.v5 import transport, lsat, lsad from impacket.dcerpc.v5 import transport, lsat, lsad
from impacket.dcerpc.v5.dtypes import MAXIMUM_ALLOWED from impacket.dcerpc.v5.dtypes import MAXIMUM_ALLOWED
from impacket.dcerpc.v5.samr import SID_NAME_USE from impacket.dcerpc.v5.samr import SID_NAME_USE
except ImportError: except ImportError:
notfound.append('impacket') notfound.append('impacket')
class SMB_Connection(TCP_Connection): class SMB_Connection(TCP_Connection):
def close(self): def close(self):
self.fp.getSMBServer().get_socket().close() self.fp.getSMBServer().get_socket().close()
@ -2743,7 +2786,6 @@ class SMB_login(TCP_Cache):
return self.Response(code, mesg, timing) return self.Response(code, mesg, timing)
class DCE_Connection(TCP_Connection): class DCE_Connection(TCP_Connection):
def __init__(self, fp, smbt): def __init__(self, fp, smbt):
self.smbt = smbt self.smbt = smbt
TCP_Connection.__init__(self, fp) TCP_Connection.__init__(self, fp)
@ -2816,6 +2858,7 @@ class SMB_lookupsid(TCP_Cache):
# POP {{{ # POP {{{
from poplib import POP3, POP3_SSL, error_proto as pop_error from poplib import POP3, POP3_SSL, error_proto as pop_error
class POP_Connection(TCP_Connection): class POP_Connection(TCP_Connection):
def close(self): def close(self):
self.fp.quit() self.fp.quit()
@ -2916,8 +2959,8 @@ class POP_passd:
trace += '%s\r\n%s\r\n' % (cmd, resp) trace += '%s\r\n%s\r\n' % (cmd, resp)
except LineReceiver_Error as e: except LineReceiver_Error as e:
logger.debug('LineReceiver_Error: %s' % e)
resp = str(e) resp = str(e)
logger.debug('LineReceiver_Error: %s' % resp)
trace += '%s\r\n%s\r\n' % (cmd, resp) trace += '%s\r\n%s\r\n' % (cmd, resp)
finally: finally:
@ -2930,6 +2973,7 @@ class POP_passd:
# IMAP {{{ # IMAP {{{
from imaplib import IMAP4, IMAP4_SSL from imaplib import IMAP4, IMAP4_SSL
class IMAP_login: class IMAP_login:
'''Brute-force IMAP4''' '''Brute-force IMAP4'''
@ -3019,34 +3063,40 @@ class Rlogin_login(TCP_Cache):
fp, _ = self.bind(host, port, timeout=int(timeout)) fp, _ = self.bind(host, port, timeout=int(timeout))
trace = '' trace = b''
timeout = int(timeout) timeout = int(timeout)
with Timing() as timing: with Timing() as timing:
if self.need_handshake: if self.need_handshake:
fp.write('\x00%s\x00%s\x00vt100/9600\x00' % (luser, user)) fp.write(b('\x00%s\x00%s\x00vt100/9600\x00' % (luser, user)))
self.need_handshake = False self.need_handshake = False
else: else:
fp.write('%s\r' % user) fp.write(b('%s\r' % user))
_, _, resp = fp.expect([prompt_re], timeout=timeout) # expecting the Password: prompt _, _, resp = fp.expect([prompt_re], timeout=timeout) # expecting the Password: prompt
trace += resp trace += resp
if password is not None: if password is not None:
fp.write('%s\r' % password) fp.write(b('%s\r' % password))
_, _, resp = fp.expect([prompt_re], timeout=timeout) # expecting the login: prompt _, _, resp = fp.expect([prompt_re], timeout=timeout) # expecting the login: prompt
trace += resp trace += resp
if persistent == '0': if persistent == '0':
self.reset() self.reset()
resp = B(resp)
trace = B(trace)
mesg = repr(resp.strip())[1:-1] mesg = repr(resp.strip())[1:-1]
return self.Response(0, mesg, timing, trace) return self.Response(0, mesg, timing, trace)
# }}} # }}}
# VMauthd {{{ # VMauthd {{{
from ssl import wrap_socket from ssl import wrap_socket
class LineReceiver_Error(Exception): pass
class LineReceiver_Error(Exception):
pass
class LineReceiver: class LineReceiver:
def connect(self, host, port, timeout, ssl=False): def connect(self, host, port, timeout, ssl=False):
@ -3062,15 +3112,15 @@ class LineReceiver:
self.sock.close() self.sock.close()
def sendcmd(self, cmd): def sendcmd(self, cmd):
self.sock.sendall(cmd + '\r\n') self.sock.sendall(b(cmd + '\r\n'))
return self.getresp() return self.getresp()
def getresp(self): def getresp(self):
resp = self.sock.recv(1024) resp = self.sock.recv(1024)
while not resp.endswith('\n'): while not resp.endswith(b'\n'):
resp += self.sock.recv(1024) resp += self.sock.recv(1024)
resp = resp.rstrip() resp = B(resp).rstrip()
code, _ = self.parse(resp) code, _ = self.parse(resp)
if not code.isdigit(): if not code.isdigit():
@ -3133,8 +3183,8 @@ class VMauthd_login(TCP_Cache):
trace += '%s\r\n%s\r\n' % (cmd, resp) trace += '%s\r\n%s\r\n' % (cmd, resp)
except LineReceiver_Error as e: except LineReceiver_Error as e:
logger.debug('LineReceiver_Error: %s' % e)
resp = str(e) resp = str(e)
logger.debug('LineReceiver_Error: %s' % resp)
trace += '%s\r\n%s\r\n' % (cmd, resp) trace += '%s\r\n%s\r\n' % (cmd, resp)
if persistent == '0': if persistent == '0':
@ -3228,7 +3278,8 @@ try:
from impacket import tds from impacket import tds
from impacket.tds import TDS_ERROR_TOKEN, TDS_LOGINACK_TOKEN from impacket.tds import TDS_ERROR_TOKEN, TDS_LOGINACK_TOKEN
except ImportError: except ImportError:
notfound.append('impacket') notfound.append('pyopenssl')
class MSSQL_login: class MSSQL_login:
'''Brute-force MSSQL''' '''Brute-force MSSQL'''
@ -3291,8 +3342,8 @@ class Oracle_login:
'''Brute-force Oracle''' '''Brute-force Oracle'''
usage_hints = ( usage_hints = (
"""%prog host=10.0.0.1 sid=FILE0 0=sids.txt -x ignore:code=ORA-12505""", '''%prog host=10.0.0.1 sid=FILE0 0=sids.txt -x ignore:code=ORA-12505''',
"""%prog host=10.0.0.1 user=SYS password=FILE0 0=passwords.txt -x ignore:code=ORA-01017""", '''%prog host=10.0.0.1 user=SYS password=FILE0 0=passwords.txt -x ignore:code=ORA-01017''',
) )
available_options = ( available_options = (
@ -3418,14 +3469,18 @@ class Response_HTTP(Response_Base):
return re.search(val, self.mesg, re.M) return re.search(val, self.mesg, re.M)
def str_target(self): def str_target(self):
return ' '.join('%s=%s' % (k, xmlquoteattr(str(v))) for k, v in self.target.iteritems()) return ' '.join('%s=%s' % (k, xmlquoteattr(str(v))) for k, v in self.target.items())
available_conditions = Response_Base.available_conditions available_conditions = Response_Base.available_conditions
available_conditions += ( available_conditions += (
('clen', 'match Content-Length header (N or N-M or N- or -N)'), ('clen', 'match Content-Length header (N or N-M or N- or -N)'),
) )
from BaseHTTPServer import BaseHTTPRequestHandler try:
from http.server import BaseHTTPRequestHandler
except ImportError:
from BaseHTTPServer import BaseHTTPRequestHandler
class HTTPRequestParser(BaseHTTPRequestHandler): class HTTPRequestParser(BaseHTTPRequestHandler):
def __init__(self, fd): def __init__(self, fd):
self.rfile = fd self.rfile = fd
@ -3435,7 +3490,8 @@ class HTTPRequestParser(BaseHTTPRequestHandler):
self.parse_request() self.parse_request()
if self.command == 'POST': if self.command == 'POST':
self.body = self.rfile.read(-1).rstrip('\r\n') self.body = B(self.rfile.read(-1)).rstrip('\r\n')
if 'Content-Length' in self.headers: if 'Content-Length' in self.headers:
del self.headers['Content-Length'] del self.headers['Content-Length']
@ -3448,7 +3504,7 @@ class Controller_HTTP(Controller):
key, val = arg.split('=', 1) key, val = arg.split('=', 1)
if key == 'raw_request': if key == 'raw_request':
with open(val) as fd: with open(val, 'rb') as fd:
r = HTTPRequestParser(fd) r = HTTPRequestParser(fd)
if r.error: if r.error:
@ -3466,7 +3522,7 @@ class Controller_HTTP(Controller):
opts['method'] = r.command opts['method'] = r.command
opts['body'] = r.body opts['body'] = r.body
for key, val in opts.iteritems(): for key, val in opts.items():
if val: if val:
yield (key, val) yield (key, val)
@ -3477,13 +3533,10 @@ class HTTP_fuzz(TCP_Cache):
'''Brute-force HTTP''' '''Brute-force HTTP'''
usage_hints = [ usage_hints = [
"""%prog url=http://10.0.0.1/FILE0 0=paths.txt -x ignore:code=404 -x ignore,retry:code=500""", '''%prog url=http://10.0.0.1/FILE0 0=paths.txt -x ignore:code=404 -x ignore,retry:code=500''',
'''%prog url=http://10.0.0.1/manager/html user_pass=COMBO00:COMBO01 0=combos.txt -x ignore:code=401''',
"""%prog url=http://10.0.0.1/manager/html user_pass=COMBO00:COMBO01 0=combos.txt""" '''%prog url=http://10.0.0.1/phpmyadmin/index.php method=POST'''
""" -x ignore:code=401""", ''' body='pma_username=root&pma_password=FILE0&server=1&lang=en' 0=passwords.txt follow=1'''
"""%prog url=http://10.0.0.1/phpmyadmin/index.php method=POST"""
""" body='pma_username=root&pma_password=FILE0&server=1&lang=en' 0=passwords.txt follow=1"""
""" accept_cookie=1 -x ignore:fgrep='Cannot log in to the MySQL server'""", """ accept_cookie=1 -x ignore:fgrep='Cannot log in to the MySQL server'""",
] ]
@ -3574,9 +3627,14 @@ class HTTP_fuzz(TCP_Cache):
if max_mem > 0 and trace.tell() > max_mem: if max_mem > 0 and trace.tell() > max_mem:
return 0 return 0
s = B(s)
if t in (pycurl.INFOTYPE_HEADER_OUT, pycurl.INFOTYPE_DATA_OUT): if t in (pycurl.INFOTYPE_HEADER_OUT, pycurl.INFOTYPE_DATA_OUT):
trace.write(s) trace.write(s)
elif t == pycurl.INFOTYPE_TEXT and b'upload completely sent off' in s:
trace.write('\n\n')
elif t in (pycurl.INFOTYPE_HEADER_IN, pycurl.INFOTYPE_DATA_IN): elif t in (pycurl.INFOTYPE_HEADER_IN, pycurl.INFOTYPE_DATA_IN):
trace.write(s) trace.write(s)
response.write(s) response.write(s)
@ -3697,12 +3755,12 @@ class Response_AJP(Response_HTTP):
self.status_msg = status_msg self.status_msg = status_msg
def __str__(self): def __str__(self):
return self.status_msg or self.mesg return self.status_msg or self.mesg
def prepare_ajp_forward_request(target_host, req_uri, method): def prepare_ajp_forward_request(target_host, req_uri, method):
fr = AjpForwardRequest(AjpForwardRequest.SERVER_TO_CONTAINER) fr = AjpForwardRequest(AjpForwardRequest.SERVER_TO_CONTAINER)
fr.method = method fr.method = method
fr.protocol = "HTTP/1.1" fr.protocol = 'HTTP/1.1'
fr.req_uri = req_uri fr.req_uri = req_uri
fr.remote_addr = target_host fr.remote_addr = target_host
fr.remote_host = None fr.remote_host = None
@ -3728,9 +3786,8 @@ class AJP_fuzz(TCP_Cache):
'''Brute-force AJP''' '''Brute-force AJP'''
usage_hints = [ usage_hints = [
"""%prog url=ajp://10.0.0.1/FILE0 0=paths.txt -x ignore:code=404 -x ignore,retry:code=500""", '''%prog url=ajp://10.0.0.1/FILE0 0=paths.txt -x ignore:code=404 -x ignore,retry:code=500''',
"""%prog url=ajp://10.0.0.1/manager/html user_pass=COMBO00:COMBO01 0=combos.txt""" '''%prog url=ajp://10.0.0.1/manager/html user_pass=COMBO00:COMBO01 0=combos.txt -x ignore:code=401''',
""" -x ignore:code=401""",
] ]
available_options = ( available_options = (
@ -3801,7 +3858,7 @@ class RDP_login:
'''Brute-force RDP (NLA)''' '''Brute-force RDP (NLA)'''
usage_hints = ( usage_hints = (
"""%prog host=10.0.0.1 user='administrator' password=FILE0 0=passwords.txt""", '''%prog host=10.0.0.1 user='administrator' password=FILE0 0=passwords.txt''',
) )
available_options = ( available_options = (
@ -3820,7 +3877,7 @@ class RDP_login:
with Timing() as timing: with Timing() as timing:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate() out, err = map(B, p.communicate())
code = p.returncode code = p.returncode
err = err.replace('''Authentication only. Don't connect to X. err = err.replace('''Authentication only. Don't connect to X.
@ -3847,35 +3904,37 @@ try:
except ImportError: except ImportError:
notfound.append('pycrypto') notfound.append('pycrypto')
class VNC_Error(Exception): pass class VNC_Error(Exception):
pass
class VNC: class VNC:
def connect(self, host, port, timeout): def connect(self, host, port, timeout):
self.fp = socket.create_connection((host, port), timeout=timeout) self.fp = socket.create_connection((host, port), timeout=timeout)
resp = self.fp.recv(99) # banner resp = self.fp.recv(99) # banner
logger.debug('banner: %r' % resp) logger.debug('banner: %r' % resp)
self.version = resp[:11].decode('ascii') self.version = B(resp[:11])
if len(resp) > 12: if len(resp) > 12:
raise VNC_Error('%s %s' % (self.version, resp[12:].decode('ascii', 'ignore'))) raise VNC_Error('%s %r' % (self.version, B(resp[12:])))
return self.version return self.version
def login(self, password): def login(self, password):
logger.debug('Remote version: %s' % self.version) logger.debug('Remote version: %r' % self.version)
major, minor = self.version[6], self.version[10] major, minor = self.version[6], self.version[10]
if (major, minor) in [('3', '8'), ('4', '1')]: if (major, minor) in [('3', '8'), ('4', '1')]:
proto = b'RFB 003.008\n' proto = 'RFB 003.008\n'
elif (major, minor) == ('3', '7'): elif (major, minor) == ('3', '7'):
proto = b'RFB 003.007\n' proto = 'RFB 003.007\n'
else: else:
proto = b'RFB 003.003\n' proto = 'RFB 003.003\n'
logger.debug('Client version: %s' % proto[:-1]) logger.debug('Client version: %r' % proto[:-1])
self.fp.sendall(proto) self.fp.sendall(b(proto))
sleep(0.5) sleep(0.5)
@ -3885,7 +3944,7 @@ class VNC:
if major == '4' or (major == '3' and int(minor) >= 7): if major == '4' or (major == '3' and int(minor) >= 7):
code = ord(resp[0:1]) code = ord(resp[0:1])
if code == 0: if code == 0:
raise VNC_Error('Session setup failed: %s' % resp.decode('ascii', 'ignore')) raise VNC_Error('Session setup failed: %s' % B(resp))
self.fp.sendall(b'\x02') # always use classic VNC authentication self.fp.sendall(b'\x02') # always use classic VNC authentication
resp = self.fp.recv(99) resp = self.fp.recv(99)
@ -3893,7 +3952,7 @@ class VNC:
else: # minor == '3': else: # minor == '3':
code = ord(resp[3:4]) code = ord(resp[3:4])
if code != 2: if code != 2:
raise VNC_Error('Session setup failed: %s' % resp.decode('ascii', 'ignore')) raise VNC_Error('Session setup failed: %s' % B(resp))
resp = resp[-16:] resp = resp[-16:]
@ -3916,7 +3975,7 @@ class VNC:
logger.debug('resp: %r' % resp) logger.debug('resp: %r' % resp)
code = ord(resp[3:4]) code = ord(resp[3:4])
mesg = resp[8:].decode('ascii', 'ignore') mesg = B(resp[8:])
if code == 1: if code == 1:
return code, mesg or 'Authentication failure' return code, mesg or 'Authentication failure'
@ -3938,17 +3997,16 @@ class VNC:
btgt = btgt | (1 << 7-i) btgt = btgt | (1 << 7-i)
newkey.append(btgt) newkey.append(btgt)
if sys.version_info[0] == 2: if PY3:
return ''.join(chr(c) for c in newkey)
else:
return bytes(newkey) return bytes(newkey)
else:
return ''.join(chr(c) for c in newkey)
class VNC_login: class VNC_login:
'''Brute-force VNC''' '''Brute-force VNC'''
usage_hints = ( usage_hints = (
"""%prog host=10.0.0.1 password=FILE0 0=passwords.txt -t 1 -x retry:fgrep!='Authentication failure' --max-retries -1 -x quit:code=0""", '''%prog host=10.0.0.1 password=FILE0 0=passwords.txt -t 1 -x retry:fgrep!='Authentication failure' --max-retries -1 -x quit:code=0''',
) )
available_options = ( available_options = (
@ -3981,7 +4039,6 @@ class VNC_login:
# }}} # }}}
# DNS {{{ # DNS {{{
try: try:
import dns.rdatatype import dns.rdatatype
import dns.message import dns.message
@ -4252,13 +4309,12 @@ class Controller_DNS(Controller):
name, data = name[:-1], data[:-1] name, data = name[:-1], data[:-1]
self.hostmap[data].alias.add(name) self.hostmap[data].alias.add(name)
class DNS_reverse: class DNS_reverse:
'''Reverse DNS lookup''' '''Reverse DNS lookup'''
usage_hints = [ usage_hints = [
"""%prog host=NET0 0=192.168.0.0/24 -x ignore:code=3""", '''%prog host=NET0 0=192.168.0.0/24 -x ignore:code=3''',
"""%prog host=NET0 0=216.239.32.0-216.239.47.255,8.8.8.0/24 -x ignore:code=3 -x ignore:fgrep!=google.com -x ignore:fgrep=216-239-""", '''%prog host=NET0 0=216.239.32.0-216.239.47.255,8.8.8.0/24 -x ignore:code=3 -x ignore:fgrep!=google.com -x ignore:fgrep=216-239-''',
] ]
available_options = ( available_options = (
@ -4291,9 +4347,9 @@ class DNS_forward:
'''Forward DNS lookup''' '''Forward DNS lookup'''
usage_hints = [ usage_hints = [
"""%prog name=FILE0.google.com 0=names.txt -x ignore:code=3""", '''%prog name=FILE0.google.com 0=names.txt -x ignore:code=3''',
"""%prog name=google.MOD0 0=TLD -x ignore:code=3""", '''%prog name=google.MOD0 0=TLD -x ignore:code=3''',
"""%prog name=MOD0.microsoft.com 0=SRV qtype=SRV -x ignore:code=3""", '''%prog name=MOD0.microsoft.com 0=SRV qtype=SRV -x ignore:code=3''',
] ]
available_options = ( available_options = (
@ -4337,6 +4393,11 @@ try:
except ImportError: except ImportError:
notfound.append('pysnmp') notfound.append('pysnmp')
try:
import pyasn1
except ImportError:
notfound.append('pyasn1')
class SNMP_login: class SNMP_login:
'''Brute-force SNMP v1/2/3''' '''Brute-force SNMP v1/2/3'''
@ -4412,7 +4473,7 @@ IKE_GROUP = [('1', 'modp768'), ('2', 'modp1024'), ('5', 'modp1536'),
# '27', '28', '29', '30', # RFC6932 # '27', '28', '29', '30', # RFC6932
def generate_transforms(): def generate_transforms():
lists = map(lambda l: [i[0] for i in l], [IKE_ENC, IKE_HASH, IKE_AUTH, IKE_GROUP]) lists = list(map(lambda l: [i[0] for i in l], [IKE_ENC, IKE_HASH, IKE_AUTH, IKE_GROUP]))
return map(lambda p: ','.join(p), product(*[chain(l) for l in lists])), reduce(lambda x,y: x*y, map(len, lists)) return map(lambda p: ','.join(p), product(*[chain(l) for l in lists])), reduce(lambda x,y: x*y, map(len, lists))
class Controller_IKE(Controller): class Controller_IKE(Controller):
@ -4443,7 +4504,7 @@ class Controller_IKE(Controller):
ike_ath = dict(IKE_AUTH) ike_ath = dict(IKE_AUTH)
ike_grp = dict(IKE_GROUP) ike_grp = dict(IKE_GROUP)
for endpoint, transforms in self.results.iteritems(): for endpoint, transforms in self.results.items():
print('\n+ %s' % endpoint) print('\n+ %s' % endpoint)
print(' %10s %10s %12s %10s' % ('Encryption', 'Hash', 'Auth', 'Group')) print(' %10s %10s %12s %10s' % ('Encryption', 'Hash', 'Auth', 'Group'))
print(' %10s %10s %12s %10s' % ('-'*10, '-'*10, '-'*10, '-'*10)) print(' %10s %10s %12s %10s' % ('-'*10, '-'*10, '-'*10, '-'*10))
@ -4464,8 +4525,8 @@ class IKE_enum:
'''Enumerate IKE transforms''' '''Enumerate IKE transforms'''
usage_hints = [ usage_hints = [
"""%prog host=10.0.0.1 transform=MOD0 0=TRANS -x ignore:fgrep=NO-PROPOSAL""", '''%prog host=10.0.0.1 transform=MOD0 0=TRANS -x ignore:fgrep=NO-PROPOSAL''',
"""%prog host=10.0.0.1 transform=MOD0 0=TRANS -x ignore:fgrep=NO-PROPOSAL aggressive=RANGE1 1=int:0-1""", '''%prog host=10.0.0.1 transform=MOD0 0=TRANS -x ignore:fgrep=NO-PROPOSAL aggressive=RANGE1 1=int:0-1''',
] ]
available_options = ( available_options = (
@ -4486,7 +4547,7 @@ class IKE_enum:
def __init__(self): def __init__(self):
uid = multiprocessing.current_process().name[9:] uid = multiprocessing.current_process().name[9:]
self.sport = '51%s' % uid self.sport = '51%d' % int(uid)
def execute(self, host, port='500', transform='5,1,1,2', aggressive='0', groupname='foo', vid=''): def execute(self, host, port='500', transform='5,1,1,2', aggressive='0', groupname='foo', vid=''):
@ -4500,7 +4561,7 @@ class IKE_enum:
with Timing() as timing: with Timing() as timing:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate() out, err = map(B, p.communicate())
code = p.returncode code = p.returncode
trace = '%s\n[out]\n%s\n[err]\n%s' % (cmd, out, err) trace = '%s\n[out]\n%s\n[err]\n%s' % (cmd, out, err)
@ -4532,7 +4593,7 @@ class Unzip_pass:
'''Brute-force the password of encrypted ZIP files''' '''Brute-force the password of encrypted ZIP files'''
usage_hints = [ usage_hints = [
"""%prog zipfile=path/to/file.zip password=FILE0 0=passwords.txt -x ignore:code!=0""", """%prog zipfile=file.zip password=FILE0 0=passwords.txt -x ignore:code!=0""",
] ]
available_options = ( available_options = (
@ -4550,7 +4611,7 @@ class Unzip_pass:
with Timing() as timing: with Timing() as timing:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate() out, err = map(B, p.communicate())
code = p.returncode code = p.returncode
mesg = repr(out.strip())[1:-1] mesg = repr(out.strip())[1:-1]
@ -4568,7 +4629,7 @@ class Keystore_pass:
'''Brute-force the password of Java keystore files''' '''Brute-force the password of Java keystore files'''
usage_hints = [ usage_hints = [
"""%prog keystore=path/to/keystore.jks password=FILE0 0=passwords.txt -x ignore:fgrep='password was incorrect'""", """%prog keystore=keystore.jks password=FILE0 0=passwords.txt -x ignore:fgrep='password was incorrect'""",
] ]
available_options = ( available_options = (
@ -4587,7 +4648,7 @@ class Keystore_pass:
with Timing() as timing: with Timing() as timing:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate() out, err = map(B, p.communicate())
code = p.returncode code = p.returncode
mesg = repr(out.strip())[1:-1] mesg = repr(out.strip())[1:-1]
@ -4607,7 +4668,7 @@ class SQLCipher_pass:
'''Brute-force the password of SQLCipher-encrypted databases''' '''Brute-force the password of SQLCipher-encrypted databases'''
usage_hints = [ usage_hints = [
"""%prog database=path/to/db.sqlite password=FILE0 0=passwords.txt -x ignore:fgrep='file is encrypted'""", """%prog database=db.sqlite password=FILE0 0=passwords.txt -x ignore:fgrep='file is encrypted'""",
] ]
available_options = ( available_options = (
@ -4636,11 +4697,12 @@ class SQLCipher_pass:
# Umbraco {{{ # Umbraco {{{
import hmac import hmac
class Umbraco_crack: class Umbraco_crack:
'''Crack Umbraco HMAC-SHA1 password hashes''' '''Crack Umbraco HMAC-SHA1 password hashes'''
usage_hints = ( usage_hints = (
"""%prog hashlist=@umbraco_users.pw password=FILE0 0=rockyou.txt""", '''%prog hashlist=@umbraco_users.pw password=FILE0 0=passwords.txt''',
) )
available_options = ( available_options = (
@ -4654,7 +4716,7 @@ class Umbraco_crack:
def execute(self, password, hashlist): def execute(self, password, hashlist):
p = password.encode('utf-16-le') p = password.encode('utf-16-le')
h = b64encode(hmac.new(p, p, digestmod=hashlib.sha1).digest()) h = B(b64encode(hmac.new(p, p, digestmod=hashlib.sha1).digest()))
if h not in hashlist: if h not in hashlist:
code, mesg = 1, 'fail' code, mesg = 1, 'fail'
@ -4768,25 +4830,27 @@ modules = [
] ]
dependencies = { dependencies = {
'paramiko': [('ssh_login',), 'http://www.lag.net/paramiko/', '1.7.7.1'], 'paramiko': [('ssh_login',), 'http://www.paramiko.org/', '1.7.7.1'],
'pycurl': [('http_fuzz',), 'http://pycurl.sourceforge.net/', '7.43.0'], 'pycurl': [('http_fuzz',), 'http://pycurl.io/', '7.43.0'],
'libcurl': [('http_fuzz',), 'https://curl.haxx.se/', '7.21.0'], 'libcurl': [('http_fuzz',), 'https://curl.haxx.se/', '7.21.0'],
'ajpy': [('ajp_fuzz',), 'https://github.com/hypn0s/AJPy/', '0.0.1'], 'ajpy': [('ajp_fuzz',), 'https://github.com/hypn0s/AJPy/', '0.0.1'],
'openldap': [('ldap_login',), 'http://www.openldap.org/', '2.4.24'], 'openldap': [('ldap_login',), 'http://www.openldap.org/', '2.4.24'],
'impacket': [('smb_login','smb_lookupsid','mssql_login'), 'https://github.com/CoreSecurity/impacket', '0.9.12'], 'impacket': [('smb_login', 'smb_lookupsid', 'mssql_login'), 'https://github.com/CoreSecurity/impacket', '0.9.12'],
'pyopenssl': [('mssql_login',), 'https://pyopenssl.org/', '17.5.0'],
'cx_Oracle': [('oracle_login',), 'http://cx-oracle.sourceforge.net/', '5.1.1'], 'cx_Oracle': [('oracle_login',), 'http://cx-oracle.sourceforge.net/', '5.1.1'],
'mysqlclient': [('mysql_login',), 'https://github.com/PyMySQL/mysqlclient-python', '1.3.12'], 'mysqlclient': [('mysql_login',), 'https://github.com/PyMySQL/mysqlclient-python', '1.3.12'],
'xfreerdp': [('rdp_login',), 'https://github.com/FreeRDP/FreeRDP.git', '1.2.0-beta1'], 'xfreerdp': [('rdp_login',), 'https://github.com/FreeRDP/FreeRDP.git', '1.2.0-beta1'],
'psycopg': [('pgsql_login',), 'http://initd.org/psycopg/', '2.4.5'], 'psycopg': [('pgsql_login',), 'http://initd.org/psycopg/', '2.4.5'],
'pycrypto': [('vnc_login',), 'http://www.dlitz.net/software/pycrypto/', '2.3'], 'pycrypto': [('smb_login', 'smb_lookupsid', 'mssql_login', 'vnc_login',), 'http://www.dlitz.net/software/pycrypto/', '2.6.1'],
'dnspython': [('dns_reverse', 'dns_forward'), 'http://www.dnspython.org/', '1.10.0'], 'dnspython': [('dns_reverse', 'dns_forward'), 'http://www.dnspython.org/', '1.10.0'],
'IPy': [('dns_reverse', 'dns_forward'), 'https://github.com/haypo/python-ipy', '0.75'], 'IPy': [('dns_reverse', 'dns_forward'), 'https://github.com/haypo/python-ipy', '0.75'],
'pysnmp': [('snmp_login',), 'http://pysnmp.sf.net/', '4.2.1'], 'pysnmp': [('snmp_login',), 'http://pysnmp.sf.net/', '4.2.1'],
'pyasn1': [('smb_login', 'smb_lookupsid', 'mssql_login', 'snmp_login'), 'http://sourceforge.net/projects/pyasn1/', '0.1.2'],
'ike-scan': [('ike_enum',), 'http://www.nta-monitor.com/tools-resources/security-tools/ike-scan', '1.9'], 'ike-scan': [('ike_enum',), 'http://www.nta-monitor.com/tools-resources/security-tools/ike-scan', '1.9'],
'unzip': [('unzip_pass',), 'http://www.info-zip.org/', '6.0'], 'unzip': [('unzip_pass',), 'http://www.info-zip.org/', '6.0'],
'java': [('keystore_pass',), 'http://www.oracle.com/technetwork/java/javase/', '6'], 'java': [('keystore_pass',), 'http://www.oracle.com/technetwork/java/javase/', '6'],
'pysqlcipher': [('sqlcipher_pass',), 'https://github.com/leapcode/pysqlcipher/', '2.6.10'], 'pysqlcipher': [('sqlcipher_pass',), 'https://github.com/leapcode/pysqlcipher/', '2.6.10'],
'ftp-tls': [('ftp_login',), 'TLS support unavailable before python 2.7'], 'python': [('ftp_login',), 'Patator requires Python 2.7 or above. Some features may be unavailable otherwise, such as TLS support for FTP.'],
} }
# }}} # }}}

Loading…
Cancel
Save