Moar python3 compat

pull/90/head
lanjelot 6 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 |
--------------------------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------------------------
@ -145,7 +147,7 @@ xfreerdp | RDP (NLA) | https://github.com/FreeRDP/FreeRDP/
--------------------------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------------------------
@ -153,7 +155,7 @@ IPy | NET keyword | https://github.com/haypo/python-ipy
--------------------------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------------------------
@ -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).
----------
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):
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):
record.candidate = repr(record.candidate)
else:
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:
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)
@ -714,8 +721,8 @@ class XMLFormatter(logging.Formatter):
def format(self, record):
for k, v in record.__dict__.iteritems():
if isinstance(v, basestring):
for k, v in record.__dict__.items():
if isinstance(v, str):
record.__dict__[k] = xmlescape(v)
return super(XMLFormatter, self).format(record)
@ -793,7 +800,7 @@ def process_logs(queue, indicatorsfmt, argv, log_dir):
else: # remove "</results>...</root>"
with open(results_xml, 'r+b') as f:
offset = f.read().find('</results>')
offset = f.read().find(b'</results>')
if offset != -1:
f.seek(offset)
f.truncate(f.tell())
@ -896,6 +903,23 @@ except ImportError:
from cStringIO import StringIO
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 = []
try:
from IPy import IP
@ -904,33 +928,40 @@ except ImportError:
has_ipy = False
notfound.append('IPy')
import multiprocessing.forking
class _Popen(multiprocessing.forking.Popen):
try:
# 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):
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'):
# 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'):
# On some platforms (e.g. AIX) 'os.unsetenv()' is not
# 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', '')
# On some platforms (e.g. AIX) 'os.unsetenv()' is not
# 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):
_Popen = _Popen
# Second override 'Popen' class with our modified version.
forking.Popen = _Popen
# So BaseManager.start() uses this new Process class
multiprocessing.Process = Process
from multiprocessing.managers import SyncManager
# imports }}}
# utils {{{
@ -975,7 +1006,7 @@ def create_dir(top_path):
if os.path.isdir(top_path):
files = os.listdir(top_path)
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):
if dirs:
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()
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.start()
@ -1426,6 +1457,7 @@ Please read the README inside for more examples and usage information.
p = expand_path(v[1:])
with open(p) as f:
v = f.read()
kargs.append((k, v))
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
for num in range(self.num_threads):
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.start()
self.thread_report.append(report_queue)
self.thread_progress.append(Progress())
# 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.start()
@ -2130,7 +2162,6 @@ class Timing:
# TCP_Cache {{{
class TCP_Connection:
def __init__(self, fp, banner=None):
self.fp = fp
self.banner = banner
@ -2197,16 +2228,16 @@ class TCP_Cache:
# FTP {{{
from ftplib import FTP, Error as FTP_Error
try:
from ftplib import FTP_TLS # New in python 2.7
from ftplib import FTP_TLS # only available since python 2.7
except ImportError:
notfound.append('ftp-tls')
notfound.append('python')
class FTP_login(TCP_Cache):
'''Brute-force FTP'''
usage_hints = (
"""%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""",
'''%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''',
)
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'):
with Timing() as timing:
fp, resp = self.bind(host, port, tls, timeout=timeout)
try:
with Timing() as timing:
fp, resp = self.bind(host, port, tls, timeout=timeout)
if user is not None or password is not None:
with Timing() as timing:
if user is not None:
resp = fp.sendcmd('USER ' + user)
if password is not None:
resp = fp.sendcmd('PASS ' + password)
logger.debug('No error: %s' % resp)
logger.debug('No error: %r' % resp)
self.reset()
except FTP_Error as e:
logger.debug('FTP_Error: %s' % e)
resp = str(e)
logger.debug('FTP_Error: %s' % resp)
if persistent == '0':
self.reset()
@ -2264,7 +2297,6 @@ class FTP_login(TCP_Cache):
# }}}
# SSH {{{
try:
from logging import NullHandler # only available since python 2.7
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'):
with Timing() as timing:
fp, banner = self.bind(host, port, user)
try:
with Timing() as timing:
fp, banner = self.bind(host, port, user)
if user is not None:
if keyfile is not None:
@ -2359,6 +2391,7 @@ class SSH_login(TCP_Cache):
# Telnet {{{
from telnetlib import Telnet
class Telnet_login(TCP_Cache):
'''Brute-force Telnet'''
@ -2389,7 +2422,8 @@ class Telnet_login(TCP_Cache):
with Timing() as timing:
fp, _ = self.bind(host, port, timeout=timeout)
trace = ''
trace = b''
prompt_re = b(prompt_re)
timeout = int(timeout)
if self.prompt_count == 0:
@ -2400,9 +2434,10 @@ class Telnet_login(TCP_Cache):
if inputs is not None:
with Timing() as timing:
for val in inputs.split(r'\n'):
logger.debug('input: %s' % val)
cmd = val + '\n' #'\r\x00'
cmd = b(val + '\n') #'\r\x00'
fp.write(cmd)
trace += cmd
@ -2414,13 +2449,17 @@ class Telnet_login(TCP_Cache):
if persistent == '0':
self.reset()
raw = B(raw)
trace = B(trace)
mesg = repr(raw)[1:-1] # strip enclosing single quotes
return self.Response(0, mesg, timing, trace)
# }}}
# SMTP {{{
from smtplib import SMTP, SMTP_SSL, SMTPAuthenticationError, SMTPHeloError, SMTPException
from smtplib import SMTP, SMTP_SSL, SMTPException, SMTPResponseException
class SMTP_Base(TCP_Cache):
available_options = TCP_Cache.available_options
@ -2482,7 +2521,7 @@ class SMTP_vrfy(SMTP_Base):
self.reset()
code, mesg = resp
return self.Response(code, mesg, timing)
return self.Response(code, B(mesg), timing)
class SMTP_rcpt(SMTP_Base):
@ -2516,7 +2555,7 @@ class SMTP_rcpt(SMTP_Base):
self.reset()
code, mesg = resp
return self.Response(code, mesg, timing)
return self.Response(code, B(mesg), timing)
class SMTP_login(SMTP_Base):
@ -2545,14 +2584,19 @@ class SMTP_login(SMTP_Base):
logger.debug('No error: %s' % str(resp))
self.reset()
except (SMTPHeloError,SMTPAuthenticationError,SMTPException) as resp:
logger.debug('SMTPError: %s' % str(resp))
except SMTPResponseException as e:
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':
self.reset()
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)))
if user:
s.send(user)
s.send('\r\n')
s.send(b(user))
s.send(b'\r\n')
data = ''
data = b''
with Timing() as timing:
while True:
raw = s.recv(1024)
@ -2610,7 +2654,7 @@ class Finger_lookup:
logger.debug('recv: %r' % data)
data = data.strip()
data = B(data).strip()
mesg = repr(data)
resp = self.Response(0, mesg, timing, data)
@ -2668,14 +2712,13 @@ class LDAP_login:
try:
from impacket.smbconnection import SMBConnection, SessionError
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.samr import SID_NAME_USE
except ImportError:
notfound.append('impacket')
class SMB_Connection(TCP_Connection):
def close(self):
self.fp.getSMBServer().get_socket().close()
@ -2743,7 +2786,6 @@ class SMB_login(TCP_Cache):
return self.Response(code, mesg, timing)
class DCE_Connection(TCP_Connection):
def __init__(self, fp, smbt):
self.smbt = smbt
TCP_Connection.__init__(self, fp)
@ -2816,6 +2858,7 @@ class SMB_lookupsid(TCP_Cache):
# POP {{{
from poplib import POP3, POP3_SSL, error_proto as pop_error
class POP_Connection(TCP_Connection):
def close(self):
self.fp.quit()
@ -2916,8 +2959,8 @@ class POP_passd:
trace += '%s\r\n%s\r\n' % (cmd, resp)
except LineReceiver_Error as e:
logger.debug('LineReceiver_Error: %s' % e)
resp = str(e)
logger.debug('LineReceiver_Error: %s' % resp)
trace += '%s\r\n%s\r\n' % (cmd, resp)
finally:
@ -2930,6 +2973,7 @@ class POP_passd:
# IMAP {{{
from imaplib import IMAP4, IMAP4_SSL
class IMAP_login:
'''Brute-force IMAP4'''
@ -3019,34 +3063,40 @@ class Rlogin_login(TCP_Cache):
fp, _ = self.bind(host, port, timeout=int(timeout))
trace = ''
trace = b''
timeout = int(timeout)
with Timing() as timing:
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
else:
fp.write('%s\r' % user)
fp.write(b('%s\r' % user))
_, _, resp = fp.expect([prompt_re], timeout=timeout) # expecting the Password: prompt
trace += resp
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
trace += resp
if persistent == '0':
self.reset()
resp = B(resp)
trace = B(trace)
mesg = repr(resp.strip())[1:-1]
return self.Response(0, mesg, timing, trace)
# }}}
# VMauthd {{{
from ssl import wrap_socket
class LineReceiver_Error(Exception): pass
class LineReceiver_Error(Exception):
pass
class LineReceiver:
def connect(self, host, port, timeout, ssl=False):
@ -3062,15 +3112,15 @@ class LineReceiver:
self.sock.close()
def sendcmd(self, cmd):
self.sock.sendall(cmd + '\r\n')
self.sock.sendall(b(cmd + '\r\n'))
return self.getresp()
def getresp(self):
resp = self.sock.recv(1024)
while not resp.endswith('\n'):
while not resp.endswith(b'\n'):
resp += self.sock.recv(1024)
resp = resp.rstrip()
resp = B(resp).rstrip()
code, _ = self.parse(resp)
if not code.isdigit():
@ -3133,8 +3183,8 @@ class VMauthd_login(TCP_Cache):
trace += '%s\r\n%s\r\n' % (cmd, resp)
except LineReceiver_Error as e:
logger.debug('LineReceiver_Error: %s' % e)
resp = str(e)
logger.debug('LineReceiver_Error: %s' % resp)
trace += '%s\r\n%s\r\n' % (cmd, resp)
if persistent == '0':
@ -3228,7 +3278,8 @@ try:
from impacket import tds
from impacket.tds import TDS_ERROR_TOKEN, TDS_LOGINACK_TOKEN
except ImportError:
notfound.append('impacket')
notfound.append('pyopenssl')
class MSSQL_login:
'''Brute-force MSSQL'''
@ -3291,8 +3342,8 @@ class Oracle_login:
'''Brute-force Oracle'''
usage_hints = (
"""%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 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''',
)
available_options = (
@ -3418,14 +3469,18 @@ class Response_HTTP(Response_Base):
return re.search(val, self.mesg, re.M)
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 += (
('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):
def __init__(self, fd):
self.rfile = fd
@ -3435,7 +3490,8 @@ class HTTPRequestParser(BaseHTTPRequestHandler):
self.parse_request()
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:
del self.headers['Content-Length']
@ -3448,7 +3504,7 @@ class Controller_HTTP(Controller):
key, val = arg.split('=', 1)
if key == 'raw_request':
with open(val) as fd:
with open(val, 'rb') as fd:
r = HTTPRequestParser(fd)
if r.error:
@ -3466,7 +3522,7 @@ class Controller_HTTP(Controller):
opts['method'] = r.command
opts['body'] = r.body
for key, val in opts.iteritems():
for key, val in opts.items():
if val:
yield (key, val)
@ -3477,13 +3533,10 @@ class HTTP_fuzz(TCP_Cache):
'''Brute-force HTTP'''
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/manager/html user_pass=COMBO00:COMBO01 0=combos.txt"""
""" -x ignore:code=401""",
"""%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"""
'''%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/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'""",
]
@ -3574,9 +3627,14 @@ class HTTP_fuzz(TCP_Cache):
if max_mem > 0 and trace.tell() > max_mem:
return 0
s = B(s)
if t in (pycurl.INFOTYPE_HEADER_OUT, pycurl.INFOTYPE_DATA_OUT):
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):
trace.write(s)
response.write(s)
@ -3697,12 +3755,12 @@ class Response_AJP(Response_HTTP):
self.status_msg = status_msg
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):
fr = AjpForwardRequest(AjpForwardRequest.SERVER_TO_CONTAINER)
fr.method = method
fr.protocol = "HTTP/1.1"
fr.protocol = 'HTTP/1.1'
fr.req_uri = req_uri
fr.remote_addr = target_host
fr.remote_host = None
@ -3728,9 +3786,8 @@ class AJP_fuzz(TCP_Cache):
'''Brute-force AJP'''
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/manager/html user_pass=COMBO00:COMBO01 0=combos.txt"""
""" -x ignore:code=401""",
'''%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 -x ignore:code=401''',
]
available_options = (
@ -3801,7 +3858,7 @@ class RDP_login:
'''Brute-force RDP (NLA)'''
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 = (
@ -3820,7 +3877,7 @@ class RDP_login:
with Timing() as timing:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
out, err = map(B, p.communicate())
code = p.returncode
err = err.replace('''Authentication only. Don't connect to X.
@ -3847,35 +3904,37 @@ try:
except ImportError:
notfound.append('pycrypto')
class VNC_Error(Exception): pass
class VNC_Error(Exception):
pass
class VNC:
def connect(self, host, port, timeout):
self.fp = socket.create_connection((host, port), timeout=timeout)
resp = self.fp.recv(99) # banner
logger.debug('banner: %r' % resp)
self.version = resp[:11].decode('ascii')
self.version = B(resp[:11])
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
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]
if (major, minor) in [('3', '8'), ('4', '1')]:
proto = b'RFB 003.008\n'
proto = 'RFB 003.008\n'
elif (major, minor) == ('3', '7'):
proto = b'RFB 003.007\n'
proto = 'RFB 003.007\n'
else:
proto = b'RFB 003.003\n'
proto = 'RFB 003.003\n'
logger.debug('Client version: %s' % proto[:-1])
self.fp.sendall(proto)
logger.debug('Client version: %r' % proto[:-1])
self.fp.sendall(b(proto))
sleep(0.5)
@ -3885,7 +3944,7 @@ class VNC:
if major == '4' or (major == '3' and int(minor) >= 7):
code = ord(resp[0:1])
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
resp = self.fp.recv(99)
@ -3893,7 +3952,7 @@ class VNC:
else: # minor == '3':
code = ord(resp[3:4])
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:]
@ -3916,7 +3975,7 @@ class VNC:
logger.debug('resp: %r' % resp)
code = ord(resp[3:4])
mesg = resp[8:].decode('ascii', 'ignore')
mesg = B(resp[8:])
if code == 1:
return code, mesg or 'Authentication failure'
@ -3938,17 +3997,16 @@ class VNC:
btgt = btgt | (1 << 7-i)
newkey.append(btgt)
if sys.version_info[0] == 2:
return ''.join(chr(c) for c in newkey)
else:
if PY3:
return bytes(newkey)
else:
return ''.join(chr(c) for c in newkey)
class VNC_login:
'''Brute-force VNC'''
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 = (
@ -3981,7 +4039,6 @@ class VNC_login:
# }}}
# DNS {{{
try:
import dns.rdatatype
import dns.message
@ -4252,13 +4309,12 @@ class Controller_DNS(Controller):
name, data = name[:-1], data[:-1]
self.hostmap[data].alias.add(name)
class DNS_reverse:
'''Reverse DNS lookup'''
usage_hints = [
"""%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=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-''',
]
available_options = (
@ -4291,9 +4347,9 @@ class DNS_forward:
'''Forward DNS lookup'''
usage_hints = [
"""%prog name=FILE0.google.com 0=names.txt -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=FILE0.google.com 0=names.txt -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''',
]
available_options = (
@ -4337,6 +4393,11 @@ try:
except ImportError:
notfound.append('pysnmp')
try:
import pyasn1
except ImportError:
notfound.append('pyasn1')
class SNMP_login:
'''Brute-force SNMP v1/2/3'''
@ -4412,7 +4473,7 @@ IKE_GROUP = [('1', 'modp768'), ('2', 'modp1024'), ('5', 'modp1536'),
# '27', '28', '29', '30', # RFC6932
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))
class Controller_IKE(Controller):
@ -4443,7 +4504,7 @@ class Controller_IKE(Controller):
ike_ath = dict(IKE_AUTH)
ike_grp = dict(IKE_GROUP)
for endpoint, transforms in self.results.iteritems():
for endpoint, transforms in self.results.items():
print('\n+ %s' % endpoint)
print(' %10s %10s %12s %10s' % ('Encryption', 'Hash', 'Auth', 'Group'))
print(' %10s %10s %12s %10s' % ('-'*10, '-'*10, '-'*10, '-'*10))
@ -4464,8 +4525,8 @@ class IKE_enum:
'''Enumerate IKE transforms'''
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 aggressive=RANGE1 1=int:0-1""",
'''%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''',
]
available_options = (
@ -4486,7 +4547,7 @@ class IKE_enum:
def __init__(self):
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=''):
@ -4500,7 +4561,7 @@ class IKE_enum:
with Timing() as timing:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
out, err = map(B, p.communicate())
code = p.returncode
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'''
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 = (
@ -4550,7 +4611,7 @@ class Unzip_pass:
with Timing() as timing:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
out, err = map(B, p.communicate())
code = p.returncode
mesg = repr(out.strip())[1:-1]
@ -4568,7 +4629,7 @@ class Keystore_pass:
'''Brute-force the password of Java keystore files'''
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 = (
@ -4587,7 +4648,7 @@ class Keystore_pass:
with Timing() as timing:
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
out, err = map(B, p.communicate())
code = p.returncode
mesg = repr(out.strip())[1:-1]
@ -4607,7 +4668,7 @@ class SQLCipher_pass:
'''Brute-force the password of SQLCipher-encrypted databases'''
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 = (
@ -4636,11 +4697,12 @@ class SQLCipher_pass:
# Umbraco {{{
import hmac
class Umbraco_crack:
'''Crack Umbraco HMAC-SHA1 password hashes'''
usage_hints = (
"""%prog hashlist=@umbraco_users.pw password=FILE0 0=rockyou.txt""",
'''%prog hashlist=@umbraco_users.pw password=FILE0 0=passwords.txt''',
)
available_options = (
@ -4654,7 +4716,7 @@ class Umbraco_crack:
def execute(self, password, hashlist):
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:
code, mesg = 1, 'fail'
@ -4768,25 +4830,27 @@ modules = [
]
dependencies = {
'paramiko': [('ssh_login',), 'http://www.lag.net/paramiko/', '1.7.7.1'],
'pycurl': [('http_fuzz',), 'http://pycurl.sourceforge.net/', '7.43.0'],
'paramiko': [('ssh_login',), 'http://www.paramiko.org/', '1.7.7.1'],
'pycurl': [('http_fuzz',), 'http://pycurl.io/', '7.43.0'],
'libcurl': [('http_fuzz',), 'https://curl.haxx.se/', '7.21.0'],
'ajpy': [('ajp_fuzz',), 'https://github.com/hypn0s/AJPy/', '0.0.1'],
'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'],
'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'],
'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'],
'IPy': [('dns_reverse', 'dns_forward'), 'https://github.com/haypo/python-ipy', '0.75'],
'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'],
'unzip': [('unzip_pass',), 'http://www.info-zip.org/', '6.0'],
'java': [('keystore_pass',), 'http://www.oracle.com/technetwork/java/javase/', '6'],
'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