new smtp_login module

bugs fixed in smtp modules
better trace output in http_fuzz
pull/4/merge
Lanjelot 13 years ago
parent 974ad0e1cb
commit 8c4569bfac

@ -32,6 +32,7 @@ Currently it supports the following modules:
- ftp_login : Brute-force FTP - ftp_login : Brute-force FTP
- ssh_login : Brute-force SSH - ssh_login : Brute-force SSH
- telnet_login : Brute-force Telnet - telnet_login : Brute-force Telnet
- smtp_login : Brute-force SMTP
- smtp_vrfy : Enumerate valid users using the SMTP 'VRFY' command - smtp_vrfy : Enumerate valid users using the SMTP 'VRFY' command
- smtp_rcpt : Enumerate valid users using the SMTP 'RCPT TO' command - smtp_rcpt : Enumerate valid users using the SMTP 'RCPT TO' command
- http_fuzz : Brute-force HTTP/HTTPS - http_fuzz : Brute-force HTTP/HTTPS
@ -55,7 +56,6 @@ Future modules to be implemented:
- rdp_login - rdp_login
- vmware_login (902/tcp) - vmware_login (902/tcp)
- pop3_login - pop3_login
- smtp_login
The name "Patator" comes from http://www.youtube.com/watch?v=xoBkBvnTTjo The name "Patator" comes from http://www.youtube.com/watch?v=xoBkBvnTTjo
"Whatever the payload to fire, always use the same launch tube" "Whatever the payload to fire, always use the same launch tube"
@ -314,9 +314,14 @@ smtp_vrfy host=10.0.0.1 user=FILE0 0=logins.txt -x ignore:fgrep='User unknown in
* Use the RCPT TO command in case the VRFY command was disabled. * Use the RCPT TO command in case the VRFY command was disabled.
--------- ---------
smtp_rcpt host=10.0.0.1 user=FILE0@localhost 0=logins.txt helo='EHLO mx.fb.com' mail_from=root smtp_rcpt host=10.0.0.1 user=FILE0@localhost 0=logins.txt helo='ehlo mx.fb.com' mail_from=root
* Brute-force authentication.
(a) Send a fake hostname (by default the real hostname is sent)
------------ (a)
smtp_login host=10.0.0.1 helo='ehlo its.me.com' user=FILE0@dom.com password=FILE1 0=logins.txt 1=passwords.txt
}}} }}}
{{{ HTTP {{{ HTTP
@ -566,6 +571,7 @@ from datetime import timedelta, datetime
from struct import unpack from struct import unpack
import socket import socket
import subprocess import subprocess
import hashlib
warnings = [] warnings = []
try: try:
@ -613,6 +619,9 @@ def create_time_dir(top_path, desc):
def pprint_seconds(seconds, fmt): def pprint_seconds(seconds, fmt):
return fmt % reduce(lambda x,y: divmod(x[0], y) + x[1:], [(seconds,),60,60]) return fmt % reduce(lambda x,y: divmod(x[0], y) + x[1:], [(seconds,),60,60])
def md5hex(plain):
return hashlib.md5(plain).hexdigest()
# }}} # }}}
# Controller {{{ # Controller {{{
@ -637,6 +646,7 @@ class Controller:
available_encodings = { available_encodings = {
'hex': (hexlify, 'encode in hexadecimal'), 'hex': (hexlify, 'encode in hexadecimal'),
'b64': (b64encode, 'encode in base64'), 'b64': (b64encode, 'encode in base64'),
'md5': (md5hex, 'hash in md5'),
} }
def expand_key(self, arg): def expand_key(self, arg):
@ -1468,82 +1478,107 @@ class Telnet_login(TCP_Cache):
# }}} # }}}
# SMTP {{{ # SMTP {{{
from smtplib import SMTP from smtplib import SMTP, SMTPAuthenticationError, SMTPHeloError, SMTPException
class SMTP_vrfy(TCP_Cache): class SMTP_Base(TCP_Cache):
'''Enumerate valid users using SMTP VRFY'''
usage_hints = (
'''%prog host=10.0.0.1 user=FILE0 0=logins.txt [helo='EHLO blah.example.com']'''
''' -x ignore:fgrep='User unknown' -x ignore,reset,retry:code=421''',
)
available_options = ( available_options = TCP_Cache.available_options
available_options += (
('host', 'hostnames or subnets to target'), ('host', 'hostnames or subnets to target'),
('port', 'ports to target [25]'), ('port', 'ports to target [25]'),
('helo', 'first command to send after connect [None]'),
('user', 'usernames to test'), ('user', 'usernames to test'),
('helo', 'first command to send after connect'),
) )
available_options += TCP_Cache.available_options
Response = Response_Base Response = Response_Base
def new_tcp(self, host, port): cache_keys = ('host', 'port', 'helo')
def new_tcp(self, host, port, helo):
fp = SMTP() fp = SMTP()
resp = fp.connect(host, int(port or 25)) resp = fp.connect(host, int(port or 25))
if helo:
cmd, name = helo.split(' ', 1)
if cmd.lower() == 'ehlo':
resp = fp.ehlo(name)
else:
resp = fp.helo(name)
return fp, resp return fp, resp
def execute(self, host, port=None, helo=None, user=None, persistent='1'): class SMTP_vrfy(SMTP_Base):
fp, resp = self.get_tcp(persistent, host=host, port=port) '''Enumerate valid users using SMTP VRFY'''
if helo is not None and resp == '': usage_hints = (
resp = fp.docmd(helo) '''%prog host=10.0.0.1 user=FILE0 0=logins.txt [helo='ehlo its.me.com']'''
''' -x ignore:fgrep='User unknown' -x ignore,reset,retry:code=421''',
)
def execute(self, host, port=None, helo=None, user=None, persistent='1'):
fp, resp = self.get_tcp(persistent, host=host, port=port, helo=helo)
if user is not None: if user is not None:
resp = fp.docmd('VRFY ' + user) resp = fp.verify(user)
code, mesg = resp code, mesg = resp
return self.Response(code, mesg) return self.Response(code, mesg)
class SMTP_rcpt(TCP_Cache):
"""Enumerate valid users using SMTP RCPT TO""" class SMTP_rcpt(SMTP_Base):
'''Enumerate valid users using SMTP RCPT TO'''
usage_hints = ( usage_hints = (
'''%prog host=10.0.0.1 user=FILE0@localhost 0=logins.txt [helo='EHLO blah.example.com']''' '''%prog host=10.0.0.1 user=FILE0@localhost 0=logins.txt [helo='ehlo its.me.com']'''
''' [mail_from=foo@bar.org] -x ignore:fgrep='User unknown' -x ignore,reset,retry:code=421''', ''' [mail_from=bar@example.com] -x ignore:fgrep='User unknown' -x ignore,reset,retry:code=421''',
) )
available_options = ( available_options = SMTP_Base.available_options
('host', 'hostnames or subnets to target'), available_options += (
('port', 'ports to target [25]'),
('user', 'usernames to test'),
('mail_from', 'sender email [test@example.org]'), ('mail_from', 'sender email [test@example.org]'),
('helo', 'first command to send after connect'),
) )
available_options += TCP_Cache.available_options
Response = Response_Base def execute(self, host, port=None, helo=None, mail_from='test@example.org', user=None, persistent='1'):
fp, resp = self.get_tcp(persistent, host=host, port=port, helo=helo)
def new_tcp(self, host, port): if mail_from:
fp = SMTP() resp = fp.mail(mail_from)
resp = fp.connect(host, int(port or 25))
return fp, resp
def execute(self, host, port=None, helo=None, mail_from='test@example.org', user=None, persistent='1'): if user:
fp, resp = self.get_tcp(persistent, host=host, port=port) resp = fp.rcpt(user)
if helo is not None and resp == '': fp.rset()
resp = fp.docmd(helo)
if mail_from: code, mesg = resp
resp = fp.docmd('MAIL FROM: ' + mail_from) return self.Response(code, mesg)
if rcpt_to:
resp = fp.docmd('RCPT TO: ' + user)
fp.docmd('RSET') class SMTP_login(SMTP_Base):
'''Brute-force SMTP authentication'''
usage_hints = (
'''%prog host=10.0.0.1 user=f.bar@dom.com password=FILE0 0=passwords.txt [helo='ehlo its.me.com']''',
''' -x ignore:fgrep='Authentication failed' -x ignore,reset,retry:code=421''',
)
available_options = SMTP_Base.available_options
available_options += (
('password', 'passwords to test'),
)
def execute(self, host, port=None, helo=None, user='', password='', persistent='1'):
fp, resp = self.get_tcp(persistent, host=host, port=port, helo=helo)
try:
resp = fp.login(user, password)
except (SMTPHeloError,SMTPAuthenticationError,SMTPException) as resp:
logger.debug('SMTPError: %s' % resp)
code, mesg = resp code, mesg = resp
return self.Response(code, mesg) return self.Response(code, mesg)
# }}} # }}}
# LDAP {{{ # LDAP {{{
@ -1984,11 +2019,10 @@ class Controller_HTTP(Controller):
class Response_HTTP(Response_Base): class Response_HTTP(Response_Base):
def __init__(self, code, content_length, response, request): def __init__(self, code, content_length, response, trace):
self.code, self.content_length, \ self.code, self.content_length = code, content_length
self.response, self.request = code, content_length, response, request self.response, self.trace = response, trace
self.size = len(self.response) self.size = len(self.response)
self.trace = '%s\n%s\n\n%s' % (self.request, '='*80, self.response)
def compact(self): def compact(self):
return '%s %s' % (self.code, '%d:%d' % (self.size, self.content_length)) return '%s %s' % (self.code, '%d:%d' % (self.size, self.content_length))
@ -2082,16 +2116,18 @@ class HTTP_fuzz(TCP_Cache):
fp.setopt(pycurl.WRITEFUNCTION, noop) fp.setopt(pycurl.WRITEFUNCTION, noop)
def debug_func(t, s): def debug_func(t, s):
if max_mem > 0 and trace.tell() > max_mem:
return 0
if t in (pycurl.INFOTYPE_HEADER_IN, pycurl.INFOTYPE_DATA_IN): if t in (pycurl.INFOTYPE_HEADER_IN, pycurl.INFOTYPE_DATA_IN):
if max_mem < 0 or response.tell() < max_mem: response.write(s)
response.write(s)
elif t in (pycurl.INFOTYPE_HEADER_OUT, pycurl.INFOTYPE_DATA_OUT): if t != pycurl.INFOTYPE_TEXT:
if max_mem < 0 or response.tell() < max_mem: trace.write(s)
request.write(s)
max_mem = int(max_mem) max_mem = int(max_mem)
response, request = StringIO(), StringIO(), response, trace = StringIO(), StringIO()
fp.setopt(pycurl.DEBUGFUNCTION, debug_func) fp.setopt(pycurl.DEBUGFUNCTION, debug_func)
fp.setopt(pycurl.VERBOSE, 1) fp.setopt(pycurl.VERBOSE, 1)
@ -2158,7 +2194,7 @@ class HTTP_fuzz(TCP_Cache):
http_code = fp.getinfo(pycurl.HTTP_CODE) http_code = fp.getinfo(pycurl.HTTP_CODE)
content_length = fp.getinfo(pycurl.CONTENT_LENGTH_DOWNLOAD) content_length = fp.getinfo(pycurl.CONTENT_LENGTH_DOWNLOAD)
return self.Response(http_code, content_length, response.getvalue(), request.getvalue()) return self.Response(http_code, content_length, response.getvalue(), trace.getvalue())
# }}} # }}}
@ -2715,6 +2751,7 @@ modules = (
'ftp_login', (Controller, FTP_login), 'ftp_login', (Controller, FTP_login),
'ssh_login', (Controller, SSH_login), 'ssh_login', (Controller, SSH_login),
'telnet_login', (Controller, Telnet_login), 'telnet_login', (Controller, Telnet_login),
'smtp_login', (Controller, SMTP_login),
'smtp_vrfy', (Controller, SMTP_vrfy), 'smtp_vrfy', (Controller, SMTP_vrfy),
'smtp_rcpt', (Controller, SMTP_rcpt), 'smtp_rcpt', (Controller, SMTP_rcpt),
'http_fuzz', (Controller_HTTP, HTTP_fuzz), 'http_fuzz', (Controller_HTTP, HTTP_fuzz),
@ -2753,7 +2790,7 @@ or
Available modules: Available modules:
%s''' % '\n'.join(' + %-13s : %s' % (k, v[1].__doc__) for k, v in modules)) %s''' % '\n'.join(' + %-13s : %s' % (k, v[1].__doc__) for k, v in modules))
if warnings: if warnings:
print('\nWARNING missing dependencies (see README inside)') print('\nWARNING missing dependencies (see README inside for the supported versions)')
for w in warnings: for w in warnings:
print('- %s' % w) print('- %s' % w)
exit(2) exit(2)

Loading…
Cancel
Save