wpscan 3.2.1 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +73 -70
- data/app/controllers.rb +1 -1
- data/app/controllers/enumeration.rb +1 -1
- data/app/controllers/enumeration/cli_options.rb +32 -15
- data/app/controllers/enumeration/enum_methods.rb +7 -0
- data/app/controllers/password_attack.rb +108 -0
- data/app/finders.rb +2 -0
- data/app/finders/config_backups/known_filenames.rb +1 -1
- data/app/finders/db_exports.rb +17 -0
- data/app/finders/db_exports/known_locations.rb +49 -0
- data/app/finders/interesting_findings/mu_plugins.rb +1 -0
- data/app/finders/main_theme/css_style.rb +1 -1
- data/app/finders/medias/attachment_brute_forcing.rb +1 -1
- data/app/finders/passwords.rb +3 -0
- data/app/finders/passwords/wp_login.rb +22 -0
- data/app/finders/passwords/xml_rpc.rb +22 -0
- data/app/finders/passwords/xml_rpc_multicall.rb +102 -0
- data/app/finders/users.rb +2 -0
- data/app/finders/users/author_id_brute_forcing.rb +3 -3
- data/app/finders/users/author_posts.rb +2 -2
- data/app/finders/users/login_error_messages.rb +1 -1
- data/app/finders/users/oembed_api.rb +4 -4
- data/app/finders/users/rss_generator.rb +38 -0
- data/app/finders/users/wp_json_api.rb +5 -5
- data/app/finders/wp_version/atom_generator.rb +1 -1
- data/app/finders/wp_version/rdf_generator.rb +1 -1
- data/app/finders/wp_version/rss_generator.rb +1 -1
- data/app/models.rb +1 -1
- data/app/models/db_export.rb +5 -0
- data/app/models/wp_item.rb +2 -0
- data/app/views/cli/core/banner.erb +1 -1
- data/app/views/cli/enumeration/db_exports.erb +11 -0
- data/app/views/cli/{brute_force → password_attack}/users.erb +0 -0
- data/app/views/json/enumeration/db_exports.erb +10 -0
- data/app/views/json/{brute_force → password_attack}/users.erb +1 -1
- data/bin/wpscan +1 -1
- data/lib/wpscan/browser.rb +1 -1
- data/lib/wpscan/db/dynamic_finders/plugin.rb +2 -2
- data/lib/wpscan/db/dynamic_finders/wordpress.rb +2 -2
- data/lib/wpscan/db/fingerprints.rb +1 -1
- data/lib/wpscan/db/updater.rb +4 -1
- data/lib/wpscan/finders/dynamic_finder/version/query_parameter.rb +2 -1
- data/lib/wpscan/finders/dynamic_finder/wp_item_version.rb +2 -1
- data/lib/wpscan/finders/dynamic_finder/wp_version.rb +5 -4
- data/lib/wpscan/target.rb +13 -0
- data/lib/wpscan/target/platform/wordpress/custom_directories.rb +1 -1
- data/lib/wpscan/version.rb +1 -1
- metadata +29 -22
- data/app/controllers/brute_force.rb +0 -116
- data/app/models/user.rb +0 -31
- data/app/views/cli/brute_force/error.erb +0 -1
- data/app/views/cli/brute_force/found.erb +0 -2
data/lib/wpscan/browser.rb
CHANGED
@@ -28,7 +28,7 @@ module WPScan
|
|
28
28
|
end
|
29
29
|
|
30
30
|
fs.each do |finder_name, config|
|
31
|
-
klass = config['class']
|
31
|
+
klass = config['class'] || finder_name
|
32
32
|
|
33
33
|
next unless klass.to_sym == finder_class
|
34
34
|
|
@@ -79,7 +79,7 @@ module WPScan
|
|
79
79
|
mod = maybe_create_modudle(slug)
|
80
80
|
|
81
81
|
finders.each do |finder_class, config|
|
82
|
-
klass = config['class']
|
82
|
+
klass = config['class'] || finder_class
|
83
83
|
|
84
84
|
# Instead of raising exceptions, skip unallowed/already defined finders
|
85
85
|
# So that, when new DF configs are put in the .yml
|
@@ -34,7 +34,7 @@ module WPScan
|
|
34
34
|
end
|
35
35
|
|
36
36
|
finders.each do |finder_name, config|
|
37
|
-
klass = config['class']
|
37
|
+
klass = config['class'] || finder_name
|
38
38
|
|
39
39
|
next unless klass.to_sym == finder_class
|
40
40
|
|
@@ -51,7 +51,7 @@ module WPScan
|
|
51
51
|
|
52
52
|
def self.create_versions_finders
|
53
53
|
versions_finders_configs.each do |finder_class, config|
|
54
|
-
klass = config['class']
|
54
|
+
klass = config['class'] || finder_class
|
55
55
|
|
56
56
|
# Instead of raising exceptions, skip unallowed/already defined finders
|
57
57
|
# So that, when new DF configs are put in the .yml
|
data/lib/wpscan/db/updater.rb
CHANGED
@@ -7,7 +7,7 @@ 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 wp_fingerprints.json LICENSE
|
10
|
+
db_exports.txt dynamic_finders.yml wp_fingerprints.json LICENSE
|
11
11
|
].freeze
|
12
12
|
|
13
13
|
OLD_FILES = %w[wordpress.db dynamic_finders_01.yml].freeze
|
@@ -82,6 +82,7 @@ module WPScan
|
|
82
82
|
|
83
83
|
res = Browser.get(url, request_params)
|
84
84
|
raise DownloadError, res if res.timed_out? || res.code != 200
|
85
|
+
|
85
86
|
res.body.chomp
|
86
87
|
end
|
87
88
|
|
@@ -99,11 +100,13 @@ module WPScan
|
|
99
100
|
|
100
101
|
def create_backup(filename)
|
101
102
|
return unless File.exist?(local_file_path(filename))
|
103
|
+
|
102
104
|
FileUtils.cp(local_file_path(filename), backup_file_path(filename))
|
103
105
|
end
|
104
106
|
|
105
107
|
def restore_backup(filename)
|
106
108
|
return unless File.exist?(backup_file_path(filename))
|
109
|
+
|
107
110
|
FileUtils.cp(backup_file_path(filename), local_file_path(filename))
|
108
111
|
end
|
109
112
|
|
@@ -37,6 +37,7 @@ module WPScan
|
|
37
37
|
uri = Addressable::URI.parse(url)
|
38
38
|
|
39
39
|
next unless uri.path =~ path_pattern && uri.query&.match(self.class::PATTERN)
|
40
|
+
|
40
41
|
version = Regexp.last_match[:v].to_s
|
41
42
|
|
42
43
|
found[version] ||= []
|
@@ -48,7 +49,7 @@ module WPScan
|
|
48
49
|
|
49
50
|
# @return [ String ]
|
50
51
|
def xpath
|
51
|
-
@xpath ||= self.class::XPATH || '//link[@href]|//script[@src]'
|
52
|
+
@xpath ||= self.class::XPATH || '//link[@href]/@href|//script[@src]/@src'
|
52
53
|
end
|
53
54
|
|
54
55
|
# @return [ Regexp ]
|
@@ -30,7 +30,8 @@ module WPScan
|
|
30
30
|
|
31
31
|
def xpath
|
32
32
|
@xpath ||= self.class::XPATH ||
|
33
|
-
"//link[contains(@href,'#{target.slug}')]
|
33
|
+
"//link[contains(@href,'#{target.slug}')]/@href" \
|
34
|
+
"|//script[contains(@src,'#{target.slug}')]/@src"
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
@@ -37,13 +37,14 @@ module WPScan
|
|
37
37
|
|
38
38
|
class WpItemQueryParameter < QueryParameter
|
39
39
|
def xpath
|
40
|
-
@xpath ||=
|
41
|
-
|
42
|
-
|
40
|
+
@xpath ||=
|
41
|
+
self.class::XPATH ||
|
42
|
+
"//link[contains(@href,'#{target.plugins_dir}') or contains(@href,'#{target.themes_dir}')]/@href" \
|
43
|
+
"|//script[contains(@src,'#{target.plugins_dir}') or contains(@src,'#{target.themes_dir}')]/@src"
|
43
44
|
end
|
44
45
|
|
45
46
|
def path_pattern
|
46
|
-
@
|
47
|
+
@path_pattern ||= %r{
|
47
48
|
(?:#{Regexp.escape(target.plugins_dir)}|#{Regexp.escape(target.themes_dir)})/
|
48
49
|
[^/]+/
|
49
50
|
.*\.(?:css|js)\z
|
data/lib/wpscan/target.rb
CHANGED
@@ -12,12 +12,18 @@ module WPScan
|
|
12
12
|
end
|
13
13
|
|
14
14
|
return true unless [*@config_backups].empty?
|
15
|
+
return true unless [*@db_exports].empty?
|
15
16
|
|
16
17
|
[*@users].each { |u| return true if u.password }
|
17
18
|
|
18
19
|
false
|
19
20
|
end
|
20
21
|
|
22
|
+
# @return [ XMLRPC, nil ]
|
23
|
+
def xmlrpc
|
24
|
+
@xmlrpc ||= interesting_findings&.select { |f| f.is_a?(WPScan::XMLRPC) }&.first
|
25
|
+
end
|
26
|
+
|
21
27
|
# @param [ Hash ] opts
|
22
28
|
#
|
23
29
|
# @return [ WpVersion, false ] The WpVersion found or false if not detected
|
@@ -64,6 +70,13 @@ module WPScan
|
|
64
70
|
@config_backups ||= Finders::ConfigBackups::Base.find(self, opts)
|
65
71
|
end
|
66
72
|
|
73
|
+
# @param [ Hash ] opts
|
74
|
+
#
|
75
|
+
# @return [ Array<DBExport> ]
|
76
|
+
def db_exports(opts = {})
|
77
|
+
@db_exports ||= Finders::DbExports::Base.find(self, opts)
|
78
|
+
end
|
79
|
+
|
67
80
|
# @param [ Hash ] opts
|
68
81
|
#
|
69
82
|
# @return [ Array<Media> ]
|
@@ -15,7 +15,7 @@ module WPScan
|
|
15
15
|
def content_dir
|
16
16
|
unless @content_dir
|
17
17
|
escaped_url = Regexp.escape(url).gsub(/https?/i, 'https?')
|
18
|
-
pattern = %r{#{escaped_url}(.+?)\/(?:themes|plugins|uploads)\/}i
|
18
|
+
pattern = %r{#{escaped_url}(.+?)\/(?:themes|plugins|uploads|cache)\/}i
|
19
19
|
|
20
20
|
in_scope_urls(homepage_res) do |url|
|
21
21
|
return @content_dir = Regexp.last_match[1] if url.match(pattern)
|
data/lib/wpscan/version.rb
CHANGED
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.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- WPScanTeam
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cms_scanner
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.0.
|
19
|
+
version: 0.0.40
|
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.
|
26
|
+
version: 0.0.40
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '5.
|
33
|
+
version: '5.2'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '5.
|
40
|
+
version: '5.2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: yajl-ruby
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,28 +86,28 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '12.
|
89
|
+
version: '12.3'
|
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: '12.
|
96
|
+
version: '12.3'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rspec
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 3.
|
103
|
+
version: 3.8.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 3.
|
110
|
+
version: 3.8.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rspec-its
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,42 +128,42 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.
|
131
|
+
version: 0.59.2
|
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: 0.
|
138
|
+
version: 0.59.2
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: simplecov
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 0.
|
145
|
+
version: 0.16.1
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 0.
|
152
|
+
version: 0.16.1
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: webmock
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
157
|
- - "~>"
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: 3.
|
159
|
+
version: 3.4.2
|
160
160
|
type: :development
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version: 3.
|
166
|
+
version: 3.4.2
|
167
167
|
description: WPScan is a black box WordPress vulnerability scanner.
|
168
168
|
email:
|
169
169
|
- team@wpscan.org
|
@@ -177,17 +177,19 @@ files:
|
|
177
177
|
- app/app.rb
|
178
178
|
- app/controllers.rb
|
179
179
|
- app/controllers/aliases.rb
|
180
|
-
- app/controllers/brute_force.rb
|
181
180
|
- app/controllers/core.rb
|
182
181
|
- app/controllers/custom_directories.rb
|
183
182
|
- app/controllers/enumeration.rb
|
184
183
|
- app/controllers/enumeration/cli_options.rb
|
185
184
|
- app/controllers/enumeration/enum_methods.rb
|
186
185
|
- app/controllers/main_theme.rb
|
186
|
+
- app/controllers/password_attack.rb
|
187
187
|
- app/controllers/wp_version.rb
|
188
188
|
- app/finders.rb
|
189
189
|
- app/finders/config_backups.rb
|
190
190
|
- app/finders/config_backups/known_filenames.rb
|
191
|
+
- app/finders/db_exports.rb
|
192
|
+
- app/finders/db_exports/known_locations.rb
|
191
193
|
- app/finders/interesting_findings.rb
|
192
194
|
- app/finders/interesting_findings/backup_db.rb
|
193
195
|
- app/finders/interesting_findings/debug_log.rb
|
@@ -207,6 +209,10 @@ files:
|
|
207
209
|
- app/finders/main_theme/woo_framework_meta_generator.rb
|
208
210
|
- app/finders/medias.rb
|
209
211
|
- app/finders/medias/attachment_brute_forcing.rb
|
212
|
+
- app/finders/passwords.rb
|
213
|
+
- app/finders/passwords/wp_login.rb
|
214
|
+
- app/finders/passwords/xml_rpc.rb
|
215
|
+
- app/finders/passwords/xml_rpc_multicall.rb
|
210
216
|
- app/finders/plugin_version.rb
|
211
217
|
- app/finders/plugin_version/readme.rb
|
212
218
|
- app/finders/plugins.rb
|
@@ -234,6 +240,7 @@ files:
|
|
234
240
|
- app/finders/users/author_posts.rb
|
235
241
|
- app/finders/users/login_error_messages.rb
|
236
242
|
- app/finders/users/oembed_api.rb
|
243
|
+
- app/finders/users/rss_generator.rb
|
237
244
|
- app/finders/users/wp_json_api.rb
|
238
245
|
- app/finders/wp_items.rb
|
239
246
|
- app/finders/wp_items/urls_in_homepage.rb
|
@@ -245,24 +252,22 @@ files:
|
|
245
252
|
- app/finders/wp_version/unique_fingerprinting.rb
|
246
253
|
- app/models.rb
|
247
254
|
- app/models/config_backup.rb
|
255
|
+
- app/models/db_export.rb
|
248
256
|
- app/models/interesting_finding.rb
|
249
257
|
- app/models/media.rb
|
250
258
|
- app/models/plugin.rb
|
251
259
|
- app/models/theme.rb
|
252
260
|
- app/models/timthumb.rb
|
253
|
-
- app/models/user.rb
|
254
261
|
- app/models/wp_item.rb
|
255
262
|
- app/models/wp_version.rb
|
256
263
|
- app/models/xml_rpc.rb
|
257
|
-
- app/views/cli/brute_force/error.erb
|
258
|
-
- app/views/cli/brute_force/found.erb
|
259
|
-
- app/views/cli/brute_force/users.erb
|
260
264
|
- app/views/cli/core/banner.erb
|
261
265
|
- app/views/cli/core/db_update_finished.erb
|
262
266
|
- app/views/cli/core/db_update_started.erb
|
263
267
|
- app/views/cli/core/not_fully_configured.erb
|
264
268
|
- app/views/cli/core/version.erb
|
265
269
|
- app/views/cli/enumeration/config_backups.erb
|
270
|
+
- app/views/cli/enumeration/db_exports.erb
|
266
271
|
- app/views/cli/enumeration/medias.erb
|
267
272
|
- app/views/cli/enumeration/plugins.erb
|
268
273
|
- app/views/cli/enumeration/themes.erb
|
@@ -272,18 +277,19 @@ files:
|
|
272
277
|
- app/views/cli/info.erb
|
273
278
|
- app/views/cli/main_theme/theme.erb
|
274
279
|
- app/views/cli/notice.erb
|
280
|
+
- app/views/cli/password_attack/users.erb
|
275
281
|
- app/views/cli/theme.erb
|
276
282
|
- app/views/cli/usage.erb
|
277
283
|
- app/views/cli/vulnerability.erb
|
278
284
|
- app/views/cli/wp_item.erb
|
279
285
|
- app/views/cli/wp_version/version.erb
|
280
|
-
- app/views/json/brute_force/users.erb
|
281
286
|
- app/views/json/core/banner.erb
|
282
287
|
- app/views/json/core/db_update_finished.erb
|
283
288
|
- app/views/json/core/db_update_started.erb
|
284
289
|
- app/views/json/core/not_fully_configured.erb
|
285
290
|
- app/views/json/core/version.erb
|
286
291
|
- app/views/json/enumeration/config_backups.erb
|
292
|
+
- app/views/json/enumeration/db_exports.erb
|
287
293
|
- app/views/json/enumeration/medias.erb
|
288
294
|
- app/views/json/enumeration/plugins.erb
|
289
295
|
- app/views/json/enumeration/themes.erb
|
@@ -291,6 +297,7 @@ files:
|
|
291
297
|
- app/views/json/enumeration/users.erb
|
292
298
|
- app/views/json/finding.erb
|
293
299
|
- app/views/json/main_theme/theme.erb
|
300
|
+
- app/views/json/password_attack/users.erb
|
294
301
|
- app/views/json/theme.erb
|
295
302
|
- app/views/json/wp_item.erb
|
296
303
|
- app/views/json/wp_version/version.erb
|
@@ -1,116 +0,0 @@
|
|
1
|
-
module WPScan
|
2
|
-
module Controller
|
3
|
-
# Brute Force Controller
|
4
|
-
class BruteForce < CMSScanner::Controller::Base
|
5
|
-
def cli_options
|
6
|
-
[
|
7
|
-
OptFilePath.new(
|
8
|
-
['--passwords FILE-PATH', '-P',
|
9
|
-
'List of passwords to use during the brute forcing.',
|
10
|
-
'If no --username/s option supplied, user enumeration will be run'],
|
11
|
-
exists: true
|
12
|
-
),
|
13
|
-
OptSmartList.new(['--usernames LIST', '-U', 'List of usernames to use during the brute forcing'])
|
14
|
-
]
|
15
|
-
end
|
16
|
-
|
17
|
-
def run
|
18
|
-
return unless parsed_options[:passwords]
|
19
|
-
|
20
|
-
begin
|
21
|
-
found = []
|
22
|
-
|
23
|
-
brute_force(users, passwords(parsed_options[:passwords])) do |user|
|
24
|
-
found << user
|
25
|
-
|
26
|
-
output('found', user: user) if user_interaction?
|
27
|
-
end
|
28
|
-
ensure
|
29
|
-
output('users', users: found)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# @return [ Array<Users> ] The users to brute force
|
34
|
-
def users
|
35
|
-
return target.users unless parsed_options[:usernames]
|
36
|
-
|
37
|
-
parsed_options[:usernames].reduce([]) do |acc, elem|
|
38
|
-
acc << User.new(elem.chomp)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# the iteration should be on the passwords to be more efficient
|
43
|
-
# however, it's not that simple expecially when a combination is found:
|
44
|
-
# - the estimated number of requests (for the progressbar) has to be updated.
|
45
|
-
# - the user found has to be deleted from the loop
|
46
|
-
#
|
47
|
-
# @param [ Array<User> ] users
|
48
|
-
# @param [ Array<String> ] passwords
|
49
|
-
#
|
50
|
-
# @yield [ User ] when a valid combination is found
|
51
|
-
def brute_force(users, passwords)
|
52
|
-
hydra = Browser.instance.hydra
|
53
|
-
|
54
|
-
users.each do |user|
|
55
|
-
bar = progress_bar(passwords.size, user.username) if user_interaction?
|
56
|
-
|
57
|
-
passwords.each do |password|
|
58
|
-
request = target.login_request(user.username, password)
|
59
|
-
|
60
|
-
request.on_complete do |res|
|
61
|
-
bar.progress += 1 if user_interaction?
|
62
|
-
|
63
|
-
if res.code == 302
|
64
|
-
user.password = password
|
65
|
-
hydra.abort
|
66
|
-
|
67
|
-
yield user
|
68
|
-
next
|
69
|
-
elsif user_interaction? && res.code != 200
|
70
|
-
# Errors not displayed when using formats other than cli/cli-no-colour
|
71
|
-
output_error(res)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
hydra.queue(request)
|
76
|
-
end
|
77
|
-
hydra.run
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def progress_bar(size, username)
|
82
|
-
ProgressBar.create(
|
83
|
-
format: '%t %a <%B> (%c / %C) %P%% %e',
|
84
|
-
title: "Brute Forcing #{username} -",
|
85
|
-
total: size
|
86
|
-
)
|
87
|
-
end
|
88
|
-
|
89
|
-
# @param [ String ] wordlist_path
|
90
|
-
#
|
91
|
-
# @return [ Array<String> ]
|
92
|
-
def passwords(wordlist_path)
|
93
|
-
@passwords ||= File.open(wordlist_path).reduce([]) do |acc, elem|
|
94
|
-
acc << elem.chomp
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# @param [ Typhoeus::Response ] response
|
99
|
-
def output_error(response)
|
100
|
-
return if response.body =~ /login_error/i
|
101
|
-
|
102
|
-
error = if response.timed_out?
|
103
|
-
'Request timed out.'
|
104
|
-
elsif response.code.zero?
|
105
|
-
"No response from remote server. WAF/IPS? (#{response.return_message})"
|
106
|
-
elsif response.code.to_s =~ /^50/
|
107
|
-
'Server error, try reducing the number of threads.'
|
108
|
-
else
|
109
|
-
"Unknown response received Code: #{response.code}\n Body: #{response.body}"
|
110
|
-
end
|
111
|
-
|
112
|
-
output('error', msg: error)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|