Class: WPScan::Finders::Plugins::WpJsonApi

Inherits:
Finder
  • Object
show all
Defined in:
app/finders/plugins/wp_json_api.rb

Overview

Authenticated plugin inventory via the WordPress REST API endpoint /wp-json/wp/v2/plugins (WP >= 5.5).

Requires admin credentials with the install_plugins / activate_plugins capability. An Application Password (WP >= 5.6) is the recommended secret as it bypasses 2FA and is colon-free by construction.

Constant Summary collapse

FOUND_BY =
'WP REST API (Authenticated)'

Constants inherited from Finder

Finder::DIRECT_ACCESS

Instance Attribute Summary

Attributes inherited from Finder

#progress_bar, #target

Instance Method Summary collapse

Methods inherited from Finder

#browser, #create_progress_bar, #found_by, #hydra, #initialize, #passive, #titleize

Constructor Details

This class inherits a constructor from WPScan::Finders::Finder

Instance Method Details

#aggressive(opts = {}) ⇒ Array<Model::Plugin>

Parameters:

  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • :userpwd (String)

    “user:password” credentials for Basic Auth

Returns:



19
20
21
22
23
24
25
26
27
28
# File 'app/finders/plugins/wp_json_api.rb', line 19

def aggressive(opts = {})
  response = Browser.get(api_url, userpwd: opts[:userpwd], headers: { 'Accept' => 'application/json' })

  raise Error::WpAuthFailed.new(response.code, api_url) if [401, 403].include?(response.code)
  raise Error::WpAuthEndpointUnavailable.new(response.code, api_url) unless response.code == 200

  plugins_from_response(response)
rescue JSON::ParserError, TypeError
  []
end

#api_urlString

Returns The REST API URL for the plugins endpoint.

Returns:

  • (String)

    The REST API URL for the plugins endpoint



41
42
43
# File 'app/finders/plugins/wp_json_api.rb', line 41

def api_url
  @api_url ||= target.url('wp-json/wp/v2/plugins')
end

#plugins_from_response(response) ⇒ Array<Model::Plugin>

Parameters:

Returns:



33
34
35
36
37
38
# File 'app/finders/plugins/wp_json_api.rb', line 33

def plugins_from_response(response)
  json = JSON.parse(response.body)
  return [] unless json.is_a?(Enumerable)

  json.filter_map { |entry| build_plugin(entry, response.effective_url) }
end