Merge with master

This commit is contained in:
erwanlr
2019-08-30 08:57:22 +01:00
66 changed files with 1205 additions and 199 deletions

View File

@@ -13,7 +13,8 @@ require 'uri'
require 'time'
require 'readline'
require 'securerandom'
# Monkey Patches/Fixes/Override
require 'wpscan/typhoeus/response' # Adds a from_vuln_api? method
# Custom Libs
require 'wpscan/helper'
require 'wpscan/db'
@@ -38,12 +39,28 @@ module WPScan
APP_DIR = Pathname.new(__FILE__).dirname.join('..', 'app').expand_path
DB_DIR = Pathname.new(Dir.home).join('.wpscan', 'db')
Typhoeus.on_complete do |response|
next if response.cached? || !response.from_vuln_api?
self.api_requests += 1
end
# Override, otherwise it would be returned as 'wp_scan'
#
# @return [ String ]
def self.app_name
'wpscan'
end
# @return [ Integer ]
def self.api_requests
@@api_requests ||= 0
end
# @param [ Integer ] value
def self.api_requests=(value)
@@api_requests = value
end
end
require "#{WPScan::APP_DIR}/app"

View File

@@ -7,7 +7,7 @@ module WPScan
# @return [ String ]
def default_user_agent
"WPScan v#{VERSION} (https://wpscan.org/)"
@default_user_agent ||= "WPScan v#{VERSION} (https://wpscan.org/)"
end
end
end

View File

@@ -10,6 +10,8 @@ require_relative 'db/theme'
require_relative 'db/wp_version'
require_relative 'db/fingerprints'
require_relative 'db/vuln_api'
require_relative 'db/dynamic_finders/base'
require_relative 'db/dynamic_finders/plugin'
require_relative 'db/dynamic_finders/theme'

View File

@@ -4,9 +4,9 @@ module WPScan
module DB
# Plugin DB
class Plugin < WpItem
# @return [ String ]
def self.db_file
@db_file ||= DB_DIR.join('plugins.json').to_s
# @return [ Hash ]
def self.metadata
@metadata ||= super['plugins'] || {}
end
end
end

View File

@@ -5,8 +5,8 @@ module WPScan
# WP Plugins
class Plugins < WpItems
# @return [ JSON ]
def self.db
Plugin.db
def self.metadata
Plugin.metadata
end
end
end

View File

@@ -4,9 +4,9 @@ module WPScan
module DB
# Theme DB
class Theme < WpItem
# @return [ String ]
def self.db_file
@db_file ||= DB_DIR.join('themes.json').to_s
# @return [ Hash ]
def self.metadata
@metadata ||= super['themes'] || {}
end
end
end

View File

@@ -5,8 +5,8 @@ module WPScan
# WP Themes
class Themes < WpItems
# @return [ JSON ]
def self.db
Theme.db
def self.metadata
Theme.metadata
end
end
end

View File

@@ -7,12 +7,15 @@ module WPScan
class Updater
# /!\ Might want to also update the Enumeration#cli_options when some filenames are changed here
FILES = %w[
plugins.json themes.json wordpresses.json
metadata.json wp_fingerprints.json
timthumbs-v3.txt config_backups.txt db_exports.txt
dynamic_finders.yml wp_fingerprints.json LICENSE
dynamic_finders.yml LICENSE
].freeze
OLD_FILES = %w[wordpress.db user-agents.txt dynamic_finders_01.yml].freeze
OLD_FILES = %w[
wordpress.db user-agents.txt dynamic_finders_01.yml
wordpresses.json plugins.json themes.json
].freeze
attr_reader :repo_directory

78
lib/wpscan/db/vuln_api.rb Normal file
View File

