From 3094d3163324215f1f6dce9968c82e0688252d71 Mon Sep 17 00:00:00 2001 From: erwanlr Date: Thu, 24 Jan 2013 18:23:54 +0100 Subject: [PATCH] lib/wpscan rubocopied --- lib/wpscan/modules/brute_force.rb | 27 ++--- lib/wpscan/modules/malwares.rb | 6 +- lib/wpscan/modules/web_site.rb | 9 +- lib/wpscan/modules/wp_config_backup.rb | 1 + lib/wpscan/modules/wp_full_path_disclosure.rb | 3 +- lib/wpscan/modules/wp_login_protection.rb | 49 ++++----- lib/wpscan/modules/wp_plugins.rb | 37 ++++--- lib/wpscan/modules/wp_readme.rb | 3 +- lib/wpscan/modules/wp_themes.rb | 29 ++--- lib/wpscan/modules/wp_timthumbs.rb | 30 +++--- lib/wpscan/modules/wp_usernames.rb | 11 +- lib/wpscan/vulnerable.rb | 9 +- lib/wpscan/wp_detector.rb | 13 +-- lib/wpscan/wp_enumerator.rb | 35 +++--- lib/wpscan/wp_item.rb | 69 ++++++------ lib/wpscan/wp_options.rb | 21 ++-- lib/wpscan/wp_plugin.rb | 16 +-- lib/wpscan/wp_target.rb | 21 ++-- lib/wpscan/wp_theme.rb | 34 +++--- lib/wpscan/wp_user.rb | 21 ++-- lib/wpscan/wp_version.rb | 27 ++--- lib/wpscan/wp_vulnerability.rb | 1 + lib/wpscan/wpscan_helper.rb | 101 +++++++++--------- lib/wpscan/wpscan_options.rb | 61 +++++------ 24 files changed, 338 insertions(+), 296 deletions(-) diff --git a/lib/wpscan/modules/brute_force.rb b/lib/wpscan/modules/brute_force.rb index 185d59a7..61be1593 100644 --- a/lib/wpscan/modules/brute_force.rb +++ b/lib/wpscan/modules/brute_force.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -34,10 +35,10 @@ module BruteForce request_count = 0 password_found = false - File.open(wordlist_path, "r").each do |password| + File.open(wordlist_path, 'r').each do |password| # ignore file comments, but will miss passwords if they start with a hash... - next if password[0,1] == "#" + next if password[0, 1] == '#' # keep a count of the amount of requests to be sent request_count += 1 @@ -50,9 +51,9 @@ module BruteForce # the request object request = Browser.instance.forge_request(login_url, { - :method => :post, - :params => {:log => username, :pwd => password}, - :cache_timeout => 0 + method: :post, + params: {log: username, pwd: password}, + cache_timeout: 0 } ) @@ -64,20 +65,20 @@ module BruteForce if response.body =~ /login_error/i puts "\nIncorrect username and/or password." if @verbose elsif response.code == 302 - puts "\n " + green("[SUCCESS]") + " Username : #{username} Password : #{password}\n" if show_progression - found << { :name => username, :password => password } + puts "\n " + green('[SUCCESS]') + " Username : #{username} Password : #{password}\n" if show_progression + found << { name: username, password: password } password_found = true elsif response.timed_out? - puts red("ERROR:") + " Request timed out." if show_progression + puts red('ERROR:') + ' Request timed out.' if show_progression elsif response.code == 0 - puts red("ERROR:") + " No response from remote server. WAF/IPS?" if show_progression + puts red('ERROR:') + ' No response from remote server. WAF/IPS?' if show_progression # code is a fixnum, needs a string for regex elsif response.code.to_s =~ /^50/ - puts red("ERROR:") + " Server error, try reducing the number of threads." if show_progression + puts red('ERROR:') + ' Server error, try reducing the number of threads.' if show_progression else - puts "\n" + red("ERROR:") + " We recieved an unknown response for #{password}..." if show_progression + puts "\n" + red('ERROR:') + " We recieved an unknown response for #{password}..." if show_progression - # ugly method to get the coverage :/ (otherwise some output is present in the rspec) + # HACK to get the coverage :/ (otherwise some output is present in the rspec) puts red("Code: #{response.code.to_s}") if @verbose puts red("Body: #{response.body}") if @verbose puts if @verbose @@ -116,7 +117,7 @@ module BruteForce # wordlists, although bareable. def self.lines_in_file(file_path) lines = 0 - File.open(file_path, 'r').each { || lines += 1 } + File.open(file_path, 'r').each { |_| lines += 1 } lines end end diff --git a/lib/wpscan/modules/malwares.rb b/lib/wpscan/modules/malwares.rb index 1659d4cc..a379356a 100644 --- a/lib/wpscan/modules/malwares.rb +++ b/lib/wpscan/modules/malwares.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -17,7 +18,10 @@ #++ module Malwares - # Used as cache : nil => malwares not checked, [] => no malwares, otherwise array of malwares url found + # Used as cache : + # nil => malwares not checked, + # [] => no malwares, + # otherwise array of malwares url found @malwares = nil def has_malwares?(malwares_file_path = nil) diff --git a/lib/wpscan/modules/web_site.rb b/lib/wpscan/modules/web_site.rb index a815b641..b9093172 100644 --- a/lib/wpscan/modules/web_site.rb +++ b/lib/wpscan/modules/web_site.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -34,7 +35,7 @@ module WebSite response = Browser.instance.get( login_url(), - {:follow_location => true, :max_redirects => 2} + { follow_location: true, max_redirects: 2 } ) if response.body =~ %r{WordPress}i @@ -42,7 +43,7 @@ module WebSite else response = Browser.instance.get( xml_rpc_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 @@ -60,7 +61,7 @@ module WebSite def xml_rpc_url unless @xmlrpc_url headers = Browser.instance.get(@uri.to_s).headers_hash - value = headers["x-pingback"] + value = headers['x-pingback'] if value.nil? or value.empty? @xmlrpc_url = nil else @@ -105,7 +106,7 @@ module WebSite # Return the MD5 hash of a 404 page def error_404_hash unless @error_404_hash - non_existant_page = Digest::MD5.hexdigest(rand(9999999999).to_s) + ".html" + non_existant_page = Digest::MD5.hexdigest(rand(999_999_999).to_s) + '.html' @error_404_hash = WebSite.page_hash(@uri.merge(non_existant_page).to_s) end @error_404_hash diff --git a/lib/wpscan/modules/wp_config_backup.rb b/lib/wpscan/modules/wp_config_backup.rb index b97d556c..6055e329 100644 --- a/lib/wpscan/modules/wp_config_backup.rb +++ b/lib/wpscan/modules/wp_config_backup.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 diff --git a/lib/wpscan/modules/wp_full_path_disclosure.rb b/lib/wpscan/modules/wp_full_path_disclosure.rb index b028a2af..d95827a7 100644 --- a/lib/wpscan/modules/wp_full_path_disclosure.rb +++ b/lib/wpscan/modules/wp_full_path_disclosure.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -25,6 +26,6 @@ module WpFullPathDisclosure end def full_path_disclosure_url - @uri.merge("wp-includes/rss-functions.php").to_s + @uri.merge('wp-includes/rss-functions.php').to_s end end diff --git a/lib/wpscan/modules/wp_login_protection.rb b/lib/wpscan/modules/wp_login_protection.rb index bf20da66..3246b31c 100644 --- a/lib/wpscan/modules/wp_login_protection.rb +++ b/lib/wpscan/modules/wp_login_protection.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -37,10 +38,10 @@ module WpLoginProtection plugin_name = symbol_to_call[LOGIN_PROTECTION_METHOD_PATTERN, 1].gsub('_', '-') return @login_protection_plugin = WpPlugin.new( - :name => plugin_name, - :base_url => @uri, - :path => "/plugins/#{plugin_name}/", - :wp_content_dir => @wp_content_dir + name: plugin_name, + base_url: @uri, + path: "/plugins/#{plugin_name}/", + wp_content_dir: @wp_content_dir ) end end @@ -67,10 +68,10 @@ module WpLoginProtection end def better_wp_security_url - WpPlugin.new(:wp_content_dir => @wp_content_dir, - :base_url => @uri, - :path => "/plugins/better-wp-security/", - :name => "better-wp-security" + WpPlugin.new(wp_content_dir: @wp_content_dir, + base_url: @uri, + path: '/plugins/better-wp-security/', + name: 'better-wp-security' ).get_url_without_filename end @@ -80,10 +81,10 @@ module WpLoginProtection end def simple_login_lockdown_url - WpPlugin.new(:wp_content_dir => @wp_content_dir, - :base_url => @uri, - :path => "/plugins/simple-login-lockdown/", - :name => "simple-login-lockdown" + WpPlugin.new(wp_content_dir: @wp_content_dir, + base_url: @uri, + path: '/plugins/simple-login-lockdown/', + name: 'simple-login-lockdown' ).get_url_without_filename end @@ -93,10 +94,10 @@ module WpLoginProtection end def login_security_solution_url - WpPlugin.new(:wp_content_dir => @wp_content_dir, - :base_url => @uri, - :path => "/plugins/login-security-solution/", - :name => "login-security-solution" + WpPlugin.new(wp_content_dir: @wp_content_dir, + base_url: @uri, + path: '/plugins/login-security-solution/', + name: 'login-security-solution' ).get_url_without_filename end @@ -106,10 +107,10 @@ module WpLoginProtection end def limit_login_attempts_url - WpPlugin.new(:wp_content_dir => @wp_content_dir, - :base_url => @uri, - :path => "/plugins/limit-login-attempts/", - :name => "limit-login-attempts" + WpPlugin.new(wp_content_dir: @wp_content_dir, + base_url: @uri, + path: '/plugins/limit-login-attempts/', + name: 'limit-login-attempts' ).get_url_without_filename end @@ -119,10 +120,10 @@ module WpLoginProtection end def bluetrait_event_viewer_url - WpPlugin.new(:wp_content_dir => @wp_content_dir, - :base_url => @uri, - :path => "/plugins/bluetrait-event-viewer/", - :name => "bluetrait-event-viewer" + WpPlugin.new(wp_content_dir: @wp_content_dir, + base_url: @uri, + path: '/plugins/bluetrait-event-viewer/', + name: 'bluetrait-event-viewer' ).get_url_without_filename end end diff --git a/lib/wpscan/modules/wp_plugins.rb b/lib/wpscan/modules/wp_plugins.rb index e1d7ad3a..f1634cc7 100644 --- a/lib/wpscan/modules/wp_plugins.rb +++ b/lib/wpscan/modules/wp_plugins.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -22,22 +23,24 @@ module WpPlugins # # return array of WpPlugin def plugins_from_aggressive_detection(options) + if options[:vulns_file].nil? or options[:vulns_file] == '' + options[:vulns_file] = PLUGINS_VULNS_FILE + end + options[:file] = options[:file] || (options[:full] ? PLUGINS_FULL_FILE : PLUGINS_FILE) - options[:vulns_file] = (options[:vulns_file] != nil and options[:vulns_file] != "") ? - options[:vulns_file] : PLUGINS_VULNS_FILE options[:vulns_xpath] = "//plugin[@name='#{@name}']/vulnerability" - options[:vulns_xpath_2] = "//plugin" - options[:type] = "plugins" + options[:vulns_xpath_2] = '//plugin' + options[:type] = 'plugins' result = WpDetector.aggressive_detection(options) plugins = [] result.each do |r| plugins << WpPlugin.new( - :base_url => r.base_url, - :path => r.path, - :wp_content_dir => r.wp_content_dir, - :name => r.name, - :type => "plugins", - :wp_plugins_dir => r.wp_plugins_dir + base_url: r.base_url, + path: r.path, + wp_content_dir: r.wp_content_dir, + name: r.name, + type: 'plugins', + wp_plugins_dir: r.wp_plugins_dir ) end plugins.sort_by { |p| p.name } @@ -51,16 +54,16 @@ module WpPlugins # return array of WpPlugin def plugins_from_passive_detection(options) plugins = [] - temp = WpDetector.passive_detection(options[:base_url], "plugins", options[:wp_content_dir]) + temp = WpDetector.passive_detection(options[:base_url], 'plugins', options[:wp_content_dir]) temp.each do |item| plugins << WpPlugin.new( - :base_url => item.base_url, - :name => item.name, - :path => item.path, - :wp_content_dir => options[:wp_content_dir], - :type => "plugins", - :wp_plugins_dir => options[:wp_plugins_dir] + base_url: item.base_url, + name: item.name, + path: item.path, + wp_content_dir: options[:wp_content_dir], + type: 'plugins', + wp_plugins_dir: options[:wp_plugins_dir] ) end plugins.sort_by { |p| p.name } diff --git a/lib/wpscan/modules/wp_readme.rb b/lib/wpscan/modules/wp_readme.rb index aadce114..61b0c6b7 100644 --- a/lib/wpscan/modules/wp_readme.rb +++ b/lib/wpscan/modules/wp_readme.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -31,6 +32,6 @@ module WpReadme end def readme_url - @uri.merge("readme.html").to_s + @uri.merge('readme.html').to_s end end diff --git a/lib/wpscan/modules/wp_themes.rb b/lib/wpscan/modules/wp_themes.rb index 16a8a855..3a9d0a7d 100644 --- a/lib/wpscan/modules/wp_themes.rb +++ b/lib/wpscan/modules/wp_themes.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -19,20 +20,22 @@ module WpThemes def themes_from_aggressive_detection(options) + if options[:vulns_file].nil? or options[:vulns_file] == '' + options[:vulns_file] = THEMES_VULNS_FILE + end + options[:file] = options[:file] || (options[:full] ? THEMES_FULL_FILE : THEMES_FILE) - options[:vulns_file] = (options[:vulns_file] != nil and options[:vulns_file] != "") ? - options[:vulns_file] : THEMES_VULNS_FILE options[:vulns_xpath] = "//theme[@name='#{@name}']/vulnerability" - options[:vulns_xpath_2] = "//theme" - options[:type] = "themes" + options[:vulns_xpath_2] = '//theme' + options[:type] = 'themes' result = WpDetector.aggressive_detection(options) themes = [] result.each do |r| themes << WpTheme.new( - :base_url => r.base_url, - :path => r.path, - :wp_content_dir => r.wp_content_dir, - :name => r.name + base_url: r.base_url, + path: r.path, + wp_content_dir: r.wp_content_dir, + name: r.name ) end themes.sort_by { |t| t.name } @@ -40,14 +43,14 @@ module WpThemes def themes_from_passive_detection(options) themes = [] - temp = WpDetector.passive_detection(options[:base_url], "themes", options[:wp_content_dir]) + temp = WpDetector.passive_detection(options[:base_url], 'themes', options[:wp_content_dir]) temp.each do |item| themes << WpTheme.new( - :base_url => item.base_url, - :name => item.name, - :path => item.path, - :wp_content_dir => options[:wp_content_dir] + base_url: item.base_url, + name: item.name, + path: item.path, + wp_content_dir: options[:wp_content_dir] ) end themes.sort_by { |t| t.name } diff --git a/lib/wpscan/modules/wp_timthumbs.rb b/lib/wpscan/modules/wp_timthumbs.rb index 7d7319de..8da34038 100644 --- a/lib/wpscan/modules/wp_timthumbs.rb +++ b/lib/wpscan/modules/wp_timthumbs.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -18,7 +19,10 @@ module WpTimthumbs - # Used as cache : nil => timthumbs not checked, [] => no timthumbs, otherwise array of timthumbs url found + # Used as cache : + # nil => timthumbs not checked, + # [] => no timthumbs, + # otherwise array of timthumbs url found @wp_timthumbs = nil def has_timthumbs?(theme_name, options = {}) @@ -27,12 +31,12 @@ module WpTimthumbs def timthumbs(theme_name = nil, options = {}) if @wp_timthumbs.nil? - options[:type] = "timthumbs" + options[:type] = 'timthumbs' options[:only_vulnerable_ones] = false - options[:file] = options[:file] || DATA_DIR + "/timthumbs.txt" - options[:vulns_file] = "xxx" - options[:vulns_xpath] = "xxx" - options[:vulns_xpath_2] = "xxx" + options[:file] = options[:file] || DATA_DIR + '/timthumbs.txt' + options[:vulns_file] = 'xxx' + options[:vulns_xpath] = 'xxx' + options[:vulns_xpath_2] = 'xxx' WpOptions.check_options(options) if theme_name == nil @@ -55,13 +59,13 @@ module WpTimthumbs scripts/timthumb.php tools/timthumb.php functions/timthumb.php }.each do |file| targets << WpItem.new( - :base_url => options[:base_url], - :path => "themes/#{theme_name}/#{file}", - :wp_content_dir => options[:wp_content_dir], - :name => theme_name, - :vulns_file => "XX", - :type => "timthumbs", - :wp_plugins_dir => options[:wp_plugins_dir] + base_url: options[:base_url], + path: "themes/#{theme_name}/#{file}", + wp_content_dir: options[:wp_content_dir], + name: theme_name, + vulns_file: 'XX', + type: 'timthumbs', + wp_plugins_dir: options[:wp_plugins_dir] ) end targets diff --git a/lib/wpscan/modules/wp_usernames.rb b/lib/wpscan/modules/wp_usernames.rb index 72e3e512..c9f29cc5 100644 --- a/lib/wpscan/modules/wp_usernames.rb +++ b/lib/wpscan/modules/wp_usernames.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -58,7 +59,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) @@ -80,21 +81,21 @@ module WpUsernames def remove_junk_from_nickname(usernames) unless usernames.kind_of? Array - raise("Need an array as input") + raise('Need an array as input') end nicknames = [] usernames.each do |u| unless u.kind_of? WpUser - raise("Items must be of type WpUser") + raise('Items must be of type WpUser') end nickname = u.nickname - unless nickname == "empty" + unless nickname == 'empty' nicknames << nickname end end junk = get_equal_string_end(nicknames) usernames.each do |u| - u.nickname = u.nickname.sub(/#{Regexp.escape(junk)}$/, "") + u.nickname = u.nickname.sub(/#{Regexp.escape(junk)}$/, '') end usernames end diff --git a/lib/wpscan/vulnerable.rb b/lib/wpscan/vulnerable.rb index e23ef176..228149ad 100644 --- a/lib/wpscan/vulnerable.rb +++ b/lib/wpscan/vulnerable.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -30,10 +31,10 @@ class Vulnerable xml.xpath(@vulns_xpath).each do |node| vulnerabilities << WpVulnerability.new( - node.search("title").text, - node.search("reference").map(&:text), - node.search("type").text, - node.search("metasploit").map(&:text) + node.search('title').text, + node.search('reference').map(&:text), + node.search('type').text, + node.search('metasploit').map(&:text) ) end vulnerabilities diff --git a/lib/wpscan/wp_detector.rb b/lib/wpscan/wp_detector.rb index e6a5f670..2edee39a 100644 --- a/lib/wpscan/wp_detector.rb +++ b/lib/wpscan/wp_detector.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -63,12 +64,12 @@ class WpDetector names.each do |item| items << WpItem.new( - :base_url => url, - :name => item, - :type => type, - :path => "#{item}/", - :wp_content_dir => wp_content_dir, - :vulns_file => "" + base_url: url, + name: item, + type: type, + path: "#{item}/", + wp_content_dir: wp_content_dir, + vulns_file: '' ) end items diff --git a/lib/wpscan/wp_enumerator.rb b/lib/wpscan/wp_enumerator.rb index 36005346..fa741d34 100644 --- a/lib/wpscan/wp_enumerator.rb +++ b/lib/wpscan/wp_enumerator.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -54,7 +55,7 @@ class WpEnumerator targets.each do |target| url = target.get_full_url - request = enum_browser.forge_request(url, { :cache_timeout => 0, :follow_location => true }) + request = enum_browser.forge_request(url, { cache_timeout: 0, follow_location: true }) request_count += 1 request.on_complete do |response| @@ -102,17 +103,17 @@ class WpEnumerator unless only_vulnerable # Open and parse the 'most popular' plugin list... - File.open(file, "r") do |f| + File.open(file, 'r') do |f| f.readlines.collect do |line| l = line.strip targets_url << WpItem.new( - :base_url => url, - :path => l, - :wp_content_dir => wp_content_dir, - :name => l =~ /.+\/.+/ ? File.dirname(l) : l.sub(/\/$/, ""), - :vulns_file => vulns_file, - :type => type, - :wp_plugins_dir => plugins_dir + base_url: url, + path: l, + wp_content_dir: wp_content_dir, + name: l =~ /.+\/.+/ ? File.dirname(l) : l.sub(/\/$/, ''), + vulns_file: vulns_file, + type: type, + wp_plugins_dir: plugins_dir ) end end @@ -126,15 +127,15 @@ class WpEnumerator # We check if the plugin name from the plugin_vulns_file is already in targets, otherwise we add it xml.xpath(options[:vulns_xpath_2]).each do |node| - name = node.attribute("name").text + name = node.attribute('name').text targets_url << WpItem.new( - :base_url => url, - :path => name, - :wp_content_dir => wp_content_dir, - :name => name, - :vulns_file => vulns_file, - :type => type, - :wp_plugins_dir => plugins_dir + base_url: url, + path: name, + wp_content_dir: wp_content_dir, + name: name, + vulns_file: vulns_file, + type: type, + wp_plugins_dir: plugins_dir ) end end diff --git a/lib/wpscan/wp_item.rb b/lib/wpscan/wp_item.rb index 8361bc93..5148245d 100644 --- a/lib/wpscan/wp_item.rb +++ b/lib/wpscan/wp_item.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -24,7 +25,7 @@ class WpItem < Vulnerable def initialize(options) @type = options[:type] - @wp_content_dir = options[:wp_content_dir] ? options[:wp_content_dir].sub(/^\//, "").sub(/\/$/, "") : "wp-content" + @wp_content_dir = options[:wp_content_dir] ? options[:wp_content_dir].sub(/^\//, '').sub(/\/$/, '') : 'wp-content' @wp_plugins_dir = options[:wp_plugins_dir] || "#@wp_content_dir/plugins" @base_url = options[:base_url] @path = options[:path] @@ -32,36 +33,36 @@ class WpItem < Vulnerable @vulns_file = options[:vulns_file] @vulns_xpath = options[:vulns_xpath].sub(/\$name\$/, @name) unless options[:vulns_xpath] == nil - raise("base_url not set") unless @base_url - raise("path not set") unless @path - raise("wp_content_dir not set") unless @wp_content_dir - raise("name not set") unless @name - raise("vulns_file not set") unless @vulns_file - raise("type not set") unless @type + raise('base_url not set') unless @base_url + raise('path not set') unless @path + raise('wp_content_dir not set') unless @wp_content_dir + raise('name not set') unless @name + raise('vulns_file not set') unless @vulns_file + raise('type not set') unless @type end # The wordpress.org plugins directory URL # See: https://github.com/wpscanteam/wpscan/issues/100 def wp_org_url case @type - when "themes" - return URI("http://wordpress.org/extend/themes/").merge("#@name/") - when "plugins" - return URI("http://wordpress.org/extend/plugins/").merge("#@name/") - else - raise("No Wordpress URL for #@type") + when 'themes' + return URI('http://wordpress.org/extend/themes/').merge("#@name/") + when 'plugins' + return URI('http://wordpress.org/extend/plugins/').merge("#@name/") + else + raise("No Wordpress URL for #@type") end end # returns true if this theme or plugin is hosted on wordpress.org def wp_org_item? case @type - when "themes" - file = THEMES_FULL_FILE - when "plugins" - file = PLUGINS_FULL_FILE - else - raise("Unknown type #@type") + when 'themes' + file = THEMES_FULL_FILE + when 'plugins' + file = PLUGINS_FULL_FILE + else + raise("Unknown type #@type") end f = File.readlines(file).grep(/^#{Regexp.escape(@name)}$/i) f.empty? ? false : true @@ -69,28 +70,28 @@ class WpItem < Vulnerable def get_sub_folder case @type - when "themes" - folder = "themes" - when "timthumbs" - # not needed - folder = nil - else - raise("unknown type #@type") + when 'themes' + folder = 'themes' + when 'timthumbs' + # not needed + folder = nil + else + raise("unknown type #@type") end folder end # Get the full url for this item def get_full_url - url = @base_url.to_s.end_with?("/") ? @base_url.to_s : "#@base_url/" + url = @base_url.to_s.end_with?('/') ? @base_url.to_s : "#@base_url/" # remove first and last / - wp_content_dir = @wp_content_dir.sub(/^\//, "").sub(/\/$/, "") + wp_content_dir = @wp_content_dir.sub(/^\//, "").sub(/\/$/, '') # remove first / - path = @path.sub(/^\//, "") - if type =="plugins" + path = @path.sub(/^\//, '') + if type == 'plugins' # plugins can be outside of wp-content. wp_content_dir included in wp_plugins_dir ret = URI.parse(URI.encode("#{url}#@wp_plugins_dir/#{path}")) - elsif type == "timthumbs" + elsif type == 'timthumbs' # timthumbs have folder in path variable ret = URI.parse(URI.encode("#{url}#{wp_content_dir}/#{path}")) else @@ -112,7 +113,7 @@ class WpItem < Vulnerable # Returns version number from readme.txt if it exists def version unless @version - response = Browser.instance.get(get_full_url.merge("readme.txt").to_s) + response = Browser.instance.get(get_full_url.merge('readme.txt').to_s) @version = response.body[%r{stable tag: #{WpVersion.version_pattern}}i, 1] end @version @@ -152,12 +153,12 @@ class WpItem < Vulnerable # Url for readme.txt def readme_url - get_url_without_filename.merge("readme.txt") + get_url_without_filename.merge('readme.txt') end # Url for changelog.txt def changelog_url - get_url_without_filename.merge("changelog.txt") + get_url_without_filename.merge('changelog.txt') end # readme.txt present? diff --git a/lib/wpscan/wp_options.rb b/lib/wpscan/wp_options.rb index 09ba9b03..4e4631bf 100644 --- a/lib/wpscan/wp_options.rb +++ b/lib/wpscan/wp_options.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -32,16 +33,16 @@ # * +type+ - Type: plugins, themes class WpOptions def self.check_options(options) - raise("base_url must be set") unless options[:base_url] != nil and options[:base_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_progression must be set") unless options[:show_progression] != 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('base_url must be set') unless options[:base_url] != nil and options[:base_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_progression must be set') unless options[:show_progression] != 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]}") diff --git a/lib/wpscan/wp_plugin.rb b/lib/wpscan/wp_plugin.rb index bcebc94b..605dce43 100644 --- a/lib/wpscan/wp_plugin.rb +++ b/lib/wpscan/wp_plugin.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -18,11 +19,14 @@ class WpPlugin < WpItem def initialize(options = {}) - options[:vulns_file] = (options[:vulns_file] != nil and options[:vulns_file] != "") ? - options[:vulns_file] : PLUGINS_VULNS_FILE + if options[:vulns_file].nil? or options[:vulns_file] == '' + options[:vulns_file] = PLUGINS_VULNS_FILE + end + options[:vulns_xpath] = "//plugin[@name='$name$']/vulnerability" - options[:vulns_xpath_2] = "//plugin" - options[:type] = "plugins" + options[:vulns_xpath_2] = '//plugin' + options[:type] = 'plugins' + super(options) end @@ -32,11 +36,11 @@ 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 def error_log_url - get_full_url.merge("error_log").to_s + get_full_url.merge('error_log').to_s end end diff --git a/lib/wpscan/wp_target.rb b/lib/wpscan/wp_target.rb index 182b04a0..eb5b3dec 100644 --- a/lib/wpscan/wp_target.rb +++ b/lib/wpscan/wp_target.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -47,7 +48,7 @@ class WpTarget end def login_url - url = @uri.merge("wp-login.php").to_s + url = @uri.merge('wp-login.php').to_s # Let's check if the login url is redirected (to https url for example) redirection = redirection(url) @@ -80,9 +81,9 @@ class WpTarget uri_path = @uri.path if index_body[/\/wp-content\/(?:themes|plugins)\//i] - @wp_content_dir = "wp-content" + @wp_content_dir = 'wp-content' else - domains_excluded = "(?:www\.)?(facebook|twitter)\.com" + domains_excluded = '(?:www\.)?(facebook|twitter)\.com' @wp_content_dir = index_body[/(?:href|src)\s*=\s*(?:"|').+#{Regexp.escape(uri_path)}((?!#{domains_excluded})[^"']+)\/(?:themes|plugins)\/.*(?:"|')/i, 1] end end @@ -102,7 +103,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 @@ -114,7 +115,7 @@ class WpTarget # reveals databse credentials after hitting submit # http://interconnectit.com/124/search-and-replace-for-wordpress-databases/ def search_replace_db_2_url - @uri.merge("searchreplacedb2.php").to_s + @uri.merge('searchreplacedb2.php').to_s end def search_replace_db_2_exists? @@ -126,7 +127,7 @@ class WpTarget def registration_enabled? resp = Browser.instance.get(registration_url) # redirect only on non multi sites - if resp.code == 302 and resp.headers_hash["location"] =~ /wp-login\.php\?registration=disabled/i + if resp.code == 302 and resp.headers_hash['location'] =~ /wp-login\.php\?registration=disabled/i enabled = false # multi site registration form elsif resp.code == 200 and resp.body =~ /
/i @@ -142,18 +143,18 @@ class WpTarget end def registration_url - is_multisite? ? @uri.merge("wp-signup.php") : @uri.merge("wp-login.php?action=register") + is_multisite? ? @uri.merge('wp-signup.php') : @uri.merge('wp-login.php?action=register') end def is_multisite? unless @multisite # when multi site, there is no redirection or a redirect to the site itself # otherwise redirect to wp-login.php - url = @uri.merge("wp-signup.php") + url = @uri.merge('wp-signup.php') resp = Browser.instance.get(url) - if resp.code == 302 and resp.headers_hash["location"] =~ /wp-login\.php\?action=register/ + if resp.code == 302 and resp.headers_hash['location'] =~ /wp-login\.php\?action=register/ @multisite = false - elsif resp.code == 302 and resp.headers_hash["location"] =~ /wp-signup\.php/ + elsif resp.code == 302 and resp.headers_hash['location'] =~ /wp-signup\.php/ @multisite = true elsif resp.code == 200 @multisite = true diff --git a/lib/wpscan/wp_theme.rb b/lib/wpscan/wp_theme.rb index 2519d81e..ab27c13e 100644 --- a/lib/wpscan/wp_theme.rb +++ b/lib/wpscan/wp_theme.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -23,12 +24,15 @@ class WpTheme < WpItem attr_reader :style_url, :version def initialize(options = {}) - options[:vulns_file] = (options[:vulns_file] != nil and options[:vulns_file] != "") ? - options[:vulns_file] : THEMES_VULNS_FILE + if options[:vulns_file].nil? or options[:vulns_file] == '' + options[:vulns_file] = THEMES_VULNS_FILE + end + options[:vulns_xpath] = "//theme[@name='$name$']/vulnerability" - options[:type] = "themes" + options[:type] = 'themes' @version = options[:version] @style_url = options[:style_url] + super(options) end @@ -58,7 +62,7 @@ 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 @@ -66,11 +70,12 @@ class WpTheme < WpItem wp_content_dir = matches[1] theme_name = matches[2] - return new(:name => theme_name, - :style_url => style_url, - :base_url => target_uri, - :path => theme_name, - :wp_content_dir => wp_content_dir + return new( + name: theme_name, + style_url: style_url, + base_url: target_uri, + path: theme_name, + wp_content_dir: wp_content_dir ) end end @@ -86,11 +91,12 @@ class WpTheme < WpItem 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, - :base_url => matches[0], - :path => "", - :wp_content_dir => "" + return new( + name: woo_theme_name, + version: woo_theme_version, + base_url: matches[0], + path: '', + wp_content_dir: '' ) end end diff --git a/lib/wpscan/wp_user.rb b/lib/wpscan/wp_user.rb index 6db02605..bae87c8e 100644 --- a/lib/wpscan/wp_user.rb +++ b/lib/wpscan/wp_user.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -20,7 +21,7 @@ class WpUser def name if @name.nil? or @name.to_s.strip.empty? - return "empty" + return 'empty' end @name end @@ -31,7 +32,7 @@ class WpUser def id if @id.nil? or @id.to_s.strip.empty? - return "empty" + return 'empty' end @id end @@ -42,7 +43,7 @@ class WpUser def nickname if @nickname.nil? or @nickname.to_s.strip.empty? - return "empty" + return 'empty' end @nickname end @@ -57,15 +58,15 @@ class WpUser self.nickname = nickname end - def <=>(item) - item.name <=> self.name + def <=>(other) + other.name <=> self.name end - def ===(item) - item.name === self.name and item.id === self.id and item.nickname === self.nickname + def ===(other) + other.name === self.name and other.id === self.id and other.nickname === self.nickname end - def eql?(item) - item.name === self.name and item.id === self.id and item.nickname === self.nickname + def eql?(other) + other.name === self.name and other.id === self.id and other.nickname === self.nickname end -end \ No newline at end of file +end diff --git a/lib/wpscan/wp_version.rb b/lib/wpscan/wp_version.rb index 36d8914f..a883090f 100644 --- a/lib/wpscan/wp_version.rb +++ b/lib/wpscan/wp_version.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -38,14 +39,14 @@ class WpVersion < Vulnerable # (find_from_meta_generator, find_from_rss_generator etc) def self.find(target_uri, wp_content_dir) options = { - :base_url => target_uri, - :wp_content_dir => wp_content_dir + base_url: target_uri, + wp_content_dir: wp_content_dir } self.methods.grep(/find_from_/).each do |method_to_call| version = self.send(method_to_call, options) if version - return new(version, :discovery_method => method_to_call[%r{find_from_(.*)}, 1].gsub('_', ' ')) + return new(version, discovery_method: method_to_call[%r{find_from_(.*)}, 1].gsub('_', ' ')) end end nil @@ -60,7 +61,7 @@ class WpVersion < Vulnerable # that it is reinstated on upgrade. def self.find_from_meta_generator(options) target_uri = options[:base_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 #{WpVersion.version_pattern}"}i, 1] end @@ -69,7 +70,7 @@ class WpVersion < Vulnerable # the generator tag in the RSS feed source. def self.find_from_rss_generator(options) target_uri = options[:base_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{http://wordpress.org/\?v=#{WpVersion.version_pattern}}i, 1] end @@ -78,7 +79,7 @@ class WpVersion < Vulnerable # the generator tag in the RDF feed source. def self.find_from_rdf_generator(options) target_uri = options[:base_url] - response = Browser.instance.get(target_uri.merge("feed/rdf/").to_s, {:follow_location => true, :max_redirects => 2}) + response = Browser.instance.get(target_uri.merge('feed/rdf/').to_s, { follow_location: true, max_redirects: 2 }) response.body[%r{}i, 1] end @@ -89,7 +90,7 @@ class WpVersion < Vulnerable # Have not been able to find an example of this - Ryan #def self.find_from_rss2_generator(options) # target_uri = options[:base_url] - # response = Browser.instance.get(target_uri.merge("feed/rss/").to_s, {:follow_location => true, :max_redirects => 2}) + # response = Browser.instance.get(target_uri.merge('feed/rss/').to_s, {:follow_location => true, :max_redirects => 2}) # # response.body[%r{http://wordpress.org/?v=(#{WpVersion.version_pattern})}i, 1] #end @@ -98,7 +99,7 @@ class WpVersion < Vulnerable # the generator tag in the Atom source. def self.find_from_atom_generator(options) target_uri = options[:base_url] - response = Browser.instance.get(target_uri.merge("feed/atom/").to_s, {:follow_location => true, :max_redirects => 2}) + response = Browser.instance.get(target_uri.merge('feed/atom/').to_s, { follow_location: true, max_redirects: 2 }) response.body[%r{WordPress}i, 1] end @@ -109,7 +110,7 @@ class WpVersion < Vulnerable # Have not been able to find an example of this - Ryan #def self.find_from_comments_rss_generator(options) # target_uri = options[:base_url] - # response = Browser.instance.get(target_uri.merge("comments/feed/").to_s, {:follow_location => true, :max_redirects => 2}) + # response = Browser.instance.get(target_uri.merge('comments/feed/').to_s, {:follow_location => true, :max_redirects => 2}) # # response.body[%r{}i, 1] #end @@ -129,7 +130,7 @@ class WpVersion < Vulnerable config.noblanks end - xml.xpath("//file").each do |node| + xml.xpath('//file').each do |node| wp_content = options[:wp_content_dir] wp_plugins = "#{wp_content}/plugins" file_url = target_uri.merge(node.attribute('src').text).to_s @@ -149,7 +150,7 @@ class WpVersion < Vulnerable # Attempts to find the WordPress version from the readme.html file. def self.find_from_readme(options) target_uri = options[:base_url] - Browser.instance.get(target_uri.merge("readme.html").to_s).body[%r{
\sversion #{WpVersion.version_pattern}}i, 1] + Browser.instance.get(target_uri.merge('readme.html').to_s).body[%r{
\sversion #{WpVersion.version_pattern}}i, 1] end # Attempts to find the WordPress version from the sitemap.xml file. @@ -157,13 +158,13 @@ class WpVersion < Vulnerable # See: http://code.google.com/p/wpscan/issues/detail?id=109 def self.find_from_sitemap_generator(options) target_uri = options[:base_url] - Browser.instance.get(target_uri.merge("sitemap.xml").to_s).body[%r{generator="wordpress/#{WpVersion.version_pattern}"}i, 1] + Browser.instance.get(target_uri.merge('sitemap.xml').to_s).body[%r{generator="wordpress/#{WpVersion.version_pattern}"}i, 1] end # Attempts to find the WordPress version from the p-links-opml.php file. def self.find_from_links_opml(options) target_uri = options[:base_url] - Browser.instance.get(target_uri.merge("wp-links-opml.php").to_s).body[%r{generator="wordpress/#{WpVersion.version_pattern}"}i, 1] + Browser.instance.get(target_uri.merge('wp-links-opml.php').to_s).body[%r{generator="wordpress/#{WpVersion.version_pattern}"}i, 1] end # Used to check if the version is correct: must contain at least one dot. diff --git a/lib/wpscan/wp_vulnerability.rb b/lib/wpscan/wp_vulnerability.rb index d8666b76..c57b3a29 100644 --- a/lib/wpscan/wp_vulnerability.rb +++ b/lib/wpscan/wp_vulnerability.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 diff --git a/lib/wpscan/wpscan_helper.rb b/lib/wpscan/wpscan_helper.rb index 96966103..44b83a67 100644 --- a/lib/wpscan/wpscan_helper.rb +++ b/lib/wpscan/wpscan_helper.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -18,95 +19,95 @@ require File.expand_path(File.dirname(__FILE__) + '/../common_helper') -require_files_from_directory(WPSCAN_LIB_DIR, "**/*.rb") +require_files_from_directory(WPSCAN_LIB_DIR, '**/*.rb') # wpscan usage -def usage() +def usage script_name = $0 puts - puts "Examples :" + puts 'Examples :' puts - puts "-Further help ..." + puts '-Further help ...' puts "ruby #{script_name} --help" puts puts "-Do 'non-intrusive' checks ..." puts "ruby #{script_name} --url www.example.com" puts - puts "-Do wordlist password brute force on enumerated users using 50 threads ..." + puts '-Do wordlist password brute force on enumerated users using 50 threads ...' puts "ruby #{script_name} --url www.example.com --wordlist darkc0de.lst --threads 50" puts puts "-Do wordlist password brute force on the 'admin' username only ..." puts "ruby #{script_name} --url www.example.com --wordlist darkc0de.lst --username admin" puts - puts "-Enumerate installed plugins ..." + puts '-Enumerate installed plugins ...' puts "ruby #{script_name} --url www.example.com --enumerate p" puts - puts "-Enumerate installed themes ..." + puts '-Enumerate installed themes ...' puts "ruby #{script_name} --url www.example.com --enumerate t" puts - puts "-Enumerate users ..." + puts '-Enumerate users ...' puts "ruby #{script_name} --url www.example.com --enumerate u" puts - puts "-Enumerate installed timthumbs ..." + puts '-Enumerate installed timthumbs ...' puts "ruby #{script_name} --url www.example.com --enumerate tt" puts - puts "-Use a HTTP proxy ..." + puts '-Use a HTTP proxy ...' puts "ruby #{script_name} --url www.example.com --proxy 127.0.0.1:8118" puts - puts "-Use a SOCKS5 proxy ... (cURL >= v7.21.7 needed)" + puts '-Use a SOCKS5 proxy ... (cURL >= v7.21.7 needed)' puts "ruby #{script_name} --url www.example.com --proxy socks5://127.0.0.1:9000" puts - puts "-Use custom content directory ..." + puts '-Use custom content directory ...' puts "ruby #{script_name} -u www.example.com --wp-content-dir custom-content" puts - puts "-Use custom plugins directory ..." + puts '-Use custom plugins directory ...' puts "ruby #{script_name} -u www.example.com --wp-plugins-dir wp-content/custom-plugins" puts - puts "-Update ..." + puts '-Update ...' puts "ruby #{script_name} --update" puts - puts "See README for further information." + puts 'See README for further information.' puts end # command help -def help() - puts "Help :" +def help + puts 'Help :' puts - puts "Some values are settable in conf/browser.conf.json :" - puts " user-agent, proxy, proxy-auth, threads, cache timeout and request timeout" + puts 'Some values are settable in conf/browser.conf.json :' + puts ' user-agent, proxy, proxy-auth, threads, cache timeout and request timeout' puts - puts "--update Update to the latest revision" - puts "--url | -u The WordPress URL/domain to scan." - puts "--force | -f Forces WPScan to not check if the remote site is running WordPress." - puts "--enumerate | -e [option(s)] Enumeration." - puts " option :" - puts " u usernames from id 1 to 10" - puts " u[10-20] usernames from id 10 to 20 (you must write [] chars)" - puts " p plugins" - puts " vp only vulnerable plugins" - puts " ap all plugins (can take a long time)" - puts " tt timthumbs" - puts " t themes" - puts " vt only vulnerable themes" - puts " at all themes (can take a long time)" - puts " Multiple values are allowed : '-e t,p' will enumerate timthumbs and plugins" - puts " If no option is supplied, the default is 'vt,tt,u,vp'" + puts '--update Update to the latest revision' + puts '--url | -u The WordPress URL/domain to scan.' + puts '--force | -f Forces WPScan to not check if the remote site is running WordPress.' + puts '--enumerate | -e [option(s)] Enumeration.' + puts ' option :' + puts ' u usernames from id 1 to 10' + puts ' u[10-20] usernames from id 10 to 20 (you must write [] chars)' + puts ' p plugins' + puts ' vp only vulnerable plugins' + puts ' ap all plugins (can take a long time)' + puts ' tt timthumbs' + puts ' t themes' + puts ' vt only vulnerable themes' + puts ' at all themes (can take a long time)' + puts ' Multiple values are allowed : "-e t,p" will enumerate timthumbs and plugins' + puts ' If no option is supplied, the default is "vt,tt,u,vp"' puts - puts "--exclude-content-based '' Used with the enumeration option, will exclude all occurence based on the regexp or string supplied" - puts " You do not need to provide the regexp delimiters, but you must write the quotes (simple or double)" - puts "--config-file | -c Use the specified config file" - puts "--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not" - puts "--wp-content-dir WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specified it. Subdirectories are allowed" - puts "--wp-plugins-dir Same thing than --wp-content-dir but for the plugins directory. If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed" - puts "--proxy <[protocol://]host:port> Supply a proxy (will override the one from conf/browser.conf.json)." - puts " HTTP, SOCKS4 SOCKS4A and SOCKS5 are supported. If no protocol is given (format host:port), HTTP will be used" - puts "--proxy-auth Supply the proxy login credentials (will override the one from conf/browser.conf.json)." - puts "--basic-auth Set the HTTP Basic authentification" - puts "--wordlist | -w Supply a wordlist for the password bruter and do the brute." - puts "--threads | -t The number of threads to use when multi-threading requests. (will override the value from conf/browser.conf.json)" - puts "--username | -U Only brute force the supplied username." - puts "--help | -h This help screen." - puts "--verbose | -v Verbose output." + puts '--exclude-content-based "" Used with the enumeration option, will exclude all occurence based on the regexp or string supplied' + puts ' You do not need to provide the regexp delimiters, but you must write the quotes (simple or double)' + puts '--config-file | -c Use the specified config file' + puts '--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not' + puts '--wp-content-dir WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specified it. Subdirectories are allowed' + puts '--wp-plugins-dir Same thing than --wp-content-dir but for the plugins directory. If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed' + puts '--proxy <[protocol://]host:port> Supply a proxy (will override the one from conf/browser.conf.json).' + puts ' HTTP, SOCKS4 SOCKS4A and SOCKS5 are supported. If no protocol is given (format host:port), HTTP will be used' + puts '--proxy-auth Supply the proxy login credentials (will override the one from conf/browser.conf.json).' + puts '--basic-auth Set the HTTP Basic authentification' + puts '--wordlist | -w Supply a wordlist for the password bruter and do the brute.' + puts '--threads | -t The number of threads to use when multi-threading requests. (will override the value from conf/browser.conf.json)' + puts '--username | -U Only brute force the supplied username.' + puts '--help | -h This help screen.' + puts '--verbose | -v Verbose output.' puts end diff --git a/lib/wpscan/wpscan_options.rb b/lib/wpscan/wpscan_options.rb index a6d518b5..b6f14dc9 100644 --- a/lib/wpscan/wpscan_options.rb +++ b/lib/wpscan/wpscan_options.rb @@ -1,3 +1,4 @@ +# encoding: UTF-8 #-- # WPScan - WordPress Security Scanner # Copyright (C) 2012-2013 @@ -56,7 +57,7 @@ class WpscanOptions end def url=(url) - raise "Empty URL given" if !url + raise 'Empty URL given' if !url @url = URI.parse(add_http_protocol(url)).to_s end @@ -75,7 +76,7 @@ class WpscanOptions def proxy=(proxy) if proxy.index(':') == nil - raise "Invalid proxy format. Should be host:port." + raise 'Invalid proxy format. Should be host:port.' else @proxy = proxy end @@ -83,7 +84,7 @@ class WpscanOptions def proxy_auth=(auth) if auth.index(':') == nil - raise "Invalid proxy auth format, username:password expected" + raise 'Invalid proxy auth format, username:password expected' else @proxy_auth = auth end @@ -91,7 +92,7 @@ class WpscanOptions def enumerate_plugins=(enumerate_plugins) if enumerate_plugins === true and (@enumerate_all_plugins === true or @enumerate_only_vulnerable_plugins === true) - raise "Please choose only one plugin enumeration option" + raise 'Please choose only one plugin enumeration option' else @enumerate_plugins = enumerate_plugins end @@ -99,7 +100,7 @@ class WpscanOptions def enumerate_only_vulnerable_plugins=(enumerate_only_vulnerable_plugins) if enumerate_only_vulnerable_plugins === true and (@enumerate_all_plugins === true or @enumerate_plugins === true) - raise "Please choose only one plugin enumeration option" + raise 'Please choose only one plugin enumeration option' else @enumerate_only_vulnerable_plugins = enumerate_only_vulnerable_plugins end @@ -107,7 +108,7 @@ class WpscanOptions def enumerate_all_plugins=(enumerate_all_plugins) if enumerate_all_plugins === true and (@enumerate_plugins === true or @enumerate_only_vulnerable_plugins === true) - raise "Please choose only one plugin enumeration option" + raise 'Please choose only one plugin enumeration option' else @enumerate_all_plugins = enumerate_all_plugins end @@ -115,7 +116,7 @@ class WpscanOptions def enumerate_themes=(enumerate_themes) if enumerate_themes === true and (@enumerate_all_themes === true or @enumerate_only_vulnerable_themes === true) - raise "Please choose only one theme enumeration option" + raise 'Please choose only one theme enumeration option' else @enumerate_themes = enumerate_themes end @@ -123,7 +124,7 @@ class WpscanOptions def enumerate_only_vulnerable_themes=(enumerate_only_vulnerable_themes) if enumerate_only_vulnerable_themes === true and (@enumerate_all_themes === true or @enumerate_themes === true) - raise "Please choose only one theme enumeration option" + raise 'Please choose only one theme enumeration option' else @enumerate_only_vulnerable_themes = enumerate_only_vulnerable_themes end @@ -131,14 +132,14 @@ class WpscanOptions def enumerate_all_themes=(enumerate_all_themes) if enumerate_all_themes === true and (@enumerate_themes === true or @enumerate_only_vulnerable_themes === true) - raise "Please choose only one theme enumeration option" + raise 'Please choose only one theme enumeration option' else @enumerate_all_themes = enumerate_all_themes end end def basic_auth=(basic_auth) - raise "Invalid basic authentication format, login:password expected" if basic_auth.index(':').nil? + raise 'Invalid basic authentication format, login:password expected' if basic_auth.index(':').nil? @basic_auth = "Basic #{Base64.encode64(basic_auth).chomp}" end @@ -183,9 +184,9 @@ class WpscanOptions WpscanOptions.option_to_instance_variable_setter(cli_option), cli_value ) - elsif cli_option === "--enumerate" # Special cases + elsif cli_option === '--enumerate' # Special cases # Default value if no argument is given - cli_value = "vt,tt,u,vp" if cli_value.length == 0 + cli_value = 'vt,tt,u,vp' if cli_value.length == 0 enumerate_options_from_string(cli_value) else @@ -200,7 +201,7 @@ class WpscanOptions def enumerate_options_from_string(value) # Usage of self is mandatory because there are overridden setters - value = value.split(',').map{ |c| c.downcase } + value = value.split(',').map { |c| c.downcase } self.enumerate_only_vulnerable_plugins = true if value.include?('vp') @@ -231,23 +232,23 @@ 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::REQUIRED_ARGUMENT], - ["--proxy-auth", GetoptLong::REQUIRED_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], - ["--exclude-content-based", GetoptLong::REQUIRED_ARGUMENT], - ["--basic-auth", 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::REQUIRED_ARGUMENT], + ['--proxy-auth', GetoptLong::REQUIRED_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], + ['--exclude-content-based', GetoptLong::REQUIRED_ARGUMENT], + ['--basic-auth', GetoptLong::REQUIRED_ARGUMENT] ) end