Class: WPScan::Controller::PasswordAttack
- Defined in:
- app/controllers/password_attack.rb
Overview
Password Attack Controller
Constant Summary
Constants included from OptParseValidator
Instance Method Summary collapse
- #attack_opts ⇒ Object
-
#attacker ⇒ WPScan::Finders::Finder
The finder used to perform the attack.
- #attacker_from_automatic_detection ⇒ WPScan::Finders::Finder
- #attacker_from_cli_options ⇒ WPScan::Finders::Finder
- #cli_options ⇒ Object
- #run ⇒ Object
-
#users ⇒ Array<Users>
The users to brute force.
- #xmlrpc ⇒ Model::XMLRPC
- #xmlrpc_get_users_blogs_enabled? ⇒ Boolean
Methods inherited from Base
#==, #after_scan, #before_scan, #datastore, #formatter, #option_parser, option_parser=, #output, #render, reset, #target, #tmp_directory, #user_interaction?
Instance Method Details
#attack_opts ⇒ Object
34 35 36 37 38 39 40 41 |
# File 'app/controllers/password_attack.rb', line 34 def attack_opts @attack_opts ||= { show_progression: user_interaction?, multicall_max_passwords: ParsedCli.multicall_max_passwords, wordlist_skip: ParsedCli.wordlist_skip, max_retries: ParsedCli.max_retries } end |
#attacker ⇒ WPScan::Finders::Finder
Returns The finder used to perform the attack.
68 69 70 |
# File 'app/controllers/password_attack.rb', line 68 def attacker @attacker ||= || attacker_from_automatic_detection end |
#attacker_from_automatic_detection ⇒ WPScan::Finders::Finder
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'app/controllers/password_attack.rb', line 111 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 elsif target.login_url Finders::Passwords::WpLogin.new(target) else raise Error::NoLoginInterfaceDetected end end |
#attacker_from_cli_options ⇒ WPScan::Finders::Finder
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'app/controllers/password_attack.rb', line 78 def return unless ParsedCli.password_attack case ParsedCli.password_attack when :wp_login raise Error::NoLoginInterfaceDetected unless target.login_url 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_options ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'app/controllers/password_attack.rb', line 7 def [ 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.', 'Multicall will only work against WP < 4.4'], choices: %w[wp-login xmlrpc xmlrpc-multicall], normalize: %i[downcase underscore to_sym]), OptString.new(['--login-uri URI', 'The URI of the login page if different from /wp-login.php']), OptInteger.new(['--wordlist-skip N', 'Skip the first N passwords in the wordlist (resume from line N+1)'], default: 0), OptInteger.new(['--max-retries N', 'Maximum retry attempts for failed requests due to network/proxy errors'], default: 0) ] end |
#run ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'app/controllers/password_attack.rb', line 43 def run return unless ParsedCli.passwords begin found = [] if user_interaction? output('@info', msg: "Performing password attack on #{attacker.titleize} against #{users.size} user/s") end attacker.attack(users, ParsedCli.passwords, attack_opts) do |user| found << user attacker..log("[SUCCESS] - #{user.username} / #{user.password}") end rescue Error::NoLoginInterfaceDetected => e # TODO: Maybe output that in JSON as well. output('@notice', msg: e.to_s) if user_interaction? ensure output('users', users: found) end end |
#users ⇒ Array<Users>
Returns The users to brute force.
128 129 130 131 132 133 134 |
# File 'app/controllers/password_attack.rb', line 128 def users return target.users unless ParsedCli.usernames ParsedCli.usernames.reduce([]) do |acc, elem| acc << Model::User.new(elem.chomp) end end |
#xmlrpc ⇒ Model::XMLRPC
73 74 75 |
# File 'app/controllers/password_attack.rb', line 73 def xmlrpc @xmlrpc ||= target.xmlrpc end |
#xmlrpc_get_users_blogs_enabled? ⇒ Boolean
98 99 100 101 102 103 104 105 106 107 108 |
# File 'app/controllers/password_attack.rb', line 98 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.match?(/>\s*405\s*</) true else false end end |