Class: WPScan::Controller::BruteForce

Inherits:
CMSScanner::Controller::Base
  • Object
show all
Defined in:
app/controllers/brute_force.rb

Overview

Brute Force Controller

Instance Method Summary collapse

Instance Method Details

#brute_force(users, passwords) {|User| ... } ⇒ Object

the iteration should be on the passwords to be more efficient however, it’s not that simple expecially when a combination is found:

- the estimated number of requests (for the progressbar) has to be updated.
- the user found has to be deleted from the loop

Yields:

  • (User)

    when a valid combination is found



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'app/controllers/brute_force.rb', line 59

def brute_force(users, passwords)
  hydra = Browser.instance.hydra

  users.each do |user|
    bar = progress_bar(passwords.size, user.username) if user_interaction?

    passwords.each do |password|
      request = target.(user.username, password)

      request.on_complete do |res|
        bar.progress += 1 if user_interaction?

        if res.code == 302
          user.password = password
          hydra.abort

          yield user
          next
        elsif user_interaction? && res.code != 200
          # Errors not displayed when using formats other than cli/cli-no-colour
          output_error(res)
        end
      end

      hydra.queue(request)
    end
    hydra.run
  end
end

#cli_optionsObject



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# File 'app/controllers/brute_force.rb', line 5

def cli_options
  [
    OptFilePath.new(
      ['--passwords FILE-PATH', '-P',
       'List of passwords to use during the brute forcing.',
       'If no --username/s option supplied, user enumeration will be run'],
      exists: true
    ),
    OptString.new(['--username USERNAME', '-u', 'The username to brute force']),
    OptFilePath.new(
      ['--usernames FILE-PATH', '-U', 'List of usernames to use during the brute forcing'],
      exists: true
    )
  ]
end

#output_error(response) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'app/controllers/brute_force.rb', line 107

def output_error(response)
  return if response.body =~ /login_error/i

  error = if response.timed_out?
            'Request timed out.'
          elsif response.code.zero?
            "No response from remote server. WAF/IPS? (#{response.return_message})"
          elsif response.code.to_s =~ /^50/
            'Server error, try reducing the number of threads.'
          else
            "Unknown response received Code: #{response.code}\n Body: #{response.body}"
          end

  output('error', msg: error)
end

#passwords(wordlist_path) ⇒ Array<String>



100
101
102
103
104
# File 'app/controllers/brute_force.rb', line 100

def passwords(wordlist_path)
  @passwords ||= File.open(wordlist_path).reduce([]) do |acc, elem|
    acc << elem.chomp
  end
end

#progress_bar(size, username) ⇒ Object



89
90
91
92
93
94
95
# File 'app/controllers/brute_force.rb', line 89

def progress_bar(size, username)
  ProgressBar.create(
    format: '%t %a <%B> (%c / %C) %P%% %e',
    title: "Brute Forcing #{username}",
    total: size
  )
end

#runObject



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'app/controllers/brute_force.rb', line 21

def run
  return unless parsed_options[:passwords]

  begin
    found = []

    brute_force(users, passwords(parsed_options[:passwords])) do |user|
      found << user

      output('found', user: user) if user_interaction?
    end
  ensure
    output('users', users: found)
  end
end

#usersArray<Users>



38
39
40
41
42
43
44
45
46
47
48
# File 'app/controllers/brute_force.rb', line 38

def users
  return target.users unless parsed_options[:usernames] || parsed_options[:username]

  if parsed_options[:username]
    [User.new(parsed_options[:username])]
  else
    File.open(parsed_options[:usernames]).reduce([]) do |acc, elem|
      acc << User.new(elem.chomp)
    end
  end
end