Class: WPScan::Controller::PasswordAttack

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

Overview

Password Attack Controller

Instance Method Summary collapse

Instance Method Details

#attackerCMSScanner::Finders::Finder

Returns The finder used to perform the attack.

Returns:

  • (CMSScanner::Finders::Finder)

    The finder used to perform the attack



53
54
55
# File 'app/controllers/password_attack.rb', line 53

def attacker
  @attacker ||= attacker_from_cli_options || attacker_from_automatic_detection
end

#attacker_from_automatic_detectionCMSScanner::Finders::Finder

Returns:

  • (CMSScanner::Finders::Finder)


94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'app/controllers/password_attack.rb', line 94

def attacker_from_automatic_detection
  if xmlrpc_get_users_blogs_enabled?
    wp_version = target.wp_version

    if wp_version && wp_version < '4.4'
      Finders::Passwords::XMLRPCMulticall.new(xmlrpc)
    else
      Finders::Passwords::XMLRPC.new(xmlrpc)
    end
  else
    Finders::Passwords::WpLogin.new(target)
  end
end

#attacker_from_cli_optionsCMSScanner::Finders::Finder

Returns:

  • (CMSScanner::Finders::Finder)


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'app/controllers/password_attack.rb', line 63

def attacker_from_cli_options
  return unless ParsedCli.password_attack

  case ParsedCli.password_attack
  when :wp_login
    Finders::Passwords::WpLogin.new(target)
  when :xmlrpc
    raise Error::XMLRPCNotDetected unless xmlrpc

    Finders::Passwords::XMLRPC.new(xmlrpc)
  when :xmlrpc_multicall
    raise Error::XMLRPCNotDetected unless xmlrpc

    Finders::Passwords::XMLRPCMulticall.new(xmlrpc)
  end
end

#cli_optionsObject



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'app/controllers/password_attack.rb', line 7

def cli_options
  [
    OptFilePath.new(
      ['--passwords FILE-PATH', '-P',
       'List of passwords to use during the password attack.',
       'If no --username/s option supplied, user enumeration will be run.'],
      exists: true
    ),
    OptSmartList.new(['--usernames LIST', '-U', 'List of usernames to use during the password attack.']),
    OptInteger.new(['--multicall-max-passwords MAX_PWD',
                    'Maximum number of passwords to send by request with XMLRPC multicall'],
                   default: 500),
    OptChoice.new(['--password-attack ATTACK',
                   'Force the supplied attack to be used rather than automatically determining one.'],
                  choices: %w[wp-login xmlrpc xmlrpc-multicall],
                  normalize: %i[downcase underscore to_sym])
  ]
end

#passwords(wordlist_path) ⇒ Array<String>

Parameters:

  • wordlist_path (String)

Returns:

  • (Array<String>)


120
121
122
123
124
# File 'app/controllers/password_attack.rb', line 120

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

#runObject



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
# File 'app/controllers/password_attack.rb', line 26

def run
  return unless ParsedCli.passwords

  if user_interaction?
    output('@info',
           msg: "Performing password attack on #{attacker.titleize} against #{users.size} user/s")
  end

  attack_opts = {
    show_progression: user_interaction?,
    multicall_max_passwords: ParsedCli.multicall_max_passwords
  }

  begin
    found = []

    attacker.attack(users, passwords(ParsedCli.passwords), attack_opts) do |user|
      found << user

      attacker.progress_bar.log("[SUCCESS] - #{user.username} / #{user.password}")
    end
  ensure
    output('users', users: found)
  end
end

#usersArray<Users>

Returns The users to brute force.

Returns:

  • (Array<Users>)

    The users to brute force



109
110
111
112
113
114
115
# File 'app/controllers/password_attack.rb', line 109

def users
  return target.users unless ParsedCli.usernames

  ParsedCli.usernames.reduce([]) do |acc, elem|
    acc << Model::User.new(elem.chomp)
  end
end

#xmlrpcModel::XMLRPC

Returns:



58
59
60
# File 'app/controllers/password_attack.rb', line 58

def xmlrpc
  @xmlrpc ||= target.xmlrpc
end

#xmlrpc_get_users_blogs_enabled?Boolean

Returns:

  • (Boolean)


81
82
83
84
85
86
87
88
89
90
91
# File 'app/controllers/password_attack.rb', line 81

def xmlrpc_get_users_blogs_enabled?
  if xmlrpc&.enabled? &&
     xmlrpc.available_methods.include?('wp.getUsersBlogs') &&
     xmlrpc.method_call('wp.getUsersBlogs', [SecureRandom.hex[0, 6], SecureRandom.hex[0, 4]])
           .run.body !~ /XML\-RPC services are disabled/

    true
  else
    false
  end
end