diff --git a/README.md b/README.md index 99b7f45..dd253e1 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Currently it supports the following modules: * smtp_rcpt : Enumerate valid users using the SMTP RCPT TO command * finger_lookup : Enumerate valid users using Finger * http_fuzz : Brute-force HTTP/HTTPS +* rdp_gateway : Brute-force RDP Gateway * ajp_fuzz : Brute-force AJP * pop_login : Brute-force POP * pop_passd : Brute-force poppassd (not POP3) @@ -43,7 +44,7 @@ The name "Patator" comes from [this](https://www.youtube.com/watch?v=kU2yPJJdpag Patator is NOT script-kiddie friendly, please read the full README inside [patator.py](patator.py) before reporting. -And please donate if you like this project. +Please donate if you like this project! :) [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=SB36VJH4EM5WG&lc=AU&item_name=lanjelot&item_number=patator¤cy_code=AUD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted) diff --git a/patator.py b/patator.py index 5120c59..24f7f4f 100755 --- a/patator.py +++ b/patator.py @@ -39,6 +39,7 @@ Currently it supports the following modules: + smtp_rcpt : Enumerate valid users using SMTP RCPT TO + finger_lookup : Enumerate valid users using Finger + http_fuzz : Brute-force HTTP + + rdp_gateway : Brute-force RDP Gateway + ajp_fuzz : Brute-force AJP + pop_login : Brute-force POP3 + pop_passd : Brute-force poppassd (http://netwinsite.com/poppassd/) @@ -3592,6 +3593,29 @@ class HTTP_fuzz(TCP_Cache): return TCP_Connection(fp) + @staticmethod + def perform_fp(fp, method, url, header='', body=''): + #logger.debug('perform: %s' % url) + fp.setopt(pycurl.URL, url) + + if method == 'GET': + fp.setopt(pycurl.HTTPGET, 1) + + elif method == 'POST': + fp.setopt(pycurl.POST, 1) + fp.setopt(pycurl.POSTFIELDS, body) + + elif method == 'HEAD': + fp.setopt(pycurl.NOBODY, 1) + + else: + fp.setopt(pycurl.CUSTOMREQUEST, method) + + headers = [h.strip('\r') for h in header.split('\n') if h] + fp.setopt(pycurl.HTTPHEADER, headers) + + fp.perform() + def execute(self, url=None, host=None, port='', scheme='http', path='/', params='', query='', fragment='', body='', header='', method='GET', auto_urlencode='1', user_pass='', auth_type='basic', follow='0', max_follow='5', accept_cookie='0', proxy='', proxy_type='http', resolve='', ssl_cert='', timeout_tcp='10', timeout='20', persistent='1', @@ -3674,31 +3698,9 @@ class HTTP_fuzz(TCP_Cache): # produce requests with more than one Cookie: header # and the server will process only one of them (eg. Apache only reads the last one) - def perform_fp(fp, method, url, header='', body=''): - #logger.debug('perform: %s' % url) - fp.setopt(pycurl.URL, url) - - if method == 'GET': - fp.setopt(pycurl.HTTPGET, 1) - - elif method == 'POST': - fp.setopt(pycurl.POST, 1) - fp.setopt(pycurl.POSTFIELDS, body) - - elif method == 'HEAD': - fp.setopt(pycurl.NOBODY, 1) - - else: - fp.setopt(pycurl.CUSTOMREQUEST, method) - - headers = [h.strip('\r') for h in header.split('\n') if h] - fp.setopt(pycurl.HTTPHEADER, headers) - - fp.perform() - if before_urls: for before_url in before_urls.split(','): - perform_fp(fp, 'GET', before_url, before_header) + self.perform_fp(fp, 'GET', before_url, before_header) if before_egrep: for be in before_egrep.split('|'): @@ -3718,7 +3720,7 @@ class HTTP_fuzz(TCP_Cache): host = '%s:%s' % (host, port) url = urlunparse((scheme, host, path, params, query, fragment)) - perform_fp(fp, method, url, header, body) + self.perform_fp(fp, method, url, header, body) target = {} target['ip'] = fp.getinfo(pycurl.PRIMARY_IP) @@ -3734,7 +3736,7 @@ class HTTP_fuzz(TCP_Cache): if after_urls: for after_url in after_urls.split(','): - perform_fp(fp, 'GET', after_url) + self.perform_fp(fp, 'GET', after_url) http_code = fp.getinfo(pycurl.HTTP_CODE) content_length = fp.getinfo(pycurl.CONTENT_LENGTH_DOWNLOAD) @@ -3747,6 +3749,28 @@ class HTTP_fuzz(TCP_Cache): # }}} +# RDP Gateway {{{ +import uuid + +class RDP_gateway(HTTP_fuzz): + '''Brute-force RDP Gateway''' + + usage_hints = ( + '''%prog url='https://example.com/remoteDesktopGateway/' user_pass=COMBO00:COMBO01 0=combos.txt -x ignore:code=401''', + ) + + @staticmethod + def perform_fp(fp, method, url, header='', body=''): + method = 'RDG_OUT_DATA' + header += '\nRDG-Connection-Id: {%s}' % uuid.uuid4() + + # if authentication is successful the gateway server hangs and won't send a body + fp.setopt(pycurl.NOBODY, 1) + + HTTP_fuzz.perform_fp(fp, method, url, header) + +# }}} + # AJP {{{ try: from ajpy.ajp import AjpForwardRequest @@ -4807,6 +4831,7 @@ modules = [ ('smtp_rcpt', (Controller, SMTP_rcpt)), ('finger_lookup', (Controller_Finger, Finger_lookup)), ('http_fuzz', (Controller_HTTP, HTTP_fuzz)), + ('rdp_gateway', (Controller_HTTP, RDP_gateway)), ('ajp_fuzz', (Controller, AJP_fuzz)), ('pop_login', (Controller, POP_login)), ('pop_passd', (Controller, POP_passd)), @@ -4840,8 +4865,8 @@ modules = [ dependencies = { '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'], + 'pycurl': [('http_fuzz', 'rdp_gateway'), 'http://pycurl.io/', '7.43.0'], + 'libcurl': [('http_fuzz', 'rdp_gateway'), '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'], diff --git a/requirements.txt b/requirements.txt index 0e1ca73..bb8acd4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ ajpy pyopenssl cx_Oracle mysqlclient -psycopg2 +psycopg2-binary pycrypto dnspython IPy