From 68e47d70fd7effe8edd29ef31f4e1f456530fedc Mon Sep 17 00:00:00 2001 From: FireFart Date: Fri, 28 Feb 2014 21:49:01 +0100 Subject: [PATCH 01/10] Issue #415 --- conf/browser.conf.json | 65 ----------------- lib/common/browser.rb | 39 +++------- lib/common/browser/options.rb | 44 +----------- lib/wpscan/wpscan_options.rb | 4 +- spec/lib/common/browser_spec.rb | 71 +------------------ spec/samples/conf/browser/browser.conf.json | 8 --- .../conf/browser/browser.conf_proxy.json | 8 --- .../conf/browser/browser.conf_proxy_auth.json | 9 --- spec/shared_examples/browser/options.rb | 63 ---------------- 9 files changed, 19 insertions(+), 292 deletions(-) delete mode 100644 conf/browser.conf.json delete mode 100644 spec/samples/conf/browser/browser.conf.json delete mode 100644 spec/samples/conf/browser/browser.conf_proxy.json delete mode 100644 spec/samples/conf/browser/browser.conf_proxy_auth.json diff --git a/conf/browser.conf.json b/conf/browser.conf.json deleted file mode 100644 index 4c0e7a67..00000000 --- a/conf/browser.conf.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", - /* Modes : - static : will use the defined user_agent for each request - semi-static : will randomly choose a user agent into available_user_agents before each scan - random : each request will choose a random user agent in available_user_agents - */ - "user_agent_mode": "static", - - /* Uncomment the "proxy" line to use the proxy - SOCKS proxies (4, 4A, 5) are supported, ie : "proxy": "socks5://127.0.0.1:9000" - If you do not specify the protocol, http will be used - */ - //"proxy": "127.0.0.1:3128", - //"proxy_auth": "username:password", - - "cache_ttl": 600, // 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled - - "request_timeout": 2000, // 2s - - "connect_timeout": 1000, // 1s - - "max_threads": 20, - - // Some user_agents can be found there http://techpatterns.com/downloads/firefox/useragentswitcher.xml (thx to Gianluca Brindisi) - "available_user_agents": - [ - // Windows - "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5", - "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1", - "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E)", - "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1", - "Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120427 Firefox/15.0a1", - "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)", - "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0)", - "Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00", - "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5", - - // MAC - "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.15 Safari/534.13", - "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1", - "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2; rv:10.0.1) Gecko/20100101 Firefox/10.0.1", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10", - - // Linux - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.20 Safari/535.1", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.703.0 Chrome/12.0.703.0 Safari/534.24", - "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.9) Gecko/20100915 Gentoo Firefox/3.6.9", - "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120421 Gecko Firefox/11.0", - "Mozilla/5.0 (X11; Linux i686; rv:12.0) Gecko/20100101 Firefox/12.0", - "Opera/9.80 (X11; Linux x86_64; U; pl) Presto/2.7.62 Version/11.00", - "Mozilla/5.0 (X11; U; Linux x86_64; us; rv:1.9.1.19) Gecko/20110430 shadowfox/7.0 (like Firefox/7.0" - ] -} diff --git a/lib/common/browser.rb b/lib/common/browser.rb index fdb78c9d..c97d4549 100644 --- a/lib/common/browser.rb +++ b/lib/common/browser.rb @@ -9,12 +9,10 @@ class Browser include Browser::Options OPTIONS = [ - :available_user_agents, :basic_auth, :cache_ttl, :max_threads, - :user_agent, - :user_agent_mode, + :useragent, :proxy, :proxy_auth, :request_timeout, @@ -23,16 +21,15 @@ class Browser @@instance = nil - attr_reader :hydra, :config_file, :cache_dir + attr_reader :hydra, :cache_dir # @param [ Hash ] options # # @return [ Browser ] def initialize(options = {}) - @config_file = options[:config_file] || CONF_DIR + '/browser.conf.json' @cache_dir = options[:cache_dir] || CACHE_DIR + '/browser' - load_config + browser_defaults override_config(options) unless @hydra @@ -62,28 +59,14 @@ class Browser end # - # If an option was set but is not in the new config_file - # it's value is kept + # sets browser default values # - # @param [ String ] config_file - # - # @return [ void ] - def load_config(config_file = nil) - @config_file = config_file || @config_file - - if File.symlink?(@config_file) - raise '[ERROR] Config file is a symlink.' - else - data = JSON.parse(File.read(@config_file)) - end - - OPTIONS.each do |option| - option_name = option.to_s - - unless data[option_name].nil? - self.send(:"#{option_name}=", data[option_name]) - end - end + def browser_defaults + @max_threads = 20 + @cache_ttl = 600 # 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled + @request_timeout = 2000 # 2s + @connect_timeout = 1000 # 1s + @useragent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)" end # @param [ String ] url @@ -101,7 +84,7 @@ class Browser params = Browser.append_params_header_field( params, 'User-Agent', - self.user_agent + @useragent ) if @proxy diff --git a/lib/common/browser/options.rb b/lib/common/browser/options.rb index 750b8029..2ca3c227 100644 --- a/lib/common/browser/options.rb +++ b/lib/common/browser/options.rb @@ -3,11 +3,9 @@ class Browser module Options - USER_AGENT_MODES = %w{ static semi-static random } - - attr_accessor :available_user_agents, :cache_ttl, :request_timeout, :connect_timeout - attr_reader :basic_auth, :user_agent_mode, :proxy, :proxy_auth - attr_writer :user_agent + attr_accessor :cache_ttl, :request_timeout, :connect_timeout + attr_reader :basic_auth, :proxy, :proxy_auth + attr_writer :useragent # Sets the Basic Authentification credentials # Accepted format: @@ -41,42 +39,6 @@ class Browser end end - # Sets the user_agent_mode, which can be one of the following: - # static: The UA is defined by the user, and will be the same in each requests - # semi-static: The UA is randomly chosen at the first request, and will not change - # random: UA randomly chosen each request - # - # UA are from @available_user_agents - # - # @param [ String ] ua_mode - # - # @return [ void ] - def user_agent_mode=(ua_mode) - ua_mode ||= 'static' - - if USER_AGENT_MODES.include?(ua_mode) - @user_agent_mode = ua_mode - # For semi-static user agent mode, the user agent has to - # be nil the first time (it will be set with the getter) - @user_agent = nil if ua_mode === 'semi-static' - else - raise "Unknow user agent mode : '#{ua_mode}'" - end - end - - # @return [ String ] The user agent, according to the user_agent_mode - def user_agent - case @user_agent_mode - when 'semi-static' - unless @user_agent - @user_agent = @available_user_agents.sample - end - when 'random' - @user_agent = @available_user_agents.sample - end - @user_agent - end - # Sets the proxy # Accepted format: # [protocol://]host:post diff --git a/lib/wpscan/wpscan_options.rb b/lib/wpscan/wpscan_options.rb index 16046e48..d5a29114 100644 --- a/lib/wpscan/wpscan_options.rb +++ b/lib/wpscan/wpscan_options.rb @@ -30,7 +30,8 @@ class WpscanOptions :exclude_content_based, :basic_auth, :debug_output, - :version + :version, + :useragent ] attr_accessor *ACCESSOR_OPTIONS @@ -227,6 +228,7 @@ class WpscanOptions ['--wordlist', '-w', GetoptLong::REQUIRED_ARGUMENT], ['--threads', '-t', GetoptLong::REQUIRED_ARGUMENT], ['--force', '-f', GetoptLong::NO_ARGUMENT], + ['--useragent', '-a', GetoptLong::REQUIRED_ARGUMENT], ['--help', '-h', GetoptLong::NO_ARGUMENT], ['--verbose', '-v', GetoptLong::NO_ARGUMENT], ['--proxy', GetoptLong::REQUIRED_ARGUMENT], diff --git a/spec/lib/common/browser_spec.rb b/spec/lib/common/browser_spec.rb index 0d367641..f023c3aa 100644 --- a/spec/lib/common/browser_spec.rb +++ b/spec/lib/common/browser_spec.rb @@ -6,29 +6,15 @@ describe Browser do it_behaves_like 'Browser::Actions' it_behaves_like 'Browser::Options' - CONFIG_FILE_WITHOUT_PROXY = SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf.json' - CONFIG_FILE_WITH_PROXY = SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf_proxy.json' - #CONFIG_FILE_WITH_PROXY_AND_AUTH = SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf_proxy_auth.json' - subject(:browser) { Browser.reset Browser.instance(options) } let(:options) { {} } let(:instance_vars_to_check) { - ['user_agent', 'user_agent_mode', 'available_user_agents', 'proxy', + ['useragent', 'proxy', 'max_threads', 'cache_ttl', 'request_timeout', 'connect_timeout'] } - let(:json_config_without_proxy) { JSON.parse(File.read(CONFIG_FILE_WITHOUT_PROXY)) } - let(:json_config_with_proxy) { JSON.parse(File.read(CONFIG_FILE_WITH_PROXY)) } - - def check_instance_variables(browser, json_expected_vars) - json_expected_vars['max_threads'] ||= 1 # max_thread can not be nil - - instance_vars_to_check.each do |variable_name| - browser.send(:"#{variable_name}").should === json_expected_vars[variable_name] - end - end describe 'Singleton' do it 'should not allow #new' do @@ -36,59 +22,6 @@ describe Browser do end end - describe '::instance' do - after { check_instance_variables(browser, @json_expected_vars) } - - context "when default config_file = #{CONFIG_FILE_WITHOUT_PROXY}" do - it 'will check the instance vars' do - @json_expected_vars = json_config_without_proxy - end - end - - context "when :config_file = #{CONFIG_FILE_WITH_PROXY}" do - let(:options) { { config_file: CONFIG_FILE_WITH_PROXY } } - - it 'will check the instance vars' do - @json_expected_vars = json_config_with_proxy - end - end - - context 'when options[:cache_dir]' do - let(:cache_dir) { CACHE_DIR + '/somewhere' } - let(:options) { { cache_dir: cache_dir } } - - after { subject.cache_dir.should == cache_dir } - - it 'sets @cache_dir' do - @json_expected_vars = json_config_without_proxy - end - end - end - - describe '#load_config' do - context 'when config_file is a symlink' do - let(:config_file) { './rspec_symlink' } - - it 'raises an error' do - File.symlink('./testfile', config_file) - expect { browser.load_config(config_file) }.to raise_error("[ERROR] Config file is a symlink.") - File.unlink(config_file) - end - end - - context 'otherwise' do - after do - browser.load_config(@config_file) - check_instance_variables(browser, @expected) - end - - it 'sets the correct variables' do - @config_file = CONFIG_FILE_WITH_PROXY - @expected = json_config_without_proxy.merge(json_config_with_proxy) - end - end - end - describe '::append_params_header_field' do after :each do Browser.append_params_header_field( @@ -143,7 +76,7 @@ describe Browser do } after :each do - browser.stub(user_agent: 'SomeUA') + browser.useragent = 'SomeUA' browser.cache_ttl = 250 browser.merge_request_params(params).should == @expected diff --git a/spec/samples/conf/browser/browser.conf.json b/spec/samples/conf/browser/browser.conf.json deleted file mode 100644 index 9edbddfc..00000000 --- a/spec/samples/conf/browser/browser.conf.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", - "user_agent_mode": "static", - "cache_ttl": 300, - "request_timeout": 2000, - "connect_timeout": 1000, - "max_threads": 5 -} diff --git a/spec/samples/conf/browser/browser.conf_proxy.json b/spec/samples/conf/browser/browser.conf_proxy.json deleted file mode 100644 index afec262e..00000000 --- a/spec/samples/conf/browser/browser.conf_proxy.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", - "user_agent_mode": "static", - "proxy": "127.0.0.1:3038", - "cache_ttl": 300, - "request_timeout": 2000, - "connect_timeout": 1000 -} diff --git a/spec/samples/conf/browser/browser.conf_proxy_auth.json b/spec/samples/conf/browser/browser.conf_proxy_auth.json deleted file mode 100644 index 6399f8dc..00000000 --- a/spec/samples/conf/browser/browser.conf_proxy_auth.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", - "user_agent_mode": "static", - "proxy": "127.0.0.1:3038", - "proxy_auth": "user:pass", - "cache_ttl": 300, - "request_timeout": 2000, - "connect_timeout": 1000 -} diff --git a/spec/shared_examples/browser/options.rb b/spec/shared_examples/browser/options.rb index 97d34998..a02b3062 100644 --- a/spec/shared_examples/browser/options.rb +++ b/spec/shared_examples/browser/options.rb @@ -71,69 +71,6 @@ shared_examples 'Browser::Options' do end end - describe '#user_agent_mode= & #user_agent_mode' do - # Testing all valid modes - Browser::USER_AGENT_MODES.each do |user_agent_mode| - it "sets & returns #{user_agent_mode}" do - browser.user_agent_mode = user_agent_mode - browser.user_agent_mode.should === user_agent_mode - end - end - - it 'sets the mode to "static" if nil is given' do - browser.user_agent_mode = nil - browser.user_agent_mode.should === 'static' - end - - it 'raises an error if the mode is not valid' do - expect { browser.user_agent_mode = 'invalid-mode' }.to raise_error - end - end - - describe '#user_agent= & #user_agent' do - let(:available_user_agents) { %w{ ua-1 ua-2 ua-3 ua-4 ua-6 ua-7 ua-8 ua-9 ua-10 ua-11 ua-12 ua-13 ua-14 ua-15 ua-16 ua-17 } } - - context 'when static mode' do - it 'returns the same user agent' do - browser.user_agent = 'fake UA' - browser.user_agent_mode = 'static' - - (1..3).each do - browser.user_agent.should === 'fake UA' - end - end - end - - context 'when semi-static mode' do - it 'chooses a random user_agent in the available_user_agents array and always return it' do - browser.available_user_agents = available_user_agents - browser.user_agent = 'Firefox 11.0' - browser.user_agent_mode = 'semi-static' - - user_agent = browser.user_agent - user_agent.should_not === 'Firefox 11.0' - available_user_agents.include?(user_agent).should be_true - - (1..3).each do - browser.user_agent.should === user_agent - end - end - end - - context 'when random' do - it 'returns a random user agent each time' do - browser.available_user_agents = available_user_agents - browser.user_agent_mode = 'random' - - ua_1 = browser.user_agent - ua_2 = browser.user_agent - ua_3 = browser.user_agent - - fail if ua_1 === ua_2 and ua_2 === ua_3 - end - end - end - describe 'proxy=' do let(:exception) { 'Invalid proxy format. Should be [protocol://]host:port.' } From 25c2f3adad1bc717174425e52a1b85947674028f Mon Sep 17 00:00:00 2001 From: FireFart Date: Sat, 1 Mar 2014 09:01:52 +0100 Subject: [PATCH 02/10] Add random-agent --- README | 4 +++- README.md | 4 +++- data/user-agents.txt | 36 +++++++++++++++++++++++++++++++++ lib/common/browser.rb | 6 +++--- lib/common/browser/options.rb | 2 +- lib/common/common_helper.rb | 17 ++++++++++++++++ lib/wpscan/wpscan_helper.rb | 3 ++- lib/wpscan/wpscan_options.rb | 11 +++++++--- spec/lib/common/browser_spec.rb | 4 ++-- 9 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 data/user-agents.txt diff --git a/README b/README index 9f4cbb3e..2d4ff7ee 100644 --- a/README +++ b/README @@ -140,7 +140,9 @@ ryandewhurst at gmail --exclude-content-based '' Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied You do not need to provide the regexp delimiters, but you must write the quotes (simple or double) ---config-file | -c Use the specified config file +--user-agent | -a Use the specified User-Agent + +--random-agent | -r Use a random User-Agent --follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not diff --git a/README.md b/README.md index f7a1b876..7115707a 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,9 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install --exclude-content-based '' Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied You do not need to provide the regexp delimiters, but you must write the quotes (simple or double) - --config-file | -c Use the specified config file + --user-agent | -a Use the specified User-Agent + + --random-agent | -r Use a random User-Agent --follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not diff --git a/data/user-agents.txt b/data/user-agents.txt new file mode 100644 index 00000000..861cf79e --- /dev/null +++ b/data/user-agents.txt @@ -0,0 +1,36 @@ +# Windows +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1 +Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120427 Firefox/15.0a1 +Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) +Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0) +Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 + +# MAC +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.15 Safari/534.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2; rv:10.0.1) Gecko/20100101 Firefox/10.0.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10 + +# Linux +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.20 Safari/535.1 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.703.0 Chrome/12.0.703.0 Safari/534.24 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.9) Gecko/20100915 Gentoo Firefox/3.6.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120421 Gecko Firefox/11.0 +Mozilla/5.0 (X11; Linux i686; rv:12.0) Gecko/20100101 Firefox/12.0 +Opera/9.80 (X11; Linux x86_64; U; pl) Presto/2.7.62 Version/11.00 +Mozilla/5.0 (X11; U; Linux x86_64; us; rv:1.9.1.19) Gecko/20110430 shadowfox/7.0 (like Firefox/7.0 diff --git a/lib/common/browser.rb b/lib/common/browser.rb index c97d4549..74c41fff 100644 --- a/lib/common/browser.rb +++ b/lib/common/browser.rb @@ -12,7 +12,7 @@ class Browser :basic_auth, :cache_ttl, :max_threads, - :useragent, + :user_agent, :proxy, :proxy_auth, :request_timeout, @@ -66,7 +66,7 @@ class Browser @cache_ttl = 600 # 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled @request_timeout = 2000 # 2s @connect_timeout = 1000 # 1s - @useragent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)" + @user_agent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)" end # @param [ String ] url @@ -84,7 +84,7 @@ class Browser params = Browser.append_params_header_field( params, 'User-Agent', - @useragent + @user_agent ) if @proxy diff --git a/lib/common/browser/options.rb b/lib/common/browser/options.rb index 2ca3c227..7f761e54 100644 --- a/lib/common/browser/options.rb +++ b/lib/common/browser/options.rb @@ -5,7 +5,7 @@ class Browser attr_accessor :cache_ttl, :request_timeout, :connect_timeout attr_reader :basic_auth, :proxy, :proxy_auth - attr_writer :useragent + attr_writer :user_agent # Sets the Basic Authentification credentials # Accepted format: diff --git a/lib/common/common_helper.rb b/lib/common/common_helper.rb index 97d3f15c..ced34513 100644 --- a/lib/common/common_helper.rb +++ b/lib/common/common_helper.rb @@ -32,6 +32,7 @@ LOCAL_FILES_FILE = DATA_DIR + '/local_vulnerable_files.xml' VULNS_XSD = DATA_DIR + '/vuln.xsd' WP_VERSIONS_XSD = DATA_DIR + '/wp_versions.xsd' LOCAL_FILES_XSD = DATA_DIR + '/local_vulnerable_files.xsd' +USER_AGENTS_FILE = DATA_DIR + '/user-agents.txt' WPSCAN_VERSION = '2.3' @@ -186,3 +187,19 @@ def truncate(input, size, trailing = '...') trailing.length >= input.length or size-trailing.length-1 >= input.length return "#{input[0..size-trailing.length-1]}#{trailing}" end + +# Gets a random User-Agent +# +# @return [ String ] A random user-agent from data/user-agents.txt +def get_random_user_agent + user_agents = [] + f = File.open(USER_AGENTS_FILE, 'r') + f.each_line do |line| + # ignore comments + next if line.empty? or line =~ /^\s*(#|\/\/)/ + user_agents << line.strip + end + f.close + # return ransom user-agent + user_agents.sample +end diff --git a/lib/wpscan/wpscan_helper.rb b/lib/wpscan/wpscan_helper.rb index 68d5ed4d..44d409e4 100644 --- a/lib/wpscan/wpscan_helper.rb +++ b/lib/wpscan/wpscan_helper.rb @@ -82,7 +82,8 @@ def help puts puts '--exclude-content-based "" Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied' puts ' You do not need to provide the regexp delimiters, but you must write the quotes (simple or double)' - puts '--config-file | -c Use the specified config file' + puts '--user-agent | -a Use the specified User-Agent' + puts '--random-agent | -r Use a random User-Agent' puts '--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not' puts '--wp-content-dir WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specified it. Subdirectories are allowed' puts '--wp-plugins-dir Same thing than --wp-content-dir but for the plugins directory. If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed' diff --git a/lib/wpscan/wpscan_options.rb b/lib/wpscan/wpscan_options.rb index d5a29114..c88ffebb 100644 --- a/lib/wpscan/wpscan_options.rb +++ b/lib/wpscan/wpscan_options.rb @@ -31,7 +31,8 @@ class WpscanOptions :basic_auth, :debug_output, :version, - :useragent + :user_agent, + :random_agent ] attr_accessor *ACCESSOR_OPTIONS @@ -137,6 +138,10 @@ class WpscanOptions !to_h.empty? end + def random_agent=(a) + @user_agent = get_random_user_agent + end + # return Hash def to_h options = {} @@ -228,7 +233,8 @@ class WpscanOptions ['--wordlist', '-w', GetoptLong::REQUIRED_ARGUMENT], ['--threads', '-t', GetoptLong::REQUIRED_ARGUMENT], ['--force', '-f', GetoptLong::NO_ARGUMENT], - ['--useragent', '-a', GetoptLong::REQUIRED_ARGUMENT], + ['--user-agent', '-a', GetoptLong::REQUIRED_ARGUMENT], + ['--random-agent', '-r', GetoptLong::NO_ARGUMENT], ['--help', '-h', GetoptLong::NO_ARGUMENT], ['--verbose', '-v', GetoptLong::NO_ARGUMENT], ['--proxy', GetoptLong::REQUIRED_ARGUMENT], @@ -237,7 +243,6 @@ class WpscanOptions ['--follow-redirection', GetoptLong::NO_ARGUMENT], ['--wp-content-dir', GetoptLong::REQUIRED_ARGUMENT], ['--wp-plugins-dir', GetoptLong::REQUIRED_ARGUMENT], - ['--config-file', '-c', GetoptLong::REQUIRED_ARGUMENT], ['--exclude-content-based', GetoptLong::REQUIRED_ARGUMENT], ['--basic-auth', GetoptLong::REQUIRED_ARGUMENT], ['--debug-output', GetoptLong::NO_ARGUMENT], diff --git a/spec/lib/common/browser_spec.rb b/spec/lib/common/browser_spec.rb index f023c3aa..cf0aa4fd 100644 --- a/spec/lib/common/browser_spec.rb +++ b/spec/lib/common/browser_spec.rb @@ -12,7 +12,7 @@ describe Browser do } let(:options) { {} } let(:instance_vars_to_check) { - ['useragent', 'proxy', + ['user-agent', 'random-agent', 'proxy', 'max_threads', 'cache_ttl', 'request_timeout', 'connect_timeout'] } @@ -76,7 +76,7 @@ describe Browser do } after :each do - browser.useragent = 'SomeUA' + browser.user_agent = 'SomeUA' browser.cache_ttl = 250 browser.merge_request_params(params).should == @expected From b1b8066fe58107f028a4bde819ecf1eadb2240d8 Mon Sep 17 00:00:00 2001 From: FireFart Date: Sat, 1 Mar 2014 14:09:05 +0100 Subject: [PATCH 03/10] Added more CLI options --- README | 8 ++++++++ README.md | 8 ++++++++ lib/common/browser.rb | 11 ++++++++--- lib/wpscan/wpscan_helper.rb | 4 ++++ lib/wpscan/wpscan_options.rb | 14 +++++++++++--- 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/README b/README index 2d4ff7ee..b7326402 100644 --- a/README +++ b/README @@ -163,6 +163,14 @@ ryandewhurst at gmail --username | -U Only brute force the supplied username. +--cache-ttl Typhoeus cache TTL + +--request-timeout Request Timeout + +--connect-timeout Connect Timeout + +--max-threads Maximum Threads + --help | -h This help screen. --verbose | -v Verbose output. diff --git a/README.md b/README.md index 7115707a..644d1c9b 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,14 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install --username | -U Only brute force the supplied username. + --cache-ttl Typhoeus cache TTL + + --request-timeout Request Timeout + + --connect-timeout Connect Timeout + + --max-threads Maximum Threads + --help | -h This help screen. --verbose | -v Verbose output. diff --git a/lib/common/browser.rb b/lib/common/browser.rb index 74c41fff..0a3ce7a9 100644 --- a/lib/common/browser.rb +++ b/lib/common/browser.rb @@ -29,7 +29,9 @@ class Browser def initialize(options = {}) @cache_dir = options[:cache_dir] || CACHE_DIR + '/browser' + # sets browser defaults browser_defaults + # overrides defaults with user supplied values override_config(options) unless @hydra @@ -63,9 +65,12 @@ class Browser # def browser_defaults @max_threads = 20 - @cache_ttl = 600 # 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled - @request_timeout = 2000 # 2s - @connect_timeout = 1000 # 1s + # 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled + @cache_ttl = 600 + # 2s + @request_timeout = 2000 + # 1s + @connect_timeout = 1000 @user_agent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)" end diff --git a/lib/wpscan/wpscan_helper.rb b/lib/wpscan/wpscan_helper.rb index 44d409e4..39fee551 100644 --- a/lib/wpscan/wpscan_helper.rb +++ b/lib/wpscan/wpscan_helper.rb @@ -94,6 +94,10 @@ def help puts '--wordlist | -w Supply a wordlist for the password bruter and do the brute.' puts '--threads | -t The number of threads to use when multi-threading requests. (will override the value from conf/browser.conf.json)' puts '--username | -U Only brute force the supplied username.' + puts '--cache-ttl Typhoeus cache TTL' + puts '--request-timeout Request Timeout' + puts '--connect-timeout Connect Timeout' + puts '--max-threads Maximum Threads' puts '--help | -h This help screen.' puts '--verbose | -v Verbose output.' puts diff --git a/lib/wpscan/wpscan_options.rb b/lib/wpscan/wpscan_options.rb index c88ffebb..950badb7 100644 --- a/lib/wpscan/wpscan_options.rb +++ b/lib/wpscan/wpscan_options.rb @@ -32,7 +32,11 @@ class WpscanOptions :debug_output, :version, :user_agent, - :random_agent + :random_agent, + :cache_ttl, + :request_timeout, + :connect_timeout, + :max_threads ] attr_accessor *ACCESSOR_OPTIONS @@ -138,7 +142,7 @@ class WpscanOptions !to_h.empty? end - def random_agent=(a) + def random_agent=(useless) @user_agent = get_random_user_agent end @@ -246,7 +250,11 @@ class WpscanOptions ['--exclude-content-based', GetoptLong::REQUIRED_ARGUMENT], ['--basic-auth', GetoptLong::REQUIRED_ARGUMENT], ['--debug-output', GetoptLong::NO_ARGUMENT], - ['--version', GetoptLong::NO_ARGUMENT] + ['--version', GetoptLong::NO_ARGUMENT], + ['--cache_ttl', GetoptLong::REQUIRED_ARGUMENT], + ['--request_timeout', GetoptLong::REQUIRED_ARGUMENT], + ['--connect_timeout', GetoptLong::REQUIRED_ARGUMENT], + ['--max_threads', GetoptLong::REQUIRED_ARGUMENT] ) end From 7942eaf64b4999808530618863cd5cb2861059bb Mon Sep 17 00:00:00 2001 From: FireFart Date: Sat, 22 Mar 2014 14:47:31 +0100 Subject: [PATCH 04/10] config file --- README | 2 + README.md | 2 + example.conf.json | 18 +++++ lib/common/browser.rb | 23 ++++++- lib/wpscan/wpscan_helper.rb | 1 + lib/wpscan/wpscan_options.rb | 1 + spec/lib/common/browser_spec.rb | 67 +++++++++++++++++++ spec/samples/conf/browser.conf.json | 8 +++ spec/samples/conf/browser.conf_proxy.json | 8 +++ .../samples/conf/browser.conf_proxy_auth.json | 9 +++ spec/shared_examples/browser/options.rb | 2 +- 11 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 example.conf.json create mode 100644 spec/samples/conf/browser.conf.json create mode 100644 spec/samples/conf/browser.conf_proxy.json create mode 100644 spec/samples/conf/browser.conf_proxy_auth.json diff --git a/README b/README index b7326402..16366961 100644 --- a/README +++ b/README @@ -140,6 +140,8 @@ ryandewhurst at gmail --exclude-content-based '' Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied You do not need to provide the regexp delimiters, but you must write the quotes (simple or double) +--config-file | -c Use the specified config file + --user-agent | -a Use the specified User-Agent --random-agent | -r Use a random User-Agent diff --git a/README.md b/README.md index 644d1c9b..061a39d7 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,8 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install --exclude-content-based '' Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied You do not need to provide the regexp delimiters, but you must write the quotes (simple or double) + --config-file | -c Use the specified config file + --user-agent | -a Use the specified User-Agent --random-agent | -r Use a random User-Agent diff --git a/example.conf.json b/example.conf.json new file mode 100644 index 00000000..31d99dec --- /dev/null +++ b/example.conf.json @@ -0,0 +1,18 @@ +{ + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", + + /* Uncomment the "proxy" line to use the proxy + SOCKS proxies (4, 4A, 5) are supported, ie : "proxy": "socks5://127.0.0.1:9000" + If you do not specify the protocol, http will be used + */ + //"proxy": "127.0.0.1:3128", + //"proxy_auth": "username:password", + + "cache_ttl": 600, // 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled + + "request_timeout": 2000, // 2s + + "connect_timeout": 1000, // 1s + + "max_threads": 20 +} diff --git a/lib/common/browser.rb b/lib/common/browser.rb index 0a3ce7a9..6adb4cf2 100644 --- a/lib/common/browser.rb +++ b/lib/common/browser.rb @@ -31,7 +31,10 @@ class Browser # sets browser defaults browser_defaults - # overrides defaults with user supplied values + # load config file + conf = options[:config_file] + load_config(conf) if conf + # overrides defaults with user supplied values (overwrite values from config) override_config(options) unless @hydra @@ -74,6 +77,24 @@ class Browser @user_agent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)" end + # + # If an option was set but is not in the new config_file + # it's value is kept + # + # @param [ String ] config_file + # + # @return [ void ] + def load_config(config_file = nil) + + if File.symlink?(config_file) + raise '[ERROR] Config file is a symlink.' + else + data = JSON.parse(File.read(config_file)) + end + + override_config(data) + end + # @param [ String ] url # @param [ Hash ] params # diff --git a/lib/wpscan/wpscan_helper.rb b/lib/wpscan/wpscan_helper.rb index 39fee551..9eecb126 100644 --- a/lib/wpscan/wpscan_helper.rb +++ b/lib/wpscan/wpscan_helper.rb @@ -82,6 +82,7 @@ def help puts puts '--exclude-content-based "" Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied' puts ' You do not need to provide the regexp delimiters, but you must write the quotes (simple or double)' + puts '--config-file | -c Use the specified config file' puts '--user-agent | -a Use the specified User-Agent' puts '--random-agent | -r Use a random User-Agent' puts '--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not' diff --git a/lib/wpscan/wpscan_options.rb b/lib/wpscan/wpscan_options.rb index 950badb7..4ff92098 100644 --- a/lib/wpscan/wpscan_options.rb +++ b/lib/wpscan/wpscan_options.rb @@ -247,6 +247,7 @@ class WpscanOptions ['--follow-redirection', GetoptLong::NO_ARGUMENT], ['--wp-content-dir', GetoptLong::REQUIRED_ARGUMENT], ['--wp-plugins-dir', GetoptLong::REQUIRED_ARGUMENT], + ['--config-file', '-c', GetoptLong::REQUIRED_ARGUMENT], ['--exclude-content-based', GetoptLong::REQUIRED_ARGUMENT], ['--basic-auth', GetoptLong::REQUIRED_ARGUMENT], ['--debug-output', GetoptLong::NO_ARGUMENT], diff --git a/spec/lib/common/browser_spec.rb b/spec/lib/common/browser_spec.rb index cf0aa4fd..20730060 100644 --- a/spec/lib/common/browser_spec.rb +++ b/spec/lib/common/browser_spec.rb @@ -6,6 +6,10 @@ describe Browser do it_behaves_like 'Browser::Actions' it_behaves_like 'Browser::Options' + CONFIG_FILE_WITHOUT_PROXY = SPEC_FIXTURES_CONF_DIR + '/browser.conf.json' + CONFIG_FILE_WITH_PROXY = SPEC_FIXTURES_CONF_DIR + '/browser.conf_proxy.json' + #CONFIG_FILE_WITH_PROXY_AND_AUTH = SPEC_FIXTURES_CONF_DIR + '/browser.conf_proxy_auth.json' + subject(:browser) { Browser.reset Browser.instance(options) @@ -15,6 +19,16 @@ describe Browser do ['user-agent', 'random-agent', 'proxy', 'max_threads', 'cache_ttl', 'request_timeout', 'connect_timeout'] } + let(:json_config_without_proxy) { JSON.parse(File.read(CONFIG_FILE_WITHOUT_PROXY)) } + let(:json_config_with_proxy) { JSON.parse(File.read(CONFIG_FILE_WITH_PROXY)) } + + def check_instance_variables(browser, json_expected_vars) + json_expected_vars['max_threads'] ||= 1 # max_thread can not be nil + + instance_vars_to_check.each do |variable_name| + browser.send(:"#{variable_name}").should === json_expected_vars[variable_name] + end + end describe 'Singleton' do it 'should not allow #new' do @@ -22,6 +36,59 @@ describe Browser do end end + describe '::instance' do + after { check_instance_variables(browser, @json_expected_vars) } + + context "when default config_file = #{CONFIG_FILE_WITHOUT_PROXY}" do + it 'will check the instance vars' do + @json_expected_vars = json_config_without_proxy + end + end + + context "when :config_file = #{CONFIG_FILE_WITH_PROXY}" do + let(:options) { { config_file: CONFIG_FILE_WITH_PROXY } } + + it 'will check the instance vars' do + @json_expected_vars = json_config_with_proxy + end + end + + context 'when options[:cache_dir]' do + let(:cache_dir) { CACHE_DIR + '/somewhere' } + let(:options) { { cache_dir: cache_dir } } + + after { subject.cache_dir.should == cache_dir } + + it 'sets @cache_dir' do + @json_expected_vars = json_config_without_proxy + end + end + end + + describe '#load_config' do + context 'when config_file is a symlink' do + let(:config_file) { './rspec_symlink' } + + it 'raises an error' do + File.symlink('./testfile', config_file) + expect { browser.load_config(config_file) }.to raise_error("[ERROR] Config file is a symlink.") + File.unlink(config_file) + end + end + + context 'otherwise' do + after do + browser.load_config(@config_file) + check_instance_variables(browser, @expected) + end + + it 'sets the correct variables' do + @config_file = CONFIG_FILE_WITH_PROXY + @expected = json_config_without_proxy.merge(json_config_with_proxy) + end + end + end + describe '::append_params_header_field' do after :each do Browser.append_params_header_field( diff --git a/spec/samples/conf/browser.conf.json b/spec/samples/conf/browser.conf.json new file mode 100644 index 00000000..1c98ea30 --- /dev/null +++ b/spec/samples/conf/browser.conf.json @@ -0,0 +1,8 @@ +{ + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", + "user_agent_mode": "static", + "cache_ttl": 300, + "request_timeout": 2000, + "connect_timeout": 1000, + "max_threads": 5 +} diff --git a/spec/samples/conf/browser.conf_proxy.json b/spec/samples/conf/browser.conf_proxy.json new file mode 100644 index 00000000..edcf137f --- /dev/null +++ b/spec/samples/conf/browser.conf_proxy.json @@ -0,0 +1,8 @@ +{ + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", + "user_agent_mode": "static", + "proxy": "127.0.0.1:3038", + "cache_ttl": 300, + "request_timeout": 2000, + "connect_timeout": 1000 +} diff --git a/spec/samples/conf/browser.conf_proxy_auth.json b/spec/samples/conf/browser.conf_proxy_auth.json new file mode 100644 index 00000000..92324b49 --- /dev/null +++ b/spec/samples/conf/browser.conf_proxy_auth.json @@ -0,0 +1,9 @@ +{ + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", + "user_agent_mode": "static", + "proxy": "127.0.0.1:3038", + "proxy_auth": "user:pass", + "cache_ttl": 300, + "request_timeout": 2000, + "connect_timeout": 1000 +} diff --git a/spec/shared_examples/browser/options.rb b/spec/shared_examples/browser/options.rb index a02b3062..8e21f9da 100644 --- a/spec/shared_examples/browser/options.rb +++ b/spec/shared_examples/browser/options.rb @@ -122,7 +122,7 @@ shared_examples 'Browser::Options' do end context 'valid format' do - it 'sets the auth' do + it 'sets the auth' do @proxy_auth = 'username:passwd' @expected = @proxy_auth end From 781214a2f0d1bdd9537f2027e80bd8e50e2ef612 Mon Sep 17 00:00:00 2001 From: FireFart Date: Sat, 22 Mar 2014 16:05:10 +0100 Subject: [PATCH 05/10] rspecs --- lib/common/browser.rb | 8 +++++++- spec/lib/common/browser_spec.rb | 11 ++--------- spec/lib/wpscan/web_site_spec.rb | 2 +- spec/lib/wpscan/wp_target_spec.rb | 2 +- spec/samples/conf/browser.conf.json | 5 ++--- spec/samples/conf/browser.conf_proxy.json | 1 - spec/samples/conf/browser.conf_proxy_auth.json | 1 - spec/spec_helper.rb | 2 +- 8 files changed, 14 insertions(+), 18 deletions(-) diff --git a/lib/common/browser.rb b/lib/common/browser.rb index 6adb4cf2..4d8ab167 100644 --- a/lib/common/browser.rb +++ b/lib/common/browser.rb @@ -92,7 +92,13 @@ class Browser data = JSON.parse(File.read(config_file)) end - override_config(data) + OPTIONS.each do |option| + option_name = option.to_s + unless data[option_name].nil? + self.send(:"#{option_name}=", data[option_name]) + end + end + end # @param [ String ] url diff --git a/spec/lib/common/browser_spec.rb b/spec/lib/common/browser_spec.rb index 20730060..d932d034 100644 --- a/spec/lib/common/browser_spec.rb +++ b/spec/lib/common/browser_spec.rb @@ -16,14 +16,13 @@ describe Browser do } let(:options) { {} } let(:instance_vars_to_check) { - ['user-agent', 'random-agent', 'proxy', - 'max_threads', 'cache_ttl', 'request_timeout', 'connect_timeout'] + ['proxy', 'max_threads', 'cache_ttl', 'request_timeout', 'connect_timeout'] } let(:json_config_without_proxy) { JSON.parse(File.read(CONFIG_FILE_WITHOUT_PROXY)) } let(:json_config_with_proxy) { JSON.parse(File.read(CONFIG_FILE_WITH_PROXY)) } def check_instance_variables(browser, json_expected_vars) - json_expected_vars['max_threads'] ||= 1 # max_thread can not be nil + json_expected_vars['max_threads'] ||= 20 # max_thread can not be nil instance_vars_to_check.each do |variable_name| browser.send(:"#{variable_name}").should === json_expected_vars[variable_name] @@ -39,12 +38,6 @@ describe Browser do describe '::instance' do after { check_instance_variables(browser, @json_expected_vars) } - context "when default config_file = #{CONFIG_FILE_WITHOUT_PROXY}" do - it 'will check the instance vars' do - @json_expected_vars = json_config_without_proxy - end - end - context "when :config_file = #{CONFIG_FILE_WITH_PROXY}" do let(:options) { { config_file: CONFIG_FILE_WITH_PROXY } } diff --git a/spec/lib/wpscan/web_site_spec.rb b/spec/lib/wpscan/web_site_spec.rb index 1d563ea4..c69c245f 100644 --- a/spec/lib/wpscan/web_site_spec.rb +++ b/spec/lib/wpscan/web_site_spec.rb @@ -12,7 +12,7 @@ describe 'WebSite' do before :all do Browser::reset Browser.instance( - config_file: SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf.json', + config_file: SPEC_FIXTURES_CONF_DIR + '/browser.conf.json', cache_ttl: 0 ) end diff --git a/spec/lib/wpscan/wp_target_spec.rb b/spec/lib/wpscan/wp_target_spec.rb index de663d81..57d9db87 100644 --- a/spec/lib/wpscan/wp_target_spec.rb +++ b/spec/lib/wpscan/wp_target_spec.rb @@ -9,7 +9,7 @@ describe WpTarget do let(:login_url) { wp_target.uri.merge('wp-login.php').to_s } let(:options) { { - config_file: SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf.json', + config_file: SPEC_FIXTURES_CONF_DIR + '/browser.conf.json', cache_ttl: 0, wp_content_dir: 'wp-content', wp_plugins_dir: 'wp-content/plugins' diff --git a/spec/samples/conf/browser.conf.json b/spec/samples/conf/browser.conf.json index 1c98ea30..5b691431 100644 --- a/spec/samples/conf/browser.conf.json +++ b/spec/samples/conf/browser.conf.json @@ -1,8 +1,7 @@ { "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", - "user_agent_mode": "static", - "cache_ttl": 300, + "cache_ttl": 600, "request_timeout": 2000, "connect_timeout": 1000, - "max_threads": 5 + "max_threads": 20 } diff --git a/spec/samples/conf/browser.conf_proxy.json b/spec/samples/conf/browser.conf_proxy.json index edcf137f..dfbe4898 100644 --- a/spec/samples/conf/browser.conf_proxy.json +++ b/spec/samples/conf/browser.conf_proxy.json @@ -1,6 +1,5 @@ { "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", - "user_agent_mode": "static", "proxy": "127.0.0.1:3038", "cache_ttl": 300, "request_timeout": 2000, diff --git a/spec/samples/conf/browser.conf_proxy_auth.json b/spec/samples/conf/browser.conf_proxy_auth.json index 92324b49..9282e256 100644 --- a/spec/samples/conf/browser.conf_proxy_auth.json +++ b/spec/samples/conf/browser.conf_proxy_auth.json @@ -1,6 +1,5 @@ { "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", - "user_agent_mode": "static", "proxy": "127.0.0.1:3038", "proxy_auth": "user:pass", "cache_ttl": 300, diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 664e0fb6..0d9398ec 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -15,7 +15,7 @@ SPEC_FIXTURES_CONF_DIR = SPEC_FIXTURES_DIR + '/conf' # FIXME Remove it SPEC_FIXTURES_WP_VERSIONS_DIR = SPEC_FIXTURES_DIR + '/wp_versions' redefine_constant(:CACHE_DIR, SPEC_DIR + '/cache') -redefine_constant(:CONF_DIR, SPEC_FIXTURES_DIR + '/conf/browser') # FIXME Remove the /browser +redefine_constant(:CONF_DIR, SPEC_FIXTURES_DIR + '/conf') MODELS_FIXTURES = SPEC_FIXTURES_DIR + '/common/models' COLLECTIONS_FIXTURES = SPEC_FIXTURES_DIR + '/common/collections' From bbce082ec290a8bfc7220fb1c8a00e3a98472e32 Mon Sep 17 00:00:00 2001 From: FireFart Date: Fri, 28 Feb 2014 21:49:01 +0100 Subject: [PATCH 06/10] Issue #415 --- conf/browser.conf.json | 65 ----------------- lib/common/browser.rb | 39 +++------- lib/common/browser/options.rb | 44 +----------- lib/wpscan/wpscan_options.rb | 4 +- spec/lib/common/browser_spec.rb | 71 +------------------ spec/samples/conf/browser/browser.conf.json | 8 --- .../conf/browser/browser.conf_proxy.json | 8 --- .../conf/browser/browser.conf_proxy_auth.json | 9 --- spec/shared_examples/browser/options.rb | 63 ---------------- 9 files changed, 19 insertions(+), 292 deletions(-) delete mode 100644 conf/browser.conf.json delete mode 100644 spec/samples/conf/browser/browser.conf.json delete mode 100644 spec/samples/conf/browser/browser.conf_proxy.json delete mode 100644 spec/samples/conf/browser/browser.conf_proxy_auth.json diff --git a/conf/browser.conf.json b/conf/browser.conf.json deleted file mode 100644 index 4c0e7a67..00000000 --- a/conf/browser.conf.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", - /* Modes : - static : will use the defined user_agent for each request - semi-static : will randomly choose a user agent into available_user_agents before each scan - random : each request will choose a random user agent in available_user_agents - */ - "user_agent_mode": "static", - - /* Uncomment the "proxy" line to use the proxy - SOCKS proxies (4, 4A, 5) are supported, ie : "proxy": "socks5://127.0.0.1:9000" - If you do not specify the protocol, http will be used - */ - //"proxy": "127.0.0.1:3128", - //"proxy_auth": "username:password", - - "cache_ttl": 600, // 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled - - "request_timeout": 2000, // 2s - - "connect_timeout": 1000, // 1s - - "max_threads": 20, - - // Some user_agents can be found there http://techpatterns.com/downloads/firefox/useragentswitcher.xml (thx to Gianluca Brindisi) - "available_user_agents": - [ - // Windows - "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5", - "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1", - "Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E)", - "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1", - "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1", - "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1", - "Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0", - "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120427 Firefox/15.0a1", - "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)", - "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)", - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0)", - "Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00", - "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5", - - // MAC - "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.15 Safari/534.13", - "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1", - "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2; rv:10.0.1) Gecko/20100101 Firefox/10.0.1", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10", - - // Linux - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.20 Safari/535.1", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.703.0 Chrome/12.0.703.0 Safari/534.24", - "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.9) Gecko/20100915 Gentoo Firefox/3.6.9", - "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120421 Gecko Firefox/11.0", - "Mozilla/5.0 (X11; Linux i686; rv:12.0) Gecko/20100101 Firefox/12.0", - "Opera/9.80 (X11; Linux x86_64; U; pl) Presto/2.7.62 Version/11.00", - "Mozilla/5.0 (X11; U; Linux x86_64; us; rv:1.9.1.19) Gecko/20110430 shadowfox/7.0 (like Firefox/7.0" - ] -} diff --git a/lib/common/browser.rb b/lib/common/browser.rb index fdb78c9d..c97d4549 100644 --- a/lib/common/browser.rb +++ b/lib/common/browser.rb @@ -9,12 +9,10 @@ class Browser include Browser::Options OPTIONS = [ - :available_user_agents, :basic_auth, :cache_ttl, :max_threads, - :user_agent, - :user_agent_mode, + :useragent, :proxy, :proxy_auth, :request_timeout, @@ -23,16 +21,15 @@ class Browser @@instance = nil - attr_reader :hydra, :config_file, :cache_dir + attr_reader :hydra, :cache_dir # @param [ Hash ] options # # @return [ Browser ] def initialize(options = {}) - @config_file = options[:config_file] || CONF_DIR + '/browser.conf.json' @cache_dir = options[:cache_dir] || CACHE_DIR + '/browser' - load_config + browser_defaults override_config(options) unless @hydra @@ -62,28 +59,14 @@ class Browser end # - # If an option was set but is not in the new config_file - # it's value is kept + # sets browser default values # - # @param [ String ] config_file - # - # @return [ void ] - def load_config(config_file = nil) - @config_file = config_file || @config_file - - if File.symlink?(@config_file) - raise '[ERROR] Config file is a symlink.' - else - data = JSON.parse(File.read(@config_file)) - end - - OPTIONS.each do |option| - option_name = option.to_s - - unless data[option_name].nil? - self.send(:"#{option_name}=", data[option_name]) - end - end + def browser_defaults + @max_threads = 20 + @cache_ttl = 600 # 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled + @request_timeout = 2000 # 2s + @connect_timeout = 1000 # 1s + @useragent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)" end # @param [ String ] url @@ -101,7 +84,7 @@ class Browser params = Browser.append_params_header_field( params, 'User-Agent', - self.user_agent + @useragent ) if @proxy diff --git a/lib/common/browser/options.rb b/lib/common/browser/options.rb index 750b8029..2ca3c227 100644 --- a/lib/common/browser/options.rb +++ b/lib/common/browser/options.rb @@ -3,11 +3,9 @@ class Browser module Options - USER_AGENT_MODES = %w{ static semi-static random } - - attr_accessor :available_user_agents, :cache_ttl, :request_timeout, :connect_timeout - attr_reader :basic_auth, :user_agent_mode, :proxy, :proxy_auth - attr_writer :user_agent + attr_accessor :cache_ttl, :request_timeout, :connect_timeout + attr_reader :basic_auth, :proxy, :proxy_auth + attr_writer :useragent # Sets the Basic Authentification credentials # Accepted format: @@ -41,42 +39,6 @@ class Browser end end - # Sets the user_agent_mode, which can be one of the following: - # static: The UA is defined by the user, and will be the same in each requests - # semi-static: The UA is randomly chosen at the first request, and will not change - # random: UA randomly chosen each request - # - # UA are from @available_user_agents - # - # @param [ String ] ua_mode - # - # @return [ void ] - def user_agent_mode=(ua_mode) - ua_mode ||= 'static' - - if USER_AGENT_MODES.include?(ua_mode) - @user_agent_mode = ua_mode - # For semi-static user agent mode, the user agent has to - # be nil the first time (it will be set with the getter) - @user_agent = nil if ua_mode === 'semi-static' - else - raise "Unknow user agent mode : '#{ua_mode}'" - end - end - - # @return [ String ] The user agent, according to the user_agent_mode - def user_agent - case @user_agent_mode - when 'semi-static' - unless @user_agent - @user_agent = @available_user_agents.sample - end - when 'random' - @user_agent = @available_user_agents.sample - end - @user_agent - end - # Sets the proxy # Accepted format: # [protocol://]host:post diff --git a/lib/wpscan/wpscan_options.rb b/lib/wpscan/wpscan_options.rb index 16046e48..d5a29114 100644 --- a/lib/wpscan/wpscan_options.rb +++ b/lib/wpscan/wpscan_options.rb @@ -30,7 +30,8 @@ class WpscanOptions :exclude_content_based, :basic_auth, :debug_output, - :version + :version, + :useragent ] attr_accessor *ACCESSOR_OPTIONS @@ -227,6 +228,7 @@ class WpscanOptions ['--wordlist', '-w', GetoptLong::REQUIRED_ARGUMENT], ['--threads', '-t', GetoptLong::REQUIRED_ARGUMENT], ['--force', '-f', GetoptLong::NO_ARGUMENT], + ['--useragent', '-a', GetoptLong::REQUIRED_ARGUMENT], ['--help', '-h', GetoptLong::NO_ARGUMENT], ['--verbose', '-v', GetoptLong::NO_ARGUMENT], ['--proxy', GetoptLong::REQUIRED_ARGUMENT], diff --git a/spec/lib/common/browser_spec.rb b/spec/lib/common/browser_spec.rb index 0d367641..f023c3aa 100644 --- a/spec/lib/common/browser_spec.rb +++ b/spec/lib/common/browser_spec.rb @@ -6,29 +6,15 @@ describe Browser do it_behaves_like 'Browser::Actions' it_behaves_like 'Browser::Options' - CONFIG_FILE_WITHOUT_PROXY = SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf.json' - CONFIG_FILE_WITH_PROXY = SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf_proxy.json' - #CONFIG_FILE_WITH_PROXY_AND_AUTH = SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf_proxy_auth.json' - subject(:browser) { Browser.reset Browser.instance(options) } let(:options) { {} } let(:instance_vars_to_check) { - ['user_agent', 'user_agent_mode', 'available_user_agents', 'proxy', + ['useragent', 'proxy', 'max_threads', 'cache_ttl', 'request_timeout', 'connect_timeout'] } - let(:json_config_without_proxy) { JSON.parse(File.read(CONFIG_FILE_WITHOUT_PROXY)) } - let(:json_config_with_proxy) { JSON.parse(File.read(CONFIG_FILE_WITH_PROXY)) } - - def check_instance_variables(browser, json_expected_vars) - json_expected_vars['max_threads'] ||= 1 # max_thread can not be nil - - instance_vars_to_check.each do |variable_name| - browser.send(:"#{variable_name}").should === json_expected_vars[variable_name] - end - end describe 'Singleton' do it 'should not allow #new' do @@ -36,59 +22,6 @@ describe Browser do end end - describe '::instance' do - after { check_instance_variables(browser, @json_expected_vars) } - - context "when default config_file = #{CONFIG_FILE_WITHOUT_PROXY}" do - it 'will check the instance vars' do - @json_expected_vars = json_config_without_proxy - end - end - - context "when :config_file = #{CONFIG_FILE_WITH_PROXY}" do - let(:options) { { config_file: CONFIG_FILE_WITH_PROXY } } - - it 'will check the instance vars' do - @json_expected_vars = json_config_with_proxy - end - end - - context 'when options[:cache_dir]' do - let(:cache_dir) { CACHE_DIR + '/somewhere' } - let(:options) { { cache_dir: cache_dir } } - - after { subject.cache_dir.should == cache_dir } - - it 'sets @cache_dir' do - @json_expected_vars = json_config_without_proxy - end - end - end - - describe '#load_config' do - context 'when config_file is a symlink' do - let(:config_file) { './rspec_symlink' } - - it 'raises an error' do - File.symlink('./testfile', config_file) - expect { browser.load_config(config_file) }.to raise_error("[ERROR] Config file is a symlink.") - File.unlink(config_file) - end - end - - context 'otherwise' do - after do - browser.load_config(@config_file) - check_instance_variables(browser, @expected) - end - - it 'sets the correct variables' do - @config_file = CONFIG_FILE_WITH_PROXY - @expected = json_config_without_proxy.merge(json_config_with_proxy) - end - end - end - describe '::append_params_header_field' do after :each do Browser.append_params_header_field( @@ -143,7 +76,7 @@ describe Browser do } after :each do - browser.stub(user_agent: 'SomeUA') + browser.useragent = 'SomeUA' browser.cache_ttl = 250 browser.merge_request_params(params).should == @expected diff --git a/spec/samples/conf/browser/browser.conf.json b/spec/samples/conf/browser/browser.conf.json deleted file mode 100644 index 9edbddfc..00000000 --- a/spec/samples/conf/browser/browser.conf.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", - "user_agent_mode": "static", - "cache_ttl": 300, - "request_timeout": 2000, - "connect_timeout": 1000, - "max_threads": 5 -} diff --git a/spec/samples/conf/browser/browser.conf_proxy.json b/spec/samples/conf/browser/browser.conf_proxy.json deleted file mode 100644 index afec262e..00000000 --- a/spec/samples/conf/browser/browser.conf_proxy.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", - "user_agent_mode": "static", - "proxy": "127.0.0.1:3038", - "cache_ttl": 300, - "request_timeout": 2000, - "connect_timeout": 1000 -} diff --git a/spec/samples/conf/browser/browser.conf_proxy_auth.json b/spec/samples/conf/browser/browser.conf_proxy_auth.json deleted file mode 100644 index 6399f8dc..00000000 --- a/spec/samples/conf/browser/browser.conf_proxy_auth.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", - "user_agent_mode": "static", - "proxy": "127.0.0.1:3038", - "proxy_auth": "user:pass", - "cache_ttl": 300, - "request_timeout": 2000, - "connect_timeout": 1000 -} diff --git a/spec/shared_examples/browser/options.rb b/spec/shared_examples/browser/options.rb index 97d34998..a02b3062 100644 --- a/spec/shared_examples/browser/options.rb +++ b/spec/shared_examples/browser/options.rb @@ -71,69 +71,6 @@ shared_examples 'Browser::Options' do end end - describe '#user_agent_mode= & #user_agent_mode' do - # Testing all valid modes - Browser::USER_AGENT_MODES.each do |user_agent_mode| - it "sets & returns #{user_agent_mode}" do - browser.user_agent_mode = user_agent_mode - browser.user_agent_mode.should === user_agent_mode - end - end - - it 'sets the mode to "static" if nil is given' do - browser.user_agent_mode = nil - browser.user_agent_mode.should === 'static' - end - - it 'raises an error if the mode is not valid' do - expect { browser.user_agent_mode = 'invalid-mode' }.to raise_error - end - end - - describe '#user_agent= & #user_agent' do - let(:available_user_agents) { %w{ ua-1 ua-2 ua-3 ua-4 ua-6 ua-7 ua-8 ua-9 ua-10 ua-11 ua-12 ua-13 ua-14 ua-15 ua-16 ua-17 } } - - context 'when static mode' do - it 'returns the same user agent' do - browser.user_agent = 'fake UA' - browser.user_agent_mode = 'static' - - (1..3).each do - browser.user_agent.should === 'fake UA' - end - end - end - - context 'when semi-static mode' do - it 'chooses a random user_agent in the available_user_agents array and always return it' do - browser.available_user_agents = available_user_agents - browser.user_agent = 'Firefox 11.0' - browser.user_agent_mode = 'semi-static' - - user_agent = browser.user_agent - user_agent.should_not === 'Firefox 11.0' - available_user_agents.include?(user_agent).should be_true - - (1..3).each do - browser.user_agent.should === user_agent - end - end - end - - context 'when random' do - it 'returns a random user agent each time' do - browser.available_user_agents = available_user_agents - browser.user_agent_mode = 'random' - - ua_1 = browser.user_agent - ua_2 = browser.user_agent - ua_3 = browser.user_agent - - fail if ua_1 === ua_2 and ua_2 === ua_3 - end - end - end - describe 'proxy=' do let(:exception) { 'Invalid proxy format. Should be [protocol://]host:port.' } From c4ca7e471a4f8bfacba0fe4405757f6141c471d5 Mon Sep 17 00:00:00 2001 From: FireFart Date: Sat, 1 Mar 2014 09:01:52 +0100 Subject: [PATCH 07/10] Add random-agent --- README | 4 +++- README.md | 4 +++- data/user-agents.txt | 36 +++++++++++++++++++++++++++++++++ lib/common/browser.rb | 6 +++--- lib/common/browser/options.rb | 2 +- lib/common/common_helper.rb | 17 ++++++++++++++++ lib/wpscan/wpscan_helper.rb | 3 ++- lib/wpscan/wpscan_options.rb | 11 +++++++--- spec/lib/common/browser_spec.rb | 4 ++-- 9 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 data/user-agents.txt diff --git a/README b/README index 9f4cbb3e..2d4ff7ee 100644 --- a/README +++ b/README @@ -140,7 +140,9 @@ ryandewhurst at gmail --exclude-content-based '' Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied You do not need to provide the regexp delimiters, but you must write the quotes (simple or double) ---config-file | -c Use the specified config file +--user-agent | -a Use the specified User-Agent + +--random-agent | -r Use a random User-Agent --follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not diff --git a/README.md b/README.md index f7a1b876..7115707a 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,9 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install --exclude-content-based '' Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied You do not need to provide the regexp delimiters, but you must write the quotes (simple or double) - --config-file | -c Use the specified config file + --user-agent | -a Use the specified User-Agent + + --random-agent | -r Use a random User-Agent --follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not diff --git a/data/user-agents.txt b/data/user-agents.txt new file mode 100644 index 00000000..861cf79e --- /dev/null +++ b/data/user-agents.txt @@ -0,0 +1,36 @@ +# Windows +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5 +Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.14 (KHTML, like Gecko) Chrome/9.0.601.0 Safari/534.14 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.27 (KHTML, like Gecko) Chrome/12.0.712.0 Safari/534.27 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.24 Safari/535.1 +Mozilla/5.0 (Windows; U; Windows NT 5.1; tr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8 ( .NET CLR 3.5.30729; .NET4.0E) +Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 +Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 +Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.1) Gecko/20100101 Firefox/10.0.1 +Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0 +Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120427 Firefox/15.0a1 +Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0) +Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) +Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0) +Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00 +Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5 + +# MAC +Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.15 Safari/534.13 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.2.15) Gecko/20110303 Firefox/3.6.15 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.8 (KHTML, like Gecko) Safari/419.3 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 (KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2; rv:10.0.1) Gecko/20100101 Firefox/10.0.1 +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10 + +# Linux +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.20 Safari/535.1 +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Ubuntu/10.10 Chromium/12.0.703.0 Chrome/12.0.703.0 Safari/534.24 +Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.9) Gecko/20100915 Gentoo Firefox/3.6.9 +Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.16) Gecko/20120421 Gecko Firefox/11.0 +Mozilla/5.0 (X11; Linux i686; rv:12.0) Gecko/20100101 Firefox/12.0 +Opera/9.80 (X11; Linux x86_64; U; pl) Presto/2.7.62 Version/11.00 +Mozilla/5.0 (X11; U; Linux x86_64; us; rv:1.9.1.19) Gecko/20110430 shadowfox/7.0 (like Firefox/7.0 diff --git a/lib/common/browser.rb b/lib/common/browser.rb index c97d4549..74c41fff 100644 --- a/lib/common/browser.rb +++ b/lib/common/browser.rb @@ -12,7 +12,7 @@ class Browser :basic_auth, :cache_ttl, :max_threads, - :useragent, + :user_agent, :proxy, :proxy_auth, :request_timeout, @@ -66,7 +66,7 @@ class Browser @cache_ttl = 600 # 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled @request_timeout = 2000 # 2s @connect_timeout = 1000 # 1s - @useragent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)" + @user_agent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)" end # @param [ String ] url @@ -84,7 +84,7 @@ class Browser params = Browser.append_params_header_field( params, 'User-Agent', - @useragent + @user_agent ) if @proxy diff --git a/lib/common/browser/options.rb b/lib/common/browser/options.rb index 2ca3c227..7f761e54 100644 --- a/lib/common/browser/options.rb +++ b/lib/common/browser/options.rb @@ -5,7 +5,7 @@ class Browser attr_accessor :cache_ttl, :request_timeout, :connect_timeout attr_reader :basic_auth, :proxy, :proxy_auth - attr_writer :useragent + attr_writer :user_agent # Sets the Basic Authentification credentials # Accepted format: diff --git a/lib/common/common_helper.rb b/lib/common/common_helper.rb index 6e1e532e..cd3fa6bc 100644 --- a/lib/common/common_helper.rb +++ b/lib/common/common_helper.rb @@ -32,6 +32,7 @@ LOCAL_FILES_FILE = DATA_DIR + '/local_vulnerable_files.xml' VULNS_XSD = DATA_DIR + '/vuln.xsd' WP_VERSIONS_XSD = DATA_DIR + '/wp_versions.xsd' LOCAL_FILES_XSD = DATA_DIR + '/local_vulnerable_files.xsd' +USER_AGENTS_FILE = DATA_DIR + '/user-agents.txt' WPSCAN_VERSION = '2.3' @@ -187,3 +188,19 @@ def truncate(input, size, trailing = '...') trailing.length >= input.length or size-trailing.length-1 >= input.length return "#{input[0..size-trailing.length-1]}#{trailing}" end + +# Gets a random User-Agent +# +# @return [ String ] A random user-agent from data/user-agents.txt +def get_random_user_agent + user_agents = [] + f = File.open(USER_AGENTS_FILE, 'r') + f.each_line do |line| + # ignore comments + next if line.empty? or line =~ /^\s*(#|\/\/)/ + user_agents << line.strip + end + f.close + # return ransom user-agent + user_agents.sample +end diff --git a/lib/wpscan/wpscan_helper.rb b/lib/wpscan/wpscan_helper.rb index 68d5ed4d..44d409e4 100644 --- a/lib/wpscan/wpscan_helper.rb +++ b/lib/wpscan/wpscan_helper.rb @@ -82,7 +82,8 @@ def help puts puts '--exclude-content-based "" Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied' puts ' You do not need to provide the regexp delimiters, but you must write the quotes (simple or double)' - puts '--config-file | -c Use the specified config file' + puts '--user-agent | -a Use the specified User-Agent' + puts '--random-agent | -r Use a random User-Agent' puts '--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not' puts '--wp-content-dir WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specified it. Subdirectories are allowed' puts '--wp-plugins-dir Same thing than --wp-content-dir but for the plugins directory. If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed' diff --git a/lib/wpscan/wpscan_options.rb b/lib/wpscan/wpscan_options.rb index d5a29114..c88ffebb 100644 --- a/lib/wpscan/wpscan_options.rb +++ b/lib/wpscan/wpscan_options.rb @@ -31,7 +31,8 @@ class WpscanOptions :basic_auth, :debug_output, :version, - :useragent + :user_agent, + :random_agent ] attr_accessor *ACCESSOR_OPTIONS @@ -137,6 +138,10 @@ class WpscanOptions !to_h.empty? end + def random_agent=(a) + @user_agent = get_random_user_agent + end + # return Hash def to_h options = {} @@ -228,7 +233,8 @@ class WpscanOptions ['--wordlist', '-w', GetoptLong::REQUIRED_ARGUMENT], ['--threads', '-t', GetoptLong::REQUIRED_ARGUMENT], ['--force', '-f', GetoptLong::NO_ARGUMENT], - ['--useragent', '-a', GetoptLong::REQUIRED_ARGUMENT], + ['--user-agent', '-a', GetoptLong::REQUIRED_ARGUMENT], + ['--random-agent', '-r', GetoptLong::NO_ARGUMENT], ['--help', '-h', GetoptLong::NO_ARGUMENT], ['--verbose', '-v', GetoptLong::NO_ARGUMENT], ['--proxy', GetoptLong::REQUIRED_ARGUMENT], @@ -237,7 +243,6 @@ class WpscanOptions ['--follow-redirection', GetoptLong::NO_ARGUMENT], ['--wp-content-dir', GetoptLong::REQUIRED_ARGUMENT], ['--wp-plugins-dir', GetoptLong::REQUIRED_ARGUMENT], - ['--config-file', '-c', GetoptLong::REQUIRED_ARGUMENT], ['--exclude-content-based', GetoptLong::REQUIRED_ARGUMENT], ['--basic-auth', GetoptLong::REQUIRED_ARGUMENT], ['--debug-output', GetoptLong::NO_ARGUMENT], diff --git a/spec/lib/common/browser_spec.rb b/spec/lib/common/browser_spec.rb index f023c3aa..cf0aa4fd 100644 --- a/spec/lib/common/browser_spec.rb +++ b/spec/lib/common/browser_spec.rb @@ -12,7 +12,7 @@ describe Browser do } let(:options) { {} } let(:instance_vars_to_check) { - ['useragent', 'proxy', + ['user-agent', 'random-agent', 'proxy', 'max_threads', 'cache_ttl', 'request_timeout', 'connect_timeout'] } @@ -76,7 +76,7 @@ describe Browser do } after :each do - browser.useragent = 'SomeUA' + browser.user_agent = 'SomeUA' browser.cache_ttl = 250 browser.merge_request_params(params).should == @expected From be672cbcba537a53c2081e903fa06d58332b48f9 Mon Sep 17 00:00:00 2001 From: FireFart Date: Sat, 1 Mar 2014 14:09:05 +0100 Subject: [PATCH 08/10] Added more CLI options --- README | 8 ++++++++ README.md | 8 ++++++++ lib/common/browser.rb | 11 ++++++++--- lib/wpscan/wpscan_helper.rb | 4 ++++ lib/wpscan/wpscan_options.rb | 14 +++++++++++--- 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/README b/README index 2d4ff7ee..b7326402 100644 --- a/README +++ b/README @@ -163,6 +163,14 @@ ryandewhurst at gmail --username | -U Only brute force the supplied username. +--cache-ttl Typhoeus cache TTL + +--request-timeout Request Timeout + +--connect-timeout Connect Timeout + +--max-threads Maximum Threads + --help | -h This help screen. --verbose | -v Verbose output. diff --git a/README.md b/README.md index 7115707a..644d1c9b 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,14 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install --username | -U Only brute force the supplied username. + --cache-ttl Typhoeus cache TTL + + --request-timeout Request Timeout + + --connect-timeout Connect Timeout + + --max-threads Maximum Threads + --help | -h This help screen. --verbose | -v Verbose output. diff --git a/lib/common/browser.rb b/lib/common/browser.rb index 74c41fff..0a3ce7a9 100644 --- a/lib/common/browser.rb +++ b/lib/common/browser.rb @@ -29,7 +29,9 @@ class Browser def initialize(options = {}) @cache_dir = options[:cache_dir] || CACHE_DIR + '/browser' + # sets browser defaults browser_defaults + # overrides defaults with user supplied values override_config(options) unless @hydra @@ -63,9 +65,12 @@ class Browser # def browser_defaults @max_threads = 20 - @cache_ttl = 600 # 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled - @request_timeout = 2000 # 2s - @connect_timeout = 1000 # 1s + # 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled + @cache_ttl = 600 + # 2s + @request_timeout = 2000 + # 1s + @connect_timeout = 1000 @user_agent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)" end diff --git a/lib/wpscan/wpscan_helper.rb b/lib/wpscan/wpscan_helper.rb index 44d409e4..39fee551 100644 --- a/lib/wpscan/wpscan_helper.rb +++ b/lib/wpscan/wpscan_helper.rb @@ -94,6 +94,10 @@ def help puts '--wordlist | -w Supply a wordlist for the password bruter and do the brute.' puts '--threads | -t The number of threads to use when multi-threading requests. (will override the value from conf/browser.conf.json)' puts '--username | -U Only brute force the supplied username.' + puts '--cache-ttl Typhoeus cache TTL' + puts '--request-timeout Request Timeout' + puts '--connect-timeout Connect Timeout' + puts '--max-threads Maximum Threads' puts '--help | -h This help screen.' puts '--verbose | -v Verbose output.' puts diff --git a/lib/wpscan/wpscan_options.rb b/lib/wpscan/wpscan_options.rb index c88ffebb..950badb7 100644 --- a/lib/wpscan/wpscan_options.rb +++ b/lib/wpscan/wpscan_options.rb @@ -32,7 +32,11 @@ class WpscanOptions :debug_output, :version, :user_agent, - :random_agent + :random_agent, + :cache_ttl, + :request_timeout, + :connect_timeout, + :max_threads ] attr_accessor *ACCESSOR_OPTIONS @@ -138,7 +142,7 @@ class WpscanOptions !to_h.empty? end - def random_agent=(a) + def random_agent=(useless) @user_agent = get_random_user_agent end @@ -246,7 +250,11 @@ class WpscanOptions ['--exclude-content-based', GetoptLong::REQUIRED_ARGUMENT], ['--basic-auth', GetoptLong::REQUIRED_ARGUMENT], ['--debug-output', GetoptLong::NO_ARGUMENT], - ['--version', GetoptLong::NO_ARGUMENT] + ['--version', GetoptLong::NO_ARGUMENT], + ['--cache_ttl', GetoptLong::REQUIRED_ARGUMENT], + ['--request_timeout', GetoptLong::REQUIRED_ARGUMENT], + ['--connect_timeout', GetoptLong::REQUIRED_ARGUMENT], + ['--max_threads', GetoptLong::REQUIRED_ARGUMENT] ) end From f9efdcb6547d191353e50e66b7a6a348389a2f5f Mon Sep 17 00:00:00 2001 From: FireFart Date: Sat, 22 Mar 2014 14:47:31 +0100 Subject: [PATCH 09/10] config file --- README | 2 + README.md | 2 + example.conf.json | 18 +++++ lib/common/browser.rb | 23 ++++++- lib/wpscan/wpscan_helper.rb | 1 + lib/wpscan/wpscan_options.rb | 1 + spec/lib/common/browser_spec.rb | 67 +++++++++++++++++++ spec/samples/conf/browser.conf.json | 8 +++ spec/samples/conf/browser.conf_proxy.json | 8 +++ .../samples/conf/browser.conf_proxy_auth.json | 9 +++ spec/shared_examples/browser/options.rb | 2 +- 11 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 example.conf.json create mode 100644 spec/samples/conf/browser.conf.json create mode 100644 spec/samples/conf/browser.conf_proxy.json create mode 100644 spec/samples/conf/browser.conf_proxy_auth.json diff --git a/README b/README index b7326402..16366961 100644 --- a/README +++ b/README @@ -140,6 +140,8 @@ ryandewhurst at gmail --exclude-content-based '' Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied You do not need to provide the regexp delimiters, but you must write the quotes (simple or double) +--config-file | -c Use the specified config file + --user-agent | -a Use the specified User-Agent --random-agent | -r Use a random User-Agent diff --git a/README.md b/README.md index 644d1c9b..061a39d7 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,8 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install --exclude-content-based '' Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied You do not need to provide the regexp delimiters, but you must write the quotes (simple or double) + --config-file | -c Use the specified config file + --user-agent | -a Use the specified User-Agent --random-agent | -r Use a random User-Agent diff --git a/example.conf.json b/example.conf.json new file mode 100644 index 00000000..31d99dec --- /dev/null +++ b/example.conf.json @@ -0,0 +1,18 @@ +{ + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", + + /* Uncomment the "proxy" line to use the proxy + SOCKS proxies (4, 4A, 5) are supported, ie : "proxy": "socks5://127.0.0.1:9000" + If you do not specify the protocol, http will be used + */ + //"proxy": "127.0.0.1:3128", + //"proxy_auth": "username:password", + + "cache_ttl": 600, // 10 minutes, at this time the cache is cleaned before each scan. If this value is set to 0, the cache will be disabled + + "request_timeout": 2000, // 2s + + "connect_timeout": 1000, // 1s + + "max_threads": 20 +} diff --git a/lib/common/browser.rb b/lib/common/browser.rb index 0a3ce7a9..6adb4cf2 100644 --- a/lib/common/browser.rb +++ b/lib/common/browser.rb @@ -31,7 +31,10 @@ class Browser # sets browser defaults browser_defaults - # overrides defaults with user supplied values + # load config file + conf = options[:config_file] + load_config(conf) if conf + # overrides defaults with user supplied values (overwrite values from config) override_config(options) unless @hydra @@ -74,6 +77,24 @@ class Browser @user_agent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)" end + # + # If an option was set but is not in the new config_file + # it's value is kept + # + # @param [ String ] config_file + # + # @return [ void ] + def load_config(config_file = nil) + + if File.symlink?(config_file) + raise '[ERROR] Config file is a symlink.' + else + data = JSON.parse(File.read(config_file)) + end + + override_config(data) + end + # @param [ String ] url # @param [ Hash ] params # diff --git a/lib/wpscan/wpscan_helper.rb b/lib/wpscan/wpscan_helper.rb index 39fee551..9eecb126 100644 --- a/lib/wpscan/wpscan_helper.rb +++ b/lib/wpscan/wpscan_helper.rb @@ -82,6 +82,7 @@ def help puts puts '--exclude-content-based "" Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied' puts ' You do not need to provide the regexp delimiters, but you must write the quotes (simple or double)' + puts '--config-file | -c Use the specified config file' puts '--user-agent | -a Use the specified User-Agent' puts '--random-agent | -r Use a random User-Agent' puts '--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not' diff --git a/lib/wpscan/wpscan_options.rb b/lib/wpscan/wpscan_options.rb index 950badb7..4ff92098 100644 --- a/lib/wpscan/wpscan_options.rb +++ b/lib/wpscan/wpscan_options.rb @@ -247,6 +247,7 @@ class WpscanOptions ['--follow-redirection', GetoptLong::NO_ARGUMENT], ['--wp-content-dir', GetoptLong::REQUIRED_ARGUMENT], ['--wp-plugins-dir', GetoptLong::REQUIRED_ARGUMENT], + ['--config-file', '-c', GetoptLong::REQUIRED_ARGUMENT], ['--exclude-content-based', GetoptLong::REQUIRED_ARGUMENT], ['--basic-auth', GetoptLong::REQUIRED_ARGUMENT], ['--debug-output', GetoptLong::NO_ARGUMENT], diff --git a/spec/lib/common/browser_spec.rb b/spec/lib/common/browser_spec.rb index cf0aa4fd..20730060 100644 --- a/spec/lib/common/browser_spec.rb +++ b/spec/lib/common/browser_spec.rb @@ -6,6 +6,10 @@ describe Browser do it_behaves_like 'Browser::Actions' it_behaves_like 'Browser::Options' + CONFIG_FILE_WITHOUT_PROXY = SPEC_FIXTURES_CONF_DIR + '/browser.conf.json' + CONFIG_FILE_WITH_PROXY = SPEC_FIXTURES_CONF_DIR + '/browser.conf_proxy.json' + #CONFIG_FILE_WITH_PROXY_AND_AUTH = SPEC_FIXTURES_CONF_DIR + '/browser.conf_proxy_auth.json' + subject(:browser) { Browser.reset Browser.instance(options) @@ -15,6 +19,16 @@ describe Browser do ['user-agent', 'random-agent', 'proxy', 'max_threads', 'cache_ttl', 'request_timeout', 'connect_timeout'] } + let(:json_config_without_proxy) { JSON.parse(File.read(CONFIG_FILE_WITHOUT_PROXY)) } + let(:json_config_with_proxy) { JSON.parse(File.read(CONFIG_FILE_WITH_PROXY)) } + + def check_instance_variables(browser, json_expected_vars) + json_expected_vars['max_threads'] ||= 1 # max_thread can not be nil + + instance_vars_to_check.each do |variable_name| + browser.send(:"#{variable_name}").should === json_expected_vars[variable_name] + end + end describe 'Singleton' do it 'should not allow #new' do @@ -22,6 +36,59 @@ describe Browser do end end + describe '::instance' do + after { check_instance_variables(browser, @json_expected_vars) } + + context "when default config_file = #{CONFIG_FILE_WITHOUT_PROXY}" do + it 'will check the instance vars' do + @json_expected_vars = json_config_without_proxy + end + end + + context "when :config_file = #{CONFIG_FILE_WITH_PROXY}" do + let(:options) { { config_file: CONFIG_FILE_WITH_PROXY } } + + it 'will check the instance vars' do + @json_expected_vars = json_config_with_proxy + end + end + + context 'when options[:cache_dir]' do + let(:cache_dir) { CACHE_DIR + '/somewhere' } + let(:options) { { cache_dir: cache_dir } } + + after { subject.cache_dir.should == cache_dir } + + it 'sets @cache_dir' do + @json_expected_vars = json_config_without_proxy + end + end + end + + describe '#load_config' do + context 'when config_file is a symlink' do + let(:config_file) { './rspec_symlink' } + + it 'raises an error' do + File.symlink('./testfile', config_file) + expect { browser.load_config(config_file) }.to raise_error("[ERROR] Config file is a symlink.") + File.unlink(config_file) + end + end + + context 'otherwise' do + after do + browser.load_config(@config_file) + check_instance_variables(browser, @expected) + end + + it 'sets the correct variables' do + @config_file = CONFIG_FILE_WITH_PROXY + @expected = json_config_without_proxy.merge(json_config_with_proxy) + end + end + end + describe '::append_params_header_field' do after :each do Browser.append_params_header_field( diff --git a/spec/samples/conf/browser.conf.json b/spec/samples/conf/browser.conf.json new file mode 100644 index 00000000..1c98ea30 --- /dev/null +++ b/spec/samples/conf/browser.conf.json @@ -0,0 +1,8 @@ +{ + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", + "user_agent_mode": "static", + "cache_ttl": 300, + "request_timeout": 2000, + "connect_timeout": 1000, + "max_threads": 5 +} diff --git a/spec/samples/conf/browser.conf_proxy.json b/spec/samples/conf/browser.conf_proxy.json new file mode 100644 index 00000000..edcf137f --- /dev/null +++ b/spec/samples/conf/browser.conf_proxy.json @@ -0,0 +1,8 @@ +{ + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", + "user_agent_mode": "static", + "proxy": "127.0.0.1:3038", + "cache_ttl": 300, + "request_timeout": 2000, + "connect_timeout": 1000 +} diff --git a/spec/samples/conf/browser.conf_proxy_auth.json b/spec/samples/conf/browser.conf_proxy_auth.json new file mode 100644 index 00000000..92324b49 --- /dev/null +++ b/spec/samples/conf/browser.conf_proxy_auth.json @@ -0,0 +1,9 @@ +{ + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", + "user_agent_mode": "static", + "proxy": "127.0.0.1:3038", + "proxy_auth": "user:pass", + "cache_ttl": 300, + "request_timeout": 2000, + "connect_timeout": 1000 +} diff --git a/spec/shared_examples/browser/options.rb b/spec/shared_examples/browser/options.rb index a02b3062..8e21f9da 100644 --- a/spec/shared_examples/browser/options.rb +++ b/spec/shared_examples/browser/options.rb @@ -122,7 +122,7 @@ shared_examples 'Browser::Options' do end context 'valid format' do - it 'sets the auth' do + it 'sets the auth' do @proxy_auth = 'username:passwd' @expected = @proxy_auth end From aeefd3e873f97364549d3345e7491765a1b62aa5 Mon Sep 17 00:00:00 2001 From: FireFart Date: Sat, 22 Mar 2014 16:05:10 +0100 Subject: [PATCH 10/10] rspecs --- lib/common/browser.rb | 8 +++++++- spec/lib/common/browser_spec.rb | 11 ++--------- spec/lib/wpscan/web_site_spec.rb | 2 +- spec/lib/wpscan/wp_target_spec.rb | 2 +- spec/samples/conf/browser.conf.json | 5 ++--- spec/samples/conf/browser.conf_proxy.json | 1 - spec/samples/conf/browser.conf_proxy_auth.json | 1 - spec/spec_helper.rb | 2 +- 8 files changed, 14 insertions(+), 18 deletions(-) diff --git a/lib/common/browser.rb b/lib/common/browser.rb index 6adb4cf2..4d8ab167 100644 --- a/lib/common/browser.rb +++ b/lib/common/browser.rb @@ -92,7 +92,13 @@ class Browser data = JSON.parse(File.read(config_file)) end - override_config(data) + OPTIONS.each do |option| + option_name = option.to_s + unless data[option_name].nil? + self.send(:"#{option_name}=", data[option_name]) + end + end + end # @param [ String ] url diff --git a/spec/lib/common/browser_spec.rb b/spec/lib/common/browser_spec.rb index 20730060..d932d034 100644 --- a/spec/lib/common/browser_spec.rb +++ b/spec/lib/common/browser_spec.rb @@ -16,14 +16,13 @@ describe Browser do } let(:options) { {} } let(:instance_vars_to_check) { - ['user-agent', 'random-agent', 'proxy', - 'max_threads', 'cache_ttl', 'request_timeout', 'connect_timeout'] + ['proxy', 'max_threads', 'cache_ttl', 'request_timeout', 'connect_timeout'] } let(:json_config_without_proxy) { JSON.parse(File.read(CONFIG_FILE_WITHOUT_PROXY)) } let(:json_config_with_proxy) { JSON.parse(File.read(CONFIG_FILE_WITH_PROXY)) } def check_instance_variables(browser, json_expected_vars) - json_expected_vars['max_threads'] ||= 1 # max_thread can not be nil + json_expected_vars['max_threads'] ||= 20 # max_thread can not be nil instance_vars_to_check.each do |variable_name| browser.send(:"#{variable_name}").should === json_expected_vars[variable_name] @@ -39,12 +38,6 @@ describe Browser do describe '::instance' do after { check_instance_variables(browser, @json_expected_vars) } - context "when default config_file = #{CONFIG_FILE_WITHOUT_PROXY}" do - it 'will check the instance vars' do - @json_expected_vars = json_config_without_proxy - end - end - context "when :config_file = #{CONFIG_FILE_WITH_PROXY}" do let(:options) { { config_file: CONFIG_FILE_WITH_PROXY } } diff --git a/spec/lib/wpscan/web_site_spec.rb b/spec/lib/wpscan/web_site_spec.rb index 1d563ea4..c69c245f 100644 --- a/spec/lib/wpscan/web_site_spec.rb +++ b/spec/lib/wpscan/web_site_spec.rb @@ -12,7 +12,7 @@ describe 'WebSite' do before :all do Browser::reset Browser.instance( - config_file: SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf.json', + config_file: SPEC_FIXTURES_CONF_DIR + '/browser.conf.json', cache_ttl: 0 ) end diff --git a/spec/lib/wpscan/wp_target_spec.rb b/spec/lib/wpscan/wp_target_spec.rb index de663d81..57d9db87 100644 --- a/spec/lib/wpscan/wp_target_spec.rb +++ b/spec/lib/wpscan/wp_target_spec.rb @@ -9,7 +9,7 @@ describe WpTarget do let(:login_url) { wp_target.uri.merge('wp-login.php').to_s } let(:options) { { - config_file: SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf.json', + config_file: SPEC_FIXTURES_CONF_DIR + '/browser.conf.json', cache_ttl: 0, wp_content_dir: 'wp-content', wp_plugins_dir: 'wp-content/plugins' diff --git a/spec/samples/conf/browser.conf.json b/spec/samples/conf/browser.conf.json index 1c98ea30..5b691431 100644 --- a/spec/samples/conf/browser.conf.json +++ b/spec/samples/conf/browser.conf.json @@ -1,8 +1,7 @@ { "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", - "user_agent_mode": "static", - "cache_ttl": 300, + "cache_ttl": 600, "request_timeout": 2000, "connect_timeout": 1000, - "max_threads": 5 + "max_threads": 20 } diff --git a/spec/samples/conf/browser.conf_proxy.json b/spec/samples/conf/browser.conf_proxy.json index edcf137f..dfbe4898 100644 --- a/spec/samples/conf/browser.conf_proxy.json +++ b/spec/samples/conf/browser.conf_proxy.json @@ -1,6 +1,5 @@ { "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", - "user_agent_mode": "static", "proxy": "127.0.0.1:3038", "cache_ttl": 300, "request_timeout": 2000, diff --git a/spec/samples/conf/browser.conf_proxy_auth.json b/spec/samples/conf/browser.conf_proxy_auth.json index 92324b49..9282e256 100644 --- a/spec/samples/conf/browser.conf_proxy_auth.json +++ b/spec/samples/conf/browser.conf_proxy_auth.json @@ -1,6 +1,5 @@ { "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0) Gecko/20100101 Firefox/11.0", - "user_agent_mode": "static", "proxy": "127.0.0.1:3038", "proxy_auth": "user:pass", "cache_ttl": 300, diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 664e0fb6..0d9398ec 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -15,7 +15,7 @@ SPEC_FIXTURES_CONF_DIR = SPEC_FIXTURES_DIR + '/conf' # FIXME Remove it SPEC_FIXTURES_WP_VERSIONS_DIR = SPEC_FIXTURES_DIR + '/wp_versions' redefine_constant(:CACHE_DIR, SPEC_DIR + '/cache') -redefine_constant(:CONF_DIR, SPEC_FIXTURES_DIR + '/conf/browser') # FIXME Remove the /browser +redefine_constant(:CONF_DIR, SPEC_FIXTURES_DIR + '/conf') MODELS_FIXTURES = SPEC_FIXTURES_DIR + '/common/models' COLLECTIONS_FIXTURES = SPEC_FIXTURES_DIR + '/common/collections'