110 lines
3.5 KiB
Ruby
110 lines
3.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module WPScan
|
|
module Controller
|
|
# Specific Core controller to include WordPress checks
|
|
class Core < CMSScanner::Controller::Core
|
|
# @return [ Array<OptParseValidator::Opt> ]
|
|
def cli_options
|
|
[OptURL.new(['--url URL', 'The URL of the blog to scan'],
|
|
required_unless: %i[update help hh version], default_protocol: 'http')] +
|
|
super.drop(1) + # delete the --url from CMSScanner
|
|
[
|
|
OptChoice.new(['--server SERVER', 'Force the supplied server module to be loaded'],
|
|
choices: %w[apache iis nginx],
|
|
normalize: %i[downcase to_sym],
|
|
advanced: true),
|
|
OptBoolean.new(['--force', 'Do not check if the target is running WordPress']),
|
|
OptBoolean.new(['--[no-]update', 'Whether or not to update the Database'])
|
|
]
|
|
end
|
|
|
|
# @return [ DB::Updater ]
|
|
def local_db
|
|
@local_db ||= DB::Updater.new(DB_DIR)
|
|
end
|
|
|
|
# @return [ Boolean ]
|
|
def update_db_required?
|
|
if local_db.missing_files?
|
|
raise Error::MissingDatabaseFile if ParsedCli.update == false
|
|
|
|
return true
|
|
end
|
|
|
|
return ParsedCli.update unless ParsedCli.update.nil?
|
|
|
|
return false unless user_interaction? && local_db.outdated?
|
|
|
|
output('@notice', msg: 'It seems like you have not updated the database for some time.')
|
|
print '[?] Do you want to update now? [Y]es [N]o, default: [N]'
|
|
|
|
/^y/i.match?(Readline.readline) ? true : false
|
|
end
|
|
|
|
def update_db
|
|
output('db_update_started')
|
|
output('db_update_finished', updated: local_db.update, verbose: ParsedCli.verbose)
|
|
|
|
exit(0) unless ParsedCli.url
|
|
end
|
|
|
|
def before_scan
|
|
@last_update = local_db.last_update
|
|
|
|
maybe_output_banner_help_and_version # From CMSScanner
|
|
|
|
update_db if update_db_required?
|
|
setup_cache
|
|
check_target_availability
|
|
load_server_module
|
|
check_wordpress_state
|
|
rescue Error::NotWordPress => e
|
|
target.maybe_add_cookies
|
|
raise e unless target.wordpress?(ParsedCli.detection_mode)
|
|
end
|
|
|
|
# Raises errors if the target is hosted on wordpress.com or is not running WordPress
|
|
# Also check if the homepage_url is still the install url
|
|
def check_wordpress_state
|
|
raise Error::WordPressHosted if target.wordpress_hosted?
|
|
|
|
if %r{/wp-admin/install.php$}i.match?(Addressable::URI.parse(target.homepage_url).path)
|
|
|
|
output('not_fully_configured', url: target.homepage_url)
|
|
|
|
exit(WPScan::ExitCode::VULNERABLE)
|
|
end
|
|
|
|
raise Error::NotWordPress unless target.wordpress?(ParsedCli.detection_mode) || ParsedCli.force
|
|
end
|
|
|
|
# Loads the related server module in the target
|
|
# and includes it in the WpItem class which will be needed
|
|
# to check if directory listing is enabled etc
|
|
#
|
|
# @return [ Symbol ] The server module loaded
|
|
def load_server_module
|
|
server = target.server || :Apache # Tries to auto detect the server
|
|
|
|
# Force a specific server module to be loaded if supplied
|
|
case ParsedCli.server
|
|
when :apache
|
|
server = :Apache
|
|
when :iis
|
|
server = :IIS
|
|
when :nginx
|
|
server = :Nginx
|
|
end
|
|
|
|
mod = CMSScanner::Target::Server.const_get(server)
|
|
|
|
target.extend mod
|
|
Model::WpItem.include mod
|
|
|
|
server
|
|
end
|
|
end
|
|
end
|
|
end
|