Merge branch 'new-enumeration-system'

This commit is contained in:
erwanlr
2013-04-05 14:07:06 +02:00
292 changed files with 6555 additions and 26491 deletions

View File

@@ -1,36 +1,19 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 BruteForce
# param array of string logins
# param array of WpUsers wp_users
# param string wordlist_path
# param hash options
# boolean :show_progression If true, will output the details (Sucess, error etc)
def brute_force(logins, wordlist_path, options = {})
def brute_force(wp_users, wordlist_path, options = {})
hydra = Browser.instance.hydra
number_of_passwords = BruteForce.lines_in_file(wordlist_path)
login_url = login_url()
found = []
show_progression = options[:show_progression] || false
logins.each do |login|
wp_users.each do |wp_user|
queue_count = 0
request_count = 0
password_found = false
@@ -46,14 +29,14 @@ module BruteForce
queue_count += 1
# create local vars for on_complete call back, Issue 51.
username = login.name != 'empty' ? login.name : login.nickname # Issue #66
login = wp_user.login
password = password
# the request object
request = Browser.instance.forge_request(login_url,
{
method: :post,
body: { log: URI::encode(username), pwd: URI::encode(password) },
body: { log: URI::encode(login), pwd: URI::encode(password) },
cache_ttl: 0
}
)
@@ -61,13 +44,13 @@ module BruteForce
# tell hydra what to do when the request completes
request.on_complete do |response|
puts "\n Trying Username : #{username} Password : #{password}" if @verbose
puts "\n Trying Username : #{login} Password : #{password}" if @verbose
if response.body =~ /login_error/i
puts "\nIncorrect username and/or password." if @verbose
puts "\nIncorrect login 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]') + " Login : #{login} Password : #{password}\n" if show_progression
found << { name: login, password: password }
password_found = true
elsif response.timed_out?
puts red('ERROR:') + ' Request timed out.' if show_progression
@@ -86,14 +69,14 @@ module BruteForce
end
end
# move onto the next username if we have found a valid password
# move onto the next login if we have found a valid password
break if password_found
# queue the request to be sent later
hydra.queue(request)
# progress indicator
print "\r Brute forcing user '#{username}' with #{number_of_passwords} passwords... #{(request_count * 100) / number_of_passwords}% complete." if show_progression
print "\r Brute forcing user '#{login}' with #{number_of_passwords} passwords... #{(request_count * 100) / number_of_passwords}% complete." if show_progression
# it can take a long time to queue 2 million requests,
# for that reason, we queue @threads, send @threads, queue @threads and so on.

View File

@@ -1,21 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 Malwares
# Used as cache :

View File

@@ -1,21 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WpConfigBackup

View File

@@ -1,21 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WpFullPathDisclosure

View File

@@ -1,21 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WpLoginProtection
@@ -38,10 +21,10 @@ module WpLoginProtection
plugin_name = symbol_to_call[LOGIN_PROTECTION_METHOD_PATTERN, 1].gsub('_', '-')
return @login_protection_plugin = WpPlugin.new(
@uri,
name: plugin_name,
base_url: @uri,
path: "/plugins/#{plugin_name}/",
wp_content_dir: @wp_content_dir
wp_content_dir: wp_content_dir,
wp_plugins_dir: wp_plugins_dir
)
end
end
@@ -54,38 +37,39 @@ module WpLoginProtection
# Thanks to Alip Aswalid for providing this method.
# http://wordpress.org/extend/plugins/login-lockdown/
def has_login_lockdown_protection?
Browser.instance.get(login_url()).body =~ %r{Login LockDown}i ? true : false
Browser.instance.get(login_url).body =~ %r{Login LockDown}i ? true : false
end
# http://wordpress.org/extend/plugins/login-lock/
def has_login_lock_protection?
Browser.instance.get(login_url()).body =~ %r{LOGIN LOCK} ? true : false
Browser.instance.get(login_url).body =~ %r{LOGIN LOCK} ? true : false
end
# http://wordpress.org/extend/plugins/better-wp-security/
def has_better_wp_security_protection?
Browser.instance.get(better_wp_security_url()).code != 404
Browser.instance.get(better_wp_security_url).code != 404
end
def plugin_url(plugin_name)
WpPlugin.new(
@uri,
name: plugin_name,
wp_content_dir: wp_content_dir,
wp_plugins_dir: wp_plugins_dir
).url
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'
).get_url_without_filename
plugin_url('better-wp-security/')
end
# http://wordpress.org/extend/plugins/simple-login-lockdown/
def has_simple_login_lockdown_protection?
Browser.instance.get(simple_login_lockdown_url()).code != 404
Browser.instance.get(simple_login_lockdown_url).code != 404
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'
).get_url_without_filename
plugin_url('simple-login-lockdown/')
end
# http://wordpress.org/extend/plugins/login-security-solution/
@@ -94,36 +78,24 @@ 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'
).get_url_without_filename
plugin_url('login-security-solution')
end
# http://wordpress.org/extend/plugins/limit-login-attempts/
def has_limit_login_attempts_protection?
Browser.instance.get(limit_login_attempts_url()).code != 404
Browser.instance.get(limit_login_attempts_url).code != 404
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'
).get_url_without_filename
plugin_url('limit-login-attempts')
end
# http://wordpress.org/extend/plugins/bluetrait-event-viewer/
def has_bluetrait_event_viewer_protection?
Browser.instance.get(bluetrait_event_viewer_url()).code != 404
Browser.instance.get(bluetrait_event_viewer_url).code != 404
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'
).get_url_without_filename
plugin_url('bluetrait-event-viewer')
end
end

