wpscan 3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile.lock +139 -0
- data/LICENSE +74 -0
- data/README.md +146 -0
- data/app/app.rb +3 -0
- data/app/controllers.rb +6 -0
- data/app/controllers/brute_force.rb +126 -0
- data/app/controllers/core.rb +104 -0
- data/app/controllers/custom_directories.rb +23 -0
- data/app/controllers/enumeration.rb +53 -0
- data/app/controllers/enumeration/cli_options.rb +126 -0
- data/app/controllers/enumeration/enum_methods.rb +157 -0
- data/app/controllers/main_theme.rb +27 -0
- data/app/controllers/wp_version.rb +30 -0
- data/app/finders.rb +13 -0
- data/app/finders/config_backups.rb +17 -0
- data/app/finders/config_backups/known_filenames.rb +46 -0
- data/app/finders/interesting_findings.rb +33 -0
- data/app/finders/interesting_findings/backup_db.rb +25 -0
- data/app/finders/interesting_findings/debug_log.rb +20 -0
- data/app/finders/interesting_findings/duplicator_installer_log.rb +23 -0
- data/app/finders/interesting_findings/full_path_disclosure.rb +23 -0
- data/app/finders/interesting_findings/mu_plugins.rb +48 -0
- data/app/finders/interesting_findings/multisite.rb +29 -0
- data/app/finders/interesting_findings/readme.rb +26 -0
- data/app/finders/interesting_findings/registration.rb +31 -0
- data/app/finders/interesting_findings/tmm_db_migrate.rb +24 -0
- data/app/finders/interesting_findings/upload_directory_listing.rb +24 -0
- data/app/finders/interesting_findings/upload_sql_dump.rb +28 -0
- data/app/finders/main_theme.rb +22 -0
- data/app/finders/main_theme/css_style.rb +43 -0
- data/app/finders/main_theme/urls_in_homepage.rb +25 -0
- data/app/finders/main_theme/woo_framework_meta_generator.rb +22 -0
- data/app/finders/medias.rb +17 -0
- data/app/finders/medias/attachment_brute_forcing.rb +44 -0
- data/app/finders/plugin_version.rb +44 -0
- data/app/finders/plugin_version/layer_slider/translation_file.rb +40 -0
- data/app/finders/plugin_version/readme.rb +79 -0
- data/app/finders/plugin_version/revslider/release_log.rb +35 -0
- data/app/finders/plugin_version/sitepress_multilingual_cms/meta_generator.rb +27 -0
- data/app/finders/plugin_version/sitepress_multilingual_cms/version_parameter.rb +31 -0
- data/app/finders/plugin_version/w3_total_cache/headers.rb +28 -0
- data/app/finders/plugins.rb +24 -0
- data/app/finders/plugins/comments.rb +31 -0
- data/app/finders/plugins/headers.rb +36 -0
- data/app/finders/plugins/known_locations.rb +48 -0
- data/app/finders/plugins/urls_in_homepage.rb +29 -0
- data/app/finders/theme_version.rb +41 -0
- data/app/finders/theme_version/style.rb +43 -0
- data/app/finders/theme_version/woo_framework_meta_generator.rb +19 -0
- data/app/finders/themes.rb +20 -0
- data/app/finders/themes/known_locations.rb +48 -0
- data/app/finders/themes/urls_in_homepage.rb +23 -0
- data/app/finders/timthumb_version.rb +17 -0
- data/app/finders/timthumb_version/bad_request.rb +21 -0
- data/app/finders/timthumbs.rb +17 -0
- data/app/finders/timthumbs/known_locations.rb +56 -0
- data/app/finders/users.rb +24 -0
- data/app/finders/users/author_id_brute_forcing.rb +111 -0
- data/app/finders/users/author_posts.rb +61 -0
- data/app/finders/users/login_error_messages.rb +50 -0
- data/app/finders/users/wp_json_api.rb +31 -0
- data/app/finders/wp_items.rb +1 -0
- data/app/finders/wp_items/urls_in_homepage.rb +68 -0
- data/app/finders/wp_version.rb +34 -0
- data/app/finders/wp_version/atom_generator.rb +40 -0
- data/app/finders/wp_version/meta_generator.rb +27 -0
- data/app/finders/wp_version/opml_generator.rb +23 -0
- data/app/finders/wp_version/rdf_generator.rb +38 -0
- data/app/finders/wp_version/readme.rb +28 -0
- data/app/finders/wp_version/rss_generator.rb +43 -0
- data/app/finders/wp_version/sitemap_generator.rb +23 -0
- data/app/finders/wp_version/stylesheets.rb +55 -0
- data/app/finders/wp_version/unique_fingerprinting.rb +64 -0
- data/app/models.rb +10 -0
- data/app/models/config_backup.rb +5 -0
- data/app/models/interesting_finding.rb +6 -0
- data/app/models/media.rb +5 -0
- data/app/models/plugin.rb +25 -0
- data/app/models/theme.rb +99 -0
- data/app/models/timthumb.rb +74 -0
- data/app/models/user.rb +31 -0
- data/app/models/wp_item.rb +142 -0
- data/app/models/wp_version.rb +49 -0
- data/app/models/xml_rpc.rb +19 -0
- data/app/views/cli/brute_force/error.erb +1 -0
- data/app/views/cli/brute_force/found.erb +2 -0
- data/app/views/cli/brute_force/users.erb +9 -0
- data/app/views/cli/core/banner.erb +14 -0
- data/app/views/cli/core/db_update_finished.erb +8 -0
- data/app/views/cli/core/db_update_started.erb +1 -0
- data/app/views/cli/core/not_fully_configured.erb +1 -0
- data/app/views/cli/enumeration/config_backups.erb +11 -0
- data/app/views/cli/enumeration/medias.erb +11 -0
- data/app/views/cli/enumeration/plugins.erb +35 -0
- data/app/views/cli/enumeration/themes.erb +11 -0
- data/app/views/cli/enumeration/timthumbs.erb +18 -0
- data/app/views/cli/enumeration/users.erb +11 -0
- data/app/views/cli/finding.erb +32 -0
- data/app/views/cli/info.erb +1 -0
- data/app/views/cli/main_theme/theme.erb +6 -0
- data/app/views/cli/notice.erb +1 -0
- data/app/views/cli/theme.erb +64 -0
- data/app/views/cli/usage.erb +3 -0
- data/app/views/cli/vulnerability.erb +14 -0
- data/app/views/cli/wp_version/version.erb +6 -0
- data/app/views/json/brute_force/users.erb +10 -0
- data/app/views/json/core/banner.erb +12 -0
- data/app/views/json/core/db_update_finished.erb +2 -0
- data/app/views/json/core/db_update_started.erb +1 -0
- data/app/views/json/core/not_fully_configured.erb +1 -0
- data/app/views/json/enumeration/config_backups.erb +10 -0
- data/app/views/json/enumeration/medias.erb +10 -0
- data/app/views/json/enumeration/plugins.erb +25 -0
- data/app/views/json/enumeration/themes.erb +10 -0
- data/app/views/json/enumeration/timthumbs.erb +19 -0
- data/app/views/json/enumeration/users.erb +11 -0
- data/app/views/json/finding.erb +26 -0
- data/app/views/json/main_theme/theme.erb +7 -0
- data/app/views/json/theme.erb +38 -0
- data/app/views/json/wp_version/version.erb +8 -0
- data/bin/wpscan +15 -0
- data/coverage/assets/0.10.0/application.css +799 -0
- data/coverage/assets/0.10.0/application.js +1707 -0
- data/coverage/assets/0.10.0/colorbox/border.png +0 -0
- data/coverage/assets/0.10.0/colorbox/controls.png +0 -0
- data/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
- data/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.10.0/favicon_green.png +0 -0
- data/coverage/assets/0.10.0/favicon_red.png +0 -0
- data/coverage/assets/0.10.0/favicon_yellow.png +0 -0
- data/coverage/assets/0.10.0/loading.gif +0 -0
- data/coverage/assets/0.10.0/magnify.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/index.html +27510 -0
- data/lib/wpscan.rb +44 -0
- data/lib/wpscan/browser.rb +16 -0
- data/lib/wpscan/controller.rb +8 -0
- data/lib/wpscan/controllers.rb +8 -0
- data/lib/wpscan/db.rb +28 -0
- data/lib/wpscan/db/dynamic_finders.rb +63 -0
- data/lib/wpscan/db/plugin.rb +11 -0
- data/lib/wpscan/db/plugins.rb +11 -0
- data/lib/wpscan/db/schema.rb +39 -0
- data/lib/wpscan/db/theme.rb +11 -0
- data/lib/wpscan/db/themes.rb +11 -0
- data/lib/wpscan/db/updater.rb +148 -0
- data/lib/wpscan/db/wp_item.rb +18 -0
- data/lib/wpscan/db/wp_items.rb +21 -0
- data/lib/wpscan/db/wp_version.rb +11 -0
- data/lib/wpscan/errors/http.rb +34 -0
- data/lib/wpscan/errors/update.rb +8 -0
- data/lib/wpscan/errors/wordpress.rb +22 -0
- data/lib/wpscan/finders.rb +14 -0
- data/lib/wpscan/finders/finder/plugin_version/comments.rb +25 -0
- data/lib/wpscan/finders/finder/wp_version/smart_url_checker.rb +23 -0
- data/lib/wpscan/helper.rb +6 -0
- data/lib/wpscan/references.rb +31 -0
- data/lib/wpscan/target.rb +81 -0
- data/lib/wpscan/target/platform/wordpress.rb +74 -0
- data/lib/wpscan/target/platform/wordpress/custom_directories.rb +93 -0
- data/lib/wpscan/version.rb +4 -0
- data/lib/wpscan/vulnerability.rb +25 -0
- data/lib/wpscan/vulnerable.rb +10 -0
- data/wpscan-v3.sublime-project +8 -0
- data/wpscan-v3.sublime-workspace +895 -0
- data/wpscan.gemspec +55 -0
- metadata +419 -0
data/lib/wpscan.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Gems
|
|
2
|
+
require 'cms_scanner'
|
|
3
|
+
require 'yajl/json_gem'
|
|
4
|
+
require 'addressable/uri'
|
|
5
|
+
require 'active_support/all'
|
|
6
|
+
# Standard Lib
|
|
7
|
+
require 'uri'
|
|
8
|
+
require 'time'
|
|
9
|
+
require 'readline'
|
|
10
|
+
require 'securerandom'
|
|
11
|
+
# Custom Libs
|
|
12
|
+
require 'wpscan/helper'
|
|
13
|
+
require 'wpscan/db'
|
|
14
|
+
require 'wpscan/version'
|
|
15
|
+
require 'wpscan/errors/wordpress'
|
|
16
|
+
require 'wpscan/errors/http'
|
|
17
|
+
require 'wpscan/errors/update'
|
|
18
|
+
require 'wpscan/browser'
|
|
19
|
+
require 'wpscan/target'
|
|
20
|
+
require 'wpscan/finders'
|
|
21
|
+
require 'wpscan/controller'
|
|
22
|
+
require 'wpscan/controllers'
|
|
23
|
+
require 'wpscan/references'
|
|
24
|
+
require 'wpscan/vulnerable'
|
|
25
|
+
require 'wpscan/vulnerability'
|
|
26
|
+
|
|
27
|
+
Encoding.default_external = Encoding::UTF_8
|
|
28
|
+
|
|
29
|
+
# WPScan
|
|
30
|
+
module WPScan
|
|
31
|
+
include CMSScanner
|
|
32
|
+
|
|
33
|
+
APP_DIR = Pathname.new(__FILE__).dirname.join('..', 'app').expand_path
|
|
34
|
+
DB_DIR = File.join(Dir.home, '.wpscan', 'db')
|
|
35
|
+
|
|
36
|
+
# Override, otherwise it would be returned as 'wp_scan'
|
|
37
|
+
#
|
|
38
|
+
# @return [ String ]
|
|
39
|
+
def self.app_name
|
|
40
|
+
'wpscan'
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
require "#{WPScan::APP_DIR}/app"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module WPScan
|
|
2
|
+
# Custom Browser
|
|
3
|
+
class Browser < CMSScanner::Browser
|
|
4
|
+
extend Actions
|
|
5
|
+
|
|
6
|
+
# @return [ String ] The path to the user agents list
|
|
7
|
+
def user_agents_list
|
|
8
|
+
@user_agents_list ||= File.join(DB_DIR, 'user-agents.txt')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @return [ String ]
|
|
12
|
+
def default_user_agent
|
|
13
|
+
"WPScan v#{VERSION} (http://wpscan.org/)"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module WPScan
|
|
2
|
+
# Override to set the OptParser's summary width to 45 (instead of 40 from the CMSScanner)
|
|
3
|
+
class Controllers < CMSScanner::Controllers
|
|
4
|
+
def initialize(option_parser = OptParseValidator::OptParser.new(nil, 45))
|
|
5
|
+
super(option_parser)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
end
|
data/lib/wpscan/db.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'dm-core'
|
|
2
|
+
require 'dm-migrations'
|
|
3
|
+
require 'dm-constraints'
|
|
4
|
+
require 'dm-sqlite-adapter'
|
|
5
|
+
|
|
6
|
+
require 'wpscan/db/wp_item'
|
|
7
|
+
require 'wpscan/db/schema'
|
|
8
|
+
require 'wpscan/db/updater'
|
|
9
|
+
require 'wpscan/db/wp_items'
|
|
10
|
+
require 'wpscan/db/plugins'
|
|
11
|
+
require 'wpscan/db/themes'
|
|
12
|
+
require 'wpscan/db/plugin'
|
|
13
|
+
require 'wpscan/db/theme'
|
|
14
|
+
require 'wpscan/db/wp_version'
|
|
15
|
+
require 'wpscan/db/dynamic_finders'
|
|
16
|
+
|
|
17
|
+
module WPScan
|
|
18
|
+
# DB
|
|
19
|
+
module DB
|
|
20
|
+
def self.init_db
|
|
21
|
+
db_file ||= File.join(DB_DIR, 'wordpress.db')
|
|
22
|
+
|
|
23
|
+
# DataMapper::Logger.new($stdout, :debug)
|
|
24
|
+
DataMapper.setup(:default, "sqlite://#{db_file}")
|
|
25
|
+
DataMapper.auto_upgrade!
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module WPScan
|
|
2
|
+
module DB
|
|
3
|
+
# Dynamic Finders
|
|
4
|
+
class DynamicFinders
|
|
5
|
+
# @return [ String ]
|
|
6
|
+
def self.db_file
|
|
7
|
+
@db_file ||= File.join(DB_DIR, 'dynamic_finders.yml')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @return [ Hash ]
|
|
11
|
+
def self.db_data
|
|
12
|
+
@db_data ||= YAML.load_file(db_file)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [ Hash ]
|
|
16
|
+
def self.finder_configs(finder_klass)
|
|
17
|
+
configs = {}
|
|
18
|
+
|
|
19
|
+
db_data.each do |slug, config|
|
|
20
|
+
next unless config[finder_klass]
|
|
21
|
+
|
|
22
|
+
configs[slug] = config[finder_klass].dup
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
configs
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Dynamic Plugin Finders
|
|
30
|
+
class DynamicPluginFinders < DynamicFinders
|
|
31
|
+
# @return [ Hash ]
|
|
32
|
+
def self.db_data
|
|
33
|
+
@db_data ||= super['plugins'] || {}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [ Hash ]
|
|
37
|
+
def self.comments
|
|
38
|
+
unless @comments
|
|
39
|
+
@comments = finder_configs('Comments')
|
|
40
|
+
|
|
41
|
+
@comments.each do |slug, config|
|
|
42
|
+
@comments[slug]['pattern'] = Regexp.new(config['pattern'], Regexp::IGNORECASE)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
@comments
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [ Hash ]
|
|
50
|
+
def self.urls_in_page
|
|
51
|
+
@urls_in_page ||= finder_configs('UrlsInPage')
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Dynamic Theme Finders (none ATM)
|
|
56
|
+
class DynamicThemeFinders < DynamicFinders
|
|
57
|
+
# @return [ Hash ]
|
|
58
|
+
def self.db_data
|
|
59
|
+
@db_data ||= super['themes'] || {}
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module WPScan
|
|
2
|
+
module DB
|
|
3
|
+
# WP Version
|
|
4
|
+
class Version < WpItem
|
|
5
|
+
include DataMapper::Resource
|
|
6
|
+
|
|
7
|
+
storage_names[:default] = 'versions'
|
|
8
|
+
|
|
9
|
+
has n, :fingerprints, constraint: :destroy
|
|
10
|
+
|
|
11
|
+
property :id, Serial
|
|
12
|
+
property :number, String, required: true, unique: true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Path
|
|
16
|
+
class Path
|
|
17
|
+
include DataMapper::Resource
|
|
18
|
+
|
|
19
|
+
storage_names[:default] = 'paths'
|
|
20
|
+
|
|
21
|
+
has n, :fingerprints, constraint: :destroy
|
|
22
|
+
|
|
23
|
+
property :id, Serial
|
|
24
|
+
property :value, String, required: true, unique: true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Fingerprint
|
|
28
|
+
class Fingerprint
|
|
29
|
+
include DataMapper::Resource
|
|
30
|
+
|
|
31
|
+
storage_names[:default] = 'fingerprints'
|
|
32
|
+
|
|
33
|
+
belongs_to :version, key: true
|
|
34
|
+
belongs_to :path, key: true
|
|
35
|
+
|
|
36
|
+
property :md5_hash, String, required: true, length: 32
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
module WPScan
|
|
2
|
+
module DB
|
|
3
|
+
# Class used to perform DB updates
|
|
4
|
+
# :nocov:
|
|
5
|
+
class Updater
|
|
6
|
+
# /!\ Might want to also update the Enumeration#cli_options when some filenames are changed here
|
|
7
|
+
FILES = %w(
|
|
8
|
+
plugins.json themes.json wordpresses.json
|
|
9
|
+
timthumbs-v3.txt user-agents.txt config_backups.txt
|
|
10
|
+
dynamic_finders.yml wordpress.db LICENSE
|
|
11
|
+
).freeze
|
|
12
|
+
|
|
13
|
+
attr_reader :repo_directory
|
|
14
|
+
|
|
15
|
+
def initialize(repo_directory)
|
|
16
|
+
@repo_directory = repo_directory
|
|
17
|
+
|
|
18
|
+
FileUtils.mkdir_p(repo_directory) unless Dir.exist?(repo_directory)
|
|
19
|
+
|
|
20
|
+
raise "#{repo_directory} is not writable" unless Pathname.new(repo_directory).writable?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [ Time, nil ]
|
|
24
|
+
def last_update
|
|
25
|
+
Time.parse(File.read(last_update_file))
|
|
26
|
+
rescue ArgumentError, Errno::ENOENT
|
|
27
|
+
nil # returns nil if the file does not exist or contains invalid time data
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @return [ String ]
|
|
31
|
+
def last_update_file
|
|
32
|
+
@last_update_file ||= File.join(repo_directory, '.last_update')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [ Boolean ]
|
|
36
|
+
def outdated?
|
|
37
|
+
date = last_update
|
|
38
|
+
|
|
39
|
+
date.nil? || date < 5.days.ago
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [ Boolean ]
|
|
43
|
+
def missing_files?
|
|
44
|
+
FILES.each do |file|
|
|
45
|
+
return true unless File.exist?(File.join(repo_directory, file))
|
|
46
|
+
end
|
|
47
|
+
false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @return [ Hash ] The params for Typhoeus::Request
|
|
51
|
+
def request_params
|
|
52
|
+
{
|
|
53
|
+
ssl_verifyhost: 2,
|
|
54
|
+
ssl_verifypeer: true,
|
|
55
|
+
timeout: 300,
|
|
56
|
+
connecttimeout: 120,
|
|
57
|
+
accept_encoding: 'gzip, deflate',
|
|
58
|
+
cache_ttl: 0
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @return [ String ] The raw file URL associated with the given filename
|
|
63
|
+
def remote_file_url(filename)
|
|
64
|
+
"https://data.wpscan.org/#{filename}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @return [ String ] The checksum of the associated remote filename
|
|
68
|
+
def remote_file_checksum(filename)
|
|
69
|
+
url = "#{remote_file_url(filename)}.sha512"
|
|
70
|
+
|
|
71
|
+
res = Browser.get(url, request_params)
|
|
72
|
+
raise DownloadError, res if res.timed_out? || res.code != 200
|
|
73
|
+
res.body.chomp
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def local_file_path(filename)
|
|
77
|
+
File.join(repo_directory, filename.to_s)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def local_file_checksum(filename)
|
|
81
|
+
Digest::SHA512.file(local_file_path(filename)).hexdigest
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def backup_file_path(filename)
|
|
85
|
+
File.join(repo_directory, "#{filename}.back")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def create_backup(filename)
|
|
89
|
+
return unless File.exist?(local_file_path(filename))
|
|
90
|
+
FileUtils.cp(local_file_path(filename), backup_file_path(filename))
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def restore_backup(filename)
|
|
94
|
+
return unless File.exist?(backup_file_path(filename))
|
|
95
|
+
FileUtils.cp(backup_file_path(filename), local_file_path(filename))
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def delete_backup(filename)
|
|
99
|
+
FileUtils.rm(backup_file_path(filename))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# @return [ String ] The checksum of the downloaded file
|
|
103
|
+
def download(filename)
|
|
104
|
+
file_path = local_file_path(filename)
|
|
105
|
+
file_url = remote_file_url(filename)
|
|
106
|
+
|
|
107
|
+
res = Browser.get(file_url, request_params)
|
|
108
|
+
raise DownloadError, res if res.timed_out? || res.code != 200
|
|
109
|
+
|
|
110
|
+
File.open(file_path, 'wb') { |f| f.write(res.body) }
|
|
111
|
+
|
|
112
|
+
local_file_checksum(filename)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# rubocop:disable MethodLength
|
|
116
|
+
# @return [ Array<String> ] The filenames updated
|
|
117
|
+
def update
|
|
118
|
+
updated = []
|
|
119
|
+
|
|
120
|
+
FILES.each do |filename|
|
|
121
|
+
begin
|
|
122
|
+
db_checksum = remote_file_checksum(filename)
|
|
123
|
+
|
|
124
|
+
# Checking if the file needs to be updated
|
|
125
|
+
next if File.exist?(local_file_path(filename)) && db_checksum == local_file_checksum(filename)
|
|
126
|
+
|
|
127
|
+
create_backup(filename)
|
|
128
|
+
dl_checksum = download(filename)
|
|
129
|
+
|
|
130
|
+
raise "#{filename}: checksums do not match" unless dl_checksum == db_checksum
|
|
131
|
+
updated << filename
|
|
132
|
+
rescue => e
|
|
133
|
+
restore_backup(filename)
|
|
134
|
+
raise e
|
|
135
|
+
ensure
|
|
136
|
+
delete_backup(filename) if File.exist?(backup_file_path(filename))
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
File.write(last_update_file, Time.now)
|
|
141
|
+
|
|
142
|
+
updated
|
|
143
|
+
end
|
|
144
|
+
# rubocop:enable MethodLength
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
# :nocov:
|
|
148
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module WPScan
|
|
2
|
+
module DB
|
|
3
|
+
# WpItem - super DB class for Plugin, Theme and Version
|
|
4
|
+
class WpItem
|
|
5
|
+
# @param [ String ] identifier The plugin/theme slug or version number
|
|
6
|
+
#
|
|
7
|
+
# @return [ Hash ] The JSON data from the DB associated to the identifier
|
|
8
|
+
def self.db_data(identifier)
|
|
9
|
+
db[identifier] || {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @return [ JSON ]
|
|
13
|
+
def self.db
|
|
14
|
+
@db ||= read_json_file(db_file)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module WPScan
|
|
2
|
+
module DB
|
|
3
|
+
# WP Items
|
|
4
|
+
class WpItems
|
|
5
|
+
# @return [ Array<String> ] The slug of all items
|
|
6
|
+
def self.all_slugs
|
|
7
|
+
db.keys
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @return [ Array<String> ] The slug of all popular items
|
|
11
|
+
def self.popular_slugs
|
|
12
|
+
db.select { |_key, item| item['popular'] == true }.keys
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [ Array<String> ] The slug of all vulnerable items
|
|
16
|
+
def self.vulnerable_slugs
|
|
17
|
+
db.select { |_key, item| !item['vulnerabilities'].empty? }.keys
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|