First commit for more generic enumerating and scanning

This commit is contained in:
Christian Mehlmauer
2012-09-15 20:30:06 +02:00
parent bf940b2065
commit 8bc9f47cc7
10 changed files with 370 additions and 192 deletions

View File

@@ -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 <http://www.gnu.org/licenses/>.
#++
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{<title>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

View File

@@ -37,11 +37,8 @@ module WpLoginProtection
plugin_name = symbol_to_call[@@login_protection_method_pattern, 1].gsub('_', '-') plugin_name = symbol_to_call[@@login_protection_method_pattern, 1].gsub('_', '-')
return @login_protection_plugin = WpPlugin.new( return @login_protection_plugin = WpPlugin.new(
WpPlugin::create_location_url_from_name( :name => plugin_name,
plugin_name, :base_url => @uri.to_s
@uri.to_s
),
:name => plugin_name
) )
end end
end end

View File

@@ -19,92 +19,18 @@
module WpPlugins module WpPlugins
# Enumerate installed plugins. # Enumerate installed plugins.
# Available options : see #targets_url
# :show_progress_bar - default false
# #
# return array of WpPlugin # return array of WpPlugin
def plugins_from_aggressive_detection(options = {}) def plugins_from_aggressive_detection(options)
browser = Browser.instance options[:file] = "#{DATA_DIR}/plugins.txt"
hydra = browser.hydra options[:vulns_file] = "#{DATA_DIR}/plugin_vulns.xml"
found_plugins = options[:only_vulnerable_ones] ? [] : plugins_from_passive_detection() options[:vulns_xpath] = "//plugin[@name='#{@name}']/vulnerability"
request_count = 0 options[:type] = "plugins"
queue_count = 0 result = WpDetector.aggressive_detection(options)
local_404_hash = error_404_hash() result
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 end
hydra.queue(request) private
queue_count += 1
if queue_count == browser.max_threads
hydra.run
queue_count = 0
end
end
hydra.run
found_plugins
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
# http://code.google.com/p/wpscan/issues/detail?id=42 # http://code.google.com/p/wpscan/issues/detail?id=42
# plugins can be found in the source code : # plugins can be found in the source code :
@@ -112,18 +38,16 @@ module WpPlugins
# <link rel='stylesheet' href='http://example.com/wp-content/plugins/wp-minify/..' type='text/css' media='screen'/> # <link rel='stylesheet' href='http://example.com/wp-content/plugins/wp-minify/..' type='text/css' media='screen'/>
# ... # ...
# return array of WpPlugin # return array of WpPlugin
def plugins_from_passive_detection def plugins_from_passive_detection(wp_content_dir)
plugins = [] plugins = []
response = Browser.instance.get(url()) temp = WpDetector.passive_detection(url(), "plugins", wp_content_dir)
plugins_names = response.body.scan(%r{(?:[^=:]+)\s?(?:=|:)\s?(?:"|')[^"']+\\?/wp-content\\?/plugins\\?/([^/\\"']+)\\?(?:/|"|')}i)
plugins_names.flatten! temp.each do |item|
plugins_names.uniq!
plugins_names.each do |plugin_name|
plugins << WpPlugin.new( plugins << WpPlugin.new(
WpPlugin.create_location_url_from_name(plugin_name, url()), :base_url => item[:base_url],
:name => plugin_name :name => item[:name],
:path => item[:path],
:wp_content_dir => wp_content_dir
) )
end end
plugins plugins

57
lib/wpscan/wp_detector.rb Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
#++
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 :
# <script src='http://example.com/wp-content/plugins/s2member/...' />
# <link rel='stylesheet' href='http://example.com/wp-content/plugins/wp-minify/..' type='text/css' media='screen'/>
# ...
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

118
lib/wpscan/wp_enumerator.rb Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
#++
# 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

50
lib/wpscan/wp_options.rb Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
#++
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

View File

@@ -19,38 +19,22 @@
require "#{WPSCAN_LIB_DIR}/vulnerable" require "#{WPSCAN_LIB_DIR}/vulnerable"
class WpPlugin < Vulnerable class WpPlugin < Vulnerable
@@location_url_pattern = %r{^(https?://.*/([^/]+)/)}i include WpItem
attr_reader :name def initialize(options = {})
@base_url = options[:base_url]
def initialize(location_url, options = {}) @path = options[:path]
@location_uri = WpPlugin.location_uri_from_url(location_url) @wp_content_dir = options[:wp_content_dir]
@name = options[:name] || WpPlugin.extract_name_from_location_url(location_url) @name = options[:name] || extract_name_from_url(get_url)
@vulns_xml = options[:vulns_xml] || DATA_DIR + '/plugin_vulns.xml' @vulns_xml = options[:vulns_xml] || DATA_DIR + '/plugin_vulns.xml'
@vulns_xpath = "//plugin[@name='#{@name}']/vulnerability" @vulns_xpath = "//plugin[@name='#@name']/vulnerability"
end @version = nil
def location_url raise("base_url not set") unless @base_url
@location_uri.to_s raise("path not set") unless @path
end raise("wp_content_dir not set") unless @wp_content_dir
raise("name not set") unless @name
def ==(plugin) raise("vulns_xml not set") unless @vulns_xml
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}"
end end
# Discover any error_log files created by WordPress # Discover any error_log files created by WordPress
@@ -64,39 +48,7 @@ class WpPlugin < Vulnerable
end end
def error_log_url def error_log_url
@location_uri.merge("error_log").to_s get_url.merge("error_log").to_s
end 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{<title>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 end

View File

@@ -50,7 +50,7 @@ class WpTarget
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) # Let's check if the login url is redirected (to https url for example)
if redirection = redirection(url) if redirection == redirection(url)
url = redirection url = redirection
end end
@@ -70,6 +70,11 @@ class WpTarget
@error_404_hash @error_404_hash
end end
# Valid HTTP return codes
def self.valid_response_codes
[200, 403, 301, 302]
end
# return WpTheme # return WpTheme
def theme def theme
WpTheme.find(@uri) WpTheme.find(@uri)

View File

@@ -44,6 +44,11 @@ describe WpPlugin do
@expected_uri_string = "http://example.com/wp-content/plugins/example/" @expected_uri_string = "http://example.com/wp-content/plugins/example/"
end 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 it "should return the same uri" do
@url = "http://example.com/wp-content/plugins/hello-world/" @url = "http://example.com/wp-content/plugins/hello-world/"
@expected_uri_string = @url @expected_uri_string = @url
@@ -65,6 +70,10 @@ describe WpPlugin do
it "should return 'example-plugin'" do it "should return 'example-plugin'" do
WpPlugin.extract_name_from_location_url('http://example.com/wp-content/plugins/example-plugin/').should === 'example-plugin' WpPlugin.extract_name_from_location_url('http://example.com/wp-content/plugins/example-plugin/').should === 'example-plugin'
end 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 end
describe "#create_location_url_from_name" do describe "#create_location_url_from_name" do

View File

@@ -78,9 +78,7 @@ begin
end end
end end
if wp_content_dir = wp_target.wp_content_dir() unless 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
raise "The wp_content_dir has not been found, please supply it with --wp-content-dir" raise "The wp_content_dir has not been found, please supply it with --wp-content-dir"
end end
@@ -89,7 +87,7 @@ begin
puts "| Started on #{Time.now.asctime}" puts "| Started on #{Time.now.asctime}"
puts puts
if wp_theme = wp_target.theme if wp_theme == wp_target.theme
theme_version = wp_theme.version theme_version = wp_theme.version
puts "[!] The WordPress theme in use is #{wp_theme}" 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 :" puts "[+] We have identified #{theme_vulnerabilities.size} vulnerabilities for this theme :"
theme_vulnerabilities.each do |vulnerability| theme_vulnerabilities.each do |vulnerability|
puts puts
puts " | * Title: " + vulnerability.title puts " | * Title: #{vulnerability.title}"
puts " | * Reference: " + vulnerability.reference puts " | * Reference: #{vulnerability.reference}"
end end
puts puts
end end
@@ -132,7 +130,7 @@ begin
puts puts
end 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}" puts "[!] WordPress version #{wp_version.number} identified from #{wp_version.discovery_method}"
version_vulnerabilities = wp_version.vulnerabilities version_vulnerabilities = wp_version.vulnerabilities
@@ -142,33 +140,33 @@ begin
puts "[+] We have identified #{version_vulnerabilities.size} vulnerabilities from the version number :" puts "[+] We have identified #{version_vulnerabilities.size} vulnerabilities from the version number :"
version_vulnerabilities.each do |vulnerability| version_vulnerabilities.each do |vulnerability|
puts puts
puts " | * Title: " + vulnerability.title puts " | * Title: #{vulnerability.title}"
puts " | * Reference: " + vulnerability.reference puts " | * Reference: #{vulnerability.reference}"
end end
end end
end end
if wpscan_options.enumerate_plugins == nil and wpscan_options.enumerate_only_vulnerable_plugins == nil if wpscan_options.enumerate_plugins == nil and wpscan_options.enumerate_only_vulnerable_plugins == nil
puts puts
print "[+] Enumerating plugins from passive detection ... " puts "[+] Enumerating plugins from passive detection ... "
plugins = wp_target.plugins_from_passive_detection plugins = wp_target.plugins_from_passive_detection
unless plugins.empty? unless plugins.empty?
print "#{plugins.size} found :\n" puts "#{plugins.size} found :"
plugins.each do |plugin| plugins.each do |plugin|
puts puts
puts " | Name: " + plugin.name puts " | Name: #{plugin.name}"
puts " | Location: " + plugin.location_url.gsub("$wp-plugins$", wp_target.wp_plugins_dir()) #Hotfix puts " | Location: #{plugin.get_url}"
plugin.vulnerabilities.each do |vulnerability| plugin.vulnerabilities.each do |vulnerability|
puts " |" puts " |"
puts " | [!] " + vulnerability.title puts " | [!] #{vulnerability.title}"
puts " | * Reference: " + vulnerability.reference puts " | * Reference: #{vulnerability.reference}"
end end
end end
else else
print "No plugins found :(\n" puts "No plugins found :("
end end
end end
@@ -178,20 +176,22 @@ begin
puts "[+] Enumerating installed plugins #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_plugins} ..." puts "[+] Enumerating installed plugins #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_plugins} ..."
puts puts
plugins = wp_target.plugins_from_aggressive_detection( options = WpOptions.get_empty_options
:only_vulnerable_ones => wpscan_options.enumerate_only_vulnerable_plugins, options[:base_url] = wp_target.uri
:show_progress_bar => true 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? unless plugins.empty?
puts puts
puts puts
puts "[+] We found " + plugins.size.to_s + " plugins:" puts "[+] We found #{plugins.size.to_s} plugins:"
plugins.each do |plugin| plugins.each do |plugin|
puts puts
puts " | Name: #{plugin}" #this will also output the version number if detected 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."}" puts " | Directory listing enabled? #{plugin.directory_listing? ? "Yes." : "No."}"
plugin.vulnerabilities.each do |vulnerability| plugin.vulnerabilities.each do |vulnerability|
@@ -199,8 +199,8 @@ begin
#vulnerability['vulnerability'][0]['postdata'] == nil ? "" : postdata = CGI.unescapeHTML(vulnerability['vulnerability'][0]['postdata']) # postdata #vulnerability['vulnerability'][0]['postdata'] == nil ? "" : postdata = CGI.unescapeHTML(vulnerability['vulnerability'][0]['postdata']) # postdata
puts " |" puts " |"
puts " | [!] " + vulnerability.title puts " | [!] #{vulnerability.title}"
puts " | * Reference: " + vulnerability.reference puts " | * Reference: #{vulnerability.reference}"
# This has been commented out as MSF are moving from # This has been commented out as MSF are moving from
# XML-RPC to MessagePack. # XML-RPC to MessagePack.
@@ -212,7 +212,7 @@ begin
end end
if plugin.error_log? 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
end end
else else
@@ -230,11 +230,11 @@ begin
timthumbs = wp_target.timthumbs timthumbs = wp_target.timthumbs
puts puts
puts "[+] We found " + timthumbs.size.to_s + " timthumb file/s :" puts "[+] We found #{timthumbs.size.to_s} timthumb file/s :"
puts puts
timthumbs.each do |file_url| timthumbs.each do |file_url|
puts " | [!] " + file_url puts " | [!] #{file_url}"
end end
puts puts
puts " * Reference: http://www.exploit-db.com/exploits/17602/" puts " * Reference: http://www.exploit-db.com/exploits/17602/"
@@ -259,10 +259,10 @@ begin
exit(1) exit(1)
else else
puts puts
puts "We found the following " + usernames.length.to_s + " username/s :" puts "We found the following #{usernames.length.to_s} username/s :"
puts puts
usernames.each {|username| puts " " + username} usernames.each {|username| puts " #{username}"}
end end
else else
@@ -296,7 +296,7 @@ begin
end end
puts puts
puts '[+] Finished at ' + Time.now.asctime puts "[+] Finished at #{Time.now.asctime}"
exit() # must exit! exit() # must exit!
rescue => e rescue => e
puts "[ERROR] #{e.message}" puts "[ERROR] #{e.message}"