mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-08-14 02:37:06 -07:00
This is a vewwwy big commit
- The inject plugin now uses beautifulsoup4 to actually parse HTML and add content to it as supposed to using regexes - The logging of the whole framework has been compleatly overhauled - plugindetect.js now includes os.js from the metasploit framework for os and browser detection, let's us fingerprint hosts even if UA is lying! - New plugin HTA Drive-by has been added, prompts the user for a plugin update and makes them download an hta app which contains a powershell payload - the API of the plugins has been simplified - Improvements and error handling to user-agent parsing - Some misc bugfixes
This commit is contained in:
parent
ff0ada2a39
commit
5e2f30fb89
64 changed files with 3748 additions and 1473 deletions
|
@ -39,8 +39,10 @@ from SSLServerConnection import SSLServerConnection
|
|||
from URLMonitor import URLMonitor
|
||||
from CookieCleaner import CookieCleaner
|
||||
from DnsCache import DnsCache
|
||||
from core.logger import logger
|
||||
|
||||
log = logging.getLogger('mitmf')
|
||||
formatter = logging.Formatter("%(asctime)s [ClientRequest] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||
log = logger().setup_logger("ClientRequest", formatter)
|
||||
|
||||
class ClientRequest(Request):
|
||||
|
||||
|
@ -76,13 +78,13 @@ class ClientRequest(Request):
|
|||
|
||||
if 'host' in headers:
|
||||
host = self.urlMonitor.URLgetRealHost(str(headers['host']))
|
||||
log.debug("[ClientRequest][HSTS] Modifing HOST header: {} -> {}".format(headers['host'], host))
|
||||
log.debug("Modifing HOST header: {} -> {}".format(headers['host'], host))
|
||||
headers['host'] = host
|
||||
self.setHeader('Host', host)
|
||||
|
||||
if 'accept-encoding' in headers:
|
||||
del headers['accept-encoding']
|
||||
log.debug("[ClientRequest] Zapped encoding")
|
||||
log.debug("Zapped encoding")
|
||||
|
||||
if 'if-none-match' in headers:
|
||||
del headers['if-none-match']
|
||||
|
@ -109,11 +111,11 @@ class ClientRequest(Request):
|
|||
|
||||
if os.path.exists(scriptPath): return scriptPath
|
||||
|
||||
log.warning("[ClientRequest] Error: Could not find lock.ico")
|
||||
log.warning("Error: Could not find lock.ico")
|
||||
return "lock.ico"
|
||||
|
||||
def handleHostResolvedSuccess(self, address):
|
||||
log.debug("[ClientRequest] Resolved host successfully: {} -> {}".format(self.getHeader('host'), address))
|
||||
log.debug("Resolved host successfully: {} -> {}".format(self.getHeader('host'), address))
|
||||
host = self.getHeader("host")
|
||||
headers = self.cleanHeaders()
|
||||
client = self.getClientIP()
|
||||
|
@ -151,22 +153,22 @@ class ClientRequest(Request):
|
|||
self.dnsCache.cacheResolution(hostparts[0], address)
|
||||
|
||||
if (not self.cookieCleaner.isClean(self.method, client, host, headers)):
|
||||
log.debug("[ClientRequest] Sending expired cookies")
|
||||
log.debug("Sending expired cookies")
|
||||
self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, host, headers, path))
|
||||
|
||||
elif (self.urlMonitor.isSecureFavicon(client, path)):
|
||||
log.debug("[ClientRequest] Sending spoofed favicon response")
|
||||
log.debug("Sending spoofed favicon response")
|
||||
self.sendSpoofedFaviconResponse()
|
||||
|
||||
elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)):
|
||||
if 'securelink' in headers:
|
||||
del headers['securelink']
|
||||
|
||||
log.debug("[ClientRequest] Sending request via SSL ({})".format((client,url)))
|
||||
log.debug("Sending request via SSL ({})".format((client,url)))
|
||||
self.proxyViaSSL(address, self.method, path, postData, headers, self.urlMonitor.getSecurePort(client, url))
|
||||
|
||||
else:
|
||||
log.debug("[ClientRequest] Sending request via HTTP")
|
||||
log.debug("Sending request via HTTP")
|
||||
#self.proxyViaHTTP(address, self.method, path, postData, headers)
|
||||
port = 80
|
||||
if len(hostparts) > 1:
|
||||
|
@ -175,7 +177,7 @@ class ClientRequest(Request):
|
|||
self.proxyViaHTTP(address, self.method, path, postData, headers, port)
|
||||
|
||||
def handleHostResolvedError(self, error):
|
||||
log.debug("[ClientRequest] Host resolution error: {}".format(error))
|
||||
log.debug("Host resolution error: {}".format(error))
|
||||
try:
|
||||
self.finish()
|
||||
except:
|
||||
|
@ -185,23 +187,23 @@ class ClientRequest(Request):
|
|||
address = self.dnsCache.getCachedAddress(host)
|
||||
|
||||
if address != None:
|
||||
log.debug("[ClientRequest] Host cached: {} {}".format(host, address))
|
||||
log.debug("Host cached: {} {}".format(host, address))
|
||||
return defer.succeed(address)
|
||||
else:
|
||||
|
||||
log.debug("[ClientRequest] Host not cached.")
|
||||
log.debug("Host not cached.")
|
||||
self.customResolver.port = self.urlMonitor.getResolverPort()
|
||||
|
||||
try:
|
||||
log.debug("[ClientRequest] Resolving with DNSChef")
|
||||
log.debug("Resolving with DNSChef")
|
||||
address = str(self.customResolver.query(host)[0].address)
|
||||
return defer.succeed(address)
|
||||
except Exception:
|
||||
log.debug("[ClientRequest] Exception occured, falling back to Twisted")
|
||||
log.debug("Exception occured, falling back to Twisted")
|
||||
return reactor.resolve(host)
|
||||
|
||||
def process(self):
|
||||
log.debug("[ClientRequest] Resolving host: {}".format(self.getHeader('host')))
|
||||
log.debug("Resolving host: {}".format(self.getHeader('host')))
|
||||
host = self.getHeader('host').split(":")[0]
|
||||
|
||||
if self.hsts:
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
#
|
||||
|
||||
import logging
|
||||
from core.logger import logger
|
||||
|
||||
log = logging.getLogger('mitmf')
|
||||
formatter = logging.Formatter("%(asctime)s [DnsCache] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||
log = logger().setup_logger("DnsCache", formatter)
|
||||
|
||||
class DnsCache:
|
||||
|
||||
|
@ -51,7 +53,7 @@ class DnsCache:
|
|||
def setCustomRes(self, host, ip_address=None):
|
||||
if ip_address is not None:
|
||||
self.cache[host] = ip_address
|
||||
log.debug("[DNSCache] DNS entry set: %s -> %s" %(host, ip_address))
|
||||
log.debug("DNS entry set: %s -> %s" %(host, ip_address))
|
||||
else:
|
||||
if self.customAddress is not None:
|
||||
self.cache[host] = self.customAddress
|
||||
|
|
|
@ -22,8 +22,10 @@ import string
|
|||
|
||||
from ServerConnection import ServerConnection
|
||||
from URLMonitor import URLMonitor
|
||||
from core.logger import logger
|
||||
|
||||
log = logging.getLogger('mitmf')
|
||||
formatter = logging.Formatter("%(asctime)s [SSLServerConnection] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||
log = logger().setup_logger("SSLServerConnection", formatter)
|
||||
|
||||
class SSLServerConnection(ServerConnection):
|
||||
|
||||
|
@ -59,11 +61,11 @@ class SSLServerConnection(ServerConnection):
|
|||
for v in values:
|
||||
if v[:7].lower()==' domain':
|
||||
dominio=v.split("=")[1]
|
||||
log.debug("[SSLServerConnection][HSTS] Parsing cookie domain parameter: %s"%v)
|
||||
log.debug("Parsing cookie domain parameter: %s"%v)
|
||||
real = self.urlMonitor.real
|
||||
if dominio in real:
|
||||
v=" Domain=%s"%real[dominio]
|
||||
log.debug("[SSLServerConnection][HSTS] New cookie domain parameter: %s"%v)
|
||||
log.debug("New cookie domain parameter: %s"%v)
|
||||
newvalues.append(v)
|
||||
value = ';'.join(newvalues)
|
||||
|
||||
|
@ -87,13 +89,13 @@ class SSLServerConnection(ServerConnection):
|
|||
if ((not link.startswith('http')) and (not link.startswith('/'))):
|
||||
absoluteLink = "http://"+self.headers['host']+self.stripFileFromPath(self.uri)+'/'+link
|
||||
|
||||
log.debug("[SSLServerConnection] Found path-relative link in secure transmission: " + link)
|
||||
log.debug("[SSLServerConnection] New Absolute path-relative link: " + absoluteLink)
|
||||
log.debug("Found path-relative link in secure transmission: " + link)
|
||||
log.debug("New Absolute path-relative link: " + absoluteLink)
|
||||
elif not link.startswith('http'):
|
||||
absoluteLink = "http://"+self.headers['host']+link
|
||||
|
||||
log.debug("[SSLServerConnection] Found relative link in secure transmission: " + link)
|
||||
log.debug("[SSLServerConnection] New Absolute link: " + absoluteLink)
|
||||
log.debug("Found relative link in secure transmission: " + link)
|
||||
log.debug("New Absolute link: " + absoluteLink)
|
||||
|
||||
if not absoluteLink == "":
|
||||
absoluteLink = absoluteLink.replace('&', '&')
|
||||
|
|
|
@ -32,6 +32,9 @@ from core.sergioproxy.ProxyPlugins import ProxyPlugins
|
|||
from core.logger import logger
|
||||
|
||||
formatter = logging.Formatter("%(asctime)s %(clientip)s [type:%(browser)s-%(browserv)s os:%(clientos)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||
clientlog = logger().setup_logger("ServerConnection_clientlog", formatter)
|
||||
|
||||
formatter = logging.Formatter("%(asctime)s [ServerConnection] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||
log = logger().setup_logger("ServerConnection", formatter)
|
||||
|
||||
class ServerConnection(HTTPClient):
|
||||
|
@ -57,57 +60,64 @@ class ServerConnection(HTTPClient):
|
|||
self.postData = postData
|
||||
self.headers = headers
|
||||
self.client = client
|
||||
self.printPostData = True
|
||||
self.clientInfo = {}
|
||||
self.plugins = ProxyPlugins()
|
||||
self.urlMonitor = URLMonitor.getInstance()
|
||||
self.hsts = URLMonitor.getInstance().hsts
|
||||
self.app = URLMonitor.getInstance().app
|
||||
self.plugins = ProxyPlugins.getInstance()
|
||||
self.isImageRequest = False
|
||||
self.isCompressed = False
|
||||
self.contentLength = None
|
||||
self.shutdownComplete = False
|
||||
|
||||
self.handle_post_output = False
|
||||
|
||||
def sendRequest(self):
|
||||
if self.command == 'GET':
|
||||
|
||||
log.info(self.headers['host'], extra=self.clientInfo)
|
||||
clientlog.info(self.headers['host'], extra=self.clientInfo)
|
||||
|
||||
log.debug("[ServerConnection] Full request: {}{}".format(self.headers['host'], self.uri))
|
||||
log.debug("Full request: {}{}".format(self.headers['host'], self.uri))
|
||||
|
||||
self.sendCommand(self.command, self.uri)
|
||||
|
||||
def sendHeaders(self):
|
||||
for header, value in self.headers.iteritems():
|
||||
log.debug("[ServerConnection] Sending header: ({}: {})".format(header, value))
|
||||
log.debug("Sending header: ({}: {})".format(header, value))
|
||||
self.sendHeader(header, value)
|
||||
|
||||
self.endHeaders()
|
||||
|
||||
def sendPostData(self):
|
||||
if self.printPostData is True: #So we can disable printing POST data coming from plugins
|
||||
if self.handle_post_output is False: #So we can disable printing POST data coming from plugins
|
||||
try:
|
||||
postdata = self.postData.decode('utf8') #Anything that we can't decode to utf-8 isn't worth logging
|
||||
if len(postdata) > 0:
|
||||
log.warning("POST Data ({}):\n{}".format(self.headers['host'], postdata), extra=self.clientInfo)
|
||||
clientlog.warning("POST Data ({}):\n{}".format(self.headers['host'], postdata), extra=self.clientInfo)
|
||||
except Exception as e:
|
||||
if ('UnicodeDecodeError' or 'UnicodeEncodeError') in e.message:
|
||||
log.debug("[ServerConnection] {} Ignored post data from {}".format(self.clientInfo['clientip'], self.headers['host']))
|
||||
log.debug("{} Ignored post data from {}".format(self.clientInfo['clientip'], self.headers['host']))
|
||||
|
||||
self.printPostData = True
|
||||
self.handle_post_output = False
|
||||
self.transport.write(self.postData)
|
||||
|
||||
def connectionMade(self):
|
||||
log.debug("[ServerConnection] HTTP connection made.")
|
||||
log.debug("HTTP connection made.")
|
||||
|
||||
user_agent = parse(self.headers['user-agent'])
|
||||
|
||||
self.clientInfo["clientip"] = self.client.getClientIP()
|
||||
self.clientInfo["clientos"] = user_agent.os.family
|
||||
self.clientInfo["browser"] = user_agent.browser.family
|
||||
|
||||
try:
|
||||
self.clientInfo["browserv"] = user_agent.browser.version[0]
|
||||
except IndexError:
|
||||
user_agent = parse(self.headers['user-agent'])
|
||||
|
||||
self.clientInfo["clientos"] = user_agent.os.family
|
||||
self.clientInfo["browser"] = user_agent.browser.family
|
||||
try:
|
||||
self.clientInfo["browserv"] = user_agent.browser.version[0]
|
||||
except IndexError:
|
||||
self.clientInfo["browserv"] = "Other"
|
||||
except KeyError:
|
||||
self.clientInfo["clientos"] = "Other"
|
||||
self.clientInfo["browser"] = "Other"
|
||||
self.clientInfo["browserv"] = "Other"
|
||||
|
||||
self.plugins.hook()
|
||||
|
@ -125,7 +135,7 @@ class ServerConnection(HTTPClient):
|
|||
code = values['code']
|
||||
message = values['message']
|
||||
|
||||
log.debug("[ServerConnection] Server response: {} {} {}".format(version, code, message))
|
||||
log.debug("Server response: {} {} {}".format(version, code, message))
|
||||
self.client.setResponseCode(int(code), message)
|
||||
|
||||
def handleHeader(self, key, value):
|
||||
|
@ -137,15 +147,15 @@ class ServerConnection(HTTPClient):
|
|||
if (key.lower() == 'content-type'):
|
||||
if (value.find('image') != -1):
|
||||
self.isImageRequest = True
|
||||
log.debug("[ServerConnection] Response is image content, not scanning")
|
||||
log.debug("Response is image content, not scanning")
|
||||
|
||||
if (key.lower() == 'content-encoding'):
|
||||
if (value.find('gzip') != -1):
|
||||
log.debug("[ServerConnection] Response is compressed")
|
||||
log.debug("Response is compressed")
|
||||
self.isCompressed = True
|
||||
|
||||
elif (key.lower()== 'strict-transport-security'):
|
||||
log.info("Zapped a strict-trasport-security header", extra=self.clientInfo)
|
||||
clientlog.info("Zapped a strict-trasport-security header", extra=self.clientInfo)
|
||||
|
||||
elif (key.lower() == 'content-length'):
|
||||
self.contentLength = value
|
||||
|
@ -170,7 +180,7 @@ class ServerConnection(HTTPClient):
|
|||
|
||||
if logging.getLevelName(log.getEffectiveLevel()) == "DEBUG":
|
||||
for header, value in self.client.headers.iteritems():
|
||||
log.debug("[ServerConnection] Receiving header: ({}: {})".format(header, value))
|
||||
log.debug("Receiving header: ({}: {})".format(header, value))
|
||||
|
||||
def handleResponsePart(self, data):
|
||||
if (self.isImageRequest):
|
||||
|
@ -190,13 +200,14 @@ class ServerConnection(HTTPClient):
|
|||
|
||||
def handleResponse(self, data):
|
||||
if (self.isCompressed):
|
||||
log.debug("[ServerConnection] Decompressing content...")
|
||||
log.debug("Decompressing content...")
|
||||
data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read()
|
||||
|
||||
data = self.replaceSecureLinks(data)
|
||||
data = self.plugins.hook()['data']
|
||||
|
||||
log.debug("[ServerConnection] Read from server {} bytes of data".format(len(data)))
|
||||
log.debug("Read from server {} bytes of data:\n{}".format(len(data), data))
|
||||
#log.debug("Read from server {} bytes of data".format(len(data)))
|
||||
|
||||
if (self.contentLength != None):
|
||||
self.client.setHeader('Content-Length', len(data))
|
||||
|
@ -209,7 +220,7 @@ class ServerConnection(HTTPClient):
|
|||
try:
|
||||
self.shutdown()
|
||||
except:
|
||||
log.info("[ServerConnection] Client connection dropped before request finished.")
|
||||
log.info("Client connection dropped before request finished.")
|
||||
|
||||
def replaceSecureLinks(self, data):
|
||||
if self.hsts:
|
||||
|
@ -225,9 +236,9 @@ class ServerConnection(HTTPClient):
|
|||
for match in iterator:
|
||||
url = match.group()
|
||||
|
||||
log.debug("[ServerConnection][HSTS] Found secure reference: " + url)
|
||||
log.debug("Found secure reference: " + url)
|
||||
nuevaurl=self.urlMonitor.addSecureLink(self.clientInfo['clientip'], url)
|
||||
log.debug("[ServerConnection][HSTS] Replacing {} => {}".format(url,nuevaurl))
|
||||
log.debug("Replacing {} => {}".format(url,nuevaurl))
|
||||
sustitucion[url] = nuevaurl
|
||||
|
||||
if sustitucion:
|
||||
|
@ -243,7 +254,7 @@ class ServerConnection(HTTPClient):
|
|||
for match in iterator:
|
||||
url = match.group()
|
||||
|
||||
log.debug("[ServerConnection] Found secure reference: " + url)
|
||||
log.debug("Found secure reference: " + url)
|
||||
|
||||
url = url.replace('https://', 'http://', 1)
|
||||
url = url.replace('&', '&')
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
|
||||
import logging
|
||||
|
||||
from core.logger import logger
|
||||
from twisted.internet.protocol import ClientFactory
|
||||
|
||||
log = logging.getLogger('mitmf')
|
||||
formatter = logging.Formatter("%(asctime)s [ServerConnectionFactory] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||
log = logger().setup_logger("ServerConnectionFactory", formatter)
|
||||
|
||||
class ServerConnectionFactory(ClientFactory):
|
||||
|
||||
|
@ -35,12 +37,12 @@ class ServerConnectionFactory(ClientFactory):
|
|||
return self.protocol(self.command, self.uri, self.postData, self.headers, self.client)
|
||||
|
||||
def clientConnectionFailed(self, connector, reason):
|
||||
log.debug("[ServerConnectionFactory] Server connection failed.")
|
||||
log.debug("Server connection failed.")
|
||||
|
||||
destination = connector.getDestination()
|
||||
|
||||
if (destination.port != 443):
|
||||
log.debug("[ServerConnectionFactory] Retrying via SSL")
|
||||
log.debug("Retrying via SSL")
|
||||
self.client.proxyViaSSL(self.headers['host'], self.command, self.uri, self.postData, self.headers, 443)
|
||||
else:
|
||||
try:
|
||||
|
|
|
@ -20,10 +20,12 @@ import re, os
|
|||
import logging
|
||||
|
||||
from core.configwatcher import ConfigWatcher
|
||||
from core.logger import logger
|
||||
|
||||
log = logging.getLogger('mitmf')
|
||||
formatter = logging.Formatter("%(asctime)s [URLMonitor] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||
log = logger().setup_logger("URLMonitor", formatter)
|
||||
|
||||
class URLMonitor:
|
||||
class URLMonitor:
|
||||
|
||||
'''
|
||||
The URL monitor maintains a set of (client, url) tuples that correspond to requests which the
|
||||
|
@ -79,7 +81,7 @@ class URLMonitor:
|
|||
s.add(to_url)
|
||||
return
|
||||
url_set = set([from_url, to_url])
|
||||
log.debug("[URLMonitor][AppCachePoison] Set redirection: {}".format(url_set))
|
||||
log.debug("Set redirection: {}".format(url_set))
|
||||
self.redirects.append(url_set)
|
||||
|
||||
def getRedirectionSet(self, url):
|
||||
|
@ -120,7 +122,7 @@ class URLMonitor:
|
|||
else:
|
||||
self.sustitucion[host] = "web"+host
|
||||
self.real["web"+host] = host
|
||||
log.debug("[URLMonitor][HSTS] SSL host ({}) tokenized ({})".format(host, self.sustitucion[host]))
|
||||
log.debug("SSL host ({}) tokenized ({})".format(host, self.sustitucion[host]))
|
||||
|
||||
url = 'http://' + host + path
|
||||
|
||||
|
@ -139,7 +141,7 @@ class URLMonitor:
|
|||
self.faviconSpoofing = faviconSpoofing
|
||||
|
||||
def updateHstsConfig(self):
|
||||
for k,v in ConfigWatcher.getInstance().config['SSLstrip+'].iteritems():
|
||||
for k,v in ConfigWatcher().config['SSLstrip+'].iteritems():
|
||||
self.sustitucion[k] = v
|
||||
self.real[v] = k
|
||||
|
||||
|
@ -156,14 +158,14 @@ class URLMonitor:
|
|||
return ((self.faviconSpoofing == True) and (url.find("favicon-x-favicon-x.ico") != -1))
|
||||
|
||||
def URLgetRealHost(self, host):
|
||||
log.debug("[URLMonitor][HSTS] Parsing host: {}".format(host))
|
||||
log.debug("Parsing host: {}".format(host))
|
||||
|
||||
self.updateHstsConfig()
|
||||
|
||||
if self.real.has_key(host):
|
||||
log.debug("[URLMonitor][HSTS] Found host in list: {}".format(self.real[host]))
|
||||
log.debug("Found host in list: {}".format(self.real[host]))
|
||||
return self.real[host]
|
||||
|
||||
else:
|
||||
log.debug("[URLMonitor][HSTS] Host not in list: {}".format(host))
|
||||
log.debug("Host not in list: {}".format(host))
|
||||
return host
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue