Module: WPScan::Finders::Finder::BreadthFirstDictionaryAttack

Included in:
Passwords::WpLogin, Passwords::XMLRPC
Defined in:
lib/wpscan/finders/finder/breadth_first_dictionary_attack.rb

Overview

Module to provide an easy way to perform password attacks

Defined Under Namespace

Classes: LoginAttempt, LoginConfig, ProgressTracker

Instance Method Summary collapse

Instance Method Details

#attack(users, wordlist_path, opts = {}) {|WPScan::User| ... } ⇒ Object

Due to Typhoeus threads shenanigans, in rare cases the progress-bar might be incorrectly updated, hence the ‘rescue ProgressBar::InvalidProgressError’

TODO: Make rubocop happy about metrics etc

rubocop:disable all

Parameters:

Options Hash (opts):

  • :show_progression (Boolean)
  • :wordlist_skip (Integer)

    Number of passwords to skip from the beginning

  • :max_retries (Integer)

    Maximum retry attempts for failed requests

Yields:

  • (WPScan::User)

    When a valid combination is found



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/wpscan/finders/finder/breadth_first_dictionary_attack.rb', line 153

def attack(users, wordlist_path, opts = {})
  wordlist = File.open(wordlist_path)
  skip_count = opts[:wordlist_skip] || 0
  max_retries = opts[:max_retries] || 0

  # Calculate total, accounting for skipped passwords
  total_passwords = wordlist.count
  effective_passwords = [total_passwords - skip_count, 0].max

  create_progress_bar(total: users.size * effective_passwords, show_progression: opts[:show_progression])
  tracker = ProgressTracker.new(progress_bar: progress_bar, total_passwords: effective_passwords)
  config = (tracker, opts)

  # Show skip progress if skipping
  if skip_count.positive? && opts[:show_progression]
    tracker.log("[INFO] Skipping first #{skip_count} password(s) from wordlist...")
  end

  queue_count = 0

  File.foreach(wordlist, chomp: true).lazy.drop(skip_count).each do |password|
    remaining_users = users.select { |u| u.password.nil? }
    break if remaining_users.empty?

    remaining_users.each do |user|
      attempt = LoginAttempt.new(user: user, password: password, max_retries: max_retries, config: config)
      attempt.execute { |found_user| yield found_user if block_given? }
      queue_count += 1

      if queue_count >= hydra.max_concurrency
        hydra.run
        queue_count = 0
      end
    end
  end

  hydra.run
  tracker.stop
end

#create_login_config(tracker, opts) ⇒ LoginConfig

Create login configuration with all dependencies

Parameters:

Returns:



201
202
203
204
205
206
207
208
209
210
211
# File 'lib/wpscan/finders/finder/breadth_first_dictionary_attack.rb', line 201

def (tracker, opts)
  LoginConfig.new(
    tracker: tracker,
    request_builder: method(:login_request).to_proc,
    credentials_validator: method(:valid_credentials?).to_proc,
    error_checker: method(:errored_response?).to_proc,
    error_handler: method(:output_error).to_proc,
    hydra: hydra,
    opts: opts
  )
end

#errored_response?(response) ⇒ Boolean

Returns Whether or not something wrong happened other than wrong credentials.

Parameters:

Returns:

  • (Boolean)

    Whether or not something wrong happened other than wrong credentials



232
233
234
# File 'lib/wpscan/finders/finder/breadth_first_dictionary_attack.rb', line 232

def errored_response?(response)
  # To Implement in the finder related to the attack
end

#login_request(username, password) ⇒ Typhoeus::Request

param [ String ] password

Parameters:

  • username (String)

Returns:

  • (Typhoeus::Request)


217
218
219
# File 'lib/wpscan/finders/finder/breadth_first_dictionary_attack.rb', line 217

def (username, password)
  # To Implement in the finder related to the attack
end

#valid_credentials?(response) ⇒ Boolean

Returns Whether or not credentials related to the request are valid.

Parameters:

Returns:

  • (Boolean)

    Whether or not credentials related to the request are valid



224
225
226
# File 'lib/wpscan/finders/finder/breadth_first_dictionary_attack.rb', line 224

def valid_credentials?(response)
  # To Implement in the finder related to the attack
end