Uses ParsedCli

This commit is contained in:
erwanlr
2019-04-05 16:39:13 +01:00
parent 8a6f3056a3
commit 7888fe1176
17 changed files with 66 additions and 67 deletions

View File

@@ -27,12 +27,12 @@ module WPScan
# @return [ Boolean ] # @return [ Boolean ]
def update_db_required? def update_db_required?
if local_db.missing_files? if local_db.missing_files?
raise Error::MissingDatabaseFile if parsed_options[:update] == false raise Error::MissingDatabaseFile if ParsedCli.update == false
return true return true
end end
return parsed_options[:update] unless parsed_options[:update].nil? return ParsedCli.update unless ParsedCli.update.nil?
return false unless user_interaction? && local_db.outdated? return false unless user_interaction? && local_db.outdated?
@@ -44,9 +44,9 @@ module WPScan
def update_db def update_db
output('db_update_started') output('db_update_started')
output('db_update_finished', updated: local_db.update, verbose: parsed_options[:verbose]) output('db_update_finished', updated: local_db.update, verbose: ParsedCli.verbose)
exit(0) unless parsed_options[:url] exit(0) unless ParsedCli.url
end end
def before_scan def before_scan
@@ -61,7 +61,7 @@ module WPScan
check_wordpress_state check_wordpress_state
rescue Error::NotWordPress => e rescue Error::NotWordPress => e
target.maybe_add_cookies target.maybe_add_cookies
raise e unless target.wordpress?(parsed_options[:detection_mode]) raise e unless target.wordpress?(ParsedCli.detection_mode)
end end
# Raises errors if the target is hosted on wordpress.com or is not running WordPress # Raises errors if the target is hosted on wordpress.com or is not running WordPress
@@ -76,7 +76,7 @@ module WPScan
exit(WPScan::ExitCode::VULNERABLE) exit(WPScan::ExitCode::VULNERABLE)
end end
raise Error::NotWordPress unless target.wordpress?(parsed_options[:detection_mode]) || parsed_options[:force] raise Error::NotWordPress unless target.wordpress?(ParsedCli.detection_mode) || ParsedCli.force
end end
# Loads the related server module in the target # Loads the related server module in the target
@@ -88,7 +88,7 @@ module WPScan
server = target.server || :Apache # Tries to auto detect the server server = target.server || :Apache # Tries to auto detect the server
# Force a specific server module to be loaded if supplied # Force a specific server module to be loaded if supplied
case parsed_options[:server] case ParsedCli.server
when :apache when :apache
server = :Apache server = :Apache
when :iis when :iis

View File

@@ -13,8 +13,8 @@ module WPScan
end end
def before_scan def before_scan
target.content_dir = parsed_options[:wp_content_dir] if parsed_options[:wp_content_dir] target.content_dir = ParsedCli.wp_content_dir if ParsedCli.wp_content_dir
target.plugins_dir = parsed_options[:wp_plugins_dir] if parsed_options[:wp_plugins_dir] target.plugins_dir = ParsedCli.wp_plugins_dir if ParsedCli.wp_plugins_dir
return if target.content_dir return if target.content_dir

View File

@@ -17,7 +17,7 @@ module WPScan
end end
def run def run
enum = parsed_options[:enumerate] || {} enum = ParsedCli.enumerate || {}
enum_plugins if enum_plugins?(enum) enum_plugins if enum_plugins?(enum)
enum_themes if enum_themes?(enum) enum_themes if enum_themes?(enum)

View File