View File

@@ -1,72 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WpPlugins
# Enumerate installed plugins.
#
# 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_xpath] = "//plugin[@name='#{@name}']/vulnerability"
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
)
end
plugins.sort_by { |p| p.name }
end
# http://code.google.com/p/wpscan/issues/detail?id=42
# plugins 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'/>
# ...
# return array of WpPlugin
def plugins_from_passive_detection(options)
plugins = []
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]
)
end
plugins.sort_by { |p| p.name }
end
end

View File

@@ -1,21 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WpReadme

View File

@@ -1,59 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 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_xpath] = "//theme[@name='#{@name}']/vulnerability"
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
)
end
themes.sort_by { |t| t.name }
end
def themes_from_passive_detection(options)
themes = []
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]
)
end
themes.sort_by { |t| t.name }
end
end

View File

@@ -1,74 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WpTimthumbs
# Used as cache :
# nil => timthumbs not checked,
# [] => no timthumbs,
# otherwise array of timthumbs url found
@wp_timthumbs = nil
def has_timthumbs?(theme_name, options = {})
!timthumbs(theme_name, options).empty?
end
def timthumbs(theme_name = nil, options = {})
if @wp_timthumbs.nil?
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'
WpOptions.check_options(options)
if theme_name == nil
custom_items = nil
else
custom_items = targets_url_from_theme(theme_name, options)
end
@wp_timthumbs = WpEnumerator.enumerate(options, custom_items)
end
@wp_timthumbs
end
protected
def targets_url_from_theme(theme_name, options)
targets = []
theme_name = URI.escape(theme_name)
%w{
timthumb.php lib/timthumb.php inc/timthumb.php includes/timthumb.php
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]
)
end
targets
end
end

View File

@@ -1,117 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WpUsernames
# Enumerate wordpress usernames by using Veronica Valeros's technique:
# http://seclists.org/fulldisclosure/2011/May/493
#
# Available options :
# :range - default : 1..10
#
# returns an array of WpUser (can be empty)
def usernames(options = {})
range = options[:range] || (1..10)
browser = Browser.instance
usernames = []
range.each do |author_id|
url = author_url(author_id)
response = browser.get(url)
username = nil
nickname = nil
if response.code == 301 # username in location?
username = response.headers_hash['location'][%r{/author/([^/\b]+)/?}i, 1]
# Get the real name from the redirect site
nickname = get_nickname_from_url(url)
elsif response.code == 200 # username in body?
# get the username from the author feed URL
username = get_username_from_response(response)
nickname = get_nickname_from_response(response)
end
unless username == nil and nickname == nil
usernames << WpUser.new(username, author_id, nickname)
end
end
usernames = remove_junk_from_nickname(usernames)
# clean the array, remove nils and possible duplicates
usernames.flatten!
usernames.compact!
usernames.uniq
end
def get_nickname_from_url(url)
resp = Browser.instance.get_and_follow_location(url)
nickname = nil
if resp.code == 200
nickname = extract_nickname_from_body(resp.body)
end
nickname
end
def get_nickname_from_response(resp)
nickname = nil
if resp.code == 200
nickname = extract_nickname_from_body(resp.body)
end
nickname
end
def get_username_from_response(resp)
# Feed URL with Permalinks
username = resp.body[%r{/author/([^/\b]+)/?}i, 1]
if username.nil?
# No Permalinks
username = resp.body[%r{<body class="archive author author-([^\s]+) author-(\d+)}i, 1]
end
username
end
def extract_nickname_from_body(body)
body[%r{<title>([^<]*)</title>}i, 1]
end
def remove_junk_from_nickname(usernames)
unless usernames.kind_of? Array
raise('Need an array as input')
end
nicknames = []
usernames.each do |u|
unless u.kind_of? WpUser
raise('Items must be of type WpUser')
end
nickname = u.nickname
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)}$/, '')
end
usernames
end
def author_url(author_id)
@uri.merge("?author=#{author_id}").to_s
end
end

