diff --git a/app/finders/passwords/xml_rpc_multicall.rb b/app/finders/passwords/xml_rpc_multicall.rb index d216a75a..b85a127d 100644 --- a/app/finders/passwords/xml_rpc_multicall.rb +++ b/app/finders/passwords/xml_rpc_multicall.rb @@ -22,6 +22,28 @@ module WPScan target.multi_call(methods, cache_ttl: 0).run end + # @param [ IO ] file + # @param [ Integer ] passwords_size + # @return [ Array ] The passwords from the last checked position in the file until there are + # passwords_size passwords retrieved + def passwords_from_wordlist(file, passwords_size) + pwds = [] + added_pwds = 0 + + return pwds if passwords_size.zero? + + # Make sure that the main code does not call #sysseek or #count etc + # otherwise the file descriptor will be set to somwehere else + file.each_line(chomp: true) do |line| + pwds << line + added_pwds += 1 + + break if added_pwds == passwords_size + end + + pwds + end + # @param [ Array ] users # @param [ String ] wordlist_path # @param [ Hash ] opts @@ -34,18 +56,21 @@ module WPScan # # rubocop:disable all def attack(users, wordlist_path, opts = {}) - wordlist_index = 0 - passwords = File.open(wordlist_path).reduce([]) { |acc, elem| acc << elem.chomp } + checked_passwords = 0 + wordlist = File.open(wordlist_path) + wordlist_size = wordlist.count max_passwords = opts[:multicall_max_passwords] current_passwords_size = passwords_size(max_passwords, users.size) - create_progress_bar(total: (passwords.size / current_passwords_size.round(1)).ceil, + create_progress_bar(total: (wordlist_size / current_passwords_size.round(1)).ceil, show_progression: opts[:show_progression]) + wordlist.sysseek(0) # reset the descriptor to the beginning of the file as it changed with #count + loop do - current_users = users.select { |user| user.password.nil? } - current_passwords = passwords[wordlist_index, current_passwords_size] - wordlist_index += current_passwords_size + current_users = users.select { |user| user.password.nil? } + current_passwords = passwords_from_wordlist(wordlist, current_passwords_size) + checked_passwords += current_passwords_size break if current_users.empty? || current_passwords.nil? || current_passwords.empty? @@ -78,12 +103,14 @@ module WPScan end begin - progress_bar.total = progress_bar.progress + ((passwords.size - wordlist_index) / current_passwords_size.round(1)).ceil + progress_bar.total = progress_bar.progress + ((wordlist_size - checked_passwords) / current_passwords_size.round(1)).ceil rescue ProgressBar::InvalidProgressError end end end # Maybe a progress_bar.stop ? + ensure + wordlist.close end # rubocop:enable all