wpscan 3.7.2 → 3.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b58caaf90d2a23acc6f23bdb4506d09a34803a8af5b42409785cf33d4580d17
4
- data.tar.gz: 1001a14717f1051666ad6d923e977b901483c4e89dbc9c94d7a3bfffe4ea0ab5
3
+ metadata.gz: b09450bc3d471ad71176d276e4e1d5961ce9bc8b12511a133efe17145fe5206b
4
+ data.tar.gz: b31d1f2425c69100b985f660447e967d88a2706f737fe313d2517cc2ed3b726a
5
5
  SHA512:
6
- metadata.gz: daa9d7134979336b9c05eda0ec4cdd4cd269f11e9feebdda88c5c251aef8408670dae2ee433e578e210d0fa1cf710967ca13823a719904f548ab7ea04b9aabb9
7
- data.tar.gz: d7ca8fb4e69a5cfa592884c17d791ad155a334070e68b5d8becb222349d1e75397d617b2fa2b48be06d95c7910fafcb4884c7edc1cc78d3901b06eb6f80004e2
6
+ metadata.gz: 24e87decb82a9f01edcdf77b46fbecb7c816bef1b1ed2c7a3d839ef3f5975326920d1b3d6cd74684054744d56a8d0baa0f85f831c39477d9ac02355d9f47b8ca
7
+ data.tar.gz: 4c593ed0dd0bc0bb27bbf8b1827095d82ea601a25b17f673cc972c6e540ad21d13f61162d95c32b32fb06e7a93153264b432e5147caa779cfcbdba93d508b943
@@ -18,7 +18,7 @@ module WPScan
18
18
  target.content_dir = ParsedCli.wp_content_dir if ParsedCli.wp_content_dir
19
19
  target.plugins_dir = ParsedCli.wp_plugins_dir if ParsedCli.wp_plugins_dir
20
20
 
21
- return if target.content_dir(ParsedCli.detection_mode)
21
+ return if target.content_dir
22
22
 
23
23
  raise Error::WpContentDirNotDetected
24
24
  end
@@ -97,9 +97,12 @@ module WPScan
97
97
  # @return [ String, nil ]
98
98
  def display_name_from_body(body)
99
99
  page = Nokogiri::HTML.parse(body)
100
+
100
101
  # WP >= 3.0
101
102
  page.css('h1.page-title span').each do |node|
102
- return node.text.to_s
103
+ text = node.text.to_s.strip
104
+
105
+ return text unless text.empty?
103
106
  end
104
107
 
105
108
  # WP < 3.0
@@ -34,6 +34,8 @@ module WPScan
34
34
  def user_details_from_oembed_data(oembed_data)
35
35
  return unless oembed_data
36
36
 
37
+ oembed_data = oembed_data.first if oembed_data.is_a?(Array)
38
+
37
39
  if oembed_data['author_url'] =~ %r{/author/([^/]+)/?\z}
38
40
  details = [Regexp.last_match[1], 'Author URL', 90]
39
41
  elsif oembed_data['author_name'] && !oembed_data['author_name'].empty?
@@ -15,7 +15,9 @@ module WPScan
15
15
  target.in_scope_uris(target.homepage_res) do |uri|
16
16
  next unless uri.to_s =~ item_attribute_pattern(type)
17
17
 
18
- found << Regexp.last_match[1]
18
+ slug = Regexp.last_match[1]&.strip
19
+
20
+ found << slug unless slug&.empty?
19
21
  end
20
22
 
21
23
  uniq ? found.uniq.sort : found.sort
@@ -28,7 +30,7 @@ module WPScan
28
30
  def items_from_codes(type, uniq = true)
29
31
  found = []
30
32
 
31
- target.homepage_res.html.css('script,style').each do |tag|
33
+ target.homepage_res.html.xpath('//script[not(@src)]|//style[not(@src)]').each do |tag|
32
34
  code = tag.text.to_s
33
35
  next if code.empty?
34
36
 
@@ -42,7 +44,7 @@ module WPScan
42
44
  #
43
45
  # @return [ Regexp ]
44
46
  def item_attribute_pattern(type)