View File

@@ -1,40 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 Vulnerable
attr_reader :vulns_file, :vulns_xpath
# @return an array of WpVulnerability (can be empty)
def vulnerabilities
xml = xml(@vulns_file)
vulnerabilities = []
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)
)
end
vulnerabilities
end
end

View File

@@ -1,21 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WebSite

View File

@@ -1,78 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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
if items == nil or items.length == 0
unless options[:only_vulnerable_ones]
result = passive_detection(options[:base_url], options[:type], options[:wp_content_dir])
end
end
enum_results = WpEnumerator.enumerate(options)
enum_results.each do |enum_result|
already_present = false
result.each do |r|
# Already found via passive detection
if r.name == enum_result.name
already_present = true
break
end
end
unless already_present
result << enum_result
end
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}#{Regexp.escape(wp_content_dir)}#{regex2}#{Regexp.escape(type)}#{regex3}/i)
names.flatten!
names.uniq!
names.each do |item|
items << WpItem.new(
base_url: url,
name: item,
type: type,
path: "#{item}/",
wp_content_dir: wp_content_dir,
vulns_file: ''
)
end
items
end
end

View File

@@ -1,146 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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_progression+ - Show a progress bar during enumeration
def self.enumerate(options = {}, items = nil)
WpOptions.check_options(options)
targets = self.generate_items(options)
unless items == nil
items.each do |i|
targets << i
end
end
found = []
queue_count = 0
request_count = 0
enum_browser = Browser.instance
enum_hydra = enum_browser.hydra
enumerate_size = targets.size
exclude_regexp = options[:exclude_content_based] ? %r{#{options[:exclude_content_based]}} : nil
show_progression = options[:show_progression] || false
targets.each do |target|
url = target.get_full_url
request = enum_browser.forge_request(url, cache_ttl: 0, followlocation: true)
request_count += 1
request.on_complete do |response|
page_hash = Digest::MD5.hexdigest(response.body)
print "\rChecking for #{enumerate_size} total #{options[:type]}... #{(request_count * 100) / enumerate_size}% complete." if show_progression
if WpTarget.valid_response_codes.include?(response.code)
if page_hash != options[:error_404_hash] and page_hash != options[:homepage_hash]
if options[:exclude_content_based]
unless response.body[exclude_regexp]
found << target
end
else
found << target
end
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
protected
def self.generate_items(options = {})
only_vulnerable = options[:only_vulnerable_ones]
file = options[:file]
vulns_file = options[:vulns_file]
wp_content_dir = options[:wp_content_dir]
url = options[:base_url]
type = options[:type]
plugins_dir = options[:wp_plugins_dir]
targets_url = []
unless only_vulnerable
# Open and parse the 'most popular' plugin list...
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
)
end
end
end
# Timthumbs have no XML file
unless type =~ /timthumbs/i
xml = xml(vulns_file)
# 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
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
)
end
end
targets_url.flatten! { |t| t.name }
targets_url.uniq! { |t| t.name }
# randomize the plugins array to *maybe* help in some crappy IDS/IPS/WAF detection
targets_url.sort_by! { rand }
end
end

View File

