From 08f9d0e67a649ae256a146cb32f29bca69160113 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Sun, 17 Mar 2013 22:05:34 +0100 Subject: [PATCH] Added checks for old ruby. Otherwise there will be syntax errors --- lib/common/common_helper.rb | 4 - lib/environment.rb | 7 + main.rb | 402 ++++++++++++++++++++++++++++++++++++ wpscan.rb | 382 +--------------------------------- 4 files changed, 412 insertions(+), 383 deletions(-) create mode 100644 main.rb diff --git a/lib/common/common_helper.rb b/lib/common/common_helper.rb index 62200cb1..2561aa38 100644 --- a/lib/common/common_helper.rb +++ b/lib/common/common_helper.rb @@ -124,10 +124,6 @@ def banner puts ' Sponsored by the RandomStorm Open Source Initiative' puts '_____________________________________________________' puts - if RUBY_VERSION < '1.9' - puts '[WARNING] Ruby < 1.9 not officially supported, please upgrade.' - puts - end end def colorize(text, color_code) diff --git a/lib/environment.rb b/lib/environment.rb index ad5939e1..0579a25b 100644 --- a/lib/environment.rb +++ b/lib/environment.rb @@ -17,6 +17,13 @@ # along with this program. If not, see . #++ +require 'rubygems' + +if Gem::Version.create(RUBY_VERSION) < Gem::Version.create(1.9) + puts "Ruby >= 1.9 required to run wpscan (You have #{RUBY_VERSION})" + exit(1) +end + begin # Standard libs require 'rubygems' diff --git a/main.rb b/main.rb new file mode 100644 index 00000000..d96c36ae --- /dev/null +++ b/main.rb @@ -0,0 +1,402 @@ +#!/usr/bin/env ruby +# encoding: UTF-8 + +#-- +# WPScan - WordPress Security Scanner +# Copyright (C) 2012-2013 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +#++ + +def output_vulnerabilities(vulns) + vulns.each do |vulnerability| + puts + puts ' | ' + red("* Title: #{vulnerability.title}") + vulnerability.references.each do |r| + puts ' | ' + red("* Reference: #{r}") + end + vulnerability.metasploit_modules.each do |m| + puts ' | ' + red("* Metasploit module: #{get_metasploit_url(m)}") + end + end +end + +def output_item_details(item) + puts + puts " | Name: #{item}" #this will also output the version number if detected + puts " | Location: #{item.get_url_without_filename}" + puts " | WordPress: #{item.wp_org_url}" if item.wp_org_item? + puts ' | Directory listing enabled: Yes' if item.directory_listing? + puts " | Readme: #{item.readme_url}" if item.has_readme? + puts " | Changelog: #{item.changelog_url}" if item.has_changelog? + + output_vulnerabilities(item.vulnerabilities) + + if item.error_log? + puts ' | ' + red('[!]') + " A WordPress error_log file has been found : #{item.error_log_url}" + end +end + +def main + # delete old logfile, check if it is a symlink first. + File.delete(LOG_FILE) if File.exist?(LOG_FILE) and !File.symlink?(LOG_FILE) + + banner() + + begin + wpscan_options = WpscanOptions.load_from_arguments + + unless wpscan_options.has_options? + raise "No argument supplied\n#{usage()}" + end + + if wpscan_options.help + help() + usage() + exit + end + + # Check for updates + if wpscan_options.update + if !@updater.nil? + if @updater.has_local_changes? + puts "#{red('[!]')} Local file changes detected, an update will override local changes, do you want to continue updating? [y/n]" + Readline.readline =~ /^y/i ? @updater.reset_head : raise('Update aborted') + end + puts @updater.update() + else + puts 'Svn / Git not installed, or wpscan has not been installed with one of them.' + puts 'Update aborted' + end + exit(1) + end + + wp_target = WpTarget.new(wpscan_options.url, wpscan_options.to_h) + + # Remote website up? + unless wp_target.online? + raise "The WordPress URL supplied '#{wp_target.uri}' seems to be down." + end + + if wpscan_options.proxy + proxy_response = Browser.instance.get(wp_target.url) + + unless WpTarget::valid_response_codes.include?(proxy_response.code) + raise "Proxy Error :\r\n#{proxy_response.headers}" + end + end + + redirection = wp_target.redirection + if redirection + if wpscan_options.follow_redirection + puts "Following redirection #{redirection}" + puts + else + puts "The remote host tried to redirect us to #{redirection}" + puts 'Do you want follow the redirection ? [y/n]' + end + + if wpscan_options.follow_redirection or Readline.readline =~ /^y/i + wpscan_options.url = redirection + wp_target = WpTarget.new(redirection, wpscan_options.to_h) + else + puts 'Scan aborted' + exit + end + end + + if wp_target.has_basic_auth? && wpscan_options.basic_auth.nil? + raise 'Basic authentication is required, please provide it with --basic-auth ' + end + + # Remote website is wordpress? + unless wpscan_options.force + unless wp_target.wordpress? + raise 'The remote website is up, but does not seem to be running WordPress.' + end + end + + unless wp_target.wp_content_dir + raise 'The wp_content_dir has not been found, please supply it with --wp-content-dir' + end + + unless wp_target.wp_plugins_dir_exists? + puts "The plugins directory '#{wp_target.wp_plugins_dir}' does not exist." + puts 'You can specify one per command line option (don\'t forget to include the wp-content directory if needed)' + puts 'Continue? [y/n]' + unless Readline.readline =~ /^y/i + exit + end + end + + # Output runtime data + start_time = Time.now + puts "| URL: #{wp_target.url}" + puts "| Started on #{start_time.asctime}" + puts + + if wp_target.has_robots? + puts green('[+]') + " robots.txt available under '#{wp_target.robots_url}'" + end + + if wp_target.has_readme? + puts red('[!]') + " The WordPress '#{wp_target.readme_url}' file exists" + end + + if wp_target.has_full_path_disclosure? + puts red('[!]') + " Full Path Disclosure (FPD) in '#{wp_target.full_path_disclosure_url}'" + end + + if wp_target.has_debug_log? + puts red('[!]') + " Debug log file found : #{wp_target.debug_log_url}" + end + + wp_target.config_backup.each do |file_url| + puts red("[!] A wp-config.php backup file has been found '#{file_url}'") + end + + if wp_target.search_replace_db_2_exists? + puts red("[!] searchreplacedb2.php has been found '#{wp_target.search_replace_db_2_url}'") + end + + if wp_target.is_multisite? + puts green('[+]') + ' This site seems to be a multisite (http://codex.wordpress.org/Glossary#Multisite)' + end + + if wp_target.registration_enabled? + puts green('[+]') + ' User registration is enabled' + end + + if wp_target.has_xml_rpc? + puts green('[+]') + " XML-RPC Interface available under #{wp_target.xml_rpc_url}" + end + + if wp_target.has_malwares? + malwares = wp_target.malwares + puts red('[!]') + " #{malwares.size} malware(s) found :" + + malwares.each do |malware_url| + puts + puts ' | ' + red("#{malware_url}") + end + puts + end + + wp_version = wp_target.version + if wp_version + puts green('[+]') + " WordPress version #{wp_version.number} identified from #{wp_version.discovery_method}" + + version_vulnerabilities = wp_version.vulnerabilities + + unless version_vulnerabilities.empty? + puts + puts red('[!]') + " We have identified #{version_vulnerabilities.size} vulnerabilities from the version number :" + output_vulnerabilities(version_vulnerabilities) + end + end + + wp_theme = wp_target.theme + if wp_theme + puts + # Theme version is handled in wp_item.to_s + puts green('[+]') + " The WordPress theme in use is #{wp_theme}" + output_item_details(wp_theme) + end + + if wpscan_options.enumerate_plugins == nil and wpscan_options.enumerate_only_vulnerable_plugins == nil + puts + puts green('[+]') + ' Enumerating plugins from passive detection ... ' + + plugins = wp_target.plugins_from_passive_detection(base_url: wp_target.uri, wp_content_dir: wp_target.wp_content_dir) + if !plugins.empty? + puts "#{plugins.size} plugins found :" + + plugins.each do |plugin| + output_item_details(plugin) + end + else + puts 'No plugins found :(' + end + end + + # Enumerate the installed plugins + if wpscan_options.enumerate_plugins or wpscan_options.enumerate_only_vulnerable_plugins or wpscan_options.enumerate_all_plugins + puts + puts green('[+]') + " Enumerating installed plugins #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_plugins} ..." + puts + + options = { + base_url: wp_target.uri, + only_vulnerable_ones: wpscan_options.enumerate_only_vulnerable_plugins || false, + show_progression: true, + wp_content_dir: wp_target.wp_content_dir, + error_404_hash: wp_target.error_404_hash, + homepage_hash: wp_target.homepage_hash, + wp_plugins_dir: wp_target.wp_plugins_dir, + full: wpscan_options.enumerate_all_plugins, + exclude_content_based: wpscan_options.exclude_content_based + } + + plugins = wp_target.plugins_from_aggressive_detection(options) + if !plugins.empty? + puts + puts + puts green('[+]') + " We found #{plugins.size.to_s} plugins:" + + plugins.each do |plugin| + output_item_details(plugin) + end + else + puts + puts 'No plugins found :(' + end + end + + # Enumerate installed themes + if wpscan_options.enumerate_themes or wpscan_options.enumerate_only_vulnerable_themes or wpscan_options.enumerate_all_themes + puts + puts green('[+]') + " Enumerating installed themes #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_themes} ..." + puts + + options = { + base_url: wp_target.uri, + only_vulnerable_ones: wpscan_options.enumerate_only_vulnerable_themes || false, + show_progression: true, + wp_content_dir: wp_target.wp_content_dir, + error_404_hash: wp_target.error_404_hash, + homepage_hash: wp_target.homepage_hash, + full: wpscan_options.enumerate_all_themes, + exclude_content_based: wpscan_options.exclude_content_based + } + + themes = wp_target.themes_from_aggressive_detection(options) + if !themes.empty? + puts + puts + puts green('[+]') + " We found #{themes.size.to_s} themes:" + + themes.each do |theme| + output_item_details(theme) + end + else + puts + puts 'No themes found :(' + end + end + + if wpscan_options.enumerate_timthumbs + puts + puts green('[+]') + ' Enumerating timthumb files ...' + puts + + options = { + base_url: wp_target.uri, + show_progression: true, + wp_content_dir: wp_target.wp_content_dir, + error_404_hash: wp_target.error_404_hash, + homepage_hash: wp_target.homepage_hash, + exclude_content_based: wpscan_options.exclude_content_based + } + + theme_name = wp_theme ? wp_theme.name : nil + if wp_target.has_timthumbs?(theme_name, options) + timthumbs = wp_target.timthumbs + + puts + puts green('[+]') + " We found #{timthumbs.size.to_s} timthumb file/s :" + puts + + timthumbs.each do |t| + puts ' | ' + red('[!]') + " #{t.get_full_url.to_s}" + end + puts + puts red(' * Reference: http://www.exploit-db.com/exploits/17602/') + else + puts + puts 'No timthumb files found :(' + end + end + + # If we haven't been supplied a username, enumerate them... + if !wpscan_options.username and wpscan_options.wordlist or wpscan_options.enumerate_usernames + puts + puts green('[+]') + ' Enumerating usernames ...' + + usernames = wp_target.usernames(range: wpscan_options.enumerate_usernames_range) + + if usernames.empty? + puts + puts 'We did not enumerate any usernames :(' + puts 'Try supplying your own username with the --username option' + puts + exit(1) + else + puts + puts green('[+]') + " We found the following #{usernames.length.to_s} username/s :" + puts + + max_id_length = usernames.sort { |a, b| a.id.to_s.length <=> b.id.to_s.length }.last.id.to_s.length + max_name_length = usernames.sort { |a, b| a.name.length <=> b.name.length }.last.name.length + max_nickname_length = usernames.sort { |a, b| a.nickname.length <=> b.nickname.length }.last.nickname.length + + space = 1 + usernames.each do |u| + id_string = "id: #{u.id.to_s.ljust(max_id_length + space)}" + name_string = "name: #{u.name.ljust(max_name_length + space)}" + nickname_string = "nickname: #{u.nickname.ljust(max_nickname_length + space)}" + puts " | #{id_string}| #{name_string}| #{nickname_string}" + end + end + + else + usernames = [WpUser.new(wpscan_options.username, -1, 'empty')] + end + + # Start the brute forcer + bruteforce = true + if wpscan_options.wordlist + if wp_target.has_login_protection? + + protection_plugin = wp_target.login_protection_plugin() + + puts + puts "The plugin #{protection_plugin.name} has been detected. It might record the IP and timestamp of every failed login. Not a good idea for brute forcing !" + puts '[?] Do you want to start the brute force anyway ? [y/n]' + + bruteforce = false if Readline.readline !~ /^y/i + end + + if bruteforce + puts + puts green('[+]') + ' Starting the password brute forcer' + puts + wp_target.brute_force(usernames, wpscan_options.wordlist, {show_progression: true}) + else + puts + puts 'Brute forcing aborted' + end + end + + stop_time = Time.now + puts + puts green("[+] Finished at #{stop_time.asctime}") + elapsed = stop_time - start_time + puts green("[+] Elapsed time: #{Time.at(elapsed).utc.strftime('%H:%M:%S')}") + exit() # must exit! + rescue => e + puts red("[ERROR] #{e.message}") + puts red('Trace :') + puts red(e.backtrace.join("\n")) + end +end \ No newline at end of file diff --git a/wpscan.rb b/wpscan.rb index c4245719..9b13bd07 100755 --- a/wpscan.rb +++ b/wpscan.rb @@ -19,385 +19,9 @@ # along with this program. If not, see . #++ + $: << '.' require File.dirname(__FILE__) + '/lib/wpscan/wpscan_helper' +require File.dirname(__FILE__) + '/main' -def output_vulnerabilities(vulns) - vulns.each do |vulnerability| - puts - puts ' | ' + red("* Title: #{vulnerability.title}") - vulnerability.references.each do |r| - puts ' | ' + red("* Reference: #{r}") - end - vulnerability.metasploit_modules.each do |m| - puts ' | ' + red("* Metasploit module: #{get_metasploit_url(m)}") - end - end -end - -def output_item_details(item) - puts - puts " | Name: #{item}" #this will also output the version number if detected - puts " | Location: #{item.get_url_without_filename}" - puts " | WordPress: #{item.wp_org_url}" if item.wp_org_item? - puts ' | Directory listing enabled: Yes' if item.directory_listing? - puts " | Readme: #{item.readme_url}" if item.has_readme? - puts " | Changelog: #{item.changelog_url}" if item.has_changelog? - - output_vulnerabilities(item.vulnerabilities) - - if item.error_log? - puts ' | ' + red('[!]') + " A WordPress error_log file has been found : #{item.error_log_url}" - end -end - -# delete old logfile, check if it is a symlink first. -File.delete(LOG_FILE) if File.exist?(LOG_FILE) and !File.symlink?(LOG_FILE) - -banner() - -begin - wpscan_options = WpscanOptions.load_from_arguments - - unless wpscan_options.has_options? - raise "No argument supplied\n#{usage()}" - end - - if wpscan_options.help - help() - usage() - exit - end - - # Check for updates - if wpscan_options.update - if !@updater.nil? - if @updater.has_local_changes? - puts "#{red('[!]')} Local file changes detected, an update will override local changes, do you want to continue updating? [y/n]" - Readline.readline =~ /^y/i ? @updater.reset_head : raise('Update aborted') - end - puts @updater.update() - else - puts 'Svn / Git not installed, or wpscan has not been installed with one of them.' - puts 'Update aborted' - end - exit(1) - end - - wp_target = WpTarget.new(wpscan_options.url, wpscan_options.to_h) - - # Remote website up? - unless wp_target.online? - raise "The WordPress URL supplied '#{wp_target.uri}' seems to be down." - end - - if wpscan_options.proxy - proxy_response = Browser.instance.get(wp_target.url) - - unless WpTarget::valid_response_codes.include?(proxy_response.code) - raise "Proxy Error :\r\n#{proxy_response.headers}" - end - end - - redirection = wp_target.redirection - if redirection - if wpscan_options.follow_redirection - puts "Following redirection #{redirection}" - puts - else - puts "The remote host tried to redirect us to #{redirection}" - puts 'Do you want follow the redirection ? [y/n]' - end - - if wpscan_options.follow_redirection or Readline.readline =~ /^y/i - wpscan_options.url = redirection - wp_target = WpTarget.new(redirection, wpscan_options.to_h) - else - puts 'Scan aborted' - exit - end - end - - if wp_target.has_basic_auth? && wpscan_options.basic_auth.nil? - raise 'Basic authentication is required, please provide it with --basic-auth ' - end - - # Remote website is wordpress? - unless wpscan_options.force - unless wp_target.wordpress? - raise 'The remote website is up, but does not seem to be running WordPress.' - end - end - - unless wp_target.wp_content_dir - raise 'The wp_content_dir has not been found, please supply it with --wp-content-dir' - end - - unless wp_target.wp_plugins_dir_exists? - puts "The plugins directory '#{wp_target.wp_plugins_dir}' does not exist." - puts 'You can specify one per command line option (don\'t forget to include the wp-content directory if needed)' - puts 'Continue? [y/n]' - unless Readline.readline =~ /^y/i - exit - end - end - - # Output runtime data - start_time = Time.now - puts "| URL: #{wp_target.url}" - puts "| Started on #{start_time.asctime}" - puts - - if wp_target.has_robots? - puts green('[+]') + " robots.txt available under '#{wp_target.robots_url}'" - end - - if wp_target.has_readme? - puts red('[!]') + " The WordPress '#{wp_target.readme_url}' file exists" - end - - if wp_target.has_full_path_disclosure? - puts red('[!]') + " Full Path Disclosure (FPD) in '#{wp_target.full_path_disclosure_url}'" - end - - if wp_target.has_debug_log? - puts red('[!]') + " Debug log file found : #{wp_target.debug_log_url}" - end - - wp_target.config_backup.each do |file_url| - puts red("[!] A wp-config.php backup file has been found '#{file_url}'") - end - - if wp_target.search_replace_db_2_exists? - puts red("[!] searchreplacedb2.php has been found '#{wp_target.search_replace_db_2_url}'") - end - - if wp_target.is_multisite? - puts green('[+]') + ' This site seems to be a multisite (http://codex.wordpress.org/Glossary#Multisite)' - end - - if wp_target.registration_enabled? - puts green('[+]') + ' User registration is enabled' - end - - if wp_target.has_xml_rpc? - puts green('[+]') + " XML-RPC Interface available under #{wp_target.xml_rpc_url}" - end - - if wp_target.has_malwares? - malwares = wp_target.malwares - puts red('[!]') + " #{malwares.size} malware(s) found :" - - malwares.each do |malware_url| - puts - puts ' | ' + red("#{malware_url}") - end - puts - end - - wp_version = wp_target.version - if wp_version - puts green('[+]') + " WordPress version #{wp_version.number} identified from #{wp_version.discovery_method}" - - version_vulnerabilities = wp_version.vulnerabilities - - unless version_vulnerabilities.empty? - puts - puts red('[!]') + " We have identified #{version_vulnerabilities.size} vulnerabilities from the version number :" - output_vulnerabilities(version_vulnerabilities) - end - end - - wp_theme = wp_target.theme - if wp_theme - puts - # Theme version is handled in wp_item.to_s - puts green('[+]') + " The WordPress theme in use is #{wp_theme}" - output_item_details(wp_theme) - end - - if wpscan_options.enumerate_plugins == nil and wpscan_options.enumerate_only_vulnerable_plugins == nil - puts - puts green('[+]') + ' Enumerating plugins from passive detection ... ' - - plugins = wp_target.plugins_from_passive_detection(base_url: wp_target.uri, wp_content_dir: wp_target.wp_content_dir) - if !plugins.empty? - puts "#{plugins.size} plugins found :" - - plugins.each do |plugin| - output_item_details(plugin) - end - else - puts 'No plugins found :(' - end - end - - # Enumerate the installed plugins - if wpscan_options.enumerate_plugins or wpscan_options.enumerate_only_vulnerable_plugins or wpscan_options.enumerate_all_plugins - puts - puts green('[+]') + " Enumerating installed plugins #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_plugins} ..." - puts - - options = { - base_url: wp_target.uri, - only_vulnerable_ones: wpscan_options.enumerate_only_vulnerable_plugins || false, - show_progression: true, - wp_content_dir: wp_target.wp_content_dir, - error_404_hash: wp_target.error_404_hash, - homepage_hash: wp_target.homepage_hash, - wp_plugins_dir: wp_target.wp_plugins_dir, - full: wpscan_options.enumerate_all_plugins, - exclude_content_based: wpscan_options.exclude_content_based - } - - plugins = wp_target.plugins_from_aggressive_detection(options) - if !plugins.empty? - puts - puts - puts green('[+]') + " We found #{plugins.size.to_s} plugins:" - - plugins.each do |plugin| - output_item_details(plugin) - end - else - puts - puts 'No plugins found :(' - end - end - - # Enumerate installed themes - if wpscan_options.enumerate_themes or wpscan_options.enumerate_only_vulnerable_themes or wpscan_options.enumerate_all_themes - puts - puts green('[+]') + " Enumerating installed themes #{'(only vulnerable ones)' if wpscan_options.enumerate_only_vulnerable_themes} ..." - puts - - options = { - base_url: wp_target.uri, - only_vulnerable_ones: wpscan_options.enumerate_only_vulnerable_themes || false, - show_progression: true, - wp_content_dir: wp_target.wp_content_dir, - error_404_hash: wp_target.error_404_hash, - homepage_hash: wp_target.homepage_hash, - full: wpscan_options.enumerate_all_themes, - exclude_content_based: wpscan_options.exclude_content_based - } - - themes = wp_target.themes_from_aggressive_detection(options) - if !themes.empty? - puts - puts - puts green('[+]') + " We found #{themes.size.to_s} themes:" - - themes.each do |theme| - output_item_details(theme) - end - else - puts - puts 'No themes found :(' - end - end - - if wpscan_options.enumerate_timthumbs - puts - puts green('[+]') + ' Enumerating timthumb files ...' - puts - - options = { - base_url: wp_target.uri, - show_progression: true, - wp_content_dir: wp_target.wp_content_dir, - error_404_hash: wp_target.error_404_hash, - homepage_hash: wp_target.homepage_hash, - exclude_content_based: wpscan_options.exclude_content_based - } - - theme_name = wp_theme ? wp_theme.name : nil - if wp_target.has_timthumbs?(theme_name, options) - timthumbs = wp_target.timthumbs - - puts - puts green('[+]') + " We found #{timthumbs.size.to_s} timthumb file/s :" - puts - - timthumbs.each do |t| - puts ' | ' + red('[!]') + " #{t.get_full_url.to_s}" - end - puts - puts red(' * Reference: http://www.exploit-db.com/exploits/17602/') - else - puts - puts 'No timthumb files found :(' - end - end - - # If we haven't been supplied a username, enumerate them... - if !wpscan_options.username and wpscan_options.wordlist or wpscan_options.enumerate_usernames - puts - puts green('[+]') + ' Enumerating usernames ...' - - usernames = wp_target.usernames(range: wpscan_options.enumerate_usernames_range) - - if usernames.empty? - puts - puts 'We did not enumerate any usernames :(' - puts 'Try supplying your own username with the --username option' - puts - exit(1) - else - puts - puts green('[+]') + " We found the following #{usernames.length.to_s} username/s :" - puts - - max_id_length = usernames.sort { |a, b| a.id.to_s.length <=> b.id.to_s.length }.last.id.to_s.length - max_name_length = usernames.sort { |a, b| a.name.length <=> b.name.length }.last.name.length - max_nickname_length = usernames.sort { |a, b| a.nickname.length <=> b.nickname.length }.last.nickname.length - - space = 1 - usernames.each do |u| - id_string = "id: #{u.id.to_s.ljust(max_id_length + space)}" - name_string = "name: #{u.name.ljust(max_name_length + space)}" - nickname_string = "nickname: #{u.nickname.ljust(max_nickname_length + space)}" - puts " | #{id_string}| #{name_string}| #{nickname_string}" - end - end - - else - usernames = [WpUser.new(wpscan_options.username, -1, 'empty')] - end - - # Start the brute forcer - bruteforce = true - if wpscan_options.wordlist - if wp_target.has_login_protection? - - protection_plugin = wp_target.login_protection_plugin() - - puts - puts "The plugin #{protection_plugin.name} has been detected. It might record the IP and timestamp of every failed login. Not a good idea for brute forcing !" - puts '[?] Do you want to start the brute force anyway ? [y/n]' - - bruteforce = false if Readline.readline !~ /^y/i - end - - if bruteforce - puts - puts green('[+]') + ' Starting the password brute forcer' - puts - wp_target.brute_force(usernames, wpscan_options.wordlist, {show_progression: true}) - else - puts - puts 'Brute forcing aborted' - end - end - - stop_time = Time.now - puts - puts green("[+] Finished at #{stop_time.asctime}") - elapsed = stop_time - start_time - puts green("[+] Elapsed time: #{Time.at(elapsed).utc.strftime('%H:%M:%S')}") - exit() # must exit! -rescue => e - puts red("[ERROR] #{e.message}") - puts red('Trace :') - puts red(e.backtrace.join("\n")) -end +main() \ No newline at end of file