wpscan 3.0.5 → 3.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d9fd4bc758b868aa36848d44911b54335efdaefc
4
- data.tar.gz: e02f0a0f89271384cd00a1d9ab760205c5bd1837
3
+ metadata.gz: 798d7f0db156c00bfee19eb7f540ffd6a1884ef1
4
+ data.tar.gz: 89eba229e55e42aa5629e76a8f6ca38e6e1a36a8
5
5
  SHA512:
6
- metadata.gz: 955e80f693240687635f34d3b7081a302c452511e6d4191624edae196b7395f08759206b9aefc56f95449eccd5bdb9b91e6e48b613d9a27c681e1370759ed6bd
7
- data.tar.gz: 9944fa88fba74980f74df6225dd47a2cf2d419eb02da52cf844f296ab729b58a3c7d747d623614bd950832a680352d5fbd9de0c3d0eb0e8dddae3bf46c17a57f
6
+ metadata.gz: 8af7943d9c8ed54283853d0c9a89d397847d66262f53888c820f177cbc3d86642b6eba9131955cc3fe4406632a38c4fd61b765ac25cee578ae239a637f70a4ea
7
+ data.tar.gz: 2d356dcfe246a074bc47fd24a4e8bb7b52e253d47a6a0c491b6ff7a6912d283fabb0db7a495c0a1ab03ca7011699c09031e4664b02e6a0811a50732f63b4702e
@@ -10,11 +10,7 @@ module WPScan
10
10
  'If no --username/s option supplied, user enumeration will be run'],
11
11
  exists: true
12
12
  ),
13
- OptString.new(['--username USERNAME', '-u', 'The username to brute force']),
14
- OptFilePath.new(
15
- ['--usernames FILE-PATH', '-U', 'List of usernames to use during the brute forcing'],
16
- exists: true
17
- )
13
+ OptSmartList.new(['--usernames LIST', '-U', 'List of usernames to use during the brute forcing'])
18
14
  ]
19
15
  end
20
16
 
@@ -36,14 +32,10 @@ module WPScan
36
32
 
37
33
  # @return [ Array<Users> ] The users to brute force
38
34
  def users
39
- return target.users unless parsed_options[:usernames] || parsed_options[:username]
35
+ return target.users unless parsed_options[:usernames]
40
36
 
41
- if parsed_options[:username]
42
- [User.new(parsed_options[:username])]
43
- else
44
- File.open(parsed_options[:usernames]).reduce([]) do |acc, elem|
45
- acc << User.new(elem.chomp)
46
- end
37
+ parsed_options[:usernames].reduce([]) do |acc, elem|
38
+ acc << User.new(elem.chomp)
47
39
  end
48
40
  end
49
41
 
@@ -89,7 +81,7 @@ module WPScan
89
81
  def progress_bar(size, username)
90
82
  ProgressBar.create(
91
83
  format: '%t %a <%B> (%c / %C) %P%% %e',
92
- title: "Brute Forcing #{username}",
84
+ title: "Brute Forcing #{username} -",
93
85
  total: size
94
86
  )
95
87
  end
@@ -52,8 +52,6 @@ module WPScan
52
52
 
53
53
  super(false) # disable banner output
54
54
 
55
- DB.init_db
56
-
57
55
  load_server_module
58
56
 
59
57
  check_wordpress_state
@@ -31,7 +31,7 @@ module WPScan
31
31
  def create_plugins_comments_finders(mod, config)
32
32
  mod.const_set(
33
33
  :Comments, Class.new(Finders::Finder::PluginVersion::Comments) do
34
- const_set(:PATTERN, Regexp.new(config['pattern'], Regexp::IGNORECASE))
34
+ const_set(:PATTERN, config['pattern'])
35
35
  end
36
36
  )
37
37
  end
@@ -42,7 +42,7 @@ module WPScan
42
42
  # @return [ Array<OptParseValidator::OptBase> ]