@@ -1,196 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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/>.
#++
require "wpscan/vulnerable"
class WpItem < Vulnerable
attr_reader :base_url, :path, :wp_content_dir, :name, :vulns_file, :vulns_xpath, :wp_plugins_dir, :type
@version = nil
def initialize(options)
@type = options[:type]
@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]
@name = options[:name] || extract_name_from_url
@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
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")
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")
end
f = File.readlines(file, encoding: 'UTF-8').grep(/^#{Regexp.escape(@name)}$/i)
f.empty? ? false : true
end
def get_sub_folder
case @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/"
# remove first and last /
wp_content_dir = @wp_content_dir.sub(/^\//, "").sub(/\/$/, '')
# remove first /
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'
# timthumbs have folder in path variable
ret = URI.parse(URI.encode("#{url}#{wp_content_dir}/#{path}"))
else
ret = URI.parse(URI.encode("#{url}#{wp_content_dir}/#{get_sub_folder}/#{path}"))
end
ret
end
# Gets the full url for this item without filenames
def get_url_without_filename
location_url = get_full_url.to_s
valid_location_url = location_url[%r{^(https?://.*/)[^.]+\.[^/]+$}, 1]
unless valid_location_url
valid_location_url = add_trailing_slash(location_url)
end
URI.parse(URI.encode(valid_location_url))
end
# Returns version number from readme.txt if it exists
def version
unless @version
response = Browser.instance.get(readme_url.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(get_url_without_filename).body[%r{<title>Index of}] ? true : false
end
# Extract item name from a url
def extract_name_from_url
get_full_url.to_s[%r{^(https?://.*/([^/]+)/)}i, 2]
end
# To string. Adds a version number if detected
def to_s
item_version = version
"#@name#{' v' + item_version.strip if item_version}"
end
# Compare
def ==(other)
other.name == self.name
end
# Compare
def ===(other)
other.name == self.name
end
# Compare
def <=>(other)
other.name <=> self.name
end
# Url for readme.txt
def readme_url
get_url_without_filename.merge('readme.txt')
end
# Url for changelog.txt
def changelog_url
get_url_without_filename.merge('changelog.txt')
end
def error_log_url
get_url_without_filename.merge('error_log')
end
# Discover any error_log files created by WordPress
# These are created by the WordPress error_log() function
# They are normally found in the /plugins/ directory,
# 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[%r{PHP Fatal error}i] ? true : false
end
# readme.txt present?
def has_readme?
unless @readme
status = Browser.instance.get(readme_url).code
@readme = status == 200 ? true : false
end
@readme
end
# changelog.txt present?
def has_changelog?
unless @changelog
status = Browser.instance.get(changelog_url).code
@changelog = status == 200 ? true : false
end
@changelog
end
end

View File

@@ -1,52 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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/>.
#++
# Options Hash
#
# ==== Options
#
# * +url+ - The base URL of the WordPress site
# * +only_vulnerable_ones+ - Only detect vulnerable items
# * +file+ - Filename with items to detect
# * +vulns_file+ - XML file with vulnerabilities
# * +vulns_xpath+ - XPath for vulnerability XML file
# * +vulns_xpath_2+ - XPath for vulnerability XML file
# * +wp_content_dir+ - Name of the wp-content directory
# * +show_progression+ - Show a progress bar during enumeration
# * +error_404_hash+ - MD5 hash of a 404 page
# * +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
unless options[:type] =~ /plugins/i or options[:type] =~ /themes/i or options[:type] =~ /timthumbs/i
raise("Unknown type #{options[:type]}")
end
end
end

View File

@@ -1,32 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WpPlugin < WpItem
def initialize(options = {})
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'
super(options)
end
end

View File

@@ -1,21 +1,12 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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/>.
#++
require 'web_site'
require 'modules/wp_readme'
require 'modules/wp_full_path_disclosure'
require 'modules/wp_config_backup'
require 'modules/wp_login_protection'
require 'modules/malwares'
require 'modules/brute_force'
class WpTarget < WebSite
include WpReadme
@@ -23,10 +14,6 @@ class WpTarget < WebSite
include WpConfigBackup
include WpLoginProtection
include Malwares
include WpUsernames
include WpTimthumbs
include WpPlugins
include WpThemes
include BruteForce
attr_reader :verbose
@@ -90,9 +77,21 @@ class WpTarget < WebSite
WpTheme.find(@uri)
end
# return WpVersion
def version
WpVersion.find(@uri, wp_content_dir)
# @param [ String ] versions_xml
#
# @return [ WpVersion ]
def version(versions_xml)
WpVersion.find(@uri, wp_content_dir, wp_plugins_dir, versions_xml)
end
def has_plugin?(name, version = nil)
WpPlugin.new(
@uri,
name: name,
version: version,
wp_content_dir: wp_content_dir,
wp_plugins_dir: wp_plugins_dir
).exists?
end
def wp_content_dir

View File

@@ -1,115 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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/>.
#++
require "wpscan/vulnerable"
class WpTheme < WpItem
attr_reader :style_url, :version
def initialize(options = {})
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'
@version = options[:version]
@style_url = options[:style_url]
super(options)
end
def version
unless @version
if @style_url
url = @style_url
else
url = default_style_url
end
@version = Browser.instance.get(url).body[%r{Version:\s([^\s]+)}i, 1]
# Get Version from readme.txt
if @version.nil?
@version = super
end
end
@version
end
def default_style_url
get_url_without_filename.merge('style.css')
end
def self.find(target_uri)
self.methods.grep(/find_from_/).each do |method_to_call|
theme = self.send(method_to_call, target_uri)
return theme if theme
end
nil
end
def ===(wp_theme)
wp_theme.name === @name and wp_theme.version === @version
end
protected
# Discover the wordpress theme name by parsing the css link rel
def self.find_from_css_link(target_uri)
response = Browser.instance.get_and_follow_location(target_uri.to_s)
# https + domain is optional because of relative links
matches = %r{(?:https?://[^"']+)?/([^/]+)/themes/([^"']+)/style.css}i.match(response.body)
if matches
style_url = matches[0]
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
)
end
end
# http://code.google.com/p/wpscan/issues/detail?id=141
def self.find_from_wooframework(target_uri)
body = Browser.instance.get(target_uri.to_s).body
regexp = %r{<meta name="generator" content="([^\s"]+)\s?([^"]+)?" />\s+<meta name="generator" content="WooFramework\s?([^"]+)?" />}
matches = regexp.match(body)
if matches
woo_theme_name = matches[1]
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: target_uri.to_s,
path: woo_theme_name
)
end
end
end

View File

@@ -1,76 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WpUser
def name
if @name.nil? or @name.to_s.strip.empty?
return 'empty'
end
@name
end
def name=(new_name)
@name = new_name
end
def id
if @id.nil? or @id.to_s.strip.empty?
return 'empty'
end
@id
end
def id=(new_id)
@id = new_id
end
def nickname
if @nickname.nil? or @nickname.to_s.strip.empty?
return 'empty'
end
@nickname
end
def nickname=(new_nickname)
@nickname = new_nickname
end
def initialize(name, id, nickname)
self.name = name
self.id = id
self.nickname = nickname
end
def <=>(other)
other.name <=> self.name
end
def ==(other)
self === other
end
def ===(other)
other.name === self.name and other.id === self.id and other.nickname === self.nickname
end
def eql?(other)
self === other
end
end

View File

@@ -1,202 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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/>.
#++
require "wpscan/vulnerable"
class WpVersion < Vulnerable
attr_reader :number, :discovery_method
def initialize(number, options = {})
@number = number
@discovery_method = options[:discovery_method]
@vulns_file = options[:vulns_file] || WP_VULNS_FILE
@vulns_xpath = "//wordpress[@version='#{@number}']/vulnerability"
end
# Will use all method self.find_from_* to try to detect the version
# Once the version is found, it will return a WpVersion object
# The method_name will be without 'find_from_' and '_' will be replace by ' ' (IE 'meta generator', 'rss generator' etc)
# If the version is not found, nil is returned
#
# The order in which the find_from_* methods are is important, they will be called in the same order
# (find_from_meta_generator, find_from_rss_generator etc)
def self.find(target_uri, wp_content_dir)
options = {
base_uri: 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('_', ' '))
end
end
nil
end
protected
# Returns the first match of <pattern> in the body of the url
def self.scan_url(base_uri, pattern, path = nil)
url = path ? base_uri.merge(path).to_s : base_uri.to_s
response = Browser.instance.get_and_follow_location(url)
response.body[pattern, 1]
end
#
# DO NOT Change the order of the following methods
# unless you know what you are doing
# See WpVersion.find
#
# Attempts to find the wordpress version from,
# the generator meta tag in the html source.
#
# The meta tag can be removed however it seems,
# that it is reinstated on upgrade.
def self.find_from_meta_generator(options)
WpVersion.scan_url(
options[:base_uri],
%r{name="generator" content="wordpress #{WpVersion.version_pattern}"}i
)
end
# Attempts to find the WordPress version from,
# the generator tag in the RSS feed source.
def self.find_from_rss_generator(options)
WpVersion.scan_url(
options[:base_uri],
%r{<generator>http://wordpress.org/\?v=#{WpVersion.version_pattern}</generator>}i,
'feed/'
)
end
# Attempts to find WordPress version from,
# the generator tag in the RDF feed source.
def self.find_from_rdf_generator(options)
WpVersion.scan_url(
options[:base_uri],
%r{<admin:generatorAgent rdf:resource="http://wordpress.org/\?v=#{WpVersion.version_pattern}" />}i,
'feed/rdf/'
)
end
# Attempts to find the WordPress version from,
# the generator tag in the RSS2 feed source.
#
# Have not been able to find an example of this - Ryan
#def self.find_from_rss2_generator(options)
# WpVersion.scan_url(
# options[:base_uri],
# %r{<generator>http://wordpress.org/?v=(#{WpVersion.version_pattern})</generator>}i,
# 'feed/rss/'
# )
#end
# Attempts to find the WordPress version from,
# the generator tag in the Atom source.
def self.find_from_atom_generator(options)
WpVersion.scan_url(
options[:base_uri],
%r{<generator uri="http://wordpress.org/" version="#{WpVersion.version_pattern}">WordPress</generator>}i,
'feed/atom/'
)
end
# Attempts to find the WordPress version from,
# the generator tag in the comment rss source.
#
# Have not been able to find an example of this - Ryan
#def self.find_from_comments_rss_generator(options)
# WpVersion.scan_url(
# options[:base_uri],
# %r{<!-- generator="WordPress/#{WpVersion.version_pattern}" -->}i,
# 'comments/feed/'
# )
#end
# Uses data/wp_versions.xml to try to identify a
# wordpress version.
#
# It does this by using client side file hashing
#
# /!\ Warning : this method might return false positive if the file used for fingerprinting is part of a theme (they can be updated)
#
def self.find_from_advanced_fingerprinting(options)
target_uri = options[:base_uri]
version_xml = options[:version_xml] || WP_VERSIONS_FILE # needed for rpsec
wp_content = options[:wp_content_dir]
wp_plugins = "#{wp_content}/plugins"
xml = xml(version_xml)
xml.xpath('//file').each do |node|
file_src = node.attribute('src').text
file_url = target_uri.merge(file_src).to_s.
gsub(/\$wp-plugins\$/i, wp_plugins).
gsub(/\$wp-content\$/i, wp_content)
response = Browser.instance.get(file_url)
md5sum = Digest::MD5.hexdigest(response.body)
node.search('hash').each do |hash|
if hash.attribute('md5').text == md5sum
return hash.search('version').text
end
end
end
nil
end
# Attempts to find the WordPress version from the readme.html file.
def self.find_from_readme(options)
WpVersion.scan_url(
options[:base_uri],
%r{<br />\sversion #{WpVersion.version_pattern}}i,
'readme.html'
)
end
# Attempts to find the WordPress version from the sitemap.xml file.
#
# See: http://code.google.com/p/wpscan/issues/detail?id=109
def self.find_from_sitemap_generator(options)
WpVersion.scan_url(
options[:base_uri],
%r{generator="wordpress/#{WpVersion.version_pattern}"}i,
'sitemap.xml'
)
end
# Attempts to find the WordPress version from the p-links-opml.php file.
def self.find_from_links_opml(options)
WpVersion.scan_url(
options[:base_uri],
%r{generator="wordpress/#{WpVersion.version_pattern}"}i,
'wp-links-opml.php'
)
end
# Used to check if the version is correct: must contain at least one dot.
def self.version_pattern
'([^\r\n"\']+\.[^\r\n"\']+)'
end
end

View File

@@ -1,29 +0,0 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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 WpVulnerability
attr_accessor :title, :references, :type, :metasploit_modules
def initialize(title, references, type, metasploit_modules)
@title = title
@references = references
@type = type
@metasploit_modules = metasploit_modules
end
end

View File

@@ -1,21 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# 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/>.
#++
require File.expand_path(File.dirname(__FILE__) + '/../common/common_helper')

View File

@@ -1,21 +1,4 @@
# encoding: UTF-8
#--
# WPScan - WordPress Security Scanner
# Copyright (C) 2012-2013
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
class WpscanOptions