New enumeration system

This commit is contained in:
erwanlr
2013-03-19 22:59:20 +01:00
parent 634a6222f7
commit d016d33747
79 changed files with 3798 additions and 6388 deletions

View File

@@ -0,0 +1,8 @@
# encoding: UTF-8
require 'common/collections/vulnerabilities/output'
class Vulnerabilities < Array
include Vulnerabilities::Output
end

View File

@@ -0,0 +1,13 @@
# encoding: UTF-8
class Vulnerabilities < Array
module Output
def output
self.each do |v|
v.output
end
end
end
end

View File

@@ -0,0 +1,10 @@
# encoding: UTF-8
require 'common/collections/wp_items/detectable'
require 'common/collections/wp_items/output'
class WpItems < Array
extend WpItems::Detectable
include WpItems::Output
end

View File

@@ -0,0 +1,154 @@
# 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

View File

@@ -0,0 +1,11 @@
# encoding: UTF-8
class WpItems < Array
module Output
def output
self.each { |item| item.output }
end
end
end

View File

@@ -0,0 +1,8 @@
# encoding: UTF-8
require 'common/collections/wp_plugins/detectable'
class WpPlugins < WpItems
extend WpPlugins::Detectable
end

View File

@@ -0,0 +1,18 @@
# encoding: UTF-8
class WpPlugins < WpItems
module Detectable
def vulns_file
unless @vulns_file
@vulns_file = PLUGINS_VULNS_FILE
end
@vulns_file
end
def item_xpath
'//plugin'
end
end
end

View File

@@ -0,0 +1,8 @@
# encoding: UTF-8
require 'common/collections/wp_themes/detectable'
class WpThemes < WpItems
extend WpThemes::Detectable
end

View File

@@ -0,0 +1,18 @@
# encoding: UTF-8
class WpThemes < WpItems
module Detectable
def vulns_file
unless @vulns_file
@vulns_file = THEMES_VULNS_FILE
end
@vulns_file
end
def item_xpath
'//theme'
end
end
end

View File

@@ -0,0 +1,8 @@
# encoding: UTF-8
require 'common/collections/wp_timthumbs/detectable'
class WpTimthumbs < WpItems
extend WpTimthumbs::Detectable
end

View File

@@ -0,0 +1,56 @@
# encoding: UTF-8
class WpTimthumbs < WpItems
module Detectable
# No passive detection
# @return [ WpTimthumbs ]
def passive_detection(wp_target, topns = {})
new
end
def targets_items(wp_target, options = {})
unless options[:file]
raise 'A file must be supplied'
end
targets = options[:theme_name] ? theme_timthumbs(options[:theme_name], wp_target) : []
File.open(options[:file], 'r') do |f|
f.readlines.collect do |path|
targets << create_item(wp_target, path.strip)
end
end
targets.uniq { |i| i.url }
end
# @return [ WpTimthumb Array ]
def theme_timthumbs(theme_name, wp_target)
targets = []
wp_timthumb = create_item(wp_target)
%w{
timthumb.php lib/timthumb.php inc/timthumb.php includes/timthumb.php
scripts/timthumb.php tools/timthumb.php functions/timthumb.php
}.each do |path|
wp_timthumb.path = "$wp-content$/themes/#{theme_name}/#{path}"
targets << wp_timthumb.dup
end
targets
end
# @return [ WpTimthumb ]
def create_item(wp_target, path = nil)
options = {
wp_content_dir: wp_target.wp_content_dir,
wp_plugins_dir: wp_target.wp_plugins_dir
}
options.merge!(path: path) if path
WpTimthumb.new(wp_target.uri, options)
end
end
end

View File

@@ -0,0 +1,10 @@
# encoding: UTF-8
require 'common/collections/wp_users/detectable'
require 'common/collections/wp_users/output'
class WpUsers < WpItems
extend WpUsers::Detectable
include WpUsers::Output
end

View File

@@ -0,0 +1,27 @@
# encoding: UTF-8
class WpUsers < WpItems
module Detectable
def request_params; {} end
# options:
# :range - default 1..10
def targets_items(wp_target, options = {})
range = options[:range] || (1..10)
targets = []
range.each do |user_id|
targets << WpUser.new(wp_target.uri, id: user_id)
end
targets
end
# No passive detection
# @return [ WpUsers ]
def passive_detection(wp_target, options = {})
new
end
end
end

View File

@@ -0,0 +1,29 @@
# encoding: UTF-8
class WpUsers < WpItems
module Output
# TODO : create a generic method to output tabs
def output(left_margin = '')
max_id_length = self.sort { |a, b| a.id.to_s.length <=> b.id.to_s.length }.last.id.to_s.length
max_login_length = self.sort { |a, b| a.login.length <=> b.login.length }.last.login.length
max_display_name_length = self.sort { |a, b| a.display_name.length <=> b.display_name.length }.last.display_name.length
inner_space = 2
id_length = (max_id_length + inner_space * 2) /2 *2
login_length = max_login_length + inner_space * 2
display_name_length = max_display_name_length + inner_space * 2
puts left_margin + '+' * (id_length + login_length + display_name_length + 4)
puts left_margin + '|' + 'id'.center(id_length) + '|' + 'login'.center(login_length) + '|' + 'display name'.center(display_name_length) + '|'
puts left_margin + '|' + '+' * (id_length + login_length + display_name_length + 2) + '|'
self.each do |u|
puts left_margin + '|' + u.id.to_s.center(id_length) + '|' + u.login.center(login_length) + '|' + u.display_name.center(display_name_length) + '|'
end
puts left_margin + '+' * (id_length + login_length + display_name_length + 4)
end
end
end