Class: WPScan::Model::WpItem

Inherits:
Object
  • Object
show all
Includes:
CMSScanner::Target::Platform::PHP, CMSScanner::Target::Server::Generic, Finders::Finding, Vulnerable
Defined in:
app/models/wp_item.rb

Overview

WpItem (superclass of Plugin & Theme)

Direct Known Subclasses

Plugin, Theme

Constant Summary collapse

READMES =

Most common readme filenames, based on checking all public plugins and themes.

%w[readme.txt README.txt README.md readme.md Readme.txt].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Vulnerable

#vulnerable?

Constructor Details

#initialize(slug, blog, opts = {}) ⇒ WpItem

Returns a new instance of WpItem.

Parameters:

  • slug (String)

    The plugin/theme slug

  • blog (Target)

    The targeted blog

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

Options Hash (opts):

  • :mode (Symbol)

    The detection mode to use

  • :version_detection (Hash)

    The options to use when looking for the version

  • :url (String)

    The URL of the item



25
26
27
28
29
30
31
32
33
34
# File 'app/models/wp_item.rb', line 25

def initialize(slug, blog, opts = {})
  @slug  = Addressable::URI.unencode(slug)
  @blog  = blog
  @uri   = Addressable::URI.parse(opts[:url]) if opts[:url]

  @detection_opts         = { mode: opts[:mode] }
  @version_detection_opts = opts[:version_detection] || {}

  parse_finding_options(opts)
end

Instance Attribute Details

#blogObject (readonly)

Returns the value of attribute blog.



15
16
17
# File 'app/models/wp_item.rb', line 15

def blog
  @blog
end

#db_dataObject (readonly)

Returns the value of attribute db_data.



15
16
17
# File 'app/models/wp_item.rb', line 15

def db_data
  @db_data
end

#detection_optsObject (readonly)

Returns the value of attribute detection_opts.



15
16
17
# File 'app/models/wp_item.rb', line 15

def detection_opts
  @detection_opts
end

#path_from_blogObject (readonly)

Returns the value of attribute path_from_blog.



15
16
17
# File 'app/models/wp_item.rb', line 15

def path_from_blog
  @path_from_blog
end

#slugObject (readonly)

Returns the value of attribute slug.



15
16
17
# File 'app/models/wp_item.rb', line 15

def slug
  @slug
end

#uriObject (readonly)

Returns the value of attribute uri.



15
16
17
# File 'app/models/wp_item.rb', line 15

def uri
  @uri
end

#version_detection_optsObject (readonly)

Returns the value of attribute version_detection_opts.



15
16
17
# File 'app/models/wp_item.rb', line 15

def version_detection_opts
  @version_detection_opts
end

Instance Method Details

#==(other) ⇒ Boolean

Returns:

  • (Boolean)


99
100
101
# File 'app/models/wp_item.rb', line 99

def ==(other)
  self.class == other.class && slug == other.slug
end

#classifySymbol

Returns The Class symbol associated to the item.

Returns:

  • (Symbol)

    The Class symbol associated to the item



108
109
110
# File 'app/models/wp_item.rb', line 108

def classify
  @classify ||= classify_slug(slug)
end

#directory_listing?(path = nil, params = {}) ⇒ Boolean

Parameters:

  • path (String) (defaults to: nil)
  • params (Hash) (defaults to: {})

    The request params

Returns:

  • (Boolean)


135
136
137
138
139
# File 'app/models/wp_item.rb', line 135

def directory_listing?(path = nil, params = {})
  return if detection_opts[:mode] == :passive

  super(path, params)
end

#error_log?(path = 'error_log', params = {}) ⇒ Boolean

Parameters:

  • path (String) (defaults to: 'error_log')
  • params (Hash) (defaults to: {})

    The request params

Returns:

  • (Boolean)


145
146
147
148
149
# File 'app/models/wp_item.rb', line 145

def error_log?(path = 'error_log', params = {})
  return if detection_opts[:mode] == :passive

  super(path, params)
end

