require 'redcarpet' require 'erb' module Redcarpet module Render class MsfMdHTML < Redcarpet::Render::HTML def block_code(code, language) code = $1 if code =~ /^(.+)<\/ruby>/m "
" \
          "#{code}" \
        "
" end def list(content, list_type) if list_type == :unordered && content.scan(/
  • /).flatten.length > 15 %Q|

      #{content}

      | elsif list_type == :unordered %Q|| elsif list_type == :ordered %Q|
        #{content}
      | else content end end def header(text, header_level) %Q|#{text}
      | end def table(header, body) %Q|#{header}#{body}

      | end end end end module Msf module Util module DocumentGenerator class DocumentNormalizer # # Markdown templates # CSS_BASE_PATH = 'markdown.css' HTML_TEMPLATE = 'html_template.erb' TEMPLATE_PATH = 'default_template.erb' # # Demo templates # 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. # # @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, kb) @md_template ||= lambda { template = '' 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.gsub(/##{number} - #{pr[:title]}" end 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 = [] mod_options.each_pair do |name, props| if props.required && props.default.nil? required_options << "* #{name} - #{props.desc}" end end 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, String] Module Authors # @return [String] def normalize_authors(authors) if authors.kind_of?(Array) authors.collect { |a| "* #{Rex::Text.html_encode(a)}" } * "\n" else authors 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, String] Module platforms. # @return [String] def normalize_platforms(platforms) if platforms.kind_of?(Array) platforms.collect { |p| "* #{p}" } * "\n" else platforms 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 demo ERB template. # # @param mod [Msf::Module] Metasploit module. # @param path [String] Template path. # @return [String] 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 # 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. # # @param mod [Msf::Module] Metasploit module. # @return [String] def normalize_demo_output(mod) if mod.kind_of?(Msf::Exploit::Remote::BrowserExploitServer) && mod.shortname != 'browser_autopwn2' load_demo_template(mod, BES_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Exploit::Remote::HttpServer) load_demo_template(mod, HTTPSERVER_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Exploit::Local) load_demo_template(mod, LOCALEXPLOIT_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Post) load_demo_template(mod, POST_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Payload) load_demo_template(mod, PAYLOAD_DEMO_TEMPLATE) elsif mod.kind_of?(Msf::Auxiliary::Scanner) load_demo_template(mod, AUXILIARY_SCANNER_DEMO_TEMPLATE) elsif is_remote_exploit?(mod) load_demo_template(mod, REMOTE_EXPLOIT_DEMO_TEMPLATE) else load_demo_template(mod, GENERIC_DEMO_TEMPLATE) end end end end end end