43
43
  def cli_plugins_opts
44
44
  [
45
- OptFilePath.new(['--plugins-list FILE-PATH', 'List of plugins\' location to use'], exists: true),
45
+ OptSmartList.new(['--plugins-list LIST', 'List of plugins to enumerate']),
46
46
  OptChoice.new(
47
47
  ['--plugins-detection MODE',
48
48
  'Use the supplied mode to enumerate Plugins, instead of the global (--detection-mode) mode.'],
@@ -65,7 +65,7 @@ module WPScan
65
65
  # @return [ Array<OptParseValidator::OptBase> ]
66
66
  def cli_themes_opts
67
67
  [
68
- OptFilePath.new(['--themes-list FILE-PATH', 'List of themes\' location to use'], exists: true),
68
+ OptSmartList.new(['--themes-list LIST', 'List of themes to enumerate']),
69
69
  OptChoice.new(
70
70
  ['--themes-detection MODE',
71
71
  'Use the supplied mode to enumerate Themes, instead of the global (--detection-mode) mode.'],
@@ -129,10 +129,9 @@ module WPScan
129
129
  # @return [ Array<OptParseValidator::OptBase> ]
130
130
  def cli_users_opts
131
131
  [
132
- OptFilePath.new(
133
- ['--users-list FILE-PATH',
134
- 'List of users to check during the users enumeration from the Login Error Messages'],
135
- exists: true
132
+ OptSmartList.new(
133
+ ['--users-list LIST',
134
+ 'List of users to check during the users enumeration from the Login Error Messages']
136
135
  ),
137
136
  OptChoice.new(
138
137
  ['--users-detection MODE',
@@ -63,7 +63,7 @@ module WPScan
63
63
  # @return [ Array<String> ] The plugins list associated to the cli options
64
64
  def plugins_list_from_opts(opts)
65
65
  # List file provided by the user via the cli
66
- return File.open(opts[:plugins_list]).map(&:chomp) if opts[:plugins_list]
66
+ return opts[:plugins_list] if opts[:plugins_list]
67
67
 
68
68
  if opts[:enumerate][:all_plugins]
69
69
  DB::Plugins.all_slugs
@@ -101,7 +101,7 @@ module WPScan
101
101
  # @return [ Array<String> ] The themes list associated to the cli options
102
102
  def themes_list_from_opts(opts)
103
103
  # List file provided by the user via the cli
104
- return File.open(opts[:themes_list]).map(&:chomp) if opts[:themes_list]
104
+ return opts[:themes_list] if opts[:themes_list]
105
105
 
106
106
  if opts[:enumerate][:all_themes]
107
107
  DB::Themes.all_slugs
@@ -38,9 +38,7 @@ module WPScan
38
38
  # usernames from the potential Users found
39
39
  unames = opts[:found].map(&:username)
40
40
 
41
- if opts[:list]
42
- File.open(opts[:list]).each { |uname| unames << uname.chomp }
43
- end
41
+ [*opts[:list]].each { |uname| unames << uname.chomp }
44
42
 
45
43
  unames.uniq
46
44
  end
@@ -5,19 +5,9 @@ module WPScan
5
5
  class UniqueFingerprinting < CMSScanner::Finders::Finder
6
6
  include CMSScanner::Finders::Finder::Fingerprinter
7
7
 
8
- QUERY = 'SELECT md5_hash, path_id, version_id, ' \
9
- 'versions.number AS version,' \
10
- 'paths.value AS path ' \
11
- 'FROM fingerprints ' \
12
- 'LEFT JOIN versions ON version_id = versions.id ' \
13
- 'LEFT JOIN paths on path_id = paths.id ' \
14
- 'WHERE md5_hash IN ' \
15
- '(SELECT md5_hash FROM fingerprints GROUP BY md5_hash HAVING COUNT(*) = 1) ' \
16
- 'ORDER BY version DESC'.freeze
17
-
18
8
  # @return [ WpVersion ]
19
9
  def aggressive(opts = {})
20
- fingerprint(unique_fingerprints, opts) do |version_number, url, md5sum|
10
+ fingerprint(DB::Fingerprints.wp_unique_fingerprints, opts) do |version_number, url, md5sum|
21
11
  hydra.abort
22
12
  progress_bar.finish
23
13
 
@@ -31,30 +21,6 @@ module WPScan
31
21
  nil
32
22
  end
33
23
 
34
- # @return [ Hash ] The unique fingerprints across all versions in the DB
35
- #
36
- # Format returned:
37
- # {
38
- # file_path_1: {
39
- # md5_hash_1: version_1,
40
- # md5_hash_2: version_2
41
- # },
42
- # file_path_2: {
43
- # md5_hash_3: version_1,
44
- # md5_hash_4: version_3
45
- # }
46
- # }
47
- def unique_fingerprints
48
- fingerprints = {}
49
-
50
- repository(:default).adapter.select(QUERY).each do |f|
51
- fingerprints[f.path] ||= {}
52
- fingerprints[f.path][f.md5_hash] = f.version
53
- end
54
-
55
- fingerprints
56
- end
57
-
58
24
  def create_progress_bar(opts = {})
59
25
  super(opts.merge(title: 'Fingerprinting the version -'))
60
26
  end
@@ -6,8 +6,8 @@ module WPScan
6
6
  include CMSScanner::Target::Platform::PHP
7
7
  include CMSScanner::Target::Server::Generic
8
8
 
9
- READMES = %w[readme.txt README.txt Readme.txt ReadMe.txt README.TXT readme.TXT].freeze
10
- CHANGELOGS = %w[changelog.txt Changelog.txt ChangeLog.txt CHANGELOG.txt].freeze
9
+ READMES = %w[readme.txt README.txt README.md readme.md Readme.txt].freeze
10
+ CHANGELOGS = %w[changelog.txt CHANGELOG.md changelog.md].freeze
11
11
 
12
12
  attr_reader :uri, :name, :detection_opts, :version_detection_opts, :target, :db_data
13
13
 
@@ -22,9 +22,15 @@ module WPScan
22
22
 
23
23
  @all_numbers = []
24
24
 
25
- DB::Version.all.each { |v| @all_numbers << v.number }
25
+ DB::Fingerprints.wp_fingerprints.each_value do |fp|
26
+ fp.each_value do |versions|
27
+ versions.each do |version|
28
+ @all_numbers << version unless @all_numbers.include?(version)
29
+ end
30
+ end
31
+ end
26
32
 
27
- @all_numbers
33
+ @all_numbers.sort! { |a, b| Gem::Version.new(b) <=> Gem::Version.new(a) }
28
34
  end
29
35
 
30
36
  # @return [ JSON ]
data/lib/wpscan.rb CHANGED
@@ -11,6 +11,7 @@ require 'uri'
11
11
  require 'time'
12
12
  require 'readline'
13
13
  require 'securerandom'
14
+
14
15
  # Custom Libs
15
16
  require 'wpscan/helper'
16
17
  require 'wpscan/db'
data/lib/wpscan/db.rb CHANGED
@@ -1,10 +1,4 @@
1
- require 'dm-core'
2
- require 'dm-migrations'
3
- require 'dm-constraints'
4
- require 'dm-sqlite-adapter'
5
-
6
1
  require 'wpscan/db/wp_item'
7
- require 'wpscan/db/schema'
8
2
  require 'wpscan/db/updater'
9
3
  require 'wpscan/db/wp_items'
10
4
  require 'wpscan/db/plugins'
@@ -12,17 +6,5 @@ require 'wpscan/db/themes'
12
6
  require 'wpscan/db/plugin'
13
7
  require 'wpscan/db/theme'
14
8
  require 'wpscan/db/wp_version'
9
+ require 'wpscan/db/fingerprints'
15
10
  require 'wpscan/db/dynamic_finders'
16
-
17
- module WPScan
18
- # DB
19
- module DB
20
- def self.init_db
21
- db_file ||= File.join(DB_DIR, 'wordpress.db')
22
-
23
- # DataMapper::Logger.new($stdout, :debug)
24
- DataMapper.setup(:default, "sqlite://#{db_file}")
25
- DataMapper.auto_upgrade!
26
- end
27
- end
28
- end
@@ -4,7 +4,7 @@ module WPScan
4
4
  class DynamicFinders
5
5
  # @return [ String ]
6
6
  def self.db_file
7
- @db_file ||= File.join(DB_DIR, 'dynamic_finders.yml')
7
+ @db_file ||= File.join(DB_DIR, 'dynamic_finders_01.yml')
8
8
  end
9
9
 
10
10
  # @return [ Hash ]
@@ -35,15 +35,7 @@ module WPScan
35
35
 
36
36
  # @return [ Hash ]
37
37
  def self.comments
38
- unless @comments
39
- @comments = finder_configs('Comments')
40
-
41
- @comments.each do |slug, config|
42
- @comments[slug]['pattern'] = Regexp.new(config['pattern'], Regexp::IGNORECASE)
43
- end
44
- end
45
-
46
- @comments
38
+ @comments ||= finder_configs('Comments')
47
39
  end
48
40
 
49
41
  # @return [ Hash ]
@@ -0,0 +1,50 @@
1
+ module WPScan
2
+ module DB
3
+ # Fingerprints class
4
+ class Fingerprints
5
+ # @param [ Hash ] data
6
+ #
7
+ # @return [ Hash ] the unique fingerprints in the data argument given
8
+ # Format returned:
9
+ # {
10
+ # file_path_1: {
11
+ # md5_hash_1: version_1,
12
+ # md5_hash_2: version_2
13
+ # },
14
+ # file_path_2: {
15
+ # md5_hash_3: version_1,
16
+ # md5_hash_4: version_3
17
+ # }
18
+ # }
19
+ def self.unique_fingerprints(data)
20
+ unique_fingerprints = {}
21
+
22
+ data.each do |file_path, fingerprints|
23
+ fingerprints.each do |md5sum, versions|
24
+ next unless versions.size == 1
25
+
26
+ unique_fingerprints[file_path] ||= {}
27
+ unique_fingerprints[file_path][md5sum] = versions.first
28
+ end
29
+ end
30
+
31
+ unique_fingerprints
32
+ end
33
+
34
+ # @return [ String ]
35
+ def self.wp_fingerprints_path
36
+ @wp_unique_fingerprints_path ||= File.join(DB_DIR, 'wp_fingerprints.json')
37
+ end
38
+
39
+ # @return [ Hash ]
40
+ def self.wp_fingerprints
41
+ @wp_fingerprints ||= read_json_file(wp_fingerprints_path)
42
+ end
43
+
44
+ # @return [ Hash ]
45
+ def self.wp_unique_fingerprints
46
+ @wp_unique_fingerprints ||= unique_fingerprints(wp_fingerprints)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -7,9 +7,11 @@ module WPScan
7
7
  FILES = %w[
8
8
  plugins.json themes.json wordpresses.json
9
9
  timthumbs-v3.txt user-agents.txt config_backups.txt
10
- dynamic_finders.yml wordpress.db LICENSE
10
+ dynamic_finders_01.yml wp_fingerprints.json LICENSE
11
11
  ].freeze
12
12
 
13
+ OLD_FILES = %w[wordpress.db dynamic_finders.yml].freeze
14
+
13
15
  attr_reader :repo_directory
14
16
 
15
17
  def initialize(repo_directory)
@@ -18,6 +20,16 @@ module WPScan
18
20
  FileUtils.mkdir_p(repo_directory) unless Dir.exist?(repo_directory)
19
21
 
20
22
  raise "#{repo_directory} is not writable" unless Pathname.new(repo_directory).writable?
23
+
24
+ delete_old_files
25
+ end
26
+
27
+ # Removes DB files which are no longer used
28
+ # this doesn't raise errors if they don't exist
29
+ def delete_old_files
30
+ OLD_FILES.each do |old_file|
31
+ FileUtils.remove_file(local_file_path(old_file), true)
32
+ end
21
33
  end
22
34
 
23
35
  # @return [ Time, nil ]
@@ -1,4 +1,4 @@
1
1
  # Version
2
2
  module WPScan
3
- VERSION = '3.0.5'.freeze
3
+ VERSION = '3.0.6'.freeze
4
4
  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.0.5
4
+ version: 3.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - WPScanTeam
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-06 00:00:00.000000000 Z
11
+ date: 2017-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cms_scanner
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.0.37.11
19
+ version: 0.0.37.12
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.0.37.11
26
+ version: 0.0.37.12
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: yajl-ruby
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,62 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.1'
55
- - !ruby/object:Gem::Dependency
56
- name: dm-core
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 1.2.0
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 1.2.0
69
- - !ruby/object:Gem::Dependency
70
- name: dm-migrations
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: 1.2.0
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: 1.2.0
83
- - !ruby/object:Gem::Dependency
84
- name: dm-constraints
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 1.2.0
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 1.2.0
97
- - !ruby/object:Gem::Dependency
98
- name: dm-sqlite-adapter
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: 1.2.0
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: 1.2.0
111
55
  - !ruby/object:Gem::Dependency
112
56
  name: rake
113
57
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +72,14 @@ dependencies:
128
72
  requirements:
129
73
  - - "~>"
130
74
  - !ruby/object:Gem::Version
131
- version: 3.6.0
75
+ version: 3.7.0
132
76
  type: :development
133
77
  prerelease: false
134
78
  version_requirements: !ruby/object:Gem::Requirement
135
79
  requirements:
136
80
  - - "~>"
137
81
  - !ruby/object:Gem::Version
138
- version: 3.6.0
82
+ version: 3.7.0
139
83
  - !ruby/object:Gem::Dependency
140
84
  name: rspec-its
141
85
  requirement: !ruby/object:Gem::Requirement
@@ -361,9 +305,9 @@ files:
361
305
  - lib/wpscan/controllers.rb
362
306
  - lib/wpscan/db.rb
363
307
  - lib/wpscan/db/dynamic_finders.rb
308
+ - lib/wpscan/db/fingerprints.rb
364
309
  - lib/wpscan/db/plugin.rb
365
310
  - lib/wpscan/db/plugins.rb
366
- - lib/wpscan/db/schema.rb
367
311
  - lib/wpscan/db/theme.rb
368
312
  - lib/wpscan/db/themes.rb
369
313
  - lib/wpscan/db/updater.rb
@@ -1,39 +0,0 @@
1
- module WPScan
2
- module DB
3
- # WP Version
4
- class Version < WpItem
5
- include DataMapper::Resource
6
-
7
- storage_names[:default] = 'versions'
8
-
9
- has n, :fingerprints, constraint: :destroy
10
-
11
- property :id, Serial
12
- property :number, String, required: true, unique: true
13
- end
14
-
15
- # Path
16
- class Path
17
- include DataMapper::Resource
18
-
19
- storage_names[:default] = 'paths'
20
-
21
- has n, :fingerprints, constraint: :destroy
22
-
23
- property :id, Serial
24
- property :value, String, required: true, unique: true
25
- end
26
-
27
- # Fingerprint
28
- class Fingerprint
29
- include DataMapper::Resource
30
-
31
- storage_names[:default] = 'fingerprints'
32
-
33
- belongs_to :version, key: true
34
- belongs_to :path, key: true
35
-
36
- property :md5_hash, String, required: true, length: 32
37
- end
38
- end
39
- end