Path: blob/master/app/controllers/enumeration/enum_methods.rb
485 views
# frozen_string_literal: true12module WPScan3module Controller4# Enumeration Methods5class Enumeration < CMSScanner::Controller::Base6# @param [ String ] type (plugins or themes)7# @param [ Symbol ] detection_mode8#9# @return [ String ] The related enumration message depending on the ParsedCli and type supplied10def enum_message(type, detection_mode)11return unless %w[plugins themes].include?(type)1213details = if ParsedCli.enumerate[:"vulnerable_#{type}"]14'Vulnerable'15elsif ParsedCli.enumerate[:"all_#{type}"]16'All'17else18'Most Popular'19end2021"Enumerating #{details} #{type.capitalize} #{enum_detection_message(detection_mode)}"22end2324# @param [ Symbol ] detection_mode25#26# @return [ String ]27def enum_detection_message(detection_mode)28detection_method = if detection_mode == :mixed29'Passive and Aggressive'30else31detection_mode.to_s.capitalize32end3334"(via #{detection_method} Methods)"35end3637# @param [ String ] type (plugins, themes etc)38#39# @return [ Hash ]40def default_opts(type)41mode = ParsedCli.options[:"#{type}_detection"] || ParsedCli.detection_mode4243{44mode: mode,45exclude_content: ParsedCli.exclude_content_based,46show_progression: user_interaction?,47version_detection: {48mode: ParsedCli.options[:"#{type}_version_detection"] || mode,49confidence_threshold: ParsedCli.options[:"#{type}_version_all"] ? 0 : 10050}51}52end5354# @param [ Hash ] opts55#56# @return [ Boolean ] Wether or not to enumerate the plugins57def enum_plugins?(opts)58opts[:popular_plugins] || opts[:all_plugins] || opts[:vulnerable_plugins]59end6061def enum_plugins62opts = default_opts('plugins').merge(63list: plugins_list_from_opts(ParsedCli.options),64threshold: ParsedCli.plugins_threshold,65sort: true66)6768output('@info', msg: enum_message('plugins', opts[:mode])) if user_interaction?69# Enumerate the plugins & find their versions to avoid doing that when #version70# is called in the view71plugins = target.plugins(opts)7273if user_interaction? && !plugins.empty?74output('@info',75msg: "Checking Plugin Versions #{enum_detection_message(opts[:version_detection][:mode])}")76end7778plugins.each(&:version)7980plugins.select!(&:vulnerable?) if ParsedCli.enumerate[:vulnerable_plugins]8182output('plugins', plugins: plugins)83end8485# @param [ Hash ] opts86#87# @return [ Array<String> ] The plugins list associated to the cli options88def plugins_list_from_opts(opts)89# List file provided by the user via the cli90return opts[:plugins_list] if opts[:plugins_list]9192if opts[:enumerate][:all_plugins]93DB::Plugins.all_slugs94elsif opts[:enumerate][:popular_plugins]95DB::Plugins.popular_slugs96else97DB::Plugins.vulnerable_slugs98end99end100101# @param [ Hash ] opts102#103# @return [ Boolean ] Wether or not to enumerate the themes104def enum_themes?(opts)105opts[:popular_themes] || opts[:all_themes] || opts[:vulnerable_themes]106end107108def enum_themes109opts = default_opts('themes').merge(110list: themes_list_from_opts(ParsedCli.options),111threshold: ParsedCli.themes_threshold,112sort: true113)114115output('@info', msg: enum_message('themes', opts[:mode])) if user_interaction?116# Enumerate the themes & find their versions to avoid doing that when #version117# is called in the view118themes = target.themes(opts)119120if user_interaction? && !themes.empty?121output('@info',122msg: "Checking Theme Versions #{enum_detection_message(opts[:version_detection][:mode])}")123end124125themes.each(&:version)126127themes.select!(&:vulnerable?) if ParsedCli.enumerate[:vulnerable_themes]128129output('themes', themes: themes)130end131132# @param [ Hash ] opts133#134# @return [ Array<String> ] The themes list associated to the cli options135def themes_list_from_opts(opts)136# List file provided by the user via the cli137return opts[:themes_list] if opts[:themes_list]138139if opts[:enumerate][:all_themes]140DB::Themes.all_slugs141elsif opts[:enumerate][:popular_themes]142DB::Themes.popular_slugs143else144DB::Themes.vulnerable_slugs145end146end147148def enum_timthumbs149opts = default_opts('timthumbs').merge(list: ParsedCli.timthumbs_list)150151output('@info', msg: "Enumerating Timthumbs #{enum_detection_message(opts[:mode])}") if user_interaction?152output('timthumbs', timthumbs: target.timthumbs(opts))153end154155def enum_config_backups156opts = default_opts('config_backups').merge(list: ParsedCli.config_backups_list)157158output('@info', msg: "Enumerating Config Backups #{enum_detection_message(opts[:mode])}") if user_interaction?159output('config_backups', config_backups: target.config_backups(opts))160end161162def enum_db_exports163opts = default_opts('db_exports').merge(list: ParsedCli.db_exports_list)164165output('@info', msg: "Enumerating DB Exports #{enum_detection_message(opts[:mode])}") if user_interaction?166output('db_exports', db_exports: target.db_exports(opts))167end168169def enum_medias170opts = default_opts('medias').merge(range: ParsedCli.enumerate[:medias])171172if user_interaction?173output('@info',174msg: "Enumerating Medias #{enum_detection_message(opts[:mode])} "\175'(Permalink setting must be set to "Plain" for those to be detected)')176end177178output('medias', medias: target.medias(opts))179end180181# @param [ Hash ] opts182#183# @return [ Boolean ] Wether or not to enumerate the users184def enum_users?(opts)185opts[:users] || (ParsedCli.passwords && !ParsedCli.username && !ParsedCli.usernames)186end187188def enum_users189opts = default_opts('users').merge(190range: enum_users_range,191list: ParsedCli.users_list192)193194output('@info', msg: "Enumerating Users #{enum_detection_message(opts[:mode])}") if user_interaction?195output('users', users: target.users(opts))196end197198# @return [ Range ] The user ids range to enumerate199# If the --enumerate is used, the default value is handled by the Option200# However, when using --passwords alone, the default has to be set by the code below201def enum_users_range202ParsedCli.enumerate[:users] || cli_enum_choices[0].choices[:u].validate(nil)203end204end205end206end207208209