WPSTools updated to respect ruby standards according to rubocop

This commit is contained in:
erwanlr
2013-01-24 17:04:45 +01:00
parent ce9f073f26
commit b0dd9ba989
18 changed files with 261 additions and 231 deletions

View File

@@ -1,3 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
@@ -45,7 +46,11 @@ class Browser
override_config_with_options(options)
end
@hydra = Typhoeus::Hydra.new(:max_concurrency => @max_threads, :timeout => @request_timeout)
@hydra = Typhoeus::Hydra.new(
max_concurrency: @max_threads,
timeout: @request_timeout
)
# TODO : add an option for the cache dir instead of using a constant
@cache = CacheFileStore.new(CACHE_DIR + '/browser')
@@ -69,12 +74,13 @@ class Browser
end
def user_agent_mode=(ua_mode)
ua_mode ||= "static"
ua_mode ||= 'static'
if USER_AGENT_MODES.include?(ua_mode)
@user_agent_mode = ua_mode
# For semi-static user agent mode, the user agent has to be nil the first time (it will be set with the getter)
@user_agent = nil if ua_mode === "semi-static"
# For semi-static user agent mode, the user agent has to
# be nil the first time (it will be set with the getter)
@user_agent = nil if ua_mode === 'semi-static'
else
raise "Unknow user agent mode : '#{ua_mode}'"
end
@@ -83,11 +89,11 @@ class Browser
# return the user agent, according to the user_agent_mode
def user_agent
case @user_agent_mode
when "semi-static"
when 'semi-static'
unless @user_agent
@user_agent = @available_user_agents.sample
end
when "random"
when 'random'
@user_agent = @available_user_agents.sample
end
@user_agent
@@ -109,21 +115,25 @@ class Browser
@proxy_auth = auth
elsif auth.is_a?(String)
if matches = %r{([^:]+):(.*)}.match(auth)
@proxy_auth = {:proxy_username => matches[1], :proxy_password => matches[2]}
@proxy_auth = {
proxy_username: matches[1],
proxy_password: matches[2]
}
else
raise_invalid_proxy_format()
raise_invalid_proxy_auth_format()
end
else
raise_invalid_proxy_format()
raise_invalid_proxy_auth_format()
end
end
end
def raise_invalid_proxy_format
raise "Invalid proxy auth format, expected username:password or {:proxy_username => username, :proxy_password => password}"
def raise_invalid_proxy_auth_format
raise 'Invalid proxy auth format, expected username:password or {proxy_username: username, proxy_password: password}'
end
# TODO reload hydra (if the .load_config is called on a browser object, hydra will not have the new @max_threads and @request_timeout)
# TODO reload hydra (if the .load_config is called on a browser object,
# hydra will not have the new @max_threads and @request_timeout)
def load_config(config_file = nil)
@config_file = config_file || @config_file
@@ -146,7 +156,9 @@ class Browser
end
@hydra.cache_getter do |request|
@cache.read_entry(Browser.generate_cache_key_from_request(request)) rescue nil
@cache.read_entry(
Browser.generate_cache_key_from_request(request)
) rescue nil
end
end

View File

@@ -1,3 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
@@ -18,7 +19,8 @@
#
# => @todo take consideration of the cache_timeout :
# -> create 2 files per key : one for the data storage (key.store ?) and the other for the cache timeout (key.expiration, key.timeout ?)
# -> create 2 files per key : one for the data storage (key.store ?)
# and the other for the cache timeout (key.expiration, key.timeout ?)
# or 1 file for all timeouts ?
# -> 2 dirs : 1 for storage, the other for cache_timeout ?
#
@@ -28,14 +30,16 @@ require 'yaml'
class CacheFileStore
attr_reader :storage_path, :serializer
# The serializer must have the 2 methods .load and .dump (Marshal and YAML have them)
# The serializer must have the 2 methods .load and .dump
# (Marshal and YAML have them)
# YAML is Human Readable, contrary to Marshal which store in a binary format
# Marshal does not need any "require"
def initialize(storage_path, serializer = Marshal)
@storage_path = File.expand_path(storage_path)
@serializer = serializer
# File.directory? for ruby <= 1.9 otherwise, it makes more sense to do Dir.exist? :/
# File.directory? for ruby <= 1.9 otherwise,
# it makes more sense to do Dir.exist? :/
unless File.directory?(@storage_path)
Dir.mkdir(@storage_path)
end

View File

@@ -1,3 +1,5 @@
# encoding: UTF-8
#
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#

View File

@@ -1,3 +1,5 @@
# encoding: UTF-8
#
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#

View File

@@ -1,3 +1,5 @@
# encoding: UTF-8
#
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#

View File