45
- @item_attribute_pattern ||= %r{\A#{item_url_pattern(type)}([^/]+)/}i
47
+ @item_attribute_pattern ||= %r{#{item_url_pattern(type)}([^/]+)/}i
46
48
  end
47
49
 
48
50
  # @param [ String ] type
@@ -59,7 +61,7 @@ module WPScan
59
61
  item_dir = type == 'plugins' ? target.plugins_dir : target.content_dir
60
62
  item_url = type == 'plugins' ? target.plugins_url : target.content_url
61
63
 
62
- url = /#{item_url.gsub(/\A(?:http|https)/i, 'https?').gsub('/', '\\\\\?\/')}/i
64
+ url = /#{item_url.gsub(/\A(?:https?)/i, 'https?').gsub('/', '\\\\\?\/')}/i
63
65
  item_dir = %r{(?:#{url}|\\?\/#{item_dir.gsub('/', '\\\\\?\/')}\\?/)}i
64
66
 
65
67
  type == 'plugins' ? item_dir : %r{#{item_dir}#{type}\\?\/}i
@@ -101,7 +101,7 @@ module WPScan
101
101
  #
102
102
  # @return [ String ]
103
103
  def parse_style_tag(body, tag)
104
- value = body[/^\s*#{Regexp.escape(tag)}:[\t ]*([^\r\n]+)/i, 1]
104
+ value = body[/#{Regexp.escape(tag)}:[\t ]*([^\r\n\*]+)/i, 1]
105
105
 
106
106
  value && !value.strip.empty? ? value.strip : nil
107
107
  end
@@ -11,7 +11,9 @@ module WPScan
11
11
  module WordPress
12
12
  include CMSScanner::Target::Platform::PHP
13
13
 
14
- WORDPRESS_PATTERN = %r{/(?:(?:wp-content/(?:themes|(?:mu\-)?plugins|uploads))|wp-includes)/}i.freeze
14
+ WORDPRESS_PATTERN = %r{/(?:(?:wp-content/(?:themes|(?:mu\-)?plugins|uploads))|wp-includes)/}i.freeze
15
+ WP_JSON_OEMBED_PATTERN = %r{/wp\-json/oembed/}i.freeze
16
+ WP_ADMIN_AJAX_PATTERN = %r{\\?/wp\-admin\\?/admin\-ajax\.php}i.freeze
15
17
 
16
18
  # These methods are used in the associated interesting_findings finders
17
19
  # to keep the boolean state of the finding rather than re-check the whole thing again
@@ -23,27 +25,33 @@ module WPScan
23
25
  # @param [ Symbol ] detection_mode
24
26
  #
25
27
  # @return [ Boolean ]
28
+ # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
26
29
  def wordpress?(detection_mode)
27
30
  in_scope_uris(homepage_res) do |uri|
28
- return true if uri.path.match(WORDPRESS_PATTERN)
31
+ return true if WORDPRESS_PATTERN.match?(uri.path) || WP_JSON_OEMBED_PATTERN.match?(uri.path)
29
32
  end
30
33
 
31
- homepage_res.html.css('meta[name="generator"]').each do |node|
32
- return true if /wordpress/i.match?(node['content'])
34
+ return true if homepage_res.html.css('meta[name="generator"]').any? do |node|
35
+ /wordpress/i.match?(node['content'])
33
36
  end
34
37
 
35
38
  return true unless comments_from_page(/wordpress/i, homepage_res).empty?
36
39
 
40
+ return true if homepage_res.html.xpath('//script[not(@src)]').any? do |node|
41
+ WP_ADMIN_AJAX_PATTERN.match?(node.text)
42
+ end
43
+
37
44
  if %i[mixed aggressive].include?(detection_mode)
38
45
  %w[wp-admin/install.php wp-login.php].each do |path|
39
- in_scope_uris(Browser.get_and_follow_location(url(path))).each do |uri|
40
- return true if uri.path.match(WORDPRESS_PATTERN)
46
+ return true if in_scope_uris(Browser.get_and_follow_location(url(path))).any? do |uri|
47
+ WORDPRESS_PATTERN.match?(uri.path)
41
48
  end
42
49
  end
43
50
  end
44
51
 
45
52
  false
46
53
  end
54
+ # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity
47
55
 
48
56
  COOKIE_PATTERNS = {
49
57
  'vjs' => /createCookie\('vjs','(?<c_value>\d+)',\d+\);/i
@@ -82,7 +90,7 @@ module WPScan
82
90
  def wordpress_hosted?
83
91
  return true if /\.wordpress\.com$/i.match?(uri.host)
84
92
 
85
- unless content_dir(:passive)
93
+ unless content_dir
86
94
  pattern = %r{https?://s\d\.wp\.com#{WORDPRESS_PATTERN}}i.freeze
87
95
 
88
96
  uris_from_page(homepage_res) do |uri|
@@ -13,12 +13,11 @@ module WPScan
13
13
  @plugins_dir = dir.chomp('/')
14
14
  end
15
15
 
16
- # @param [ Symbol ] detection_mode
17
16
  # @return [ String ] The wp-content directory
18
- def content_dir(detection_mode = :mixed)
17
+ def content_dir
19
18
  unless @content_dir
20
19
  # scope_url_pattern is from CMSScanner::Target
21
- pattern = %r{#{scope_url_pattern}([\w\s\-/]+)\\?/(?:themes|plugins|uploads|cache)\\?/}i
20
+ pattern = %r{#{scope_url_pattern}([\w\s\-/]+?)\\?/(?:themes|plugins|uploads|cache)\\?/}i
22
21
 
23
22
  in_scope_uris(homepage_res) do |uri|
24
23
  return @content_dir = Regexp.last_match[1] if uri.to_s.match(pattern)
@@ -29,9 +28,7 @@ module WPScan
29
28
  return @content_dir = match[1]
30
29
  end
31
30
 
32
- unless detection_mode == :passive
33
- return @content_dir = 'wp-content' if default_content_dir_exists?
34
- end
31
+ return @content_dir = 'wp-content' if default_content_dir_exists?
35
32
  end
36
33
 
37
34
  @content_dir
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Version
4
4
  module WPScan
5
- VERSION = '3.7.2'
5
+ VERSION = '3.7.3'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wpscan
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.2
4
+ version: 3.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - WPScanTeam
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-25 00:00:00.000000000 Z
11
+ date: 2019-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cms_scanner
@@ -72,28 +72,28 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '12.3'
75
+ version: '13.0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '12.3'
82
+ version: '13.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 3.8.0
89
+ version: 3.9.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 3.8.0
96
+ version: 3.9.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rspec-its
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -114,28 +114,28 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 0.74.0
117
+ version: 0.75.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 0.74.0
124
+ version: 0.75.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rubocop-performance
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 1.4.0
131
+ version: 1.5.0
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 1.4.0
138
+ version: 1.5.0
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: simplecov
141
141
  requirement: !ruby/object:Gem::Requirement