module CMSScanner::Finders::Finder::BreadthFirstDictionaryAttack
Module to provide an easy way to perform password attacks
Public Instance Methods
@param [ Array<CMSScanner::Model::User> ] users @param [ String ] wordlist_path @param [ Hash ] opts @option opts [ Boolean ] :show_progression
@yield [ CMSScanner::User ] When a valid combination is found
Due to Typhoeus
threads shenanigans, in rare cases the progress-bar might be incorrectly updated, hence the 'rescue ProgressBar::InvalidProgressError'
TODO: Make rubocop happy about metrics etc
rubocop:disable all
# File lib/cms_scanner/finders/finder/breadth_first_dictionary_attack.rb, line 21 def attack(users, wordlist_path, opts = {}) wordlist = File.open(wordlist_path) create_progress_bar(total: users.size * wordlist.count, show_progression: opts[:show_progression]) queue_count = 0 # Keep the number of requests sent for each users # to be able to correctly update the progress when a password is found user_requests_count = {} users.each { |u| user_requests_count[u.username] = 0 } File.foreach(wordlist, chomp: true) do |password| remaining_users = users.select { |u| u.password.nil? } break if remaining_users.empty? remaining_users.each do |user| request = login_request(user.username, password) user_requests_count[user.username] += 1 request.on_complete do |res| progress_bar.title = "Trying #{user.username} / #{password}" progress_bar.increment unless progress_bar.progress == progress_bar.total if valid_credentials?(res) user.password = password begin progress_bar.total -= wordlist.count - user_requests_count[user.username] rescue ProgressBar::InvalidProgressError end yield user elsif errored_response?(res) output_error(res) end end hydra.queue(request) queue_count += 1 if queue_count >= hydra.max_concurrency hydra.run queue_count = 0 end end end hydra.run progress_bar.stop end
@param [ Typhoeus::Response
] response
@return [ Boolean ] Whether or not something wrong happened
other than wrong credentials
# File lib/cms_scanner/finders/finder/breadth_first_dictionary_attack.rb, line 96 def errored_response?(response) # To Implement in the finder related to the attack end
@param [ String ] username param [ String ] password
@return [ Typhoeus::Request ]
# File lib/cms_scanner/finders/finder/breadth_first_dictionary_attack.rb, line 81 def login_request(username, password) # To Implement in the finder related to the attack end
@param [ Typhoeus::Response
] response
@return [ Boolean ] Whether or not credentials related to the request are valid
# File lib/cms_scanner/finders/finder/breadth_first_dictionary_attack.rb, line 88 def valid_credentials?(response) # To Implement in the finder related to the attack end
Protected Instance Methods
@param [ Typhoeus::Response
] response
# File lib/cms_scanner/finders/finder/breadth_first_dictionary_attack.rb, line 103 def output_error(response) 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.start_with?('50') 'Server error, try reducing the number of threads.' elsif NS::ParsedCli.verbose? "Unknown response received Code: #{response.code}\nBody: #{response.body}" else "Unknown response received Code: #{response.code}" end progress_bar.log("Error: #{error}") end