diff --git a/lib/wpscan/modules/wp_item.rb b/lib/wpscan/modules/wp_item.rb
new file mode 100644
index 00000000..ae3e25b3
--- /dev/null
+++ b/lib/wpscan/modules/wp_item.rb
@@ -0,0 +1,66 @@
+#--
+# 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 .
+#++
+
+module WpItem
+ attr_accessor :path, :base_url, :wp_content_dir
+ @version = nil
+
+ def get_url
+ URI.parse("#{@base_url.to_s}#@wp_content_dir/#@path")
+ end
+
+ def version
+ unless @version
+ response = Browser.instance.get(get_url.merge("readme.txt").to_s)
+ @version = response.body[%r{stable tag: #{WpVersion.version_pattern}}i, 1]
+ end
+ @version
+ end
+
+ # Is directory listing enabled?
+ def directory_listing?
+ # Need to remove to file part from the url
+ Browser.instance.get(location_uri_from_file_url(get_url.to_s)).body[%r{
Index of}] ? true : false
+ end
+
+ def extract_name_from_url(url)
+ url.to_s[%r{^(https?://.*/([^/]+)/)}i, 2]
+ end
+
+ def to_s
+ item_version = version
+ "#@name#{' v' + item_version if item_version}"
+ end
+
+ def ==(item)
+ item.name == @name
+ end
+
+ def <=>(item)
+ item.name <=> @name
+ end
+
+ def location_uri_from_file_url(location_url)
+ valid_location_url = location_url[%r{^(https?://.*/)[^.]+\.[^/]+$}, 1]
+ unless valid_location_url
+ valid_location_url = add_trailing_slash(location_url)
+ end
+ URI.parse(valid_location_url)
+ end
+
+end
diff --git a/lib/wpscan/modules/wp_login_protection.rb b/lib/wpscan/modules/wp_login_protection.rb
index 282c2617..7ef10739 100644
--- a/lib/wpscan/modules/wp_login_protection.rb
+++ b/lib/wpscan/modules/wp_login_protection.rb
@@ -37,11 +37,8 @@ module WpLoginProtection
plugin_name = symbol_to_call[@@login_protection_method_pattern, 1].gsub('_', '-')
return @login_protection_plugin = WpPlugin.new(
- WpPlugin::create_location_url_from_name(
- plugin_name,
- @uri.to_s
- ),
- :name => plugin_name
+ :name => plugin_name,
+ :base_url => @uri.to_s
)
end
end
diff --git a/lib/wpscan/modules/wp_plugins.rb b/lib/wpscan/modules/wp_plugins.rb
index bd5000db..3533439c 100644
--- a/lib/wpscan/modules/wp_plugins.rb
+++ b/lib/wpscan/modules/wp_plugins.rb
@@ -19,92 +19,18 @@
module WpPlugins
# Enumerate installed plugins.
- # Available options : see #targets_url
- # :show_progress_bar - default false
#
# return array of WpPlugin
- def plugins_from_aggressive_detection(options = {})
- browser = Browser.instance
- hydra = browser.hydra
- found_plugins = options[:only_vulnerable_ones] ? [] : plugins_from_passive_detection()
- request_count = 0
- queue_count = 0
- local_404_hash = error_404_hash()
- valid_response_codes = WpPlugins.valid_response_codes()
- targets_url = plugins_targets_url(options)
- show_progress_bar = options[:show_progress_bar] || false
-
- targets_url.each do |target_url|
- request = browser.forge_request(target_url, :cache_timeout => 0, :follow_location => true)
- request_count += 1
-
- request.on_complete do |response|
- print "\rChecking for #{targets_url.size} total plugins... #{(request_count * 100) / targets_url.size}% complete." if show_progress_bar
-
- if valid_response_codes.include?(response.code)
- if Digest::MD5.hexdigest(response.body) != local_404_hash
- found_plugins << WpPlugin.new(target_url)
- end
- end
- end
-
- hydra.queue(request)
- queue_count += 1
-
- if queue_count == browser.max_threads
- hydra.run
- queue_count = 0
- end
- end
-
- hydra.run
-
- found_plugins
+ def plugins_from_aggressive_detection(options)
+ options[:file] = "#{DATA_DIR}/plugins.txt"
+ options[:vulns_file] = "#{DATA_DIR}/plugin_vulns.xml"
+ options[:vulns_xpath] = "//plugin[@name='#{@name}']/vulnerability"
+ options[:type] = "plugins"
+ result = WpDetector.aggressive_detection(options)
+ result
end
- def self.valid_response_codes
- [200, 403, 301, 302]
- end
-
- # Available options :
- # :only_vulnerable_ones - default false
- # :plugins_file - default DATA_DIR/plugins.txt
- # :plugin_vulns_file - default DATA_DIR/plugin_vulns.xml
- #
- # @return Array of String
- def plugins_targets_url(options = {})
- only_vulnerable = options[:only_vulnerable_ones] || false
- plugins_file = options[:plugins_file] || "#{DATA_DIR}/plugins.txt"
- plugin_vulns_file = options[:plugin_vulns_file] || "#{DATA_DIR}/plugin_vulns.xml"
- targets_url = []
-
- if only_vulnerable == false
- # Open and parse the 'most popular' plugin list...
- File.open(plugins_file, 'r') do |file|
- file.readlines.collect do |line|
- targets_url << WpPlugin.create_url_from_raw(line.chomp, @uri)
- end
- end
- end
-
- xml = Nokogiri::XML(File.open(plugin_vulns_file)) do |config|
- config.noblanks
- end
-
- # We check if the plugin name from the plugin_vulns_file is already in targets, otherwise we add it
- xml.xpath("//plugin").each do |node|
- plugin_name = node.attribute('name').text
-
- if targets_url.grep(%r{/#{plugin_name}/}).empty?
- targets_url << WpPlugin.create_location_url_from_name(plugin_name, url())
- end
- end
-
- targets_url.flatten!
- targets_url.uniq!
- # randomize the plugins array to *maybe* help in some crappy IDS/IPS/WAF detection
- targets_url.sort_by! { rand }
- end
+ private
# http://code.google.com/p/wpscan/issues/detail?id=42
# plugins can be found in the source code :
@@ -112,18 +38,16 @@ module WpPlugins
#
# ...
# return array of WpPlugin
- def plugins_from_passive_detection
- plugins = []
- response = Browser.instance.get(url())
- plugins_names = response.body.scan(%r{(?:[^=:]+)\s?(?:=|:)\s?(?:"|')[^"']+\\?/wp-content\\?/plugins\\?/([^/\\"']+)\\?(?:/|"|')}i)
+ def plugins_from_passive_detection(wp_content_dir)
+ plugins = []
+ temp = WpDetector.passive_detection(url(), "plugins", wp_content_dir)
- plugins_names.flatten!
- plugins_names.uniq!
-
- plugins_names.each do |plugin_name|
+ temp.each do |item|
plugins << WpPlugin.new(
- WpPlugin.create_location_url_from_name(plugin_name, url()),
- :name => plugin_name
+ :base_url => item[:base_url],
+ :name => item[:name],
+ :path => item[:path],
+ :wp_content_dir => wp_content_dir
)
end
plugins
diff --git a/lib/wpscan/wp_detector.rb b/lib/wpscan/wp_detector.rb
new file mode 100644
index 00000000..f21ee7fa
--- /dev/null
+++ b/lib/wpscan/wp_detector.rb
@@ -0,0 +1,57 @@
+#--
+# 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 .
+#++
+
+class WpDetector
+
+ def self.aggressive_detection(options, items = [])
+ WpOptions.check_options(options)
+
+ result = items
+ unless items == nil or items.length == 0
+ result = passive_detection(options[:url], options[:type], options[:wp_content_dir])
+ end
+
+ enum_results = WpEnumerator.enumerate(options)
+ enum_results.each do |enum_result|
+ result << enum_result
+ end
+ result
+ end
+
+ # plugins and themes can be found in the source code :
+ #
+ #
+ # ...
+ def self.passive_detection(url, type, wp_content_dir)
+ items = []
+ response = Browser.instance.get(url)
+ regex1 = %r{(?:[^=:]+)\s?(?:=|:)\s?(?:"|')[^"']+\\?/}
+ regex2 = %r{\\?/}
+ regex3 = %r{\\?/([^/\\"']+)\\?(?:/|"|')}
+ # Custom wp-content dir is now used in this regex
+ names = response.body.scan(/#{regex1}#{wp_content_dir}#{regex2}#{type}#{regex3}/i)
+
+ names.flatten!
+ names.uniq!
+
+ names.each do |item|
+ items << { :base_url => url, :name => item, :path => "#{type}/#{item}" }
+ end
+ items
+ end
+end
\ No newline at end of file
diff --git a/lib/wpscan/wp_enumerator.rb b/lib/wpscan/wp_enumerator.rb
new file mode 100644
index 00000000..32115428
--- /dev/null
+++ b/lib/wpscan/wp_enumerator.rb
@@ -0,0 +1,118 @@
+#--
+# 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 .
+#++
+
+# Enumerate over a given set of items and check if they exist
+class WpEnumerator
+
+ # Enumerate the given Targets
+ #
+ # ==== Attributes
+ #
+ # * +targets+ - targets to enumerate
+ # * * +:base_url+ - Base URL
+ # * * +:wp_content+ - wp-content directory
+ # * * +:path+ - Path to plugin
+ # * +type+ - "plugins" or "themes", item to enumerate
+ # * +filename+ - filename in the data directory with paths
+ # * +show_progress_bar+ - Show a progress bar during enumeration
+ def self.enumerate(options = {})
+
+ WpOptions.check_options(options)
+
+ targets = self.generate_items(options)
+
+ found = []
+ queue_count = 0
+ request_count = 0
+ enum_browser = Browser.instance
+ enum_hydra = enum_browser.hydra
+ enumerate_size = targets.size
+
+ targets.each do |target|
+ url = target.get_url
+ request = enum_browser.forge_request(url, :cache_timeout => 0, :follow_location => true)
+ request_count += 1
+
+ request.on_complete do |response|
+ if options[:show_progress_bar]
+ print "\rChecking for #{enumerate_size} total #{options[:type]}... #{(request_count * 100) / enumerate_size}% complete."
+ end
+ if WpTarget.valid_response_codes.include?(response.code)
+ if Digest::MD5.hexdigest(response.body) != options[:error_404_hash]
+ found << target
+ end
+ end
+ end
+
+ enum_hydra.queue(request)
+ queue_count += 1
+
+ if queue_count == enum_browser.max_threads
+ enum_hydra.run
+ queue_count = 0
+ end
+ end
+
+ enum_hydra.run
+ found
+ end
+
+ private
+
+ def self.generate_items(options = {})
+ only_vulnerable = options[:only_vulnerable_ones]
+ plugins_file = options[:file] || "#{DATA_DIR}/plugins.txt"
+ plugin_vulns_file = options[:vulns_file] || "#{DATA_DIR}/plugin_vulns.xml"
+ wp_content_dir = options[:wp_content_dir]
+ url = options[:base_url]
+ type = options[:type]
+ targets_url = []
+
+ if only_vulnerable == false
+ # Open and parse the 'most popular' plugin list...
+ File.open(plugins_file, 'r') do |file|
+ file.readlines.collect do |line|
+ targets_url << WpPlugin.new(:base_url => url, :path => line.strip, :wp_content_dir => wp_content_dir)
+ end
+ end
+ end
+
+ xml = Nokogiri::XML(File.open(plugin_vulns_file)) do |config|
+ config.noblanks
+ end
+
+ # We check if the plugin name from the plugin_vulns_file is already in targets, otherwise we add it
+ xml.xpath("//plugin").each do |node|
+ plugin_name = node.attribute('name').text
+
+ if targets_url.grep(%r{/#{plugin_name}/}).empty?
+ targets_url << WpPlugin.new(
+ :base_url => url,
+ :path => "#{type}/#{plugin_name}",
+ :wp_content_dir => wp_content_dir,
+ :name => plugin_name
+ )
+ end
+ end
+
+ targets_url.flatten!
+ targets_url.uniq!
+ # randomize the plugins array to *maybe* help in some crappy IDS/IPS/WAF detection
+ targets_url.sort_by! { rand }
+ end
+end
diff --git a/lib/wpscan/wp_options.rb b/lib/wpscan/wp_options.rb
new file mode 100644
index 00000000..5a748ac3
--- /dev/null
+++ b/lib/wpscan/wp_options.rb
@@ -0,0 +1,50 @@
+#--
+# 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 .
+#++
+
+class WpOptions
+ def self.get_empty_options
+ options = {
+ :url => "",
+ :only_vulnerable_ones => true,
+ :file => "",
+ :vulns_file => "",
+ :vulns_xpath => "",
+ :wp_content_dir => "",
+ :show_progress_bar => true,
+ :error_404_hash => "",
+ :type => ""
+ }
+ options
+ end
+
+ def self.check_options(options)
+ raise("url must be set") unless options[:url]
+ raise("only_vulnerable_ones must be set") unless options[:only_vulnerable_ones]
+ raise("file must be set") unless options[:file]
+ raise("vulns_file must be set") unless options[:vulns_file]
+ raise("vulns_xpath must be set") unless options[:vulns_xpath]
+ raise("wp_content_dir must be set") unless options[:wp_content_dir]
+ raise("show_progress_bar must be set") unless options[:show_progress_bar]
+ raise("error_404_hash must be set") unless options[:error_404_hash]
+ raise("type must be set") unless options[:type]
+ unless options[:type] =~ /plugins/i or options[:type] =~ /themes/i
+ raise("Unknown type #{options[:type]}")
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/lib/wpscan/wp_plugin.rb b/lib/wpscan/wp_plugin.rb
index dfdecd7c..0e5177df 100644
--- a/lib/wpscan/wp_plugin.rb
+++ b/lib/wpscan/wp_plugin.rb
@@ -19,38 +19,22 @@
require "#{WPSCAN_LIB_DIR}/vulnerable"
class WpPlugin < Vulnerable
- @@location_url_pattern = %r{^(https?://.*/([^/]+)/)}i
+ include WpItem
- attr_reader :name
+ def initialize(options = {})
+ @base_url = options[:base_url]
+ @path = options[:path]
+ @wp_content_dir = options[:wp_content_dir]
+ @name = options[:name] || extract_name_from_url(get_url)
+ @vulns_xml = options[:vulns_xml] || DATA_DIR + '/plugin_vulns.xml'
+ @vulns_xpath = "//plugin[@name='#@name']/vulnerability"
+ @version = nil
- def initialize(location_url, options = {})
- @location_uri = WpPlugin.location_uri_from_url(location_url)
- @name = options[:name] || WpPlugin.extract_name_from_location_url(location_url)
- @vulns_xml = options[:vulns_xml] || DATA_DIR + '/plugin_vulns.xml'
- @vulns_xpath = "//plugin[@name='#{@name}']/vulnerability"
- end
-
- def location_url
- @location_uri.to_s
- end
-
- def ==(plugin)
- plugin.name == @name
- end
-
- def <=>(plugin)
- plugin.name <=> @name
- end
-
- # http://code.google.com/p/wpscan/issues/detail?id=97
- def version
- response = Browser.instance.get(@location_uri.merge("readme.txt").to_s)
- response.body[%r{stable tag: #{WpVersion.version_pattern}}i, 1]
- end
-
- def to_s
- version = version()
- "#{@name}#{' v' + version if version}"
+ 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_xml not set") unless @vulns_xml
end
# Discover any error_log files created by WordPress
@@ -64,39 +48,7 @@ class WpPlugin < Vulnerable
end
def error_log_url
- @location_uri.merge("error_log").to_s
+ get_url.merge("error_log").to_s
end
- # Is directory listing enabled?
- # WordPress denies directory listing however,
- # forgets about the plugin directory.
- def directory_listing?
- Browser.instance.get(location_url()).body[%r{Index of}] ? true : false
- end
-
- def self.create_location_url_from_name(name, target_uri)
- if target_uri.is_a?(String)
- target_uri = URI.parse(target_uri)
- end
- target_uri.merge(URI.escape("$wp-plugins$/#{name}/")).to_s
- end
-
- def self.create_url_from_raw(raw, target_uri)
- target_uri.merge(URI.escape("$wp-plugins$/#{raw}")).to_s
- end
-
- protected
- def self.extract_name_from_location_url(location_url)
- location_url[@@location_url_pattern, 2]
- end
-
- def self.location_uri_from_url(location_url)
- valid_location_url = location_url[%r{^(https?://.*/)[^.]+\.[^/]+$}, 1]
-
- unless valid_location_url
- valid_location_url = add_trailing_slash(location_url)
- end
-
- URI.parse(valid_location_url)
- end
end
diff --git a/lib/wpscan/wp_target.rb b/lib/wpscan/wp_target.rb
index 9e8ba8c1..d68c94c1 100644
--- a/lib/wpscan/wp_target.rb
+++ b/lib/wpscan/wp_target.rb
@@ -50,7 +50,7 @@ class WpTarget
url = @uri.merge("wp-login.php").to_s
# Let's check if the login url is redirected (to https url for example)
- if redirection = redirection(url)
+ if redirection == redirection(url)
url = redirection
end
@@ -70,6 +70,11 @@ class WpTarget
@error_404_hash
end
+ # Valid HTTP return codes
+ def self.valid_response_codes
+ [200, 403, 301, 302]
+ end
+
# return WpTheme
def theme
WpTheme.find(@uri)
diff --git a/spec/lib/wpscan/wp_plugin_spec.rb b/spec/lib/wpscan/wp_plugin_spec.rb
index e922cc7e..2759ea23 100644
--- a/spec/lib/wpscan/wp_plugin_spec.rb
+++ b/spec/lib/wpscan/wp_plugin_spec.rb
@@ -44,6 +44,11 @@ describe WpPlugin do
@expected_uri_string = "http://example.com/wp-content/plugins/example/"
end
+ it "should return the uri without the file" do
+ @url = "https://sub.example.com/path/to/dir/wp-content/plugins/example/readme.txt"
+ @expected_uri_string = "https://sub.example.com/path/to/dir/wp-content/plugins/example/"
+ end
+
it "should return the same uri" do
@url = "http://example.com/wp-content/plugins/hello-world/"
@expected_uri_string = @url
@@ -65,6 +70,10 @@ describe WpPlugin do
it "should return 'example-plugin'" do
WpPlugin.extract_name_from_location_url('http://example.com/wp-content/plugins/example-plugin/').should === 'example-plugin'
end
+
+ it "should return 'example-plugin'" do
+ WpPlugin.extract_name_from_location_url('https://sub.example.com/path/to/a/wp-content/plugins/example-plugin/').should === 'example-plugin'
+ end
end
describe "#create_location_url_from_name" do
diff --git a/wpscan.rb b/wpscan.rb
index a2ea24e0..aac4028a 100755
--- a/wpscan.rb
+++ b/wpscan.rb
@@ -78,9 +78,7 @@ begin
end
end
- if wp_content_dir = wp_target.wp_content_dir()
- Browser.instance.variables_to_replace_in_url = {"$wp-content$" => wp_content_dir, "$wp-plugins$" => wp_target.wp_plugins_dir()}
- else
+ unless wp_target.wp_content_dir
raise "The wp_content_dir has not been found, please supply it with --wp-content-dir"
end
@@ -89,7 +87,7 @@ begin
puts "| Started on #{Time.now.asctime}"
puts
- if wp_theme = wp_target.theme
+ if wp_theme == wp_target.theme
theme_version = wp_theme.version
puts "[!] The WordPress theme in use is #{wp_theme}"
@@ -98,8 +96,8 @@ begin
puts "[+] We have identified #{theme_vulnerabilities.size} vulnerabilities for this theme :"
theme_vulnerabilities.each do |vulnerability|
puts
- puts " | * Title: " + vulnerability.title
- puts " | * Reference: " + vulnerability.reference
+ puts " | * Title: #{vulnerability.title}"
+ puts " | * Reference: #{vulnerability.reference}"
end
puts
end
@@ -132,7 +130,7 @@ begin
puts
end
- if wp_version = wp_target.version
+ if wp_version == wp_target.version
puts "[!] WordPress version #{wp_version.number} identified from #{wp_version.discovery_method}"
version_vulnerabilities = wp_version.vulnerabilities
@@ -142,33 +140,33 @@ begin
puts "[+] We have identified #{version_vulnerabilities.size} vulnerabilities from the version number :"
version_vulnerabilities.each do |vulnerability|
puts
- puts " | * Title: " + vulnerability.title
- puts " | * Reference: " + vulnerability.reference
+ puts " | * Title: #{vulnerability.title}"
+ puts " | * Reference: #{vulnerability.reference}"
end
end
end
if wpscan_options.enumerate_plugins == nil and wpscan_options.enumerate_only_vulnerable_plugins == nil
puts
- print "[+] Enumerating plugins from passive detection ... "
+ puts "[+] Enumerating plugins from passive detection ... "
plugins = wp_target.plugins_from_passive_detection
unless plugins.empty?
- print "#{plugins.size} found :\n"
+ puts "#{plugins.size} found :"
plugins.each do |plugin|
puts
- puts " | Name: " + plugin.name
- puts " | Location: " + plugin.location_url.gsub("$wp-plugins$", wp_target.wp_plugins_dir()) #Hotfix
+ puts " | Name: #{plugin.name}"
+ puts " | Location: #{plugin.get_url}"
plugin.vulnerabilities.each do |vulnerability|
puts " |"
- puts " | [!] " + vulnerability.title
- puts " | * Reference: " + vulnerability.reference
+ puts " | [!] #{vulnerability.title}"
+ puts " | * Reference: #{vulnerability.reference}"
end
end
else
- print "No plugins found :(\n"
+ puts "No plugins found :("
end
end
@@ -178,20 +176,22 @@ begin
puts "[+] Enumerating installed plugins #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_plugins} ..."
puts
- plugins = wp_target.plugins_from_aggressive_detection(
- :only_vulnerable_ones => wpscan_options.enumerate_only_vulnerable_plugins,
- :show_progress_bar => true
- )
+ options = WpOptions.get_empty_options
+ options[:base_url] = wp_target.uri
+ options[:only_vulnerable_ones] = wpscan_options.enumerate_only_vulnerable_plugins,
+ options[:show_progress_bar] = true,
+ options[:wp_content_dir] = wp_target.wp_content_dir
+
+ plugins = wp_target.plugins_from_aggressive_detection(options)
unless plugins.empty?
puts
puts
- puts "[+] We found " + plugins.size.to_s + " plugins:"
+ puts "[+] 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.location_url.gsub("$wp-plugins$", wp_target.wp_plugins_dir()) #Hotfix
-
+ puts " | Location: #{plugin.get_url}"
puts " | Directory listing enabled? #{plugin.directory_listing? ? "Yes." : "No."}"
plugin.vulnerabilities.each do |vulnerability|
@@ -199,8 +199,8 @@ begin
#vulnerability['vulnerability'][0]['postdata'] == nil ? "" : postdata = CGI.unescapeHTML(vulnerability['vulnerability'][0]['postdata']) # postdata
puts " |"
- puts " | [!] " + vulnerability.title
- puts " | * Reference: " + vulnerability.reference
+ puts " | [!] #{vulnerability.title}"
+ puts " | * Reference: #{vulnerability.reference}"
# This has been commented out as MSF are moving from
# XML-RPC to MessagePack.
@@ -212,7 +212,7 @@ begin
end
if plugin.error_log?
- puts " | [!] A WordPress error_log file has been found : " + plugin.error_log_url
+ puts " | [!] A WordPress error_log file has been found : #{plugin.error_log_url}"
end
end
else
@@ -230,11 +230,11 @@ begin
timthumbs = wp_target.timthumbs
puts
- puts "[+] We found " + timthumbs.size.to_s + " timthumb file/s :"
+ puts "[+] We found #{timthumbs.size.to_s} timthumb file/s :"
puts
timthumbs.each do |file_url|
- puts " | [!] " + file_url
+ puts " | [!] #{file_url}"
end
puts
puts " * Reference: http://www.exploit-db.com/exploits/17602/"
@@ -259,10 +259,10 @@ begin
exit(1)
else
puts
- puts "We found the following " + usernames.length.to_s + " username/s :"
+ puts "We found the following #{usernames.length.to_s} username/s :"
puts
- usernames.each {|username| puts " " + username}
+ usernames.each {|username| puts " #{username}"}
end
else
@@ -296,7 +296,7 @@ begin
end
puts
- puts '[+] Finished at ' + Time.now.asctime
+ puts "[+] Finished at #{Time.now.asctime}"
exit() # must exit!
rescue => e
puts "[ERROR] #{e.message}"