Files
wpscan/lib/wpscan/wpscan_options.rb
2012-09-15 21:33:18 +02:00

229 lines
6.7 KiB
Ruby

#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
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
]
attr_accessor *ACCESSOR_OPTIONS
def initialize
end
def url=(url)
raise "Empty URL given" if !url
@url = URI.parse(add_http_protocol(url)).to_s
end
def threads=(threads)
@threads = threads.is_a?(Integer) ? threads : threads.to_i
end
def wordlist=(wordlist)
if File.exists?(wordlist)
@wordlist = wordlist
else
raise "The file #{wordlist} does not exist"
end
end
def proxy=(proxy)
if proxy.index(':') == nil
raise "Invalid proxy format. Should be host:port."
else
@proxy = proxy
end
end
def enumerate_plugins=(enumerate_plugins)
if enumerate_plugins === true and @enumerate_only_vulnerable_plugins === true
raise "You can't enumerate plugins and only vulnerable plugins at the same time, please choose only one"
else
@enumerate_plugins = enumerate_plugins
end
end
def enumerate_only_vulnerable_plugins=(enumerate_only_vulnerable_plugins)
if enumerate_only_vulnerable_plugins === true and @enumerate_plugins === true
raise "You can't enumerate plugins and only vulnerable plugins at the same time, please choose only one"
else
@enumerate_only_vulnerable_plugins = enumerate_only_vulnerable_plugins
end
end
def enumerate_themes=(enumerate_themes)
if enumerate_themes === true and @enumerate_only_vulnerable_themes === true
raise "You can't enumerate themes and only vulnerable themes at the same time, please choose only one"
else
@enumerate_themes = enumerate_themes
end
end
def enumerate_only_vulnerable_themes=(enumerate_only_vulnerable_themes)
if enumerate_only_vulnerable_themes === true and @enumerate_plugins === true
raise "You can't enumerate themes and only vulnerable themes at the same time, please choose only one"
else
@enumerate_only_vulnerable_themes = enumerate_only_vulnerable_themes
end
end
def has_options?
!to_h.empty?
end
# return Hash
def to_h
options = {}
ACCESSOR_OPTIONS.each do |option|
instance_variable = instance_variable_get("@#{option}")
unless instance_variable.nil?
options[:"#{option}"] = instance_variable
end
end
options
end
# Will load the options from ARGV
# return WpscanOptions
def self.load_from_arguments
wpscan_options = WpscanOptions.new
if ARGV.length > 0
WpscanOptions.get_opt_long.each do |opt, arg|
wpscan_options.set_option_from_cli(opt, arg)
end
end
wpscan_options
end
# string cli_option : --url, -u, --proxy etc
# string cli_value : the option value
def set_option_from_cli(cli_option, cli_value)
if WpscanOptions.is_long_option?(cli_option)
self.send(
WpscanOptions.option_to_instance_variable_setter(cli_option),
cli_value
)
elsif cli_option === "--enumerate" # Special cases
# Default value if no argument is given
cli_value = "Ttup!" if cli_value.length == 0
enumerate_options_from_string(cli_value)
else
raise "Unknow option : #{cli_option} with value #{cli_value}"
end
end
# Will set enumerate_* from the string value
# IE : if value = p! => :enumerate_only_vulnerable_plugins will be set to true
# multiple enumeration are possible : 'up' => :enumerate_usernames and :enumerate_plugins
# Special case for usernames, a range is possible : u[1-10] will enumerate usernames from 1 to 10
def enumerate_options_from_string(value)
# Usage of self is mandatory because there are overridden setters
self.enumerate_only_vulnerable_plugins = true if value =~ /p!/
self.enumerate_plugins = true if value =~ /p(?!!)/
@enumerate_timthumbs = true if value =~ /t/
self.enumerate_only_vulnerable_themes = true if value =~ /T!/
self.enumerate_themes = true if value =~ /T(?!!)/
if value =~ /u/
@enumerate_usernames = true
# Check for usernames range
if matches = %r{\[([\d]+)-([\d]+)\]}.match(value)
@enumerate_usernames_range = (matches[1].to_i..matches[2].to_i)
end
end
end
protected
# 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]
)
end
def self.is_long_option?(option)
ACCESSOR_OPTIONS.include?(:"#{WpscanOptions.clean_option(option)}")
end
# Will removed the '-' or '--' chars at the beginning of option
# and replace any remaining '-' by '_'
#
# param string option
# return string
def self.clean_option(option)
cleaned_option = option.gsub(/^--?/, '')
cleaned_option.gsub(/-/, '_')
end
def self.option_to_instance_variable_setter(option)
cleaned_option = WpscanOptions.clean_option(option)
option_syms = ACCESSOR_OPTIONS.grep(%r{^#{cleaned_option}})
option_syms.length == 1 ? :"#{option_syms.at(0)}=" : nil
end
end