@@ -7,13 +7,13 @@ module WPScan
# @param [ String ] type (plugins or themes) # @param [ String ] type (plugins or themes)
# @param [ Symbol ] detection_mode # @param [ Symbol ] detection_mode
# #
# @return [ String ] The related enumration message depending on the parsed_options and type supplied # @return [ String ] The related enumration message depending on the ParsedCli and type supplied
def enum_message(type, detection_mode) def enum_message(type, detection_mode)
return unless %w[plugins themes].include?(type) return unless %w[plugins themes].include?(type)
details = if parsed_options[:enumerate][:"vulnerable_#{type}"] details = if ParsedCli.enumerate[:"vulnerable_#{type}"]
'Vulnerable' 'Vulnerable'
elsif parsed_options[:enumerate][:"all_#{type}"] elsif ParsedCli.enumerate[:"all_#{type}"]
'All' 'All'
else else
'Most Popular' 'Most Popular'
@@ -39,15 +39,15 @@ module WPScan
# #
# @return [ Hash ] # @return [ Hash ]
def default_opts(type) def default_opts(type)
mode = parsed_options[:"#{type}_detection"] || parsed_options[:detection_mode] mode = ParsedCli.options[:"#{type}_detection"] || ParsedCli.detection_mode
{ {
mode: mode, mode: mode,
exclude_content: parsed_options[:exclude_content_based], exclude_content: ParsedCli.exclude_content_based,
show_progression: user_interaction?, show_progression: user_interaction?,
version_detection: { version_detection: {
mode: parsed_options[:"#{type}_version_detection"] || mode, mode: ParsedCli.options[:"#{type}_version_detection"] || mode,
confidence_threshold: parsed_options[:"#{type}_version_all"] ? 0 : 100 confidence_threshold: ParsedCli.options[:"#{type}_version_all"] ? 0 : 100
} }
} }
end end
@@ -61,7 +61,7 @@ module WPScan
def enum_plugins def enum_plugins
opts = default_opts('plugins').merge( opts = default_opts('plugins').merge(
list: plugins_list_from_opts(parsed_options), list: plugins_list_from_opts(ParsedCli.options),
sort: true sort: true
) )
@@ -77,7 +77,7 @@ module WPScan
plugins.each(&:version) plugins.each(&:version)
plugins.select!(&:vulnerable?) if parsed_options[:enumerate][:vulnerable_plugins] plugins.select!(&:vulnerable?) if ParsedCli.enumerate[:vulnerable_plugins]
output('plugins', plugins: plugins) output('plugins', plugins: plugins)
end end
@@ -107,7 +107,7 @@ module WPScan
def enum_themes def enum_themes
opts = default_opts('themes').merge( opts = default_opts('themes').merge(
list: themes_list_from_opts(parsed_options), list: themes_list_from_opts(ParsedCli.options),
sort: true sort: true
) )
@@ -123,7 +123,7 @@ module WPScan
themes.each(&:version) themes.each(&:version)
themes.select!(&:vulnerable?) if parsed_options[:enumerate][:vulnerable_themes] themes.select!(&:vulnerable?) if ParsedCli.enumerate[:vulnerable_themes]
output('themes', themes: themes) output('themes', themes: themes)
end end
@@ -145,28 +145,28 @@ module WPScan
end end
def enum_timthumbs def enum_timthumbs
opts = default_opts('timthumbs').merge(list: parsed_options[:timthumbs_list]) opts = default_opts('timthumbs').merge(list: ParsedCli.timthumbs_list)
output('@info', msg: "Enumerating Timthumbs #{enum_detection_message(opts[:mode])}") if user_interaction? output('@info', msg: "Enumerating Timthumbs #{enum_detection_message(opts[:mode])}") if user_interaction?
output('timthumbs', timthumbs: target.timthumbs(opts)) output('timthumbs', timthumbs: target.timthumbs(opts))
end end
def enum_config_backups def enum_config_backups
opts = default_opts('config_backups').merge(list: parsed_options[:config_backups_list]) opts = default_opts('config_backups').merge(list: ParsedCli.config_backups_list)
output('@info', msg: "Enumerating Config Backups #{enum_detection_message(opts[:mode])}") if user_interaction? output('@info', msg: "Enumerating Config Backups #{enum_detection_message(opts[:mode])}") if user_interaction?
output('config_backups', config_backups: target.config_backups(opts)) output('config_backups', config_backups: target.config_backups(opts))
end end
def enum_db_exports def enum_db_exports
opts = default_opts('db_exports').merge(list: parsed_options[:db_exports_list]) opts = default_opts('db_exports').merge(list: ParsedCli.db_exports_list)
output('@info', msg: "Enumerating DB Exports #{enum_detection_message(opts[:mode])}") if user_interaction? output('@info', msg: "Enumerating DB Exports #{enum_detection_message(opts[:mode])}") if user_interaction?
output('db_exports', db_exports: target.db_exports(opts)) output('db_exports', db_exports: target.db_exports(opts))
end end
def enum_medias def enum_medias
opts = default_opts('medias').merge(range: parsed_options[:enumerate][:medias]) opts = default_opts('medias').merge(range: ParsedCli.enumerate[:medias])
if user_interaction? if user_interaction?
output('@info', output('@info',
@@ -181,13 +181,13 @@ module WPScan
# #
# @return [ Boolean ] Wether or not to enumerate the users # @return [ Boolean ] Wether or not to enumerate the users
def enum_users?(opts) def enum_users?(opts)
opts[:users] || (parsed_options[:passwords] && !parsed_options[:username] && !parsed_options[:usernames]) opts[:users] || (ParsedCli.passwords && !ParsedCli.username && !ParsedCli.usernames)
end end
def enum_users def enum_users
opts = default_opts('users').merge( opts = default_opts('users').merge(
range: enum_users_range, range: enum_users_range,
list: parsed_options[:users_list] list: ParsedCli.users_list
) )
output('@info', msg: "Enumerating Users #{enum_detection_message(opts[:mode])}") if user_interaction? output('@info', msg: "Enumerating Users #{enum_detection_message(opts[:mode])}") if user_interaction?
@@ -198,7 +198,7 @@ module WPScan
# If the --enumerate is used, the default value is handled by the Option # If the --enumerate is used, the default value is handled by the Option
# However, when using --passwords alone, the default has to be set by the code below # However, when using --passwords alone, the default has to be set by the code below
def enum_users_range def enum_users_range
parsed_options[:enumerate][:users] || cli_enum_choices[0].choices[:u].validate(nil) ParsedCli.enumerate[:users] || cli_enum_choices[0].choices[:u].validate(nil)
end end
end end
end end

View File

@@ -18,9 +18,9 @@ module WPScan
output( output(
'theme', 'theme',
theme: target.main_theme( theme: target.main_theme(
mode: parsed_options[:main_theme_detection] || parsed_options[:detection_mode] mode: ParsedCli.main_theme_detection || ParsedCli.detection_mode
), ),
verbose: parsed_options[:verbose] verbose: ParsedCli.verbose
) )
end end
end end

View File

@@ -24,7 +24,7 @@ module WPScan
end end
def run def run
return unless parsed_options[:passwords] return unless ParsedCli.passwords
if user_interaction? if user_interaction?
output('@info', output('@info',
@@ -33,13 +33,13 @@ module WPScan
attack_opts = { attack_opts = {
show_progression: user_interaction?, show_progression: user_interaction?,
multicall_max_passwords: parsed_options[:multicall_max_passwords] multicall_max_passwords: ParsedCli.multicall_max_passwords
} }
begin begin
found = [] found = []
attacker.attack(users, passwords(parsed_options[:passwords]), attack_opts) do |user| attacker.attack(users, passwords(ParsedCli.passwords), attack_opts) do |user|
found << user found << user
attacker.progress_bar.log("[SUCCESS] - #{user.username} / #{user.password}") attacker.progress_bar.log("[SUCCESS] - #{user.username} / #{user.password}")
@@ -61,9 +61,9 @@ module WPScan
# @return [ CMSScanner::Finders::Finder ] # @return [ CMSScanner::Finders::Finder ]
def attacker_from_cli_options def attacker_from_cli_options
return unless parsed_options[:password_attack] return unless ParsedCli.password_attack
case parsed_options[:password_attack] case ParsedCli.password_attack
when :wp_login when :wp_login
WPScan::Finders::Passwords::WpLogin.new(target) WPScan::Finders::Passwords::WpLogin.new(target)
when :xmlrpc when :xmlrpc
@@ -94,9 +94,9 @@ module WPScan
# @return [ Array<Users> ] The users to brute force # @return [ Array<Users> ] The users to brute force
def users def users
return target.users unless parsed_options[:usernames] return target.users unless ParsedCli.usernames
parsed_options[:usernames].reduce([]) do |acc, elem| ParsedCli.usernames.reduce([]) do |acc, elem|
acc << Model::User.new(elem.chomp) acc << Model::User.new(elem.chomp)
end end
end end

View File

@@ -24,8 +24,8 @@ module WPScan
output( output(
'version', 'version',
version: target.wp_version( version: target.wp_version(
mode: parsed_options[:wp_version_detection] || parsed_options[:detection_mode], mode: ParsedCli.wp_version_detection || ParsedCli.detection_mode,
confidence_threshold: parsed_options[:wp_version_all] ? 0 : 100, confidence_threshold: ParsedCli.wp_version_all ? 0 : 100,
show_progression: user_interaction? show_progression: user_interaction?
) )
) )

View File

@@ -19,6 +19,7 @@ require 'wpscan/helper'
require 'wpscan/db' require 'wpscan/db'
require 'wpscan/version' require 'wpscan/version'
require 'wpscan/errors' require 'wpscan/errors'
require 'wpscan/parsed_cli'
require 'wpscan/browser' require 'wpscan/browser'
require 'wpscan/target' require 'wpscan/target'
require 'wpscan/finders' require 'wpscan/finders'

7
lib/wpscan/parsed_cli.rb Normal file
View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
module WPScan
# To be able to use ParsedCli directly, rather than having to access it via WPscan::ParsedCli
class ParsedCli < CMSScanner::ParsedCli
end
end

View File

@@ -3,12 +3,10 @@
describe WPScan::Controller::Aliases do describe WPScan::Controller::Aliases do
subject(:controller) { described_class.new } subject(:controller) { described_class.new }
let(:target_url) { 'http://ex.lo/' } let(:target_url) { 'http://ex.lo/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" } let(:cli_args) { "--url #{target_url}" }
before do before do
WPScan::Browser.reset WPScan::ParsedCli.options = rspec_parsed_options(cli_args)
described_class.parsed_options = parsed_options
end end
describe '#cli_options' do describe '#cli_options' do
@@ -22,14 +20,18 @@ describe WPScan::Controller::Aliases do
describe 'parsed_options' do describe 'parsed_options' do
context 'when no --stealthy supplied' do context 'when no --stealthy supplied' do
its(:parsed_options) { should eql parsed_options } it 'contains the correct options' do
expect(WPScan::ParsedCli.options).to include(
detection_mode: :mixed, plugins_version_detection: :mixed
)
end
end end
context 'when --stealthy supplied' do context 'when --stealthy supplied' do
let(:cli_args) { "#{super()} --stealthy" } let(:cli_args) { "#{super()} --stealthy" }
it 'contains the correct options' do it 'contains the correct options' do
expect(controller.parsed_options).to include( expect(WPScan::ParsedCli.options).to include(
random_user_agent: true, detection_mode: :passive, plugins_version_detection: :passive random_user_agent: true, detection_mode: :passive, plugins_version_detection: :passive
) )
end end

View File

@@ -3,13 +3,11 @@
describe WPScan::Controller::Core do describe WPScan::Controller::Core do
subject(:core) { described_class.new } subject(:core) { described_class.new }
let(:target_url) { 'http://ex.lo/' } let(:target_url) { 'http://ex.lo/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" } let(:cli_args) { "--url #{target_url}" }
before do before do
WPScan::Browser.reset
described_class.reset described_class.reset
described_class.parsed_options = parsed_options WPScan::ParsedCli.options = rspec_parsed_options(cli_args)
end end
describe '#cli_options' do describe '#cli_options' do
@@ -140,7 +138,7 @@ describe WPScan::Controller::Core do
expect(core.formatter).to receive(:output).with('banner', hash_including(verbose: nil), 'core') expect(core.formatter).to receive(:output).with('banner', hash_including(verbose: nil), 'core')
expect(core).to receive(:update_db_required?).and_return(false) unless parsed_options[:update] expect(core).to receive(:update_db_required?).and_return(false) unless WPScan::ParsedCli.update
end end
context 'when --update' do context 'when --update' do

View File

@@ -3,12 +3,10 @@
describe WPScan::Controller::CustomDirectories do describe WPScan::Controller::CustomDirectories do
subject(:controller) { described_class.new } subject(:controller) { described_class.new }
let(:target_url) { 'http://ex.lo/' } let(:target_url) { 'http://ex.lo/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" } let(:cli_args) { "--url #{target_url}" }
before do before do
WPScan::Browser.reset WPScan::ParsedCli.options = rspec_parsed_options(cli_args)
described_class.parsed_options = parsed_options
end end
describe '#cli_options' do describe '#cli_options' do
@@ -34,7 +32,7 @@ describe WPScan::Controller::CustomDirectories do
it 'does not raise any error' do it 'does not raise any error' do
expect { controller.before_scan }.to_not raise_error expect { controller.before_scan }.to_not raise_error
expect(controller.target.content_dir).to eq parsed_options[:wp_content_dir] expect(controller.target.content_dir).to eq WPScan::ParsedCli.wp_content_dir
end end
end end
end end

View File

@@ -3,16 +3,13 @@
describe WPScan::Controller::Enumeration do describe WPScan::Controller::Enumeration do
subject(:controller) { described_class.new } subject(:controller) { described_class.new }
let(:target_url) { 'http://wp.lab/' } let(:target_url) { 'http://wp.lab/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" } let(:cli_args) { "--url #{target_url}" }
before do before do
WPScan::Browser.reset
## For the --passwords options ## For the --passwords options
allow_any_instance_of(OptParseValidator::OptPath).to receive(:check_file) allow_any_instance_of(OptParseValidator::OptPath).to receive(:check_file)
described_class.parsed_options = parsed_options WPScan::ParsedCli.options = rspec_parsed_options(cli_args)
end end
describe '#enum_message' do describe '#enum_message' do
@@ -120,7 +117,7 @@ describe WPScan::Controller::Enumeration do
expect(controller).to receive(:enum_plugins) expect(controller).to receive(:enum_plugins)
expect(controller).to receive(:enum_config_backups) expect(controller).to receive(:enum_config_backups)
expect(parsed_options[:plugins_detection]).to eql :passive expect(WPScan::ParsedCli.plugins_detection).to eql :passive
end end
it 'calls enum_plugins and enum_config_backups' do it 'calls enum_plugins and enum_config_backups' do

View File

@@ -3,12 +3,10 @@
describe WPScan::Controller::PasswordAttack do describe WPScan::Controller::PasswordAttack do
subject(:controller) { described_class.new } subject(:controller) { described_class.new }
let(:target_url) { 'http://ex.lo/' } let(:target_url) { 'http://ex.lo/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" } let(:cli_args) { "--url #{target_url}" }
before do before do
WPScan::Browser.reset WPScan::ParsedCli.options = rspec_parsed_options(cli_args)
described_class.parsed_options = parsed_options
end end
describe '#cli_options' do describe '#cli_options' do

View File

@@ -24,12 +24,10 @@ end
describe WPScan::Controller::WpVersion do describe WPScan::Controller::WpVersion do
subject(:controller) { described_class.new } subject(:controller) { described_class.new }
let(:target_url) { 'http://ex.lo/' } let(:target_url) { 'http://ex.lo/' }
let(:parsed_options) { rspec_parsed_options(cli_args) }
let(:cli_args) { "--url #{target_url}" } let(:cli_args) { "--url #{target_url}" }
before do before do
WPScan::Browser.reset WPScan::ParsedCli.options = rspec_parsed_options(cli_args)
described_class.parsed_options = parsed_options
end end
describe '#cli_options' do describe '#cli_options' do
@@ -46,8 +44,8 @@ describe WPScan::Controller::WpVersion do
expect(controller.target).to receive(:wp_version) expect(controller.target).to receive(:wp_version)
.with( .with(
hash_including( hash_including(
mode: parsed_options[:wp_version_detection] || parsed_options[:detection_mode], mode: WPScan::ParsedCli.wp_version_detection || WPScan::ParsedCli.detection_mode,
confidence_threshold: parsed_options[:wp_version_all] ? 0 : 100 confidence_threshold: WPScan::ParsedCli.wp_version_all ? 0 : 100
) )
).and_return(stubbed) ).and_return(stubbed)
end end

View File

@@ -16,7 +16,7 @@ describe 'App::Views' do
let(:parsed_options) { { url: target_url, format: formatter.to_s.underscore.dasherize } } let(:parsed_options) { { url: target_url, format: formatter.to_s.underscore.dasherize } }
before do before do
controller.class.parsed_options = parsed_options WPScan::ParsedCli.options = parsed_options
# Resets the formatter to ensure the correct one is loaded # Resets the formatter to ensure the correct one is loaded
controller.class.class_variable_set(:@@formatter, nil) controller.class.class_variable_set(:@@formatter, nil)
end end

View File

@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
s.executables = ['wpscan'] s.executables = ['wpscan']
s.require_paths = ['lib'] s.require_paths = ['lib']
s.add_dependency 'cms_scanner', '~> 0.0.43.2' s.add_dependency 'cms_scanner', '~> 0.0.44.0'
s.add_development_dependency 'bundler', '>= 1.6' s.add_development_dependency 'bundler', '>= 1.6'
s.add_development_dependency 'coveralls', '~> 0.8.0' s.add_development_dependency 'coveralls', '~> 0.8.0'