@@ -1,3 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
@@ -18,39 +19,39 @@
LIB_DIR = File.dirname(__FILE__)
ROOT_DIR = File.expand_path(LIB_DIR + '/..') # expand_path is used to get "wpscan/" instead of "wpscan/lib/../"
DATA_DIR = ROOT_DIR + "/data"
CONF_DIR = ROOT_DIR + "/conf"
CACHE_DIR = ROOT_DIR + "/cache"
WPSCAN_LIB_DIR = LIB_DIR + "/wpscan"
WPSTOOLS_LIB_DIR = LIB_DIR + "/wpstools"
UPDATER_LIB_DIR = LIB_DIR + "/updater"
COMMON_LIB_DIR = LIB_DIR + "/common"
LOG_FILE = ROOT_DIR + "/log.txt"
DATA_DIR = ROOT_DIR + '/data'
CONF_DIR = ROOT_DIR + '/conf'
CACHE_DIR = ROOT_DIR + '/cache'
WPSCAN_LIB_DIR = LIB_DIR + '/wpscan'
WPSTOOLS_LIB_DIR = LIB_DIR + '/wpstools'
UPDATER_LIB_DIR = LIB_DIR + '/updater'
COMMON_LIB_DIR = LIB_DIR + '/common'
LOG_FILE = ROOT_DIR + '/log.txt'
# Plugins directories
COMON_PLUGINS_DIR = COMMON_LIB_DIR + "/plugins"
WPSCAN_PLUGINS_DIR = WPSCAN_LIB_DIR + "/plugins"
WPSTOOLS_PLUGINS_DIR = WPSTOOLS_LIB_DIR + "/plugins"
COMON_PLUGINS_DIR = COMMON_LIB_DIR + '/plugins'
WPSCAN_PLUGINS_DIR = WPSCAN_LIB_DIR + '/plugins'
WPSTOOLS_PLUGINS_DIR = WPSTOOLS_LIB_DIR + '/plugins'
# Data files
PLUGINS_FILE = DATA_DIR + "/plugins.txt"
PLUGINS_FULL_FILE = DATA_DIR + "/plugins_full.txt"
PLUGINS_VULNS_FILE = DATA_DIR + "/plugin_vulns.xml"
THEMES_FILE = DATA_DIR + "/themes.txt"
THEMES_FULL_FILE = DATA_DIR + "/themes_full.txt"
THEMES_VULNS_FILE = DATA_DIR + "/theme_vulns.xml"
WP_VULNS_FILE = DATA_DIR + "/wp_vulns.xml"
WP_VERSIONS_FILE = DATA_DIR + "/wp_versions.xml"
LOCAL_FILES_FILE = DATA_DIR + "/local_vulnerable_files.xml"
VULNS_XSD = DATA_DIR + "/vuln.xsd"
WP_VERSIONS_XSD = DATA_DIR + "/wp_versions.xsd"
LOCAL_FILES_XSD = DATA_DIR + "/local_vulnerable_files.xsd"
PLUGINS_FILE = DATA_DIR + '/plugins.txt'
PLUGINS_FULL_FILE = DATA_DIR + '/plugins_full.txt'
PLUGINS_VULNS_FILE = DATA_DIR + '/plugin_vulns.xml'
THEMES_FILE = DATA_DIR + '/themes.txt'
THEMES_FULL_FILE = DATA_DIR + '/themes_full.txt'
THEMES_VULNS_FILE = DATA_DIR + '/theme_vulns.xml'
WP_VULNS_FILE = DATA_DIR + '/wp_vulns.xml'
WP_VERSIONS_FILE = DATA_DIR + '/wp_versions.xml'
LOCAL_FILES_FILE = DATA_DIR + '/local_vulnerable_files.xml'
VULNS_XSD = DATA_DIR + '/vuln.xsd'
WP_VERSIONS_XSD = DATA_DIR + '/wp_versions.xsd'
LOCAL_FILES_XSD = DATA_DIR + '/local_vulnerable_files.xsd'
WPSCAN_VERSION = "2.0"
WPSCAN_VERSION = '2.0'
require "#{LIB_DIR}/environment"
# TODO : add an exclude pattern ?
def require_files_from_directory(absolute_dir_path, files_pattern = "*.rb")
def require_files_from_directory(absolute_dir_path, files_pattern = '*.rb')
Dir[File.join(absolute_dir_path, files_pattern)].sort.each do |f|
f = File.expand_path(f)
require f
@@ -59,7 +60,7 @@ def require_files_from_directory(absolute_dir_path, files_pattern = "*.rb")
end
#require_files_from_directory(COMMON_LIB_DIR)
require_files_from_directory(COMMON_LIB_DIR, "**/*.rb")
require_files_from_directory(COMMON_LIB_DIR, '**/*.rb')
# Add protocol
def add_http_protocol(url)
@@ -71,8 +72,8 @@ def add_trailing_slash(url)
end
# Gets the string all elements in stringarray ends with
def get_equal_string_end(stringarray = [""])
already_found = ""
def get_equal_string_end(stringarray = [''])
already_found = ''
looping = true
counter = -1
if stringarray.kind_of? Array and stringarray.length > 1
@@ -97,15 +98,15 @@ end
# Since ruby 1.9.2, URI::escape is obsolete
# See http://rosettacode.org/wiki/URL_encoding#Ruby and http://www.ruby-forum.com/topic/207489
if RUBY_VERSION >= "1.9.2"
if RUBY_VERSION >= '1.9.2'
module URI
def self.escape(str)
URI.encode_www_form_component(str).gsub("+", "%20")
URI.encode_www_form_component(str).gsub('+', '%20')
end
end
end
if RUBY_VERSION < "1.9"
if RUBY_VERSION < '1.9'
class Array
# Fix for grep with symbols in ruby <= 1.8.7
def _grep_(regexp)
@@ -128,25 +129,25 @@ require_files_from_directory(UPDATER_LIB_DIR)
if @updater
REVISION = @updater.local_revision_number()
else
REVISION = "NA"
REVISION = 'NA'
end
# our 1337 banner
def banner()
def banner
puts '____________________________________________________'
puts " __ _______ _____ "
puts " \\ \\ / / __ \\ / ____| "
puts " \\ \\ /\\ / /| |__) | (___ ___ __ _ _ __ "
puts " \\ \\/ \\/ / | ___/ \\___ \\ / __|/ _` | '_ \\ "
puts " \\ /\\ / | | ____) | (__| (_| | | | |"
puts ' __ _______ _____ '
puts ' \\ \\ / / __ \\ / ____| '
puts ' \\ \\ /\\ / /| |__) | (___ ___ __ _ _ __ '
puts ' \\ \\/ \\/ / | ___/ \\___ \\ / __|/ _` | \'_ \\ '
puts ' \\ /\\ / | | ____) | (__| (_| | | | |'
puts " \\/ \\/ |_| |_____/ \\___|\\__,_|_| |_| v#{WPSCAN_VERSION}r#{REVISION}"
puts
puts " WordPress Security Scanner by the WPScan Team"
puts " Sponsored by the RandomStorm Open Source Initiative"
puts ' WordPress Security Scanner by the WPScan Team'
puts ' Sponsored by the RandomStorm Open Source Initiative'
puts '_____________________________________________________'
puts
if RUBY_VERSION < "1.9"
puts "[WARNING] Ruby < 1.9 not officially supported, please upgrade."
if RUBY_VERSION < '1.9'
puts '[WARNING] Ruby < 1.9 not officially supported, please upgrade.'
puts
end
end
@@ -165,16 +166,16 @@ end
def get_metasploit_url(module_path)
# remove leading slash
module_path = module_path.sub(/^\//, "")
module_path = module_path.sub(/^\//, '')
"http://www.metasploit.com/modules/#{module_path}"
end
# Override for puts to enable logging
def puts(o = "")
def puts(o = '')
# remove color for logging
if o.respond_to?("gsub")
if o.respond_to?('gsub')
temp = o.gsub(/\e\[\d+m(.*)?\e\[0m/, '\1')
File.open(LOG_FILE, "a+") { |f| f.puts(temp) }
File.open(LOG_FILE, 'a+') { |f| f.puts(temp) }
end
super(o)
end

View File

@@ -1,3 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
@@ -47,7 +48,7 @@ rescue LoadError => e
if missing_gem
if missing_gem =~ /nokogiri/i
puts
puts "Nokogiri needs some packets, please run 'sudo apt-get install libxml2 libxml2-dev libxslt1-dev' to install them. Then run the command below"
puts 'Nokogiri needs some packets, please run \'sudo apt-get install libxml2 libxml2-dev libxslt1-dev\' to install them. Then run the command below'
puts
end
puts "[TIP] Try to run 'gem install #{missing_gem}' or 'gem install --user-install #{missing_gem}'. If you still get an error, Please see README file or https://github.com/wpscanteam/wpscan"
@@ -55,7 +56,7 @@ rescue LoadError => e
exit(1)
end
if Typhoeus::VERSION == "0.4.0"
puts "Typhoeus 0.4.0 detected, please update the gem otherwise wpscan will not work correctly"
if Typhoeus::VERSION == '0.4.0'
puts 'Typhoeus 0.4.0 detected, please update the gem otherwise wpscan will not work correctly'
exit(1)
end

View File

@@ -1,3 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
@@ -24,7 +25,8 @@ class GitUpdater < Updater
%x[git #{repo_directory_arguments()} status 2>&1] =~ /On branch/ ? true : false
end
# Git has not a revsion number like SVN, so we will take the 7 first chars of the last commit hash
# Git has not a revsion number like SVN,
# so we will take the 7 first chars of the last commit hash
def local_revision_number
git_log = %x[git #{repo_directory_arguments()} log -1 2>&1]
git_log[/commit ([0-9a-z]{7})/i, 1].to_s

View File

@@ -1,3 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
@@ -21,7 +22,7 @@ require File.expand_path(File.dirname(__FILE__) + '/updater')
class SvnUpdater < Updater
REVISION_PATTERN = /revision="(\d+)"/i
TRUNK_URL = "https://github.com/wpscanteam/wpscan"
TRUNK_URL = 'https://github.com/wpscanteam/wpscan'
def is_installed?
%x[svn info "#@repo_directory" --xml 2>&1] =~ /revision=/ ? true : false

View File

@@ -1,3 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013

View File

@@ -1,3 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013

View File

@@ -1,3 +1,5 @@
# encoding: UTF-8
#
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
@@ -18,13 +20,11 @@
class CheckerPlugin < Plugin
def initialize
super(
:author => "@wpscanteam - @erwanlr"
)
super(author: 'WPScanTeam - @erwanlr')
register_options(
["--check-vuln-ref-urls", "--cvru", "Check all the vulnerabilities reference urls for 404"],
["--check-local-vulnerable-files LOCAL_DIRECTORY", "--clvf", "Perform a recursive scan in the LOCAL_DIRECTORY to find vulnerable files or shells"]
['--check-vuln-ref-urls', '--cvru', 'Check all the vulnerabilities reference urls for 404'],
['--check-local-vulnerable-files LOCAL_DIRECTORY', '--clvf', 'Perform a recursive scan in the LOCAL_DIRECTORY to find vulnerable files or shells']
)
end
@@ -39,11 +39,11 @@ class CheckerPlugin < Plugin
end
def check_vuln_ref_urls
vuln_ref_files = [ PLUGINS_VULNS_FILE , THEMES_VULNS_FILE, WP_VULNS_FILE ]
vuln_ref_files = [PLUGINS_VULNS_FILE, THEMES_VULNS_FILE, WP_VULNS_FILE]
error_codes = [404, 500, 403]
not_found_regexp = %r{No Results Found|error 404|ID Invalid or Not Found}i
puts "[+] Checking vulnerabilities reference urls"
puts '[+] Checking vulnerabilities reference urls'
vuln_ref_files.each do |vuln_ref_file|
xml = Nokogiri::XML(File.open(vuln_ref_file)) do |config|
@@ -51,7 +51,7 @@ class CheckerPlugin < Plugin
end
urls = []
xml.xpath("//reference").each { |node| urls << node.text }
xml.xpath('//reference').each { |node| urls << node.text }
urls.uniq!
@@ -63,7 +63,7 @@ class CheckerPlugin < Plugin
number_of_urls = urls.size
urls.each do |url|
request = browser.forge_request(url, { :cache_timeout => 0, :follow_location => true })
request = browser.forge_request(url, { cache_timeout: 0, follow_location: true })
request_count += 1
request.on_complete do |response|
@@ -95,11 +95,11 @@ class CheckerPlugin < Plugin
if Dir::exist?(dir_to_scan)
xml_file = LOCAL_FILES_FILE
local_hashes = {}
file_extension_to_scan = "*.{js,php,swf,html,htm}"
file_extension_to_scan = '*.{js,php,swf,html,htm}'
print "[+] Generating local hashes ... "
print '[+] Generating local hashes ... '
Dir[File::join(dir_to_scan, "**", file_extension_to_scan)].each do |filename|
Dir[File::join(dir_to_scan, '**', file_extension_to_scan)].each do |filename|
sha1sum = Digest::SHA1.file(filename).hexdigest
if local_hashes.has_key?(sha1sum)
@@ -109,36 +109,36 @@ class CheckerPlugin < Plugin
end
end
puts "done."
puts 'done.'
puts "[+] Checking for vulnerable files ..."
puts '[+] Checking for vulnerable files ...'
xml = Nokogiri::XML(File.open(xml_file)) do |config|
config.noblanks
end
xml.xpath("//hash").each do |node|
sha1sum = node.attribute("sha1").text
xml.xpath('//hash').each do |node|
sha1sum = node.attribute('sha1').text
if local_hashes.has_key?(sha1sum)
local_filenames = local_hashes[sha1sum]
vuln_title = node.search("title").text
vuln_filename = node.search("file").text
vuln_refrence = node.search("reference").text
vuln_title = node.search('title').text
vuln_filename = node.search('file').text
vuln_refrence = node.search('reference').text
puts " #{vuln_filename} found :"
puts " | Location(s):"
puts ' | Location(s):'
local_filenames.each do |file|
puts " | - #{file}"
end
puts " |"
puts ' |'
puts " | Title: #{vuln_title}"
puts " | Refrence: #{vuln_refrence}" if !vuln_refrence.empty?
puts
end
end
puts "done."
puts 'done.'
else
puts "The supplied directory '#{dir_to_scan}' does not exist"

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env ruby
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
@@ -26,14 +25,14 @@ class GenerateList
# type = themes | plugins
def initialize(type, verbose)
if type =~ /plugins/i
@type = "plugin"
@svn_url = "http://plugins.svn.wordpress.org/"
@popular_url = "http://wordpress.org/extend/plugins/browse/popular/"
@type = 'plugin'
@svn_url = 'http://plugins.svn.wordpress.org/'
@popular_url = 'http://wordpress.org/extend/plugins/browse/popular/'
@popular_regex = %r{<h3><a href="http://wordpress.org/extend/plugins/(.+)/">.+</a></h3>}i
elsif type =~ /themes/i
@type = "theme"
@svn_url = "http://themes.svn.wordpress.org/"
@popular_url = "http://wordpress.org/extend/themes/browse/popular/"
@type = 'theme'
@svn_url = 'http://themes.svn.wordpress.org/'
@popular_url = 'http://wordpress.org/extend/themes/browse/popular/'
@popular_regex = %r{<h3><a href="http://wordpress.org/extend/themes/(.+)">.+</a></h3>}i
else
raise "Type #{type} not defined"
@@ -45,23 +44,23 @@ class GenerateList
def set_file_name(type)
case @type
when "plugin"
when 'plugin'
case type
when :full
@file_name = PLUGINS_FULL_FILE
when :popular
@file_name = PLUGINS_FILE
else
raise "Unknown type"
raise 'Unknown type'
end
when "theme"
when 'theme'
case type
when :full
@file_name = THEMES_FULL_FILE
when :popular
@file_name = THEMES_FILE
else
raise "Unknown type"
raise 'Unknown type'
end
else
raise "Unknown type #@type"
@@ -87,7 +86,7 @@ class GenerateList
page_count = 1
queue_count = 0
(1...(pages.to_i+1)).each do |page|
(1...(pages.to_i + 1)).each do |page|
# First page has another URL
url = (page == 1) ? @popular_url : @popular_url + 'page/' + page.to_s + '/'
request = @browser.forge_request(url)
@@ -95,7 +94,7 @@ class GenerateList
queue_count += 1
request.on_complete do |response|
puts "[+] Parsing page " + page_count.to_s if @verbose
puts "[+] Parsing page #{page_count}" if @verbose
page_count += 1
response.body.scan(@popular_regex).each do |item|
puts "[+] Found popular #@type: #{item}" if @verbose

View File

@@ -1,3 +1,5 @@
# encoding: UTF-8
#
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
@@ -18,18 +20,16 @@
class ListGeneratorPlugin < Plugin
def initialize
super(
:author => "WPScanTeam - @FireFart"
)
super(author: 'WPScanTeam - @FireFart')
register_options(
["--generate-plugin-list [NUMBER_OF_PAGES]", "--gpl", Integer, "Generate a new data/plugins.txt file. (supply number of *pages* to parse, default : 150)"],
["--generate-full-plugin-list", "--gfpl", "Generate a new full data/plugins.txt file"],
['--generate-plugin-list [NUMBER_OF_PAGES]', '--gpl', Integer, 'Generate a new data/plugins.txt file. (supply number of *pages* to parse, default : 150)'],
['--generate-full-plugin-list', '--gfpl', 'Generate a new full data/plugins.txt file'],
["--generate-theme-list [NUMBER_OF_PAGES]", "--gtl", Integer, "Generate a new data/themes.txt file. (supply number of *pages* to parse, default : 150)"],
["--generate-full-theme-list", "--gftl", "Generate a new full data/themes.txt file"],
['--generate-theme-list [NUMBER_OF_PAGES]', '--gtl', Integer, 'Generate a new data/themes.txt file. (supply number of *pages* to parse, default : 150)'],
['--generate-full-theme-list', '--gftl', 'Generate a new full data/themes.txt file'],
["--generate-all", "--ga", "Generate a new full plugins, full themes, popular plugins and popular themes list"],
['--generate-all', '--ga', 'Generate a new full plugins, full themes, popular plugins and popular themes list']
)
end
@@ -40,13 +40,13 @@ class ListGeneratorPlugin < Plugin
if options.has_key?(:generate_plugin_list) || generate_all
number_of_pages = options[:generate_plugin_list] || 150
puts "[+] Generating new most popular plugin list"
puts '[+] Generating new most popular plugin list'
puts
GenerateList.new('plugins', verbose).generate_popular_list(number_of_pages)
end
if options[:generate_full_plugin_list] || generate_all
puts "[+] Generating new full plugin list"
puts '[+] Generating new full plugin list'
puts
GenerateList.new('plugins', verbose).generate_full_list
end
@@ -54,13 +54,13 @@ class ListGeneratorPlugin < Plugin
if options.has_key?(:generate_theme_list) || generate_all
number_of_pages = options[:generate_theme_list] || 150
puts "[+] Generating new most popular theme list"
puts '[+] Generating new most popular theme list'
puts
GenerateList.new('themes', verbose).generate_popular_list(number_of_pages)
end
if options[:generate_full_theme_list] || generate_all
puts "[+] Generating new full theme list"
puts '[+] Generating new full theme list'
puts
GenerateList.new('themes', verbose).generate_full_list
end

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env ruby
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
@@ -29,7 +28,7 @@ class SvnParser
@svn_hydra = @svn_browser.hydra
end
def parse()
def parse
get_root_directories
end
@@ -40,9 +39,11 @@ class SvnParser
def get_root_directories
dirs = []
rootindex = @svn_browser.get(@svn_root).body
rootindex.scan(%r{<li><a href=".+">(.+)/</a></li>}i).each do |dir|
dirs << dir[0]
end
dirs.sort!
dirs.uniq
end

View File

@@ -1,3 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
@@ -19,33 +20,33 @@
require File.expand_path(File.dirname(__FILE__) + '/../common_helper')
require_files_from_directory(WPSTOOLS_LIB_DIR)
require_files_from_directory(WPSTOOLS_PLUGINS_DIR, "**/*.rb")
require_files_from_directory(WPSTOOLS_PLUGINS_DIR, '**/*.rb')
def usage()
def usage
script_name = $0
puts
puts "-h for further help."
puts '-h for further help.'
puts
puts "Examples:"
puts 'Examples:'
puts
puts "- Generate a new 'most popular' plugin list, up to 150 pages ..."
puts "ruby #{script_name} --generate-plugin-list 150"
puts
puts "- Generate a new full plugin list"
puts '- Generate a new full plugin list'
puts "ruby #{script_name} --generate-full-plugin-list"
puts
puts "- Generate a new 'most popular' theme list, up to 150 pages ..."
puts "ruby #{script_name} --generate-theme-list 150"
puts
puts "- Generate a new full theme list"
puts '- Generate a new full theme list'
puts "ruby #{script_name} --generate-full-theme-list"
puts
puts "- Generate all list"
puts '- Generate all list'
puts "ruby #{script_name} --generate-all"
puts
puts "Locally scan a wordpress installation for vulnerable files or shells"
puts 'Locally scan a wordpress installation for vulnerable files or shells'
puts "ruby #{script_name} --check-local-vulnerable-files /var/www/wordpress/"
puts
puts "See README for further information."
puts 'See README for further information.'
puts
end

156
wpscan.rb
View File

@@ -19,17 +19,17 @@
#++
$: << '.'
require File.dirname(__FILE__) +'/lib/wpscan/wpscan_helper'
require File.dirname(__FILE__) + '/lib/wpscan/wpscan_helper'
def output_vulnerabilities(vulns)
vulns.each do |vulnerability|
puts
puts " | " + red("* Title: #{vulnerability.title}")
puts ' | ' + red("* Title: #{vulnerability.title}")
vulnerability.references.each do |r|
puts " | " + red("* Reference: #{r}")
puts ' | ' + red("* Reference: #{r}")
end
vulnerability.metasploit_modules.each do |m|
puts " | " + red("* Metasploit module: #{get_metasploit_url(m)}")
puts ' | ' + red("* Metasploit module: #{get_metasploit_url(m)}")
end
end
end
@@ -61,8 +61,8 @@ begin
end
puts @updater.update()
else
puts "Svn / Git not installed, or wpscan has not been installed with one of them."
puts "Update aborted"
puts 'Svn / Git not installed, or wpscan has not been installed with one of them.'
puts 'Update aborted'
end
exit(1)
end
@@ -89,37 +89,37 @@ begin
puts
else
puts "The remote host tried to redirect us to #{redirection}"
puts "Do you want follow the redirection ? [y/n]"
puts 'Do you want follow the redirection ? [y/n]'
end
if wpscan_options.follow_redirection or Readline.readline =~ /^y/i
wpscan_options.url = redirection
wp_target = WpTarget.new(redirection, wpscan_options.to_h)
else
puts "Scan aborted"
puts 'Scan aborted'
exit
end
end
if wp_target.has_basic_auth? && wpscan_options.basic_auth.nil?
raise "A basic authentification is required, please provide it with --basic-auth <login:password>"
raise 'A basic authentification is required, please provide it with --basic-auth <login:password>'
end
# Remote website is wordpress?
unless wpscan_options.force
unless wp_target.wordpress?
raise "The remote website is up, but does not seem to be running WordPress."
raise 'The remote website is up, but does not seem to be running WordPress.'
end
end
unless wp_target.wp_content_dir
raise "The wp_content_dir has not been found, please supply it with --wp-content-dir"
raise 'The wp_content_dir has not been found, please supply it with --wp-content-dir'
end
unless wp_target.wp_plugins_dir_exists?
puts "The plugins directory '#{wp_target.wp_plugins_dir}' does not exist."
puts "You can specify one per command line option (don't forget to include the wp-content directory if needed)"
puts "Continue? [y/n]"
puts 'You can specify one per command line option (don\'t forget to include the wp-content directory if needed)'
puts 'Continue? [y/n]'
unless Readline.readline =~ /^y/i
exit
end
@@ -134,33 +134,33 @@ begin
wp_theme = wp_target.theme
if wp_theme
# Theme version is handled in wp_item.to_s
puts green("[+]") + " The WordPress theme in use is #{wp_theme}"
puts green('[+]') + " The WordPress theme in use is #{wp_theme}"
puts
puts " | Name: #{wp_theme}" #this will also output the version number if detected
puts " | Location: #{wp_theme.get_url_without_filename}"
puts " | WordPress: #{wp_theme.wp_org_url}" if wp_theme.wp_org_item?
puts " | Directory listing enabled: Yes" if wp_theme.directory_listing?
puts ' | Directory listing enabled: Yes' if wp_theme.directory_listing?
puts " | Readme: #{wp_theme.readme_url}" if wp_theme.has_readme?
puts " | Changelog: #{wp_theme.changelog_url}" if wp_theme.has_changelog?
theme_vulnerabilities = wp_theme.vulnerabilities
unless theme_vulnerabilities.empty?
puts red("[!]") + " We have identified #{theme_vulnerabilities.size} vulnerabilities for this theme :"
puts red('[!]') + " We have identified #{theme_vulnerabilities.size} vulnerabilities for this theme :"
output_vulnerabilities(theme_vulnerabilities)
end
puts
end
if wp_target.has_readme?
puts red("[!]") + " The WordPress '#{wp_target.readme_url}' file exists"
puts red('[!]') + " The WordPress '#{wp_target.readme_url}' file exists"
end
if wp_target.has_full_path_disclosure?
puts red("[!]") + " Full Path Disclosure (FPD) in '#{wp_target.full_path_disclosure_url}'"
puts red('[!]') + " Full Path Disclosure (FPD) in '#{wp_target.full_path_disclosure_url}'"
end
if wp_target.has_debug_log?
puts red("[!]") + " Debug log file found : #{wp_target.debug_log_url}"
puts red('[!]') + " Debug log file found : #{wp_target.debug_log_url}"
end
wp_target.config_backup.each do |file_url|
@@ -172,46 +172,46 @@ begin
end
if wp_target.is_multisite?
puts green("[+]") + " This site seems to be a multisite (http://codex.wordpress.org/Glossary#Multisite)"
puts green('[+]') + ' This site seems to be a multisite (http://codex.wordpress.org/Glossary#Multisite)'
end
if wp_target.registration_enabled?
puts green("[+]") + " User registration is enabled"
puts green('[+]') + ' User registration is enabled'
end
if wp_target.has_xml_rpc?
puts green("[+]") + " XML-RPC Interface available under #{wp_target.xml_rpc_url}"
puts green('[+]') + " XML-RPC Interface available under #{wp_target.xml_rpc_url}"
end
if wp_target.has_malwares?
malwares = wp_target.malwares
puts red("[!]") + " #{malwares.size} malware(s) found :"
puts red('[!]') + " #{malwares.size} malware(s) found :"
malwares.each do |malware_url|
puts
puts " | " + red("#{malware_url}")
puts ' | ' + red("#{malware_url}")
end
puts
end
wp_version = wp_target.version
if wp_version
puts green("[+]") + " WordPress version #{wp_version.number} identified from #{wp_version.discovery_method}"
puts green('[+]') + " WordPress version #{wp_version.number} identified from #{wp_version.discovery_method}"
version_vulnerabilities = wp_version.vulnerabilities
unless version_vulnerabilities.empty?
puts
puts red("[!]") + " We have identified #{version_vulnerabilities.size} vulnerabilities from the version number :"
puts red('[!]') + " We have identified #{version_vulnerabilities.size} vulnerabilities from the version number :"
output_vulnerabilities(version_vulnerabilities)
end
end
if wpscan_options.enumerate_plugins == nil and wpscan_options.enumerate_only_vulnerable_plugins == nil
puts
puts green("[+]") + " Enumerating plugins from passive detection ... "
puts green('[+]') + ' Enumerating plugins from passive detection ... '
plugins = wp_target.plugins_from_passive_detection(:base_url => wp_target.uri, :wp_content_dir => wp_target.wp_content_dir)
plugins = wp_target.plugins_from_passive_detection(base_url: wp_target.uri, wp_content_dir: wp_target.wp_content_dir)
unless plugins.empty?
puts "#{plugins.size} found :"
@@ -224,84 +224,84 @@ begin
output_vulnerabilities(plugin.vulnerabilities)
end
else
puts "No plugins found :("
puts 'No plugins found :('
end
end
# Enumerate the installed plugins
if wpscan_options.enumerate_plugins or wpscan_options.enumerate_only_vulnerable_plugins or wpscan_options.enumerate_all_plugins
puts
puts green("[+]") + " Enumerating installed plugins #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_plugins} ..."
puts green('[+]') + " Enumerating installed plugins #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_plugins} ..."
puts
options = {
:base_url => wp_target.uri,
:only_vulnerable_ones => wpscan_options.enumerate_only_vulnerable_plugins || false,
:show_progression => true,
:wp_content_dir => wp_target.wp_content_dir,
:error_404_hash => wp_target.error_404_hash,
:homepage_hash => wp_target.homepage_hash,
:wp_plugins_dir => wp_target.wp_plugins_dir,
:full => wpscan_options.enumerate_all_plugins,
:exclude_content_based => wpscan_options.exclude_content_based
base_url: wp_target.uri,
only_vulnerable_ones: wpscan_options.enumerate_only_vulnerable_plugins || false,
show_progression: true,
wp_content_dir: wp_target.wp_content_dir,
error_404_hash: wp_target.error_404_hash,
homepage_hash: wp_target.homepage_hash,
wp_plugins_dir: wp_target.wp_plugins_dir,
full: wpscan_options.enumerate_all_plugins,
exclude_content_based: wpscan_options.exclude_content_based
}
plugins = wp_target.plugins_from_aggressive_detection(options)
unless plugins.empty?
puts
puts
puts green("[+]") + " We found #{plugins.size.to_s} plugins:"
puts green('[+]') + " We found #{plugins.size.to_s} plugins:"
plugins.each do |plugin|
puts
puts " | Name: #{plugin}" #this will also output the version number if detected
puts " | Location: #{plugin.get_url_without_filename}"
puts " | WordPress: #{plugin.wp_org_url}" if plugin.wp_org_item?
puts " | Directory listing enabled: Yes" if plugin.directory_listing?
puts ' | Directory listing enabled: Yes' if plugin.directory_listing?
puts " | Readme: #{plugin.readme_url}" if plugin.has_readme?
puts " | Changelog: #{plugin.changelog_url}" if plugin.has_changelog?
output_vulnerabilities(plugin.vulnerabilities)
if plugin.error_log?
puts " | " + red("[!]") + " A WordPress error_log file has been found : #{plugin.error_log_url}"
puts ' | ' + red('[!]') + " A WordPress error_log file has been found : #{plugin.error_log_url}"
end
end
else
puts
puts "No plugins found :("
puts 'No plugins found :('
end
end
# Enumerate installed themes
if wpscan_options.enumerate_themes or wpscan_options.enumerate_only_vulnerable_themes or wpscan_options.enumerate_all_themes
puts
puts green("[+]") + " Enumerating installed themes #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_themes} ..."
puts green('[+]') + " Enumerating installed themes #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_themes} ..."
puts
options = {
:base_url => wp_target.uri,
:only_vulnerable_ones => wpscan_options.enumerate_only_vulnerable_themes || false,
:show_progression => true,
:wp_content_dir => wp_target.wp_content_dir,
:error_404_hash => wp_target.error_404_hash,
:homepage_hash => wp_target.homepage_hash,
:full => wpscan_options.enumerate_all_themes,
:exclude_content_based => wpscan_options.exclude_content_based
base_url: wp_target.uri,
only_vulnerable_ones: wpscan_options.enumerate_only_vulnerable_themes || false,
show_progression: true,
wp_content_dir: wp_target.wp_content_dir,
error_404_hash: wp_target.error_404_hash,
homepage_hash: wp_target.homepage_hash,
full: wpscan_options.enumerate_all_themes,
exclude_content_based: wpscan_options.exclude_content_based
}
themes = wp_target.themes_from_aggressive_detection(options)
unless themes.empty?
puts
puts
puts green("[+]") + " We found #{themes.size.to_s} themes:"
puts green('[+]') + " We found #{themes.size.to_s} themes:"
themes.each do |theme|
puts
puts " | Name: #{theme}" #this will also output the version number if detected
puts " | Location: #{theme.get_url_without_filename}"
puts " | WordPress: #{theme.wp_org_url}" if theme.wp_org_item?
puts " | Directory listing enabled: Yes" if theme.directory_listing?
puts ' | Directory listing enabled: Yes' if theme.directory_listing?
puts " | Readme: #{theme.readme_url}" if theme.has_readme?
puts " | Changelog: #{theme.changelog_url}" if theme.has_changelog?
@@ -309,22 +309,22 @@ begin
end
else
puts
puts "No themes found :("
puts 'No themes found :('
end
end
if wpscan_options.enumerate_timthumbs
puts
puts green("[+]") + " Enumerating timthumb files ..."
puts green('[+]') + ' Enumerating timthumb files ...'
puts
options = {
:base_url => wp_target.uri,
:show_progression => true,
:wp_content_dir => wp_target.wp_content_dir,
:error_404_hash => wp_target.error_404_hash,
:homepage_hash => wp_target.homepage_hash,
:exclude_content_based => wpscan_options.exclude_content_based
base_url: wp_target.uri,
show_progression: true,
wp_content_dir: wp_target.wp_content_dir,
error_404_hash: wp_target.error_404_hash,
homepage_hash: wp_target.homepage_hash,
exclude_content_based: wpscan_options.exclude_content_based
}
theme_name = wp_theme ? wp_theme.name : nil
@@ -332,36 +332,36 @@ begin
timthumbs = wp_target.timthumbs
puts
puts green("[+]") + " We found #{timthumbs.size.to_s} timthumb file/s :"
puts green('[+]') + " We found #{timthumbs.size.to_s} timthumb file/s :"
puts
timthumbs.each do |t|
puts " | " + red("[!]") + " #{t.get_full_url.to_s}"
puts ' | ' + red('[!]') + " #{t.get_full_url.to_s}"
end
puts
puts red(" * Reference: http://www.exploit-db.com/exploits/17602/")
puts red(' * Reference: http://www.exploit-db.com/exploits/17602/')
else
puts
puts "No timthumb files found :("
puts 'No timthumb files found :('
end
end
# If we haven't been supplied a username, enumerate them...
if !wpscan_options.username and wpscan_options.wordlist or wpscan_options.enumerate_usernames
puts
puts green("[+]") + " Enumerating usernames ..."
puts green('[+]') + ' Enumerating usernames ...'
usernames = wp_target.usernames(:range => wpscan_options.enumerate_usernames_range)
usernames = wp_target.usernames(range: wpscan_options.enumerate_usernames_range)
if usernames.empty?
puts
puts "We did not enumerate any usernames :("
puts "Try supplying your own username with the --username option"
puts 'We did not enumerate any usernames :('
puts 'Try supplying your own username with the --username option'
puts
exit(1)
else
puts
puts green("[+]") + " We found the following #{usernames.length.to_s} username/s :"
puts green('[+]') + " We found the following #{usernames.length.to_s} username/s :"
puts
max_id_length = usernames.sort { |a, b| a.id.to_s.length <=> b.id.to_s.length }.last.id.to_s.length
@@ -378,7 +378,7 @@ begin
end
else
usernames = [WpUser.new(wpscan_options.username, -1, "empty")]
usernames = [WpUser.new(wpscan_options.username, -1, 'empty')]
end
# Start the brute forcer
@@ -390,19 +390,19 @@ begin
puts
puts "The plugin #{protection_plugin.name} has been detected. It might record the IP and timestamp of every failed login. Not a good idea for brute forcing !"
puts "[?] Do you want to start the brute force anyway ? [y/n]"
puts '[?] Do you want to start the brute force anyway ? [y/n]'
bruteforce = false if Readline.readline !~ /^y/i
end
if bruteforce
puts
puts green("[+]") + " Starting the password brute forcer"
puts green('[+]') + ' Starting the password brute forcer'
puts
wp_target.brute_force(usernames, wpscan_options.wordlist, {:show_progression => true})
wp_target.brute_force(usernames, wpscan_options.wordlist, {show_progression: true})
else
puts
puts "Brute forcing aborted"
puts 'Brute forcing aborted'
end
end
@@ -410,10 +410,10 @@ begin
puts
puts green("[+] Finished at #{stop_time.asctime}")
elapsed = stop_time - start_time
puts green("[+] Elapsed time: #{Time.at(elapsed).utc.strftime("%H:%M:%S")}")
puts green("[+] Elapsed time: #{Time.at(elapsed).utc.strftime('%H:%M:%S')}")
exit() # must exit!
rescue => e
puts red("[ERROR] #{e.message}")
puts red("Trace :")
puts red('Trace :')
puts red(e.backtrace.join("\n"))
end

View File

@@ -19,15 +19,15 @@
#++
$: << '.'
require File.dirname(__FILE__) + "/lib/wpstools/wpstools_helper"
require File.dirname(__FILE__) + '/lib/wpstools/wpstools_helper'
begin
banner()
option_parser = CustomOptionParser.new("Usage: ./wpstools.rb [options]", 60)
option_parser.separator ""
option_parser.add(["-v", "--verbose", "Verbose output"])
option_parser = CustomOptionParser.new('Usage: ./wpstools.rb [options]', 60)
option_parser.separator ''
option_parser.add(['-v', '--verbose', 'Verbose output'])
plugins = Plugins.new(option_parser)
plugins.register(
@@ -47,6 +47,6 @@ begin
rescue => e
puts "[ERROR] #{e.message}"
puts "Trace :"
puts 'Trace :'
puts e.backtrace.join("\n")
end