Files
wpscan/lib/common/collections/wp_items/detectable.rb
2013-03-19 22:59:20 +01:00

155 lines
4.5 KiB
Ruby
Executable File

# encoding: UTF-8
class WpItems < Array
module Detectable
# The default request parameters
def request_params; { cache_ttl: 0, followlocation: true } end
# options:
# option name - default - description
# show_progress - false - Output a progress bar
# only_vulnerable - nil - Only check for vulnerable items
# exclude_content - nil -
def aggressive_detection(wp_target, options = {})
queue_count = 0
request_count = 0
browser = Browser.instance
hydra = browser.hydra
targets = targets_items(wp_target, options)
targets_size = targets.size
show_progression = options[:show_progression] || false
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_count += 1
request.on_complete do |response|
print "\rChecking for #{targets_size} total ... #{(request_count * 100) / targets_size}% complete." if show_progression
if target_item.exists?(exist_options, response)
if !results.include?(target_item)
results << target_item
end
end
end
hydra.queue(request)
queue_count += 1
if queue_count == browser.max_threads
hydra.run
queue_count = 0
end
end
hydra.run
results.sort!
results # can't just return results.sort because the #sort returns an array, and we want a WpItems
end
def passive_detection(wp_target, options = {})
results = new
item_class = self.item_class
type = self.to_s.gsub(/Wp/, '').downcase
response = Browser.instance.get(wp_target.url)
item_options = {
wp_content_dir: wp_target.wp_content_dir,
wp_plugins_dir: wp_target.wp_plugins_dir,
vulns_file: 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}/i)
names.flatten.uniq.each do |name|
results << item_class.new(wp_target.uri, item_options.merge(name: name))
end
results.sort!
results
end
protected
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
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
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
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
# return class
def item_class
Object.const_get(self.to_s.gsub(/.$/, ''))
end
end
end