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 =~ /