-) Code formatting
-) rspec tests
This commit is contained in:
@@ -21,16 +21,16 @@ class Browser
|
||||
@@user_agent_modes = %w{ static semi-static random }
|
||||
|
||||
ACCESSOR_OPTIONS = [
|
||||
:user_agent,
|
||||
:user_agent_mode,
|
||||
:available_user_agents,
|
||||
:proxy,
|
||||
:max_threads,
|
||||
:cache_timeout,
|
||||
:request_timeout
|
||||
:user_agent,
|
||||
:user_agent_mode,
|
||||
:available_user_agents,
|
||||
:proxy,
|
||||
:max_threads,
|
||||
:cache_timeout,
|
||||
:request_timeout
|
||||
]
|
||||
|
||||
attr_reader :hydra, :config_file
|
||||
attr_reader :hydra, :config_file
|
||||
attr_accessor *ACCESSOR_OPTIONS
|
||||
|
||||
def initialize(options = {})
|
||||
@@ -52,6 +52,7 @@ class Browser
|
||||
# might be in CacheFileStore
|
||||
setup_cache_handlers
|
||||
end
|
||||
|
||||
private_class_method :new
|
||||
|
||||
def self.instance(options = {})
|
||||
@@ -113,9 +114,9 @@ class Browser
|
||||
def setup_cache_handlers
|
||||
@hydra.cache_setter do |request|
|
||||
@cache.write_entry(
|
||||
Browser.generate_cache_key_from_request(request),
|
||||
request.response,
|
||||
request.cache_timeout
|
||||
Browser.generate_cache_key_from_request(request),
|
||||
request.response,
|
||||
request.cache_timeout
|
||||
)
|
||||
end
|
||||
|
||||
@@ -123,24 +124,25 @@ class Browser
|
||||
@cache.read_entry(Browser.generate_cache_key_from_request(request)) rescue nil
|
||||
end
|
||||
end
|
||||
|
||||
private :setup_cache_handlers
|
||||
|
||||
def get(url, params = {})
|
||||
run_request(
|
||||
forge_request(url, params.merge(:method => :get))
|
||||
forge_request(url, params.merge(:method => :get))
|
||||
)
|
||||
end
|
||||
|
||||
def post(url, params = {})
|
||||
run_request(
|
||||
forge_request(url, params.merge(:method => :post))
|
||||
forge_request(url, params.merge(:method => :post))
|
||||
)
|
||||
end
|
||||
|
||||
def forge_request(url, params = {})
|
||||
Typhoeus::Request.new(
|
||||
url.to_s,
|
||||
merge_request_params(params)
|
||||
url.to_s,
|
||||
merge_request_params(params)
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ class CacheFileStore
|
||||
# Marshal does not need any "require"
|
||||
def initialize(storage_path, serializer = Marshal)
|
||||
@storage_path = File.expand_path(storage_path)
|
||||
@serializer = serializer
|
||||
@serializer = serializer
|
||||
|
||||
# File.directory? for ruby <= 1.9 otherwise, it makes more sense to do Dir.exist? :/
|
||||
unless File.directory?(@storage_path)
|
||||
|
||||
@@ -66,7 +66,7 @@ def get_equal_string_end(stringarray = [""])
|
||||
break
|
||||
end
|
||||
end
|
||||
if looping == false or (counter * -1 ) > base.length
|
||||
if looping == false or (counter * -1) > base.length
|
||||
break
|
||||
end
|
||||
already_found = "#{character if character}#{already_found}"
|
||||
@@ -87,6 +87,7 @@ if RUBY_VERSION < "1.9"
|
||||
end
|
||||
matches
|
||||
end
|
||||
|
||||
alias_method :grep, :_grep_
|
||||
end
|
||||
end
|
||||
@@ -125,5 +126,10 @@ def colorize(text, color_code)
|
||||
"\e[#{color_code}m#{text}\e[0m"
|
||||
end
|
||||
|
||||
def red(text); colorize(text, 31) end
|
||||
def green(text); colorize(text, 32) end
|
||||
def red(text)
|
||||
; colorize(text, 31)
|
||||
end
|
||||
|
||||
def green(text)
|
||||
; colorize(text, 32)
|
||||
end
|
||||
|
||||
@@ -20,20 +20,20 @@ require File.expand_path(File.dirname(__FILE__) + '/updater')
|
||||
|
||||
class SvnUpdater < Updater
|
||||
|
||||
@@revision_pattern = /revision="(\d+)"/i
|
||||
@@trunk_url = "https://wpscan.googlecode.com/svn/trunk"
|
||||
REVISION_PATTERN = /revision="(\d+)"/i
|
||||
TRUNK_URL = "https://github.com/wpscanteam/wpscan"
|
||||
|
||||
def is_installed?
|
||||
%x[svn info "#{@repo_directory}" --xml 2>&1] =~ /revision=/ ? true : false
|
||||
%x[svn info "#@repo_directory" --xml 2>&1] =~ /revision=/ ? true : false
|
||||
end
|
||||
|
||||
def local_revision_number
|
||||
local_revision = %x[svn info "#{@repo_directory}" --xml 2>&1]
|
||||
local_revision[@@revision_pattern, 1].to_s
|
||||
local_revision = %x[svn info "#@repo_directory" --xml 2>&1]
|
||||
local_revision[REVISION_PATTERN, 1].to_s
|
||||
end
|
||||
|
||||
def update
|
||||
%x[svn up "#{@repo_directory}"]
|
||||
%x[svn up "#@repo_directory"]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -27,8 +27,8 @@ module Malwares
|
||||
# return array of string (url of malwares found)
|
||||
def malwares(malwares_file_path = nil)
|
||||
if @malwares.nil?
|
||||
malwares_found = []
|
||||
malwares_file = Malwares.malwares_file(malwares_file_path)
|
||||
malwares_found = []
|
||||
malwares_file = Malwares.malwares_file(malwares_file_path)
|
||||
index_page_body = Browser.instance.get(@uri.to_s).body
|
||||
|
||||
File.open(malwares_file, 'r') do |file|
|
||||
|
||||
@@ -24,14 +24,14 @@ module WebSite
|
||||
wordpress = false
|
||||
|
||||
response = Browser.instance.get(login_url(),
|
||||
{ :follow_location => true, :max_redirects => 2 }
|
||||
{:follow_location => true, :max_redirects => 2}
|
||||
)
|
||||
|
||||
if response.body =~ %r{WordPress}i
|
||||
wordpress = true
|
||||
else
|
||||
response = Browser.instance.get(xmlrpc_url(),
|
||||
{ :follow_location => true, :max_redirects => 2 }
|
||||
{:follow_location => true, :max_redirects => 2}
|
||||
)
|
||||
|
||||
if response.body =~ %r{XML-RPC server accepts POST requests only}i
|
||||
|
||||
@@ -22,14 +22,14 @@ module WpConfigBackup
|
||||
# See http://www.feross.org/cmsploit/
|
||||
# return an array of backup config files url
|
||||
def config_backup
|
||||
found = []
|
||||
backups = WpConfigBackup.config_backup_files
|
||||
browser = Browser.instance
|
||||
hydra = browser.hydra
|
||||
found = []
|
||||
backups = WpConfigBackup.config_backup_files
|
||||
browser = Browser.instance
|
||||
hydra = browser.hydra
|
||||
|
||||
backups.each do |file|
|
||||
file_url = @uri.merge(URI.escape(file)).to_s
|
||||
request = browser.forge_request(file_url)
|
||||
request = browser.forge_request(file_url)
|
||||
|
||||
request.on_complete do |response|
|
||||
if response.body[%r{define}i] and not response.body[%r{<\s?html}i]
|
||||
|
||||
@@ -22,19 +22,19 @@ module WpPlugins
|
||||
#
|
||||
# return array of WpPlugin
|
||||
def plugins_from_aggressive_detection(options)
|
||||
options[:file] = options[:file] || "#{DATA_DIR}/plugins.txt"
|
||||
options[:vulns_file] = options[:vulns_file] || "#{DATA_DIR}/plugin_vulns.xml"
|
||||
options[:vulns_xpath] = "//plugin[@name='#{@name}']/vulnerability"
|
||||
options[:file] = options[:file] || "#{DATA_DIR}/plugins.txt"
|
||||
options[:vulns_file] = options[:vulns_file] || "#{DATA_DIR}/plugin_vulns.xml"
|
||||
options[:vulns_xpath] = "//plugin[@name='#{@name}']/vulnerability"
|
||||
options[:vulns_xpath_2] = "//plugin"
|
||||
options[:type] = "plugins"
|
||||
result = WpDetector.aggressive_detection(options)
|
||||
options[:type] = "plugins"
|
||||
result = WpDetector.aggressive_detection(options)
|
||||
plugins = []
|
||||
result.each do |r|
|
||||
plugins << WpPlugin.new(
|
||||
:url => r[:url],
|
||||
:path => r[:path],
|
||||
:url => r[:url],
|
||||
:path => r[:path],
|
||||
:wp_content_dir => r[:wp_content_dir],
|
||||
:name => r[:name]
|
||||
:name => r[:name]
|
||||
)
|
||||
end
|
||||
plugins.sort_by { |p| p.name }
|
||||
@@ -52,9 +52,9 @@ module WpPlugins
|
||||
|
||||
temp.each do |item|
|
||||
plugins << WpPlugin.new(
|
||||
:url => item[:url],
|
||||
:name => item[:name],
|
||||
:path => item[:path],
|
||||
:url => item[:url],
|
||||
:name => item[:name],
|
||||
:path => item[:path],
|
||||
:wp_content_dir => options[:wp_content_dir]
|
||||
)
|
||||
end
|
||||
|
||||
@@ -19,19 +19,19 @@
|
||||
module WpThemes
|
||||
|
||||
def themes_from_aggressive_detection(options)
|
||||
options[:file] = options[:file] || "#{DATA_DIR}/themes.txt"
|
||||
options[:vulns_file] = options[:vulns_file] || "#{DATA_DIR}/wp_theme_vulns.xml"
|
||||
options[:vulns_xpath] = "//theme[@name='#{@name}']/vulnerability"
|
||||
options[:file] = options[:file] || "#{DATA_DIR}/themes.txt"
|
||||
options[:vulns_file] = options[:vulns_file] || "#{DATA_DIR}/wp_theme_vulns.xml"
|
||||
options[:vulns_xpath] = "//theme[@name='#{@name}']/vulnerability"
|
||||
options[:vulns_xpath_2] = "//theme"
|
||||
options[:type] = "themes"
|
||||
result = WpDetector.aggressive_detection(options)
|
||||
options[:type] = "themes"
|
||||
result = WpDetector.aggressive_detection(options)
|
||||
themes = []
|
||||
result.each do |r|
|
||||
themes << WpTheme.new(
|
||||
:url => r[:url],
|
||||
:path => r[:path],
|
||||
:url => r[:url],
|
||||
:path => r[:path],
|
||||
:wp_content_dir => r[:wp_content_dir],
|
||||
:name => r[:name]
|
||||
:name => r[:name]
|
||||
)
|
||||
end
|
||||
themes.sort_by { |t| t.name }
|
||||
@@ -43,9 +43,9 @@ module WpThemes
|
||||
|
||||
temp.each do |item|
|
||||
themes << WpTheme.new(
|
||||
:url => item[:url],
|
||||
:name => item[:name],
|
||||
:path => item[:path],
|
||||
:url => item[:url],
|
||||
:name => item[:name],
|
||||
:path => item[:path],
|
||||
:wp_content_dir => options[:wp_content_dir]
|
||||
)
|
||||
end
|
||||
|
||||
@@ -47,7 +47,7 @@ module WpTimthumbs
|
||||
|
||||
protected
|
||||
def targets_url_from_theme(theme_name, options)
|
||||
targets = []
|
||||
targets = []
|
||||
theme_name = URI.escape(theme_name)
|
||||
|
||||
%w{
|
||||
@@ -55,10 +55,10 @@ module WpTimthumbs
|
||||
scripts/timthumb.php tools/timthumb.php functions/timthumb.php
|
||||
}.each do |file|
|
||||
targets << {
|
||||
:url => options[:url],
|
||||
:path => "themes/#{theme_name}/#{file}",
|
||||
:url => options[:url],
|
||||
:path => "themes/#{theme_name}/#{file}",
|
||||
:wp_content_dir => options[:wp_content_dir],
|
||||
:name => options[:name]
|
||||
:name => options[:name]
|
||||
}
|
||||
end
|
||||
targets
|
||||
|
||||
@@ -26,9 +26,9 @@ module WpUsernames
|
||||
#
|
||||
# returns an array of WpUser (can be empty)
|
||||
def usernames(options = {})
|
||||
range = options[:range] || (1..10)
|
||||
browser = Browser.instance
|
||||
usernames = []
|
||||
range = options[:range] || (1..10)
|
||||
browser = Browser.instance
|
||||
usernames = []
|
||||
|
||||
range.each do |author_id|
|
||||
url = author_url(author_id)
|
||||
@@ -58,7 +58,7 @@ module WpUsernames
|
||||
end
|
||||
|
||||
def get_nickname_from_url(url)
|
||||
resp = Browser.instance.get(url, { :follow_location => true, :max_redirects => 2 })
|
||||
resp = Browser.instance.get(url, {:follow_location => true, :max_redirects => 2})
|
||||
nickname = nil
|
||||
if resp.code == 200
|
||||
nickname = extract_nickname_from_body(resp.body)
|
||||
|
||||
@@ -24,11 +24,11 @@ class WpItem < Vulnerable
|
||||
|
||||
def initialize(options = {})
|
||||
@wp_content_dir = options[:wp_content_dir] || "wp-content"
|
||||
@url = options[:url]
|
||||
@path = options[:path]
|
||||
@name = options[:name] || extract_name_from_url
|
||||
@vulns_xml = options[:vulns_xml]
|
||||
@vulns_xpath = options[:vulns_xpath].sub(/\$name\$/, @name)
|
||||
@url = options[:url]
|
||||
@path = options[:path]
|
||||
@name = options[:name] || extract_name_from_url
|
||||
@vulns_xml = options[:vulns_xml]
|
||||
@vulns_xpath = options[:vulns_xpath].sub(/\$name\$/, @name)
|
||||
|
||||
raise("url not set") unless @url
|
||||
raise("path not set") unless @path
|
||||
|
||||
@@ -32,16 +32,16 @@
|
||||
# * +type+ - Type: plugins, themes
|
||||
class WpOptions
|
||||
def self.check_options(options)
|
||||
raise("url must be set") unless options[:url] != nil and options[:url].to_s.length > 0
|
||||
raise("url must be set") unless options[:url] != nil and options[:url].to_s.length > 0
|
||||
raise("only_vulnerable_ones must be set") unless options[:only_vulnerable_ones] != nil
|
||||
raise("file must be set") unless options[:file] != nil and options[:file].length > 0
|
||||
raise("vulns_file must be set") unless options[:vulns_file] != nil and options[:vulns_file].length > 0
|
||||
raise("vulns_xpath must be set") unless options[:vulns_xpath] != nil and options[:vulns_xpath].length > 0
|
||||
raise("vulns_xpath_2 must be set") unless options[:vulns_xpath_2] != nil and options[:vulns_xpath_2].length > 0
|
||||
raise("wp_content_dir must be set") unless options[:wp_content_dir] != nil and options[:wp_content_dir].length > 0
|
||||
raise("show_progress_bar must be set") unless options[:show_progress_bar] != nil
|
||||
raise("error_404_hash must be set") unless options[:error_404_hash] != nil and options[:error_404_hash].length > 0
|
||||
raise("type must be set") unless options[:type] != nil and options[:type].length > 0
|
||||
raise("file must be set") unless options[:file] != nil and options[:file].length > 0
|
||||
raise("vulns_file must be set") unless options[:vulns_file] != nil and options[:vulns_file].length > 0
|
||||
raise("vulns_xpath must be set") unless options[:vulns_xpath] != nil and options[:vulns_xpath].length > 0
|
||||
raise("vulns_xpath_2 must be set") unless options[:vulns_xpath_2] != nil and options[:vulns_xpath_2].length > 0
|
||||
raise("wp_content_dir must be set") unless options[:wp_content_dir] != nil and options[:wp_content_dir].length > 0
|
||||
raise("show_progress_bar must be set") unless options[:show_progress_bar] != nil
|
||||
raise("error_404_hash must be set") unless options[:error_404_hash] != nil and options[:error_404_hash].length > 0
|
||||
raise("type must be set") unless options[:type] != nil and options[:type].length > 0
|
||||
|
||||
unless options[:type] =~ /plugins/i or options[:type] =~ /themes/i or options[:type] =~ /timthumbs/i
|
||||
raise("Unknown type #{options[:type]}")
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
|
||||
class WpPlugin < WpItem
|
||||
def initialize(options = {})
|
||||
options[:vulns_xml] = options[:vulns_xml] || DATA_DIR + '/plugin_vulns.xml'
|
||||
options[:vulns_xpath] = "//plugin[@name='$name$']/vulnerability"
|
||||
options[:vulns_xml] = options[:vulns_xml] || DATA_DIR + '/plugin_vulns.xml'
|
||||
options[:vulns_xpath] = "//plugin[@name='$name$']/vulnerability"
|
||||
options[:vulns_xpath_2] = "//plugin"
|
||||
options[:type] = "plugins"
|
||||
options[:type] = "plugins"
|
||||
super(options)
|
||||
end
|
||||
|
||||
@@ -31,7 +31,7 @@ class WpPlugin < WpItem
|
||||
# however can also be found in their specific plugin dir.
|
||||
# http://www.exploit-db.com/ghdb/3714/
|
||||
def error_log?
|
||||
response_body = Browser.instance.get(error_log_url(), :headers => { "range" => "bytes=0-700"}).body
|
||||
response_body = Browser.instance.get(error_log_url(), :headers => {"range" => "bytes=0-700"}).body
|
||||
response_body[%r{PHP Fatal error}i] ? true : false
|
||||
end
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ class WpTarget
|
||||
attr_reader :uri, :verbose
|
||||
|
||||
def initialize(target_url, options = {})
|
||||
@uri = URI.parse(add_trailing_slash(add_http_protocol(target_url)))
|
||||
@verbose = options[:verbose]
|
||||
@uri = URI.parse(add_trailing_slash(add_http_protocol(target_url)))
|
||||
@verbose = options[:verbose]
|
||||
@wp_content_dir = options[:wp_content_dir]
|
||||
@wp_plugins_dir = options[:wp_plugins_dir]
|
||||
|
||||
@@ -111,7 +111,7 @@ class WpTarget
|
||||
|
||||
def has_debug_log?
|
||||
# We only get the first 700 bytes of the file to avoid loading huge file (like 2Go)
|
||||
response_body = Browser.instance.get(debug_log_url(), :headers => { "range" => "bytes=0-700"}).body
|
||||
response_body = Browser.instance.get(debug_log_url(), :headers => {"range" => "bytes=0-700"}).body
|
||||
response_body[%r{\[[^\]]+\] PHP (?:Warning|Error|Notice):}] ? true : false
|
||||
end
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ class WpTheme < WpItem
|
||||
attr_reader :name, :style_url, :version
|
||||
|
||||
def initialize(options = {})
|
||||
options[:vulns_xml] = options[:vulns_xml] || DATA_DIR + '/wp_theme_vulns.xml'
|
||||
options[:vulns_xml] = options[:vulns_xml] || DATA_DIR + '/wp_theme_vulns.xml'
|
||||
options[:vulns_xpath] = "//theme[@name='$name$']/vulnerability"
|
||||
@version = options[:version]
|
||||
@style_url = options[:style_url]
|
||||
@version = options[:version]
|
||||
@style_url = options[:style_url]
|
||||
super(options)
|
||||
end
|
||||
|
||||
@@ -56,18 +56,18 @@ class WpTheme < WpItem
|
||||
|
||||
# Discover the wordpress theme name by parsing the css link rel
|
||||
def self.find_from_css_link(target_uri)
|
||||
response = Browser.instance.get(target_uri.to_s, { :follow_location => true, :max_redirects => 2 })
|
||||
response = Browser.instance.get(target_uri.to_s, {:follow_location => true, :max_redirects => 2})
|
||||
|
||||
matches = %r{https?://[^"']+/themes/([^"']+)/style.css}i.match(response.body)
|
||||
if matches
|
||||
style_url = matches[0]
|
||||
theme_name = matches[1]
|
||||
|
||||
return new(:name => theme_name,
|
||||
:style_url => style_url,
|
||||
:url => style_url,
|
||||
:path => "",
|
||||
:wp_content_dir => ""
|
||||
return new(:name => theme_name,
|
||||
:style_url => style_url,
|
||||
:url => style_url,
|
||||
:path => "",
|
||||
:wp_content_dir => ""
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -79,15 +79,15 @@ class WpTheme < WpItem
|
||||
|
||||
matches = regexp.match(body)
|
||||
if matches
|
||||
woo_theme_name = matches[1]
|
||||
woo_theme_version = matches[2]
|
||||
woo_theme_name = matches[1]
|
||||
woo_theme_version = matches[2]
|
||||
woo_framework_version = matches[3] # Not used at this time
|
||||
|
||||
return new(:name => woo_theme_name,
|
||||
:version => woo_theme_version,
|
||||
:url => matches[0],
|
||||
:path => "",
|
||||
:wp_content_dir => ""
|
||||
return new(:name => woo_theme_name,
|
||||
:version => woo_theme_version,
|
||||
:url => matches[0],
|
||||
:path => "",
|
||||
:wp_content_dir => ""
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,10 +23,10 @@ class WpVersion < Vulnerable
|
||||
attr_reader :number, :discovery_method
|
||||
|
||||
def initialize(number, options = {})
|
||||
@number = number
|
||||
@number = number
|
||||
@discovery_method = options[:discovery_method]
|
||||
@vulns_xml = options[:vulns_xml] || DATA_DIR + '/wp_vulns.xml'
|
||||
@vulns_xpath = "//wordpress[@version='#{@number}']/vulnerability"
|
||||
@vulns_xml = options[:vulns_xml] || DATA_DIR + '/wp_vulns.xml'
|
||||
@vulns_xpath = "//wordpress[@version='#{@number}']/vulnerability"
|
||||
end
|
||||
|
||||
# Will use all method self.find_from_* to try to detect the version
|
||||
@@ -38,7 +38,7 @@ class WpVersion < Vulnerable
|
||||
# (find_from_meta_generator, find_from_rss_generator etc)
|
||||
def self.find(target_uri, wp_content_dir)
|
||||
options = {
|
||||
:url => target_uri,
|
||||
:url => target_uri,
|
||||
:wp_content_dir => wp_content_dir
|
||||
}
|
||||
self.methods.grep(/find_from_/).each do |method_to_call|
|
||||
@@ -60,14 +60,14 @@ class WpVersion < Vulnerable
|
||||
# that it is reinstated on upgrade.
|
||||
def self.find_from_meta_generator(options)
|
||||
target_uri = options[:url]
|
||||
response = Browser.instance.get(target_uri.to_s, { :follow_location => true, :max_redirects => 2 })
|
||||
response = Browser.instance.get(target_uri.to_s, {:follow_location => true, :max_redirects => 2})
|
||||
|
||||
response.body[%r{name="generator" content="wordpress ([^"]+)"}i, 1]
|
||||
end
|
||||
|
||||
def self.find_from_rss_generator(options)
|
||||
target_uri = options[:url]
|
||||
response = Browser.instance.get(target_uri.merge("feed/").to_s, { :follow_location => true, :max_redirects => 2 })
|
||||
response = Browser.instance.get(target_uri.merge("feed/").to_s, {:follow_location => true, :max_redirects => 2})
|
||||
|
||||
response.body[%r{<generator>http://wordpress.org/\?v=([^<]+)</generator>}i, 1]
|
||||
end
|
||||
@@ -105,11 +105,11 @@ class WpVersion < Vulnerable
|
||||
file_url = target_uri.merge(node.attribute('src').text).to_s
|
||||
file_url = file_url.gsub(/\$wp-plugins\$/i, wp_plugins).gsub(/\$wp-content\$/i, wp_content)
|
||||
response = Browser.instance.get(file_url)
|
||||
md5sum = Digest::MD5.hexdigest(response.body)
|
||||
md5sum = Digest::MD5.hexdigest(response.body)
|
||||
|
||||
node.search('hash').each do |hash|
|
||||
if hash.attribute('md5').text == md5sum
|
||||
return hash.search('versions').text
|
||||
return hash.search('versions').text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,8 +20,8 @@ class WpVulnerability
|
||||
attr_accessor :title, :reference, :type
|
||||
|
||||
def initialize(title, reference, type)
|
||||
@title = title
|
||||
@title = title
|
||||
@reference = reference
|
||||
@type = type
|
||||
@type = type
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,27 +19,27 @@
|
||||
class WpscanOptions
|
||||
|
||||
ACCESSOR_OPTIONS = [
|
||||
:enumerate_plugins,
|
||||
:enumerate_only_vulnerable_plugins,
|
||||
:enumerate_themes,
|
||||
:enumerate_only_vulnerable_themes,
|
||||
:enumerate_timthumbs,
|
||||
:enumerate_usernames,
|
||||
:enumerate_usernames_range,
|
||||
:proxy,
|
||||
:threads,
|
||||
:url,
|
||||
:wordlist,
|
||||
:force,
|
||||
:update,
|
||||
:verbose,
|
||||
:username,
|
||||
:password,
|
||||
:follow_redirection,
|
||||
:wp_content_dir,
|
||||
:wp_plugins_dir,
|
||||
:help,
|
||||
:config_file
|
||||
:enumerate_plugins,
|
||||
:enumerate_only_vulnerable_plugins,
|
||||
:enumerate_themes,
|
||||
:enumerate_only_vulnerable_themes,
|
||||
:enumerate_timthumbs,
|
||||
:enumerate_usernames,
|
||||
:enumerate_usernames_range,
|
||||
:proxy,
|
||||
:threads,
|
||||
:url,
|
||||
:wordlist,
|
||||
:force,
|
||||
:update,
|
||||
:verbose,
|
||||
:username,
|
||||
:password,
|
||||
:follow_redirection,
|
||||
:wp_content_dir,
|
||||
:wp_plugins_dir,
|
||||
:help,
|
||||
:config_file
|
||||
]
|
||||
|
||||
attr_accessor *ACCESSOR_OPTIONS
|
||||
@@ -131,7 +131,7 @@ class WpscanOptions
|
||||
|
||||
if ARGV.length > 0
|
||||
WpscanOptions.get_opt_long.each do |opt, arg|
|
||||
wpscan_options.set_option_from_cli(opt, arg)
|
||||
wpscan_options.set_option_from_cli(opt, arg)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -144,11 +144,11 @@ class WpscanOptions
|
||||
|
||||
if WpscanOptions.is_long_option?(cli_option)
|
||||
self.send(
|
||||
WpscanOptions.option_to_instance_variable_setter(cli_option),
|
||||
cli_value
|
||||
WpscanOptions.option_to_instance_variable_setter(cli_option),
|
||||
cli_value
|
||||
)
|
||||
elsif cli_option === "--enumerate" # Special cases
|
||||
# Default value if no argument is given
|
||||
# Default value if no argument is given
|
||||
cli_value = "T!tup!" if cli_value.length == 0
|
||||
|
||||
enumerate_options_from_string(cli_value)
|
||||
@@ -188,20 +188,20 @@ class WpscanOptions
|
||||
# Even if a short option is given (IE : -u), the long one will be returned (IE : --url)
|
||||
def self.get_opt_long
|
||||
GetoptLong.new(
|
||||
["--url", "-u", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--enumerate", "-e", GetoptLong::OPTIONAL_ARGUMENT],
|
||||
["--username", "-U", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--wordlist", "-w", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--threads", "-t",GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--force", "-f",GetoptLong::NO_ARGUMENT],
|
||||
["--help", "-h", GetoptLong::NO_ARGUMENT],
|
||||
["--verbose", "-v", GetoptLong::NO_ARGUMENT] ,
|
||||
["--proxy", GetoptLong::OPTIONAL_ARGUMENT],
|
||||
["--update", GetoptLong::NO_ARGUMENT],
|
||||
["--follow-redirection", GetoptLong::NO_ARGUMENT],
|
||||
["--wp-content-dir", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--wp-plugins-dir", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--config-file", "-c", GetoptLong::REQUIRED_ARGUMENT]
|
||||
["--url", "-u", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--enumerate", "-e", GetoptLong::OPTIONAL_ARGUMENT],
|
||||
["--username", "-U", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--wordlist", "-w", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--threads", "-t", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--force", "-f", GetoptLong::NO_ARGUMENT],
|
||||
["--help", "-h", GetoptLong::NO_ARGUMENT],
|
||||
["--verbose", "-v", GetoptLong::NO_ARGUMENT],
|
||||
["--proxy", GetoptLong::OPTIONAL_ARGUMENT],
|
||||
["--update", GetoptLong::NO_ARGUMENT],
|
||||
["--follow-redirection", GetoptLong::NO_ARGUMENT],
|
||||
["--wp-content-dir", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--wp-plugins-dir", GetoptLong::REQUIRED_ARGUMENT],
|
||||
["--config-file", "-c", GetoptLong::REQUIRED_ARGUMENT]
|
||||
)
|
||||
end
|
||||
|
||||
@@ -221,7 +221,7 @@ class WpscanOptions
|
||||
|
||||
def self.option_to_instance_variable_setter(option)
|
||||
cleaned_option = WpscanOptions.clean_option(option)
|
||||
option_syms = ACCESSOR_OPTIONS.grep(%r{^#{cleaned_option}})
|
||||
option_syms = ACCESSOR_OPTIONS.grep(%r{^#{cleaned_option}})
|
||||
|
||||
option_syms.length == 1 ? :"#{option_syms.at(0)}=" : nil
|
||||
end
|
||||
|
||||
@@ -49,14 +49,14 @@ class Generate_List
|
||||
items = Svn_Parser.new(@svn_url, @verbose).parse
|
||||
save items
|
||||
end
|
||||
|
||||
|
||||
def generate_popular_list(pages)
|
||||
popular = get_popular_items(pages)
|
||||
items = Svn_Parser.new(@svn_url, @verbose).parse(popular)
|
||||
save items
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
# Send a HTTP request to the WordPress most popular theme or plugin webpage
|
||||
# parse the response for the names.
|
||||
def get_popular_items(pages)
|
||||
@@ -83,9 +83,9 @@ class Generate_List
|
||||
@hydra.queue(request)
|
||||
|
||||
if queue_count == @browser.max_threads
|
||||
@hydra.run
|
||||
queue_count = 0
|
||||
end
|
||||
@hydra.run
|
||||
queue_count = 0
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class Svn_Parser
|
||||
@svn_browser = Browser.instance
|
||||
@svn_hydra = @svn_browser.hydra
|
||||
end
|
||||
|
||||
|
||||
def parse(dirs=nil)
|
||||
if dirs == nil
|
||||
dirs = get_root_directories
|
||||
@@ -64,14 +64,14 @@ class Svn_Parser
|
||||
# trunk folder present
|
||||
if contains_trunk(response)
|
||||
puts "[+] Adding trunk on #{dir}" if @verbose
|
||||
urls << { :name => dir, :folder => "trunk"}
|
||||
# no trunk folder. This is true on theme svn repos
|
||||
urls << {:name => dir, :folder => "trunk"}
|
||||
# no trunk folder. This is true on theme svn repos
|
||||
else
|
||||
folders = response.body.scan(%r{^\s*<li><a href="(.+)/">.+/</a></li>$}i)
|
||||
if folders != nil and folders.length > 0
|
||||
last_version = folders.last[0]
|
||||
puts "[+] Adding #{last_version} on #{dir}" if @verbose
|
||||
urls << { :name => dir, :folder => last_version}
|
||||
urls << {:name => dir, :folder => last_version}
|
||||
else
|
||||
puts "[+] No content in #{dir}" if @verbose
|
||||
end
|
||||
@@ -89,7 +89,7 @@ class Svn_Parser
|
||||
@svn_hydra.run
|
||||
urls
|
||||
end
|
||||
|
||||
|
||||
# Get a file in each directory
|
||||
# TODO: exclude files like Thumbs.db (Example: wordpress-23-related-posts-plugin/)
|
||||
def get_svn_file_entries(dirs)
|
||||
|
||||
@@ -53,7 +53,7 @@ def help()
|
||||
puts "--gpl Alias for --generate_plugin_list"
|
||||
puts "--generate_full_plugin_list Generate a new full data/plugins.txt file"
|
||||
puts "--gfpl Alias for --generate_full_plugin_list"
|
||||
|
||||
|
||||
puts "--generate_theme_list [number of pages] Generate a new data/themes.txt file. (supply number of *pages* to parse, default : 150)"
|
||||
puts "--gtl Alias for --generate_theme_list"
|
||||
puts "--generate_full_theme_list Generate a new full data/themes.txt file"
|
||||
|
||||
Reference in New Issue
Block a user