# frozen_string_literal: true module WPScan module Finders module DynamicFinder module WpItems # Not really a dynamic finder in itself (hence not a child class of DynamicFinder::Finder) # but will use the dynamic finder DB configs to find collections of # WpItems (such as Plugins and Themes) # # Also used to factorise some code used between such finders. # The #process_response should be implemented in each child class, or the # #passive and #aggressive overriden class Finder < CMSScanner::Finders::Finder # @return [ Hash ] The related dynamic finder passive configurations # for the current class (all its usefullness comes from child classes) def passive_configs # So far only the Plugins have dynamic finders so using DB:: DynamicFinders::Plugin # is ok. However, when Themes have some, will need to create other child classes for them method = "passive_#{self.class.to_s.demodulize.underscore}_finder_configs".to_sym DB::DynamicFinders::Plugin.public_send(method) end # @param [ Hash ] opts # # @return [ Array, Array ] def passive(opts = {}) found = [] passive_configs.each do |slug, configs| configs.each do |klass, config| item = process_response(opts, target.homepage_res, slug, klass, config) found << item if item.is_a?(Model::WpItem) end end found end # @return [ Hash ] The related dynamic finder passive configurations # for the current class (all its usefullness comes from child classes) def aggressive_configs # So far only the Plugins have dynamic finders so using DB:: DynamicFinders::Plugin # is ok. However, when Themes have some, will need to create other child classes for them method = "aggressive_#{self.class.to_s.demodulize.underscore}_finder_configs".to_sym DB::DynamicFinders::Plugin.public_send(method) end # @param [ Hash ] opts # # @return [ Array, Array ] def aggressive(_opts = {}) # Disable this as it would make quite a lot of extra requests just to find plugins/themes # Kept the original method below for future implementation end # @param [ Hash ] opts # # @return [ Array, Array ] def aggressive_(opts = {}) found = [] aggressive_configs.each do |slug, configs| configs.each do |klass, config| path = aggressive_path(slug, config) response = Browser.get(target.url(path)) item = process_response(opts, response, slug, klass, config) found << item if item.is_a?(Model::WpItem) end end found end # @param [ String ] slug # @param [ Hash ] config from the YAML file with he 'path' key # # @return [ String ] The path related to the aggresive configuration # ie config['path'] if it's an absolute path (like /file.txt) # or the path from inside the related plugin directory def aggressive_path(slug, config) return config['path'] if config['path'][0] == '/' # No need to set the correct plugins dir, it will be handled by target.url() "wp-content/plugins/#{slug}/#{config['path']}" end end end end end end