@@ -0,0 +1,78 @@
# frozen_string_literal: true
module WPScan
module DB
# WPVulnDB API
class VulnApi
NON_ERROR_CODES = [200, 401, 404].freeze
class << self
attr_accessor :token
end
# @return [ Addressable::URI ]
def self.uri
@uri ||= Addressable::URI.parse('https://wpvulndb.com/api/v3/')
end
# @param [ String ] path
# @param [ Hash ] params
#
# @return [ Hash ]
def self.get(path, params = {})
return {} unless token
res = Browser.get(uri.join(path), params.merge(request_params))
return JSON.parse(res.body) if NON_ERROR_CODES.include?(res.code)
raise Error::HTTP, res
rescue Error::HTTP => e
retries ||= 0
if (retries += 1) <= 3
sleep(1)
retry
end
{ 'http_error' => e }
end
# @return [ Hash ]
def self.plugin_data(slug)
get("plugins/#{slug}")&.dig(slug) || {}
end
# @return [ Hash ]
def self.theme_data(slug)
get("themes/#{slug}")&.dig(slug) || {}
end
# @return [ Hash ]
def self.wordpress_data(version_number)
get("wordpresses/#{version_number.tr('.', '')}")&.dig(version_number) || {}
end
# @return [ Hash ]
def self.status
json = get('status', params: { version: WPScan::VERSION }, cache_ttl: 0)
json['requests_remaining'] = 'Unlimited' if json['requests_remaining'] == -1
json
end
# @return [ Hash ]
def self.request_params
{
headers: {
'Host' => uri.host, # Reset in case user provided a --vhost for the target
'Referer' => nil, # Removes referer set by the cmsscanner to the target url
'User-Agent' => Browser.instance.default_user_agent,
'Authorization' => "Token token=#{token}"
}
}
end
end
end
end

View File

@@ -6,14 +6,19 @@ module WPScan
class WpItem
# @param [ String ] identifier The plugin/theme slug or version number
#
# @return [ Hash ] The JSON data from the DB associated to the identifier
def self.db_data(identifier)
db[identifier] || {}
# @return [ Hash ] The JSON data from the metadata associated to the identifier
def self.metadata_at(identifier)
metadata[identifier] || {}
end
# @return [ JSON ]
def self.db
@db ||= read_json_file(db_file)
def self.metadata
@metadata ||= read_json_file(metadata_file)
end
# @return [ String ]
def self.metadata_file
@metadata_file ||= DB_DIR.join('metadata.json').to_s
end
end
end

View File

@@ -6,17 +6,17 @@ module WPScan
class WpItems
# @return [ Array<String> ] The slug of all items
def self.all_slugs
db.keys
metadata.keys
end
# @return [ Array<String> ] The slug of all popular items
def self.popular_slugs
db.select { |_key, item| item['popular'] == true }.keys
metadata.select { |_key, item| item['popular'] == true }.keys
end
# @return [ Array<String> ] The slug of all vulnerable items
def self.vulnerable_slugs
db.reject { |_key, item| item['vulnerabilities'].empty? }.keys
metadata.select { |_key, item| item['vulnerabilities'] == true }.keys
end
end
end

View File

@@ -4,9 +4,9 @@ module WPScan
module DB
# WP Version
class Version < WpItem
# @return [ String ]
def self.db_file
@db_file ||= DB_DIR.join('wordpresses.json').to_s
# @return [ Hash ]
def self.metadata
@metadata ||= super['wordpress'] || {}
end
end
end

View File

@@ -12,5 +12,6 @@ end
require_relative 'errors/enumeration'
require_relative 'errors/http'
require_relative 'errors/update'
require_relative 'errors/vuln_api'
require_relative 'errors/wordpress'
require_relative 'errors/xmlrpc'

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
module WPScan
module Error
# Error raised when the token given via --api-token is invalid
class InvalidApiToken < Standard
def to_s
'The API token provided is invalid'
end
end
# Error raised when the number of API requests has been reached
# currently not implemented on the API side
class ApiLimitReached < Standard
def to_s
'Your API limit has been reached'
end
end
end
end

View File

@@ -0,0 +1,13 @@
# frozen_string_literal: true
module Typhoeus
# Custom Response class
class Response
# @note: Ignores requests done to the /status endpoint of the API
#
# @return [ Boolean ]
def from_vuln_api?
effective_url.start_with?(WPScan::DB::VulnApi.uri.to_s) && !effective_url.include?('/status')
end
end
end

View File

@@ -2,5 +2,5 @@
# Version
module WPScan
VERSION = '3.6.3'
VERSION = '3.7.0-dev'
end