HELLO v3!!!
This commit is contained in:
163
app/controllers/enumeration/cli_options.rb
Normal file
163
app/controllers/enumeration/cli_options.rb
Normal file
@@ -0,0 +1,163 @@
|
||||
module WPScan
|
||||
module Controller
|
||||
# Enumeration CLI Options
|
||||
class Enumeration < CMSScanner::Controller::Base
|
||||
def cli_options
|
||||
cli_enum_choices + cli_plugins_opts + cli_themes_opts +
|
||||
cli_timthumbs_opts + cli_config_backups_opts + cli_db_exports_opts +
|
||||
cli_medias_opts + cli_users_opts
|
||||
end
|
||||
|
||||
# @return [ Array<OptParseValidator::OptBase> ]
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def cli_enum_choices
|
||||
[
|
||||
OptMultiChoices.new(
|
||||
['--enumerate [OPTS]', '-e', 'Enumeration Process'],
|
||||
choices: {
|
||||
vp: OptBoolean.new(['--vulnerable-plugins']),
|
||||
ap: OptBoolean.new(['--all-plugins']),
|
||||
p: OptBoolean.new(['--plugins']),
|
||||
vt: OptBoolean.new(['--vulnerable-themes']),
|
||||
at: OptBoolean.new(['--all-themes']),
|
||||
t: OptBoolean.new(['--themes']),
|
||||
tt: OptBoolean.new(['--timthumbs']),
|
||||
cb: OptBoolean.new(['--config-backups']),
|
||||
dbe: OptBoolean.new(['--db-exports']),
|
||||
u: OptIntegerRange.new(['--users', 'User IDs range. e.g: u1-5'], value_if_empty: '1-10'),
|
||||
m: OptIntegerRange.new(['--medias', 'Media IDs range. e.g m1-15'], value_if_empty: '1-100')
|
||||
},
|
||||
value_if_empty: 'vp,vt,tt,cb,dbe,u,m',
|
||||
incompatible: [%i[vp ap p], %i[vt at t]],
|
||||
default: { all_plugins: true, config_backups: true }
|
||||
),
|
||||
OptRegexp.new(
|
||||
[
|
||||
'--exclude-content-based REGEXP_OR_STRING',
|
||||
'Exclude all responses matching the Regexp (case insensitive) during parts of the enumeration.',
|
||||
'Both the headers and body are checked. Regexp delimiters are not required.'
|
||||
], options: Regexp::IGNORECASE
|
||||
)
|
||||
]
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
# @return [ Array<OptParseValidator::OptBase> ]
|
||||
def cli_plugins_opts
|
||||
[
|
||||
OptSmartList.new(['--plugins-list LIST', 'List of plugins to enumerate']),
|
||||
OptChoice.new(
|
||||
['--plugins-detection MODE',
|
||||
'Use the supplied mode to enumerate Plugins, instead of the global (--detection-mode) mode.'],
|
||||
choices: %w[mixed passive aggressive], normalize: :to_sym, default: :passive
|
||||
),
|
||||
OptBoolean.new(
|
||||
['--plugins-version-all',
|
||||
'Check all the plugins version locations according to the choosen mode (--detection-mode, ' \
|
||||
'--plugins-detection and --plugins-version-detection)']
|
||||
),
|
||||
OptChoice.new(
|
||||
['--plugins-version-detection MODE',
|
||||
'Use the supplied mode to check plugins versions instead of the --detection-mode ' \
|
||||
'or --plugins-detection modes.'],
|
||||
choices: %w[mixed passive aggressive], normalize: :to_sym, default: :mixed
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
# @return [ Array<OptParseValidator::OptBase> ]
|
||||
def cli_themes_opts
|
||||
[
|
||||
OptSmartList.new(['--themes-list LIST', 'List of themes to enumerate']),
|
||||
OptChoice.new(
|
||||
['--themes-detection MODE',
|
||||
'Use the supplied mode to enumerate Themes, instead of the global (--detection-mode) mode.'],
|
||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
||||
),
|
||||
OptBoolean.new(
|
||||
['--themes-version-all',
|
||||
'Check all the themes version locations according to the choosen mode (--detection-mode, ' \
|
||||
'--themes-detection and --themes-version-detection)']
|
||||
),
|
||||
OptChoice.new(
|
||||
['--themes-version-detection MODE',
|
||||
'Use the supplied mode to check themes versions instead of the --detection-mode ' \
|
||||
'or --themes-detection modes.'],
|
||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
# @return [ Array<OptParseValidator::OptBase> ]
|
||||
def cli_timthumbs_opts
|
||||
[
|
||||
OptFilePath.new(
|
||||
['--timthumbs-list FILE-PATH', 'List of timthumbs\' location to use'],
|
||||
exists: true, default: File.join(DB_DIR, 'timthumbs-v3.txt')
|
||||
),
|
||||
OptChoice.new(
|
||||
['--timthumbs-detection MODE',
|
||||
'Use the supplied mode to enumerate Timthumbs, instead of the global (--detection-mode) mode.'],
|
||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
# @return [ Array<OptParseValidator::OptBase> ]
|
||||
def cli_config_backups_opts
|
||||
[
|
||||
OptFilePath.new(
|
||||
['--config-backups-list FILE-PATH', 'List of config backups\' filenames to use'],
|
||||
exists: true, default: File.join(DB_DIR, 'config_backups.txt')
|
||||
),
|
||||
OptChoice.new(
|
||||
['--config-backups-detection MODE',
|
||||
'Use the supplied mode to enumerate Config Backups, instead of the global (--detection-mode) mode.'],
|
||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
# @return [ Array<OptParseValidator::OptBase> ]
|
||||
def cli_db_exports_opts
|
||||
[
|
||||
OptFilePath.new(
|
||||
['--db-exports-list FILE-PATH', 'List of DB exports\' paths to use'],
|
||||
exists: true, default: File.join(DB_DIR, 'db_exports.txt')
|
||||
),
|
||||
OptChoice.new(
|
||||
['--db-exports-detection MODE',
|
||||
'Use the supplied mode to enumerate DB Exports, instead of the global (--detection-mode) mode.'],
|
||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
# @return [ Array<OptParseValidator::OptBase> ]
|
||||
def cli_medias_opts
|
||||
[
|
||||
OptChoice.new(
|
||||
['--medias-detection MODE',
|
||||
'Use the supplied mode to enumerate Medias, instead of the global (--detection-mode) mode.'],
|
||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
# @return [ Array<OptParseValidator::OptBase> ]
|
||||
def cli_users_opts
|
||||
[
|
||||
OptSmartList.new(
|
||||
['--users-list LIST',
|
||||
'List of users to check during the users enumeration from the Login Error Messages']
|
||||
),
|
||||
OptChoice.new(
|
||||
['--users-detection MODE',
|
||||
'Use the supplied mode to enumerate Users, instead of the global (--detection-mode) mode.'],
|
||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
||||
)
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
178
app/controllers/enumeration/enum_methods.rb
Normal file
178
app/controllers/enumeration/enum_methods.rb
Normal file
@@ -0,0 +1,178 @@
|
||||
module WPScan
|
||||
module Controller
|
||||
# Enumeration Methods
|
||||
class Enumeration < CMSScanner::Controller::Base
|
||||
# @param [ String ] type (plugins or themes)
|
||||
#
|
||||
# @return [ String ] The related enumration message depending on the parsed_options and type supplied
|
||||
def enum_message(type)
|
||||
return unless %w[plugins themes].include?(type)
|
||||
|
||||
details = if parsed_options[:enumerate][:"vulnerable_#{type}"]
|
||||
'Vulnerable'
|
||||
elsif parsed_options[:enumerate][:"all_#{type}"]
|
||||
'All'
|
||||
else
|
||||
'Most Popular'
|
||||
end
|
||||
|
||||
"Enumerating #{details} #{type.capitalize}"
|
||||
end
|
||||
|
||||
# @param [ String ] type (plugins, themes etc)
|
||||
#
|
||||
# @return [ Hash ]
|
||||
def default_opts(type)
|
||||
mode = parsed_options[:"#{type}_detection"] || parsed_options[:detection_mode]
|
||||
|
||||
{
|
||||
mode: mode,
|
||||
exclude_content: parsed_options[:exclude_content_based],
|
||||
show_progression: user_interaction?,
|
||||
version_detection: {
|
||||
mode: parsed_options[:"#{type}_version_detection"] || mode,
|
||||
confidence_threshold: parsed_options[:"#{type}_version_all"] ? 0 : 100
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
# @return [ Boolean ] Wether or not to enumerate the plugins
|
||||
def enum_plugins?(opts)
|
||||
opts[:plugins] || opts[:all_plugins] || opts[:vulnerable_plugins]
|
||||
end
|
||||
|
||||
def enum_plugins
|
||||
opts = default_opts('plugins').merge(
|
||||
list: plugins_list_from_opts(parsed_options),
|
||||
sort: true
|
||||
)
|
||||
|
||||
output('@info', msg: enum_message('plugins')) if user_interaction?
|
||||
# Enumerate the plugins & find their versions to avoid doing that when #version
|
||||
# is called in the view
|
||||
plugins = target.plugins(opts)
|
||||
|
||||
output('@info', msg: 'Checking Plugin Versions') if user_interaction? && !plugins.empty?
|
||||
|
||||
plugins.each(&:version)
|
||||
|
||||
plugins.select!(&:vulnerable?) if parsed_options[:enumerate][:vulnerable_plugins]
|
||||
|
||||
output('plugins', plugins: plugins)
|
||||
end
|
||||
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
# @return [ Array<String> ] The plugins list associated to the cli options
|
||||
def plugins_list_from_opts(opts)
|
||||
# List file provided by the user via the cli
|
||||
return opts[:plugins_list] if opts[:plugins_list]
|
||||
|
||||
if opts[:enumerate][:all_plugins]
|
||||
DB::Plugins.all_slugs
|
||||
elsif opts[:enumerate][:plugins]
|
||||
DB::Plugins.popular_slugs
|
||||
else
|
||||
DB::Plugins.vulnerable_slugs
|
||||
end
|
||||
end
|
||||
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
# @return [ Boolean ] Wether or not to enumerate the themes
|
||||
def enum_themes?(opts)
|
||||
opts[:themes] || opts[:all_themes] || opts[:vulnerable_themes]
|
||||
end
|
||||
|
||||
def enum_themes
|
||||
opts = default_opts('themes').merge(
|
||||
list: themes_list_from_opts(parsed_options),
|
||||
sort: true
|
||||
)
|
||||
|
||||
output('@info', msg: enum_message('themes')) if user_interaction?
|
||||
# Enumerate the themes & find their versions to avoid doing that when #version
|
||||
# is called in the view
|
||||
themes = target.themes(opts)
|
||||
|
||||
output('@info', msg: 'Checking Theme Versions') if user_interaction? && !themes.empty?
|
||||
|
||||
themes.each(&:version)
|
||||
|
||||
themes.select!(&:vulnerable?) if parsed_options[:enumerate][:vulnerable_themes]
|
||||
|
||||
output('themes', themes: themes)
|
||||
end
|
||||
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
# @return [ Array<String> ] The themes list associated to the cli options
|
||||
def themes_list_from_opts(opts)
|
||||
# List file provided by the user via the cli
|
||||
return opts[:themes_list] if opts[:themes_list]
|
||||
|
||||
if opts[:enumerate][:all_themes]
|
||||
DB::Themes.all_slugs
|
||||
elsif opts[:enumerate][:themes]
|
||||
DB::Themes.popular_slugs
|
||||
else
|
||||
DB::Themes.vulnerable_slugs
|
||||
end
|
||||
end
|
||||
|
||||
def enum_timthumbs
|
||||
opts = default_opts('timthumbs').merge(list: parsed_options[:timthumbs_list])
|
||||
|
||||
output('@info', msg: 'Enumerating Timthumbs') if user_interaction?
|
||||
output('timthumbs', timthumbs: target.timthumbs(opts))
|
||||
end
|
||||
|
||||
def enum_config_backups
|
||||
opts = default_opts('config_backups').merge(list: parsed_options[:config_backups_list])
|
||||
|
||||
output('@info', msg: 'Enumerating Config Backups') if user_interaction?
|
||||
output('config_backups', config_backups: target.config_backups(opts))
|
||||
end
|
||||
|
||||
def enum_db_exports
|
||||
opts = default_opts('db_exports').merge(list: parsed_options[:db_exports_list])
|
||||
|
||||
output('@info', msg: 'Enumerating DB Exports') if user_interaction?
|
||||
output('db_exports', db_exports: target.db_exports(opts))
|
||||
end
|
||||
|
||||
def enum_medias
|
||||
opts = default_opts('medias').merge(range: parsed_options[:enumerate][:medias])
|
||||
|
||||
output('@info', msg: 'Enumerating Medias') if user_interaction?
|
||||
output('medias', medias: target.medias(opts))
|
||||
end
|
||||
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
# @return [ Boolean ] Wether or not to enumerate the users
|
||||
def enum_users?(opts)
|
||||
opts[:users] || (parsed_options[:passwords] && !parsed_options[:username] && !parsed_options[:usernames])
|
||||
end
|
||||
|
||||
def enum_users
|
||||
opts = default_opts('users').merge(
|
||||
range: enum_users_range,
|
||||
list: parsed_options[:users_list]
|
||||
)
|
||||
|
||||
output('@info', msg: 'Enumerating Users') if user_interaction?
|
||||
output('users', users: target.users(opts))
|
||||
end
|
||||
|
||||
# @return [ Range ] The user ids range to enumerate
|
||||
# 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
|
||||
def enum_users_range
|
||||
parsed_options[:enumerate][:users] || cli_enum_choices[0].choices[:u].validate(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user