#head_and_get(path, codes = [200], params = {}) ⇒ Typhoeus::Response

See CMSScanner::Target#head_and_get

This is used by the error_log? above in the super() to have the correct path (ie readme.txt checked from the plugin/theme location and not from the blog root). Could also be used in finders

Parameters:

  • path (String)
  • codes (Array<String>) (defaults to: [200])
  • params (Hash) (defaults to: {})

    The requests params

Options Hash (params):

  • :head (Hash)

    Request params for the HEAD

  • :get (hash)

    Request params for the GET

Returns:



164
165
166
167
168
169
# File 'app/models/wp_item.rb', line 164

def head_and_get(path, codes = [200], params = {})
  final_path = @path_from_blog.dup # @path_from_blog is set in the plugin/theme
  final_path << path unless path.nil?

  blog.head_and_get(final_path, codes, params)
end

#last_updatedString

Returns:

  • (String)


75
76
77
# File 'app/models/wp_item.rb', line 75

def last_updated
  @last_updated ||= ['last_updated']
end

#latest_versionString

Returns:

  • (String)


64
65
66
# File 'app/models/wp_item.rb', line 64

def latest_version
  @latest_version ||= ['latest_version'] ? Model::Version.new(['latest_version']) : nil
end

#outdated?Boolean

Returns:

  • (Boolean)


80
81
82
83
84
85
86
# File 'app/models/wp_item.rb', line 80

def outdated?
  @outdated ||= if version && latest_version
                  version < latest_version
                else
                  false
                end
end

#popular?Boolean

Not used anywhere ATM

Returns:

  • (Boolean)


70
71
72
# File 'app/models/wp_item.rb', line 70

def popular?
  @popular ||= ['popular'] ? true : false
end

#potential_readme_filenamesObject



127
128
129
# File 'app/models/wp_item.rb', line 127

def potential_readme_filenames
  @potential_readme_filenames ||= READMES
end

#readme_urlString, False

Returns The readme url if found, false otherwise.

Returns:

  • (String, False)

    The readme url if found, false otherwise



113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'app/models/wp_item.rb', line 113

def readme_url
  return if detection_opts[:mode] == :passive

  return @readme_url unless @readme_url.nil?

  potential_readme_filenames.each do |path|
    t_url = url(path)

    return @readme_url = t_url if Browser.forge_request(t_url, blog.head_or_get_params).run.code == 200
  end

  @readme_url = false
end

#to_sObject



103
104
105
# File 'app/models/wp_item.rb', line 103

def to_s
  slug
end

#url(path = nil) ⇒ String

Parameters:

  • path (String) (defaults to: nil)

    Optional path to merge with the uri

Returns:

  • (String)


91
92
93
94
95
96
# File 'app/models/wp_item.rb', line 91

def url(path = nil)
  return unless @uri
  return @uri.to_s unless path

  @uri.join(Addressable::URI.encode(path)).to_s
end

#vulnerabilitiesArray<Vulnerabily>

Returns:

  • (Array<Vulnerabily>)


37
38
39
40
41
42
43
44
45
46
47
48
# File 'app/models/wp_item.rb', line 37

def vulnerabilities
  return @vulnerabilities if @vulnerabilities

  @vulnerabilities = []

  Array(db_data['vulnerabilities']).each do |json_vuln|
    vulnerability = Vulnerability.load_from_json(json_vuln)
    @vulnerabilities << vulnerability if vulnerable_to?(vulnerability)
  end

  @vulnerabilities
end

#vulnerable_to?(vuln) ⇒ Boolean

Checks if the wp_item is vulnerable to a specific vulnerability

Parameters:

  • vuln (Vulnerability)

    Vulnerability to check the item against

Returns:

  • (Boolean)


55
56
57
58
59
60
61
# File 'app/models/wp_item.rb', line 55

def vulnerable_to?(vuln)
  return false if version && vuln&.introduced_in && version < vuln.introduced_in

  return true unless version && vuln&.fixed_in && !vuln.fixed_in.empty?

  version < vuln.fixed_in
end