module WpItems::Detectable

Attributes

item_xpath[R]
vulns_file[R]

Public Instance Methods

aggressive_detection(wp_target, options = {}) click to toggle source

@param [ WpTarget ] wp_target @param [ Hash ] options @option options [ Boolean ] :show_progression Whether or not output the progress bar @option options [ Boolean ] :only_vulnerable Only check for vulnerable items @option options [ String ] :exclude_content

@return [ WpItems ]

# File lib/common/collections/wp_items/detectable.rb, line 14
def aggressive_detection(wp_target, options = {})
  browser          = Browser.instance
  hydra            = browser.hydra
  targets          = targets_items(wp_target, options)
  progress_bar     = progress_bar(targets.size, options)
  exist_options    = {
    error_404_hash:  wp_target.error_404_hash,
    homepage_hash:   wp_target.homepage_hash,
    exclude_content: options[:exclude_content] ? %r{#{options[:exclude_content]}} : nil
  }

  # If we only want the vulnerable ones, the passive detection is ignored

  # Otherwise, a passive detection is performed, and results will be merged

  results = options[:only_vulnerable] ? new : passive_detection(wp_target, options)

  targets.each do |target_item|
    request = browser.forge_request(target_item.url, request_params)

    request.on_complete do |response|
      progress_bar.progress += 1 if options[:show_progression]

      if target_item.exists?(exist_options, response)
        if !results.include?(target_item)
          results << target_item
        end
      end
    end

    hydra.queue(request)
  end

  hydra.run
  results.sort!
  results # can't just return results.sort because the #sort returns an array, and we want a WpItems

end
passive_detection(wp_target, options = {}) click to toggle source

@param [ WpTarget ] wp_target @param [ Hash ] options

@return [ WpItems ]

# File lib/common/collections/wp_items/detectable.rb, line 71
def passive_detection(wp_target, options = {})
  results      = new
  item_class   = self.item_class
  type         = self.to_s.gsub(/Wp/, '').downcase
  response     = Browser.get(wp_target.url)
  item_options = {
    wp_content_dir: wp_target.wp_content_dir,
    wp_plugins_dir: wp_target.wp_plugins_dir,
    vulns_file:     self.vulns_file
  }

  regex1 = %r{(?:[^=:]+)\s?(?:=|:)\s?(?:"|')[^"']+\?/}
  regex2 = %r{\?/}
  regex3 = %r{\?/([^/\"']+)\?(?:/|"|')}

  names = response.body.scan(/#{regex1}#{Regexp.escape(wp_target.wp_content_dir)}#{regex2}#{Regexp.escape(type)}#{regex3}/)

  names.flatten.uniq.each do |name|
    results << item_class.new(wp_target.uri, item_options.merge(name: name))
  end

  results.sort!
  results
end
progress_bar(targets_size, options) click to toggle source

@param [ Integer ] targets_size @param [ Hash ] options

@return [ ProgressBar ] :nocov:

# File lib/common/collections/wp_items/detectable.rb, line 55
def progress_bar(targets_size, options)
  if options[:show_progression]
    ProgressBar.create(
      format: '%t %a <%B> (%c / %C) %P%% %e',
      title: '  ', # Used to craete a left margin

      length: 120,
      total: targets_size
    )
  end
end

Protected Instance Methods

create_item(klass, name, wp_target, vulns_file = nil) click to toggle source

@param [ Class ] klass @param [ String ] name @param [ WpTarget ] wp_target @option [ String ] #vulns_file

@return [ WpItem ]

# File lib/common/collections/wp_items/detectable.rb, line 153
def create_item(klass, name, wp_target, vulns_file = nil)
  klass.new(
    wp_target.uri,
    name:           name,
    vulns_file:     vulns_file,
    wp_content_dir: wp_target.wp_content_dir,
    wp_plugins_dir: wp_target.wp_plugins_dir
  )
end
item_class() click to toggle source

@return [ Class ]

# File lib/common/collections/wp_items/detectable.rb, line 186
def item_class
  Object.const_get(self.to_s.gsub(/.$/, ''))
end
request_params() click to toggle source

The default request parameters

@return [ Hash ]

# File lib/common/collections/wp_items/detectable.rb, line 101
def request_params; { cache_ttl: 0, followlocation: true } end
targets_items(wp_target, options = {}) click to toggle source

@param [ WpTarget ] wp_target @param [ options ] options @option options [ Boolean ] :only_vulnerable @option options [ String ] :file The path to the file containing the targets

@return [ Array<WpItem> ]

# File lib/common/collections/wp_items/detectable.rb, line 109
def targets_items(wp_target, options = {})
  item_class = self.item_class
  vulns_file = self.vulns_file

  targets = vulnerable_targets_items(wp_target, item_class, vulns_file)

  unless options[:only_vulnerable]
    unless options[:file]
      raise 'A file must be supplied'
    end

    targets += targets_items_from_file(options[:file], wp_target, item_class, vulns_file)
  end

  targets.uniq! { |t| t.name }
  targets.sort_by { rand }
end
targets_items_from_file(file, wp_target, item_class, vulns_file) click to toggle source

@param [ String ] file @param [ WpTarget ] wp_target @param [ Class ] #item_class @param [ String ] #vulns_file

@return [ WpItem ]

# File lib/common/collections/wp_items/detectable.rb, line 169
def targets_items_from_file(file, wp_target, item_class, vulns_file)
  targets = []

  File.open(file, 'r') do |f|
    f.readlines.collect do |item_name|
      targets << create_item(
        item_class,
        item_name.strip,
        wp_target,
        vulns_file
      )
    end
  end
  targets
end
vulnerable_targets_items(wp_target, item_class, vulns_file) click to toggle source

@param [ WpTarget ] wp_target @param [ Class ] #item_class @param [ String ] #vulns_file

@return [ Array<WpItem> ]

# File lib/common/collections/wp_items/detectable.rb, line 132
def vulnerable_targets_items(wp_target, item_class, vulns_file)
  targets = []
  xml     = xml(vulns_file)

  xml.xpath(item_xpath).each do |node|
    targets << create_item(
      item_class,
      node.attribute('name').text,
      wp_target,
      vulns_file
    )
  end
  targets
end