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