WPScan files
This commit is contained in:
293
spec/lib/browser_spec.rb
Normal file
293
spec/lib/browser_spec.rb
Normal file
@@ -0,0 +1,293 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
||||
|
||||
describe Browser do
|
||||
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'
|
||||
INSTANCE_VARS_TO_CHECK = ['user_agent', 'user_agent_mode', 'available_user_agents', 'proxy', 'max_threads', 'request_timeout', 'cache_timeout']
|
||||
|
||||
before :all do
|
||||
@json_config_without_proxy = JSON.parse(File.read(CONFIG_FILE_WITHOUT_PROXY))
|
||||
@json_config_with_proxy = JSON.parse(File.read(CONFIG_FILE_WITH_PROXY))
|
||||
end
|
||||
|
||||
before :each do
|
||||
@browser = Browser.instance(:config_file => CONFIG_FILE_WITHOUT_PROXY)
|
||||
end
|
||||
|
||||
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 |instance_variable_name|
|
||||
browser.send(:"#{instance_variable_name}").should === json_expected_vars[instance_variable_name]
|
||||
end
|
||||
end
|
||||
|
||||
describe "#user_agent_mode setter / getter" do
|
||||
# Testing all valid modes
|
||||
Browser.class_variable_get(:@@user_agent_modes).each do |user_agent_mode|
|
||||
it "should set / return #{user_agent_mode}" do
|
||||
@browser.user_agent_mode = user_agent_mode
|
||||
@browser.user_agent_mode.should === user_agent_mode
|
||||
end
|
||||
end
|
||||
|
||||
it "shoud set the mode to 'static' if nil is given" do
|
||||
@browser.user_agent_mode = nil
|
||||
@browser.user_agent_mode.should === "static"
|
||||
end
|
||||
|
||||
it "should raise an error if the mode in not valid" do
|
||||
expect { @browser.user_agent_mode = "invalid-mode" }.to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe "#max_threads=" do
|
||||
it "should set max_threads to 1 if nil is given" do
|
||||
@browser.max_threads = nil
|
||||
@browser.max_threads.should === 1
|
||||
end
|
||||
|
||||
it "should set max_threads to 1 if 0 is given" do
|
||||
@browser.max_threads = 0
|
||||
@browser.max_threads.should === 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "#user_agent" do
|
||||
available_user_agents = [ "ua-1", "ua-2", "ua-3", "ua-4", "ua-6", "ua-7", "ua-8", "ua-9", "ua-10" ]
|
||||
|
||||
it "should always return the same user agent in static mode" do
|
||||
@browser.user_agent = "fake UA"
|
||||
@browser.user_agent_mode = "static"
|
||||
|
||||
(1..3).each do
|
||||
@browser.user_agent.should === "fake UA"
|
||||
end
|
||||
end
|
||||
|
||||
it "should choose a random user_agent in the available_user_agents array an 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
|
||||
|
||||
it "should return a random user agent each time" do
|
||||
@browser.available_user_agents = available_user_agents
|
||||
@browser.user_agent_mode = "random"
|
||||
|
||||
@browser.user_agent.should_not === @browser.user_agent
|
||||
end
|
||||
end
|
||||
|
||||
describe "Singleton" do
|
||||
it "should not allow #new" do
|
||||
expect { Browser.new }.to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe "#instance with :config_file = #{CONFIG_FILE_WITHOUT_PROXY}" do
|
||||
it 'will check the instance vars' do
|
||||
Browser.reset
|
||||
check_instance_variables(
|
||||
Browser.instance(:config_file => CONFIG_FILE_WITHOUT_PROXY),
|
||||
@json_config_without_proxy
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#instance with :config_file = #{CONFIG_FILE_WITH_PROXY}" do
|
||||
it 'will check the instance vars' do
|
||||
Browser.reset
|
||||
check_instance_variables(
|
||||
Browser.instance(:config_file => CONFIG_FILE_WITH_PROXY),
|
||||
@json_config_with_proxy
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# => @todo Write something to test all possible overriding
|
||||
describe "override option : user_agent" do
|
||||
it "will check the instance vars, with an overriden one" do
|
||||
Browser.reset
|
||||
check_instance_variables(
|
||||
Browser.instance(
|
||||
:config_file => CONFIG_FILE_WITHOUT_PROXY,
|
||||
:user_agent => 'fake IE'
|
||||
),
|
||||
@json_config_without_proxy.merge('user_agent' => 'fake IE')
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#load_config" do
|
||||
|
||||
end
|
||||
|
||||
describe "#merge_request_params without proxy" do
|
||||
it "should return the default params" do
|
||||
expected_params = {
|
||||
:disable_ssl_host_verification => true,
|
||||
:disable_ssl_peer_verification => true,
|
||||
:headers => {'user-agent' => @browser.user_agent},
|
||||
:cache_timeout => @json_config_without_proxy['cache_timeout']
|
||||
}
|
||||
|
||||
@browser.merge_request_params().should == expected_params
|
||||
end
|
||||
|
||||
it "should return the default params with some values overriden" do
|
||||
expected_params = {
|
||||
:disable_ssl_host_verification => false,
|
||||
:disable_ssl_peer_verification => true,
|
||||
:headers => {'user-agent' => 'Fake IE'},
|
||||
:cache_timeout => 0
|
||||
}
|
||||
|
||||
@browser.merge_request_params(
|
||||
:disable_ssl_host_verification => false,
|
||||
:headers => {'user-agent' => 'Fake IE'},
|
||||
:cache_timeout => 0
|
||||
).should == expected_params
|
||||
end
|
||||
|
||||
it "should return the defaul params with :headers:accept = 'text/html' (should not override :headers:user-agent)" do
|
||||
expected_params = {
|
||||
:disable_ssl_host_verification => true,
|
||||
:disable_ssl_peer_verification => true,
|
||||
:headers => {'user-agent' => @browser.user_agent, 'accept' => 'text/html'},
|
||||
:cache_timeout => @json_config_without_proxy['cache_timeout']
|
||||
}
|
||||
|
||||
@browser.merge_request_params(:headers => {'accept' => 'text/html'}).should == expected_params
|
||||
end
|
||||
end
|
||||
|
||||
describe "#merge_request_params with proxy" do
|
||||
it "should return the default params" do
|
||||
Browser.reset
|
||||
browser = Browser.instance(:config_file => CONFIG_FILE_WITH_PROXY)
|
||||
|
||||
expected_params = {
|
||||
:proxy => @json_config_with_proxy['proxy'],
|
||||
:disable_ssl_host_verification => true,
|
||||
:disable_ssl_peer_verification => true,
|
||||
:headers => {'user-agent' => @json_config_with_proxy['user_agent']},
|
||||
:cache_timeout => @json_config_with_proxy['cache_timeout']
|
||||
}
|
||||
|
||||
browser.merge_request_params().should == expected_params
|
||||
end
|
||||
end
|
||||
|
||||
describe "#replace_variables_in_url" do
|
||||
after :each do
|
||||
@browser.variables_to_replace_in_url = @variables if @variables
|
||||
@browser.send(:replace_variables_in_url, @url).should === @expected
|
||||
end
|
||||
|
||||
it "should not replace anything (empty variables_to_replace_in_url)" do
|
||||
@url = "http://target.tld/wp-content/file.txt"
|
||||
@expected = @url
|
||||
end
|
||||
|
||||
it "should not replace anything (not match found)" do
|
||||
@variables = {"%nothing%" => "hello"}
|
||||
@url = "http://target.tld/nothing/file.txt"
|
||||
@expected = @url
|
||||
end
|
||||
|
||||
it "should replace %wp-content% by 'custom-content'" do
|
||||
@variables = {"%wp-content%" => "custom-content"}
|
||||
@url = "http://target.tld/%wp-content%/some-file.txt"
|
||||
@expected = "http://target.tld/custom-content/some-file.txt"
|
||||
end
|
||||
|
||||
it "should replace %wp-content% by 'custom-content' and %plugins% by 'wp_plugins'" do
|
||||
@variables = {"%wp-content%" => "custom-content", "%plugins%" => "wp_plugins"}
|
||||
@url = "http://target.tld/%wp-content%/hello/%plugins%"
|
||||
@expected = "http://target.tld/custom-content/hello/wp_plugins"
|
||||
end
|
||||
end
|
||||
|
||||
# TODO
|
||||
describe "#forge_request" do
|
||||
|
||||
end
|
||||
|
||||
describe "#post" do
|
||||
it "should return a Typhoeus::Response wth body = 'Welcome Master' if login=master&password=it's me !" do
|
||||
url = 'http://example.com/'
|
||||
|
||||
stub_request(:post, url).
|
||||
with(:body => "login=master&password=it's me !").
|
||||
to_return(:status => 200, :body => "Welcome Master")
|
||||
|
||||
response = @browser.post(url,
|
||||
:params => {:login => "master", :password => "it's me !"}
|
||||
)
|
||||
|
||||
response.should be_a Typhoeus::Response
|
||||
response.body.should == 'Welcome Master'
|
||||
end
|
||||
end
|
||||
|
||||
describe "#get" do
|
||||
it "should return a Typhoeus::Response with body = 'Hello World !'" do
|
||||
url = 'http://example.com/'
|
||||
|
||||
stub_request(:get, url).
|
||||
to_return(:status => 200, :body => "Hello World !")
|
||||
|
||||
response = @browser.get(url)
|
||||
|
||||
response.should be_a Typhoeus::Response
|
||||
response.body.should == 'Hello World !'
|
||||
end
|
||||
end
|
||||
|
||||
describe "#Browser.generate_cache_key_from_request" do
|
||||
it "2 requests with the same url, without params must have the same cache_key" do
|
||||
|
||||
url = 'http://example.com'
|
||||
key1 = Browser.generate_cache_key_from_request(@browser.forge_request(url))
|
||||
key2 = Browser.generate_cache_key_from_request(@browser.forge_request(url))
|
||||
|
||||
key1.should === key2
|
||||
end
|
||||
|
||||
it "2 requests with the same url, but with different params should have a different cache_key" do
|
||||
|
||||
url = 'http://example.com'
|
||||
key1 = Browser.generate_cache_key_from_request(@browser.forge_request(url, :params => {:login => "master", :password => "it's me !"}))
|
||||
key2 = Browser.generate_cache_key_from_request(@browser.forge_request(url))
|
||||
|
||||
key1.should_not == key2
|
||||
end
|
||||
end
|
||||
|
||||
describe "testing caching" do
|
||||
it "should only do 1 request, and retrieve the other one from the cache" do
|
||||
|
||||
url = 'http://example.localhost'
|
||||
|
||||
stub_request(:get, url).
|
||||
to_return(:status => 200, :body => "Hello World !")
|
||||
|
||||
response1 = @browser.get(url)
|
||||
response2 = @browser.get(url)
|
||||
|
||||
response1.body.should == response2.body
|
||||
#WebMock.should have_requested(:get, url).times(1) # This one fail, dunno why :s (but it works without mock)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
68
spec/lib/cache_file_store_spec.rb
Normal file
68
spec/lib/cache_file_store_spec.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
||||
|
||||
describe CacheFileStore do
|
||||
|
||||
before :all do
|
||||
@cache_dir = SPEC_CACHE_DIR + '/cache_file_store'
|
||||
end
|
||||
|
||||
before :each do
|
||||
Dir.delete(@cache_dir) rescue nil
|
||||
|
||||
@cache = CacheFileStore.new(@cache_dir)
|
||||
end
|
||||
|
||||
after :each do
|
||||
@cache.clean
|
||||
end
|
||||
|
||||
describe "#storage_path" do
|
||||
it "returns the storage path given in the #new" do
|
||||
@cache.storage_path.should == @cache_dir
|
||||
end
|
||||
end
|
||||
|
||||
describe "#serializer" do
|
||||
it "should return the default serializer : YAML" do
|
||||
@cache.serializer.should == YAML
|
||||
@cache.serializer.should_not == Marshal
|
||||
end
|
||||
end
|
||||
|
||||
describe "#clean" do
|
||||
it "should remove all files from the cache dir (#{@cache_dir}" do
|
||||
# let's create some files into the directory first
|
||||
(0..5).each do |i|
|
||||
File.new(@cache_dir + "/file_#{i}.txt", File::CREAT)
|
||||
end
|
||||
|
||||
count_files_in_dir(@cache_dir, 'file_*.txt').should == 6
|
||||
@cache.clean
|
||||
count_files_in_dir(@cache_dir).should == 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "#read_entry (nonexistent entry)" do
|
||||
it "should return nil" do
|
||||
@cache.read_entry(Digest::SHA1.hexdigest('hello world')).should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#write_entry, #read_entry (string)" do
|
||||
it "should get the same entry" do
|
||||
cache_timeout = 10
|
||||
@cache.write_entry('some_key', 'Hello World !', cache_timeout)
|
||||
@cache.read_entry('some_key').should == 'Hello World !'
|
||||
end
|
||||
end
|
||||
|
||||
## TODO write / read for an object
|
||||
|
||||
describe "#write_entry with cache_timeout = 0" do
|
||||
it "the entry should not be written" do
|
||||
cache_timeout = 0
|
||||
@cache.write_entry('another_key', 'Another Hello World !', cache_timeout)
|
||||
@cache.read_entry('another_key').should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
5
spec/lib/updater/git_updater_spec.rb
Normal file
5
spec/lib/updater/git_updater_spec.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
||||
|
||||
describe GitUpdater do
|
||||
|
||||
end
|
||||
78
spec/lib/updater/svn_updater_spec.rb
Normal file
78
spec/lib/updater/svn_updater_spec.rb
Normal file
@@ -0,0 +1,78 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
||||
|
||||
describe SvnUpdater do
|
||||
|
||||
before :each do
|
||||
@svn_updater = SvnUpdater.new
|
||||
end
|
||||
|
||||
describe "#is_installed?" do
|
||||
after :each do
|
||||
stub_system_command(@svn_updater, /^svn info/, @stub_value)
|
||||
@svn_updater.is_installed?.should === @expected
|
||||
end
|
||||
|
||||
it "should return false if the svn command is not found" do
|
||||
@stub_value = "svn: command not found"
|
||||
@expected = false
|
||||
end
|
||||
|
||||
it "should return false if the repository is not manage by svn" do
|
||||
@stub_value = "svn: '.' is not a working copy"
|
||||
@expected = false
|
||||
end
|
||||
|
||||
it "should return true" do
|
||||
@stub_value = '<?xml version="1.0"?>
|
||||
<info>
|
||||
<entry kind="dir" path="." revision="362">
|
||||
<url>https://wpscan.googlecode.com/svn/trunk</url>
|
||||
<repository>
|
||||
<root>https://wpscan.googlecode.com/svn</root>
|
||||
<uuid>0b0242d5-46e6-2201-410d-bc09fd35266c</uuid>
|
||||
</repository>
|
||||
<wc-info>
|
||||
<schedule>normal</schedule>
|
||||
<depth>infinity</depth>
|
||||
</wc-info>
|
||||
<commit revision="362">
|
||||
<author>author@mail.tld</author>
|
||||
<date>2012-06-02T06:26:25.309806Z</date>
|
||||
</commit>
|
||||
</entry>
|
||||
</info>'
|
||||
@expected = true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#local_revision_number" do
|
||||
after :each do
|
||||
stub_system_command(@svn_updater, /^svn info/, @stub_value)
|
||||
@svn_updater.local_revision_number.should === @expected
|
||||
end
|
||||
|
||||
it "should return 399" do
|
||||
@stub_value = '<?xml version="1.0"?>
|
||||
<info>
|
||||
<entry kind="dir" path="." revision="362">
|
||||
<url>https://wpscan.googlecode.com/svn/trunk</url>
|
||||
<repository>
|
||||
<root>https://wpscan.googlecode.com/svn</root>
|
||||
<uuid>0b0242d5-46e6-2201-410d-bc09fd35266c</uuid>
|
||||
</repository>
|
||||
<wc-info>
|
||||
<schedule>normal</schedule>
|
||||
<depth>infinity</depth>
|
||||
</wc-info>
|
||||
<commit revision="362">
|
||||
<author>author@mail.tld</author>
|
||||
<date>2012-06-02T06:26:25.309806Z</date>
|
||||
</commit>
|
||||
</entry>
|
||||
</info>'
|
||||
@expected = "362"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
27
spec/lib/updater/updater_factory_spec.rb
Normal file
27
spec/lib/updater/updater_factory_spec.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
||||
|
||||
describe UpdaterFactory do
|
||||
|
||||
describe "#available_updaters_classes" do
|
||||
after :each do
|
||||
UpdaterFactory.available_updaters_classes.sort.should === @expected.sort
|
||||
end
|
||||
|
||||
it "should return [:GitUpdater, :SvnUpdater]" do
|
||||
@expected = [:GitUpdater, :SvnUpdater]
|
||||
end
|
||||
|
||||
it "should return [:TestUpdater, :GitUpdater, :SvnUpdater]" do
|
||||
class TestUpdater < Updater
|
||||
end
|
||||
|
||||
@expected = [:GitUpdater, :SvnUpdater, :TestUpdater]
|
||||
end
|
||||
end
|
||||
|
||||
# TODO : Find a way to test that
|
||||
describe "#get_updater" do
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
25
spec/lib/updater/updater_spec.rb
Normal file
25
spec/lib/updater/updater_spec.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
||||
|
||||
describe Updater do
|
||||
|
||||
before :all do
|
||||
class TestUpdater < Updater
|
||||
end
|
||||
end
|
||||
|
||||
after :all do
|
||||
Object.send(:remove_const, :TestUpdater)
|
||||
end
|
||||
|
||||
describe "non implementation of #is_installed?, #has_update? and #update" do
|
||||
it "should raise errors" do
|
||||
test_updater = TestUpdater.new
|
||||
methods_to_call = [:is_installed?, :update, :local_revision_number]
|
||||
|
||||
methods_to_call.each do |method_to_call|
|
||||
expect { test_updater.send(method_to_call) }.to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
56
spec/lib/wpscan/modules/malwares_spec.rb
Normal file
56
spec/lib/wpscan/modules/malwares_spec.rb
Normal file
@@ -0,0 +1,56 @@
|
||||
shared_examples_for "Malwares" do
|
||||
|
||||
before :each do
|
||||
@module = WpScanModuleSpec.new('http://example.localhost')
|
||||
@target_url = @module.uri.to_s
|
||||
@fixtures_dir = SPEC_FIXTURES_WPSCAN_MODULES_DIR + '/malwares'
|
||||
@malwares_file_path = @fixtures_dir + '/malwares.txt'
|
||||
|
||||
@module.extend(Malwares)
|
||||
end
|
||||
|
||||
describe "#malwares_file" do
|
||||
it "should return #{SPEC_FIXTURES_WPSCAN_MODULES_DIR}/wp_malwares.txt" do
|
||||
Malwares.malwares_file(@malwares_file_path).should === @malwares_file_path
|
||||
end
|
||||
end
|
||||
|
||||
describe "#malwares & #has_malwares" do
|
||||
after :each do
|
||||
if @fixture
|
||||
stub_request_to_fixture(:url => @target_url, :fixture => File.new(@fixture))
|
||||
end
|
||||
|
||||
malwares = @module.malwares(@malwares_file_path)
|
||||
|
||||
malwares.sort.should === @expected_malwares.sort
|
||||
@module.has_malwares?.should === (@expected_malwares.empty? ? false : true)
|
||||
end
|
||||
it "should return an empty array on a 404" do
|
||||
stub_request(:get, @target_url).to_return(:status => 404)
|
||||
|
||||
@expected_malwares = []
|
||||
end
|
||||
|
||||
it "should return an array empty array if no infection found" do
|
||||
@fixture = @fixtures_dir + "/clean.html"
|
||||
@expected_malwares = []
|
||||
end
|
||||
|
||||
it "should return an array with 1 malware url (.rr.nu check)" do
|
||||
@fixture = @fixtures_dir + "/single-infection.html"
|
||||
@expected_malwares = ["http://irstde24clined.rr.nu/mm.php?d=1"]
|
||||
end
|
||||
|
||||
it "should return an array with 1 malware url (iframe check)" do
|
||||
@fixture = @fixtures_dir + "/single-iframe-infection.html"
|
||||
@expected_malwares = ["http://www.thesea.org/media.php"]
|
||||
end
|
||||
|
||||
it "should return an array with 3 malwares url" do
|
||||
@fixture = @fixtures_dir + "/multiple-infections.html"
|
||||
@expected_malwares = ["http://irstde24clined.rr.nu/mm.php?d=1", "http://atio79srem.rr.nu/pmg.php?dr=1", "http://www.thesea.org/media.php"]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
77
spec/lib/wpscan/modules/web_site_spec.rb
Normal file
77
spec/lib/wpscan/modules/web_site_spec.rb
Normal file
@@ -0,0 +1,77 @@
|
||||
shared_examples_for "WebSite" do
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_MODULES_DIR + '/web_site' }
|
||||
|
||||
before :each do
|
||||
@module = WpScanModuleSpec.new('http://example.localhost/')
|
||||
@module.extend(WebSite)
|
||||
end
|
||||
|
||||
describe "#login_url" do
|
||||
it "should return the correct url : http://example.localhost/wp-login.php" do
|
||||
@module.login_url.should === "http://example.localhost/wp-login.php"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#xmlrpc_url" do
|
||||
it "should return the correct url : http://example.localhost/xmlrpc.php" do
|
||||
@module.xmlrpc_url.should === "http://example.localhost/xmlrpc.php"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#is_wordpress?" do
|
||||
# each url (wp-login and xmlrpc) pointed to a 404
|
||||
before :each do
|
||||
[@module.login_url, @module.xmlrpc_url].each do |url|
|
||||
stub_request(:get, url).to_return(:status => 404, :body => "")
|
||||
end
|
||||
end
|
||||
|
||||
it "should return false if both files are not found (404)" do
|
||||
@module.is_wordpress?.should be_false
|
||||
end
|
||||
|
||||
it "should return true if the wp-login is found and is a valid wordpress one" do
|
||||
stub_request(:get, @module.login_url).
|
||||
to_return(:status => 200, :body => File.new(fixtures_dir + '/wp-login.php'))
|
||||
|
||||
@module.is_wordpress?.should be_true
|
||||
end
|
||||
|
||||
it "should return true if the xmlrpc is found" do
|
||||
stub_request(:get, @module.xmlrpc_url).
|
||||
to_return(:status => 200, :body => File.new(fixtures_dir + '/xmlrpc.php'))
|
||||
|
||||
@module.is_wordpress?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#is_online?" do
|
||||
it "should return false" do
|
||||
stub_request(:get, @module.url).to_return(:status => 0)
|
||||
@module.is_online?.should be_false
|
||||
end
|
||||
|
||||
it "should return true" do
|
||||
stub_request(:get, @module.url).to_return(:status => 200)
|
||||
@module.is_online?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#redirection" do
|
||||
it "should return nil if no redirection detected" do
|
||||
stub_request(:get, @module.url).to_return(:status => 200, :body => '')
|
||||
|
||||
@module.redirection.should be_nil
|
||||
end
|
||||
|
||||
[301, 302].each do |status_code|
|
||||
it "should return http://new-location.com if the status code is #{status_code}" do
|
||||
stub_request(:get, @module.url).
|
||||
to_return(:status => status_code, :headers => { :location => "http://new-location.com" })
|
||||
|
||||
@module.redirection.should === "http://new-location.com"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
61
spec/lib/wpscan/modules/wp_config_backup_spec.rb
Normal file
61
spec/lib/wpscan/modules/wp_config_backup_spec.rb
Normal file
@@ -0,0 +1,61 @@
|
||||
shared_examples_for "WpConfigBackup" do
|
||||
|
||||
before :all do
|
||||
@module = WpScanModuleSpec.new('http://example.localhost')
|
||||
@fixtures_dir = SPEC_FIXTURES_WPSCAN_MODULES_DIR + '/wp_config_backup'
|
||||
@config_backup_files = WpConfigBackup.config_backup_files
|
||||
|
||||
@module.extend(WpConfigBackup)
|
||||
end
|
||||
|
||||
describe "#config_backup" do
|
||||
|
||||
# set all @config_backup_files to point to a 404
|
||||
before :each do
|
||||
@config_backup_files.each do |backup_file|
|
||||
file_url = @module.uri.merge(URI.escape(backup_file)).to_s
|
||||
|
||||
stub_request(:get, file_url).
|
||||
to_return(:status => 404, :body => "")
|
||||
end
|
||||
end
|
||||
|
||||
it "shoud return an empty array if no config backup is present" do
|
||||
@module.config_backup.should be_empty
|
||||
end
|
||||
|
||||
it "should return an array with 1 backup file" do
|
||||
expected = []
|
||||
|
||||
@config_backup_files.sample(1).each do |backup_file|
|
||||
file_url = @module.uri.merge(URI.escape(backup_file)).to_s
|
||||
expected << file_url
|
||||
|
||||
stub_request(:get, file_url).
|
||||
to_return(:status => 200, :body => File.new(@fixtures_dir + '/wp-config.php'))
|
||||
end
|
||||
|
||||
wp_config_backup = @module.config_backup
|
||||
wp_config_backup.should_not be_empty
|
||||
wp_config_backup.should === expected
|
||||
end
|
||||
|
||||
# Is there a way to factorise that one with the previous test ?
|
||||
it "should return an array with 2 backup file" do
|
||||
expected = []
|
||||
|
||||
@config_backup_files.sample(2).each do |backup_file|
|
||||
file_url = @module.uri.merge(URI.escape(backup_file)).to_s
|
||||
expected << file_url
|
||||
|
||||
stub_request(:get, file_url).
|
||||
to_return(:status => 200, :body => File.new(@fixtures_dir + '/wp-config.php'))
|
||||
end
|
||||
|
||||
wp_config_backup = @module.config_backup
|
||||
wp_config_backup.should_not be_empty
|
||||
wp_config_backup.sort.should === expected.sort
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
40
spec/lib/wpscan/modules/wp_full_path_disclosure_spec.rb
Normal file
40
spec/lib/wpscan/modules/wp_full_path_disclosure_spec.rb
Normal file
@@ -0,0 +1,40 @@
|
||||
shared_examples_for "WpFullPathDisclosure" do
|
||||
|
||||
before :all do
|
||||
@module = WpScanModuleSpec.new('http://example.localhost')
|
||||
@module.extend(WpFullPathDisclosure)
|
||||
|
||||
@fixtures_dir = SPEC_FIXTURES_WPSCAN_MODULES_DIR + '/wp_full_path_disclosure'
|
||||
end
|
||||
|
||||
describe "#full_path_disclosure_url" do
|
||||
it "should return http://example.localhost/wp-includes/rss-functions.php" do
|
||||
@module.full_path_disclosure_url.should === "http://example.localhost/wp-includes/rss-functions.php"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#has_full_path_disclosure?" do
|
||||
|
||||
it "should return false on a 404" do
|
||||
stub_request(:get, @module.full_path_disclosure_url).
|
||||
to_return(:status => 404)
|
||||
|
||||
@module.has_full_path_disclosure?.should be_false
|
||||
end
|
||||
|
||||
it "should return false if no fpd found (blank page for example)" do
|
||||
stub_request(:get, @module.full_path_disclosure_url).
|
||||
to_return(:status => 200, :body => "")
|
||||
|
||||
@module.has_full_path_disclosure?.should be_false
|
||||
end
|
||||
|
||||
it "should return true" do
|
||||
stub_request(:get, @module.full_path_disclosure_url).
|
||||
to_return(:status => 200, :body => File.new(@fixtures_dir + '/rss-functions-disclosure.php'))
|
||||
|
||||
@module.has_full_path_disclosure?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
96
spec/lib/wpscan/modules/wp_login_protection_spec.rb
Normal file
96
spec/lib/wpscan/modules/wp_login_protection_spec.rb
Normal file
@@ -0,0 +1,96 @@
|
||||
shared_examples_for "WpLoginProtection" do
|
||||
|
||||
before :each do
|
||||
@module = WpScanModuleSpec.new('http://example.localhost')
|
||||
@module.extend(WpLoginProtection)
|
||||
|
||||
@fixtures_dir = SPEC_FIXTURES_WPSCAN_MODULES_DIR + '/wp_login_protection'
|
||||
end
|
||||
|
||||
describe "#login_url" do
|
||||
it "should return the login page url : http://example.localhost/wp-login.php" do
|
||||
@module.login_url.should === "http://example.localhost/wp-login.php"
|
||||
end
|
||||
end
|
||||
|
||||
# It will test all protected methods has_.*_protection with each fixtures to be sure that
|
||||
# there is not false positive : for example the login-lock must not be detected as login-lockdown
|
||||
describe "#has_.*_protection?" do
|
||||
|
||||
pattern = WpLoginProtection.class_variable_get(:@@login_protection_method_pattern)
|
||||
fixtures =
|
||||
[
|
||||
"wp-login-clean.php", "wp-login-login_lockdown.php", "wp-login-login_lock.php",
|
||||
"wp-login-better_wp_security.php", "wp-login-simple_login_lockdown.php", "wp-login-login_security_solution.php",
|
||||
"wp-login-limit_login_attempts.php", "wp-login-bluetrait_event_viewer.php"
|
||||
]
|
||||
# For plugins which are detected from the existence of their directory into wp-content/plugins/ (or one of their file)
|
||||
# and not from a regex into the login page
|
||||
special_plugins = ["better_wp_security", "simple_login_lockdown", "login_security_solution", "limit_login_attempts", "bluetrait_event_viewer"]
|
||||
|
||||
after :each do
|
||||
stub_request_to_fixture(:url => @module.login_url, :fixture => @fixture)
|
||||
|
||||
# Stub all special plugins urls to a 404 except if it's the one we want
|
||||
special_plugins.each do |special_plugin|
|
||||
special_plugin_call_detection_symbol = :"has_#{special_plugin}_protection?"
|
||||
special_plugin_call_url_symbol = :"#{special_plugin}_url"
|
||||
|
||||
status_code = (@symbol_to_call === special_plugin_call_detection_symbol and @expected === true) ? 200 : 404
|
||||
stub_request(:get, @module.send(special_plugin_call_url_symbol)).to_return(:status => status_code)
|
||||
end
|
||||
|
||||
@module.send(@symbol_to_call).should === @expected
|
||||
end
|
||||
|
||||
WpLoginProtection.protected_instance_methods.grep(pattern).each do |symbol_to_call|
|
||||
plugin_name_from_symbol = symbol_to_call[pattern, 1].gsub('_', '-')
|
||||
|
||||
fixtures.each do |fixture|
|
||||
plugin_name_from_fixture = fixture[/wp-login-(.*)\.php/i, 1].gsub('_', '-')
|
||||
expected = plugin_name_from_fixture === plugin_name_from_symbol ? true : false
|
||||
|
||||
it "#{symbol_to_call} with #{fixture} should return #{expected}" do
|
||||
@plugin_name = plugin_name_from_fixture
|
||||
@fixture = @fixtures_dir + '/' + fixture
|
||||
@symbol_to_call = symbol_to_call
|
||||
@expected = expected
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Factorise this with the code above ? :D
|
||||
describe "#login_protection_plugin" do
|
||||
after :each do
|
||||
stub_request_to_fixture(:url => @module.login_url, :fixture => @fixture)
|
||||
stub_request(:get, @module.send(:better_wp_security_url)).to_return(:status => 404)
|
||||
stub_request(:get, @module.send(:simple_login_lockdown_url)).to_return(:status => 404)
|
||||
stub_request(:get, @module.send(:login_security_solution_url)).to_return(:status => 404)
|
||||
stub_request(:get, @module.send(:limit_login_attempts_url)).to_return(:status => 404)
|
||||
stub_request(:get, @module.send(:bluetrait_event_viewer_url)).to_return(:status => 404)
|
||||
|
||||
@module.login_protection_plugin().should === @plugin_expected
|
||||
@module.has_login_protection?.should === @has_protection_expected
|
||||
end
|
||||
|
||||
it "should return nil if no protection is present" do
|
||||
@fixture = @fixtures_dir + "/wp-login-clean.php"
|
||||
@plugin_expected = nil
|
||||
@has_protection_expected = false
|
||||
end
|
||||
|
||||
it "should return a login-lockdown WpPlugin object" do
|
||||
@fixture = @fixtures_dir + "/wp-login-login_lockdown.php"
|
||||
@plugin_expected = WpPlugin.new(WpPlugin.create_location_url_from_name("login-lockdown", @module.url))
|
||||
@has_protection_expected = true
|
||||
end
|
||||
|
||||
it "should return a login-lock WpPlugin object" do
|
||||
@fixture = @fixtures_dir + "/wp-login-login_lock.php"
|
||||
@plugin_expected = WpPlugin.new(WpPlugin.create_location_url_from_name("login-lock", @module.url))
|
||||
@has_protection_expected = true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
132
spec/lib/wpscan/modules/wp_plugins_spec.rb
Normal file
132
spec/lib/wpscan/modules/wp_plugins_spec.rb
Normal file
@@ -0,0 +1,132 @@
|
||||
shared_examples_for "WpPlugins" do
|
||||
|
||||
before :all do
|
||||
@fixtures_dir = SPEC_FIXTURES_WPSCAN_MODULES_DIR + '/wp_plugins'
|
||||
@plugins_file = @fixtures_dir + "/plugins.txt"
|
||||
@plugin_vulns_file = @fixtures_dir + "/plugin_vulns.xml"
|
||||
end
|
||||
|
||||
before :each do
|
||||
@wp_url = "http://example.localhost"
|
||||
@module = WpScanModuleSpec.new(@wp_url)
|
||||
@module.error_404_hash = Digest::MD5.hexdigest("Error 404!")
|
||||
@module.extend(WpPlugins)
|
||||
end
|
||||
|
||||
describe "#plugins_from_passive_detection" do
|
||||
let(:passive_detection_fixtures) { @fixtures_dir + '/passive_detection' }
|
||||
|
||||
it "should return an empty array" do
|
||||
stub_request_to_fixture(:url => @module.url, :fixture => File.new(passive_detection_fixtures + '/no_plugins.htm'))
|
||||
|
||||
plugins = @module.plugins_from_passive_detection
|
||||
plugins.should be_empty
|
||||
end
|
||||
|
||||
it "should return the expected plugins" do
|
||||
stub_request_to_fixture(:url => @module.url, :fixture => File.new(passive_detection_fixtures + '/various_plugins.htm'))
|
||||
|
||||
expected_plugin_names = [
|
||||
'wp-minify',
|
||||
'comment-info-tip',
|
||||
'tweet-blender',
|
||||
'optinpop',
|
||||
's2member',
|
||||
'wp-polls',
|
||||
'commentluv'
|
||||
]
|
||||
expected_plugins = []
|
||||
expected_plugin_names.each do |plugin_name|
|
||||
expected_plugins << WpPlugin.new(
|
||||
WpPlugin.create_location_url_from_name(plugin_name, @module.url),
|
||||
:name => plugin_name
|
||||
)
|
||||
end
|
||||
|
||||
plugins = @module.plugins_from_passive_detection
|
||||
plugins.should_not be_empty
|
||||
plugins.sort.should === expected_plugins.sort
|
||||
end
|
||||
end
|
||||
|
||||
describe "#plugins_targets_url" do
|
||||
let(:expected_for_only_vulnerable) {
|
||||
[WpPlugin.create_location_url_from_name("media-library", @module.url), WpPlugin.create_location_url_from_name("deans", @module.url)]
|
||||
}
|
||||
let(:expected_for_all) {
|
||||
expected_for_only_vulnerable + File.open(@plugins_file, 'r') {|file| file.readlines.collect{|line| WpPlugin.create_url_from_raw(line.chomp, @module.uri)}}.uniq!
|
||||
}
|
||||
|
||||
it "should only return url from plugin_vulns_file if :only_vulnerable_ones is true" do
|
||||
targets_url = @module.plugins_targets_url(
|
||||
:only_vulnerable_ones => true,
|
||||
:plugin_vulns_file => @plugin_vulns_file
|
||||
)
|
||||
|
||||
targets_url.should_not be_empty
|
||||
targets_url.sort.should === expected_for_only_vulnerable.sort
|
||||
end
|
||||
|
||||
it "should return both url from plugins_file and plugin_vulns_file" do
|
||||
targets_url = @module.plugins_targets_url(
|
||||
:plugin_vulns_file => @plugin_vulns_file,
|
||||
:plugins_file => @plugins_file
|
||||
)
|
||||
|
||||
targets_url.should_not be_empty
|
||||
targets_url.sort.should === expected_for_all.sort
|
||||
end
|
||||
end
|
||||
|
||||
describe "#plugins_from_aggressive_detection" do
|
||||
|
||||
before :each do
|
||||
@targets_url = @module.plugins_targets_url(
|
||||
:plugin_vulns_file => @plugin_vulns_file,
|
||||
:plugins_file => @plugins_file
|
||||
)
|
||||
# Point all targets to a 404
|
||||
@targets_url.each do |target_url|
|
||||
stub_request(:get, target_url).to_return(:status => 404)
|
||||
end
|
||||
end
|
||||
|
||||
after :each do
|
||||
@passive_detection_fixture = SPEC_FIXTURES_DIR + "/empty-file" unless @passive_detection_fixture
|
||||
|
||||
stub_request_to_fixture(:url => @wp_url, :fixture => @passive_detection_fixture)
|
||||
|
||||
@module.plugins_from_aggressive_detection(
|
||||
:plugins_file => @plugins_file,
|
||||
:plugin_vulns_file => @plugin_vulns_file
|
||||
).sort.should === @expected_plugins.sort
|
||||
end
|
||||
|
||||
it "should return an empty array" do
|
||||
@expected_plugins = []
|
||||
end
|
||||
|
||||
it "should return an array with 3 WpPlugin (1 detected from passive method)" do
|
||||
@expected_plugins = []
|
||||
|
||||
@targets_url.sample(2).each do |target_url|
|
||||
@expected_plugins << WpPlugin.new(target_url)
|
||||
stub_request(:get, target_url).to_return(:status => 200)
|
||||
end
|
||||
|
||||
@passive_detection_fixture = @fixtures_dir + "/passive_detection/one_plugin.htm"
|
||||
@expected_plugins << WpPlugin.new("http://example.localhost/wp-content/plugins/comment-info-tip/")
|
||||
end
|
||||
|
||||
# testing response codes
|
||||
WpPlugins.valid_response_codes.each do |valid_response_code|
|
||||
it "should detect the plugin if the reponse.code is #{valid_response_code}" do
|
||||
@expected_plugins = []
|
||||
|
||||
plugin_url = @targets_url.sample
|
||||
@expected_plugins << WpPlugin.new(plugin_url)
|
||||
stub_request(:get, plugin_url).to_return(:status => valid_response_code)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
41
spec/lib/wpscan/modules/wp_readme_spec.rb
Normal file
41
spec/lib/wpscan/modules/wp_readme_spec.rb
Normal file
@@ -0,0 +1,41 @@
|
||||
shared_examples_for "WpReadme" do
|
||||
|
||||
before :all do
|
||||
@module = WpScanModuleSpec.new('http://example.localhost')
|
||||
@fixtures_dir = SPEC_FIXTURES_WPSCAN_MODULES_DIR + '/wp_readme'
|
||||
|
||||
@module.extend(WpReadme)
|
||||
end
|
||||
|
||||
describe "#readme_url" do
|
||||
it "should return http://example.localhost/readme.html" do
|
||||
@module.readme_url.should === "#{@module.uri}/readme.html"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#has_readme?" do
|
||||
|
||||
it "should return false on a 404" do
|
||||
stub_request(:get, @module.readme_url).
|
||||
to_return(:status => 404)
|
||||
|
||||
@module.has_readme?.should be_false
|
||||
end
|
||||
|
||||
it "should return true if it exists" do
|
||||
stub_request(:get, @module.readme_url).
|
||||
to_return(:status => 200, :body => File.new(@fixtures_dir + '/readme-3.2.1.html'))
|
||||
|
||||
@module.has_readme?.should be_true
|
||||
end
|
||||
|
||||
# http://code.google.com/p/wpscan/issues/detail?id=108
|
||||
it "should return true even if the readme.html is not in english" do
|
||||
stub_request(:get, @module.readme_url).
|
||||
to_return(:status => 200, :body => File.new(@fixtures_dir + '/readme-3.3.2-fr.html'))
|
||||
|
||||
@module.has_readme?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
93
spec/lib/wpscan/modules/wp_timthumbs_spec.rb
Normal file
93
spec/lib/wpscan/modules/wp_timthumbs_spec.rb
Normal file
@@ -0,0 +1,93 @@
|
||||
shared_examples_for "WpTimthumbs" do
|
||||
|
||||
before :each do
|
||||
@module = WpScanModuleSpec.new('http://example.localhost/')
|
||||
@fixtures_dir = SPEC_FIXTURES_WPSCAN_MODULES_DIR + '/wp_timthumbs'
|
||||
@theme_name = "bueno"
|
||||
@timthumbs_file = @fixtures_dir + '/timthumbs.txt'
|
||||
@targets_from_file =
|
||||
[
|
||||
"http://example.localhost/wp-content/plugins/fotoslide/timthumb.php",
|
||||
"http://example.localhost/wp-content/plugins/feature-slideshow/timthumb.php"
|
||||
]
|
||||
@targets_from_theme =
|
||||
[
|
||||
'http://example.localhost/wp-content/themes/' + @theme_name + '/timthumb.php',
|
||||
'http://example.localhost/wp-content/themes/' + @theme_name + '/lib/timthumb.php',
|
||||
'http://example.localhost/wp-content/themes/' + @theme_name + '/inc/timthumb.php',
|
||||
'http://example.localhost/wp-content/themes/' + @theme_name + '/includes/timthumb.php',
|
||||
'http://example.localhost/wp-content/themes/' + @theme_name + '/scripts/timthumb.php',
|
||||
'http://example.localhost/wp-content/themes/' + @theme_name + '/tools/timthumb.php',
|
||||
'http://example.localhost/wp-content/themes/' + @theme_name + '/functions/timthumb.php'
|
||||
]
|
||||
|
||||
@module.extend(WpTimthumbs)
|
||||
end
|
||||
|
||||
describe "#timthumbs_file" do
|
||||
it "should return #{DATA_DIR}/timthumb.txt" do
|
||||
WpTimthumbs.timthumbs_file.should === "#{DATA_DIR}/timthumbs.txt"
|
||||
end
|
||||
|
||||
it "should return hello/file.txt" do
|
||||
WpTimthumbs.timthumbs_file("hello/file.txt").should === "hello/file.txt"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#targets_url_from_theme" do
|
||||
it "should return the targets for the theme" do
|
||||
targets = @module.send(:targets_url_from_theme, @theme_name)
|
||||
|
||||
targets.should_not be_empty
|
||||
targets.sort.should === @targets_from_theme.sort
|
||||
end
|
||||
end
|
||||
|
||||
describe "#timthumbs_targets_url" do
|
||||
it "should return only the targets from the timthumbs file" do
|
||||
targets = @module.timthumbs_targets_url(:timthumbs_file => @timthumbs_file)
|
||||
|
||||
targets.should_not be_empty
|
||||
targets.sort.should === @targets_from_file.sort
|
||||
end
|
||||
|
||||
it "should return targets from timthumbs file and theme" do
|
||||
targets = @module.timthumbs_targets_url(:theme_name => @theme_name, :timthumbs_file => @timthumbs_file)
|
||||
|
||||
targets.should_not be_empty
|
||||
targets.sort.should === (@targets_from_file + @targets_from_theme).sort
|
||||
end
|
||||
end
|
||||
|
||||
describe "#timthumbs" do
|
||||
|
||||
before :each do
|
||||
@module.timthumbs_targets_url(:theme_name => @theme_name, :timthumbs_file => @timthumbs_file).each do |target_url|
|
||||
stub_request(:get, target_url).to_return(:status => 404)
|
||||
end
|
||||
end
|
||||
|
||||
it "should return an empty array" do
|
||||
timthumbs = @module.timthumbs(:theme_name => @theme_name, :timthumbs_file => @timthumbs_file)
|
||||
|
||||
timthumbs.should be_empty
|
||||
@module.has_timthumbs?.should be_false
|
||||
end
|
||||
|
||||
it "should return an array with 2 timthumbs url" do
|
||||
expected = []
|
||||
@module.timthumbs_targets_url(:theme_name => @theme_name, :timthumbs_file => @timthumbs_file).sample(2).each do |target_url|
|
||||
expected << target_url
|
||||
|
||||
stub_request(:get, target_url).
|
||||
to_return(:status => 200, :body => File.new(@fixtures_dir + "/timthumb.php"))
|
||||
end
|
||||
|
||||
timthumbs = @module.timthumbs(:theme_name => @theme_name, :timthumbs_file => @timthumbs_file)
|
||||
timthumbs.should_not be_empty
|
||||
timthumbs.sort.should === expected.sort
|
||||
@module.has_timthumbs?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
68
spec/lib/wpscan/modules/wp_usernames_spec.rb
Normal file
68
spec/lib/wpscan/modules/wp_usernames_spec.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
shared_examples_for "WpUsernames" do
|
||||
|
||||
before :each do
|
||||
@target_url = 'http://example.localhost/'
|
||||
@module = WpScanModuleSpec.new(@target_url)
|
||||
@fixtures_dir = SPEC_FIXTURES_WPSCAN_MODULES_DIR + '/wp_usernames'
|
||||
|
||||
@module.extend(WpUsernames)
|
||||
end
|
||||
|
||||
describe "#author_url" do
|
||||
it "should return the auhor url according to his id" do
|
||||
@module.author_url(1).should === "#{@target_url}?author=1"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#usernames" do
|
||||
before :each do
|
||||
(1..10).each do |index|
|
||||
stub_request(:get, @module.author_url(index)).to_return(:status => 404)
|
||||
end
|
||||
end
|
||||
|
||||
it "should return an empty array" do
|
||||
@module.usernames.should be_empty
|
||||
end
|
||||
|
||||
it "should return an array with 1 username (from header location)" do
|
||||
stub_request(:get, @module.author_url(3)).
|
||||
to_return(:status => 301, :headers => { 'location' => '/author/Youhou/'})
|
||||
|
||||
usernames = @module.usernames
|
||||
usernames.should_not be_empty
|
||||
usernames.should === ["Youhou"]
|
||||
end
|
||||
|
||||
it "should return an array with 1 username (from in the body response)" do
|
||||
stub_request(:get, @module.author_url(2)).
|
||||
to_return(:status => 200, :body => File.new(@fixtures_dir + '/admin.htm'))
|
||||
|
||||
usernames = @module.usernames(:range => (1..2))
|
||||
usernames.should_not be_empty
|
||||
usernames.should === ["admin"]
|
||||
end
|
||||
|
||||
it "should return an array with 1 username (testing duplicates)" do
|
||||
(2..3).each do |id|
|
||||
stub_request(:get, @module.author_url(id)).
|
||||
to_return(:status => 200, :body => File.new(@fixtures_dir + '/admin.htm'))
|
||||
end
|
||||
|
||||
@module.usernames(:range => (1..3)).should === ["admin"]
|
||||
end
|
||||
|
||||
it "should return an array with 2 usernames (one is a duplicate and should not be present twice)" do
|
||||
stub_request(:get, @module.author_url(4)).
|
||||
to_return(:status => 301, :headers => { 'location' => '/author/Youhou/'})
|
||||
|
||||
stub_request(:get, @module.author_url(2)).
|
||||
to_return(:status => 200, :body => File.new(@fixtures_dir + '/admin.htm'))
|
||||
|
||||
usernames = @module.usernames(:range => (1..5))
|
||||
usernames.should_not be_empty
|
||||
usernames.sort.should === ["admin", "Youhou"].sort
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
218
spec/lib/wpscan/wp_plugin_spec.rb
Normal file
218
spec/lib/wpscan/wp_plugin_spec.rb
Normal file
@@ -0,0 +1,218 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/wpscan_helper')
|
||||
|
||||
describe WpPlugin do
|
||||
|
||||
before :all do
|
||||
@browser = Browser.instance(:config_file => SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf.json')
|
||||
end
|
||||
|
||||
describe "#location_uri_from_url" do
|
||||
after :each do
|
||||
if @url
|
||||
uri = WpPlugin.location_uri_from_url(@url)
|
||||
|
||||
uri.should be_a URI
|
||||
uri.to_s.should === @expected_uri_string
|
||||
end
|
||||
end
|
||||
|
||||
#it "should raise an error if the url is not valid" do
|
||||
# expect { WpPlugin.location_uri_from_url("example.com") }.to raise_error
|
||||
# expect { WpPlugin.location_uri_from_url("http://example.com/wp-includes/plugins/example/") }.to raise_error
|
||||
#end
|
||||
|
||||
it "should return the uri without the file" do
|
||||
@url = "http://example.com/wp-content/plugins/example/readme.txt"
|
||||
@expected_uri_string = "http://example.com/wp-content/plugins/example/"
|
||||
end
|
||||
|
||||
it "should return the same uri" do
|
||||
@url = "http://example.com/wp-content/plugins/hello-world/"
|
||||
@expected_uri_string = @url
|
||||
end
|
||||
|
||||
# http://code.google.com/p/wpscan/issues/detail?id=146
|
||||
it "should not raise an error if the url uses https" do
|
||||
@url = "https://example.com/folder1/folder2/wp-content/plugins/user-role-editor/index.php"
|
||||
@expected_uri_string = "https://example.com/folder1/folder2/wp-content/plugins/user-role-editor/"
|
||||
end
|
||||
|
||||
it "should add the last slash if it's not present" do
|
||||
@url = "http://example.com/wp-content/plugins/test-one"
|
||||
@expected_uri_string = "#{@url}/"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#extract_name_from_location_url" do
|
||||
it "should return 'example-plugin'" do
|
||||
WpPlugin.extract_name_from_location_url('http://example.com/wp-content/plugins/example-plugin/').should === 'example-plugin'
|
||||
end
|
||||
end
|
||||
|
||||
describe "#create_location_url_from_name" do
|
||||
after :each do
|
||||
WpPlugin.create_location_url_from_name(@plugin_name, @target_url).should === @expected_url
|
||||
end
|
||||
|
||||
it "should return 'http://example.com/$wp-plugins$/example/'" do
|
||||
@plugin_name = "example"
|
||||
@target_url = "http://example.com/"
|
||||
@expected_url = "http://example.com/$wp-plugins$/example/"
|
||||
end
|
||||
|
||||
it "should return 'http://example.com/$wp-plugins$/example/' even if the last '/' is not in the target url" do
|
||||
@plugin_name = "example"
|
||||
@target_url = "http://example.com"
|
||||
@expected_url = "http://example.com/$wp-plugins$/example/"
|
||||
end
|
||||
|
||||
it "should return http://example.com/$wp-plugins$/example-test/" do
|
||||
@plugin_name = "example-test"
|
||||
@target_url = "http://example.com"
|
||||
@expected_url = "http://example.com/$wp-plugins$/example-test/"
|
||||
end
|
||||
|
||||
it "should return http://example.com/$wp-plugins$/something%20with%20spaces/" do
|
||||
@plugin_name = "something with spaces"
|
||||
@target_url = "http://example.com"
|
||||
@expected_url = URI.escape("http://example.com/$wp-plugins$/something with spaces/")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#create_url_from_raw" do
|
||||
it "should return http://example.com/$wp-plugins$/example-test/readme.txt" do
|
||||
WpPlugin.create_url_from_raw("example-test/readme.txt", URI.parse("http://example.com")).should === "http://example.com/$wp-plugins$/example-test/readme.txt"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#initialize" do
|
||||
let(:location_url) { 'http://example.com/wp-content/plugins/example/' }
|
||||
|
||||
it "should raise an exception" do
|
||||
expect { WpPlugin.new('invalid location url') }.to raise_error
|
||||
end
|
||||
|
||||
it "should initialize the object (no options given), :name should be 'example'" do
|
||||
wp_plugin = WpPlugin.new(location_url)
|
||||
wp_plugin.name.should === 'example'
|
||||
wp_plugin.location_url.should === location_url
|
||||
end
|
||||
|
||||
it "should initialize the object (options[:name] = 'example')" do
|
||||
wp_plugin = WpPlugin.new(location_url, :name => 'example')
|
||||
wp_plugin.name.should === 'example'
|
||||
wp_plugin.location_url.should === location_url
|
||||
end
|
||||
end
|
||||
|
||||
# TODO
|
||||
describe "operators : ==, ===, <=>" do
|
||||
|
||||
end
|
||||
|
||||
#TODO
|
||||
describe "#location_url" do
|
||||
|
||||
end
|
||||
|
||||
describe "#version" do
|
||||
let(:location_url) { 'http://example.localhost/wp-content/plugins/simple-login-lockdown/' }
|
||||
let(:wp_plugin) { WpPlugin.new(location_url) }
|
||||
let(:readme_url) { 'http://example.localhost/wp-content/plugins/simple-login-lockdown/readme.txt' }
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_PLUGIN_DIR + '/version' }
|
||||
|
||||
it "should return nil if the readme.txt does not exist" do
|
||||
stub_request(:get, readme_url).
|
||||
to_return(:status => 404)
|
||||
|
||||
wp_plugin.version.should be_nil
|
||||
end
|
||||
|
||||
it "should return nil if the version is invalid (IE : trunk etc)" do
|
||||
stub_request(:get, readme_url).
|
||||
to_return(:status => 200, :body => File.new(fixtures_dir + '/trunk-version.txt'))
|
||||
|
||||
wp_plugin.version.should be_nil
|
||||
end
|
||||
|
||||
it "should return the version 0.4" do
|
||||
stub_request(:get, readme_url).
|
||||
to_return(:status => 200, :body => File.new(fixtures_dir + '/simple-login-lockdown-0.4.txt'))
|
||||
|
||||
wp_plugin.version.should === '0.4'
|
||||
end
|
||||
end
|
||||
|
||||
describe "#vulnerabilities" do
|
||||
let(:location_url) { 'http://example.localhost/wp-content/plugins/spec-plugin/' }
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_PLUGIN_DIR + '/vulnerabilities' }
|
||||
let(:vulns_xml) { fixtures_dir + '/plugin_vulns.xml' }
|
||||
let(:wp_plugin) { WpPlugin.new(location_url, :vulns_xml => vulns_xml) }
|
||||
|
||||
|
||||
it "should return an empty array when no vulnerabilities are found" do
|
||||
WpPlugin.new(
|
||||
'http://example.localhost/wp-content/plugins/no-vulns/',
|
||||
:vulns_xml => vulns_xml
|
||||
).vulnerabilities.should be_empty
|
||||
end
|
||||
|
||||
it "should return an arry with 2 vulnerabilities" do
|
||||
vulnerabilities = wp_plugin.vulnerabilities
|
||||
|
||||
vulnerabilities.should_not be_empty
|
||||
vulnerabilities.length.should == 2
|
||||
vulnerabilities.each { |vulnerability| vulnerability.should be_a WpVulnerability }
|
||||
vulnerabilities[0].title.should === 'WPScan Spec'
|
||||
vulnerabilities[1].title.should === 'Spec SQL Injection'
|
||||
end
|
||||
end
|
||||
|
||||
describe "#error_log* (#error_log_url & #error_log?)" do
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_PLUGIN_DIR + '/error_log' }
|
||||
let(:location_url) { 'http://example.localhost/wp-content/plugins/simple-login-lockdown/' }
|
||||
let(:error_log_url) { 'http://example.localhost/wp-content/plugins/simple-login-lockdown/error_log' }
|
||||
let(:wp_plugin) { WpPlugin.new(location_url) }
|
||||
|
||||
it "should return the url of the error log" do
|
||||
wp_plugin.error_log_url.should === error_log_url
|
||||
end
|
||||
|
||||
it "should return false on a 404" do
|
||||
stub_request(:get, error_log_url).
|
||||
to_return(:status => 404)
|
||||
|
||||
wp_plugin.error_log?.should be_false
|
||||
end
|
||||
|
||||
it "should return true" do
|
||||
stub_request(:get, error_log_url).
|
||||
to_return(:status => 200, :body => File.new(fixtures_dir + '/error_log'))
|
||||
|
||||
wp_plugin.error_log?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#directory_listing?" do
|
||||
let(:wp_plugin) { WpPlugin.new('http://example.localhost/wp-content/plugins/simple-login-lockdown/readme.txt') }
|
||||
|
||||
it "should return false on a 404" do
|
||||
stub_request(:get, wp_plugin.location_url).to_return(:status => 404)
|
||||
|
||||
wp_plugin.directory_listing?.should be_false
|
||||
end
|
||||
|
||||
it "should return false on a blank page" do
|
||||
stub_request(:get, wp_plugin.location_url).to_return(:status => 200, :body => '')
|
||||
|
||||
wp_plugin.directory_listing?.should be_false
|
||||
end
|
||||
|
||||
it "should return true" do
|
||||
stub_request(:get, wp_plugin.location_url).
|
||||
to_return(:status => 200, :body => "<title>Index of simple-login-lockdown</title>")
|
||||
|
||||
wp_plugin.directory_listing?.should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
135
spec/lib/wpscan/wp_target_spec.rb
Normal file
135
spec/lib/wpscan/wp_target_spec.rb
Normal file
@@ -0,0 +1,135 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/wpscan_helper')
|
||||
|
||||
describe WpTarget do
|
||||
|
||||
before :each do
|
||||
Browser.reset
|
||||
browser_options =
|
||||
{
|
||||
:config_file => SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf.json',
|
||||
:cache_timeout => 0
|
||||
}
|
||||
@wp_target = WpTarget.new("http://example.localhost/", browser_options)
|
||||
end
|
||||
|
||||
it_should_behave_like "WebSite"
|
||||
it_should_behave_like "WpReadme"
|
||||
it_should_behave_like "WpConfigBackup"
|
||||
it_should_behave_like "WpFullPathDisclosure"
|
||||
it_should_behave_like "WpLoginProtection"
|
||||
it_should_behave_like "Malwares"
|
||||
it_should_behave_like "WpUsernames"
|
||||
it_should_behave_like "WpTimthumbs"
|
||||
it_should_behave_like "WpPlugins"
|
||||
|
||||
describe "#initialize" do
|
||||
it "should raise an error if the target_url is nil or empty" do
|
||||
expect { WpTarget.new(nil) }.to raise_error
|
||||
expect { Wptarget.new('') }.to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
describe "#url" do
|
||||
it "should return the url of the target" do
|
||||
@wp_target.url.should === @wp_target.uri.to_s
|
||||
end
|
||||
end
|
||||
|
||||
describe "#login_url" do
|
||||
let(:login_url) { @wp_target.uri.merge("wp-login.php").to_s }
|
||||
|
||||
it "should return the login url of the target" do
|
||||
stub_request(:get, login_url).to_return(:status => 200, :body => '')
|
||||
|
||||
@wp_target.login_url.should === login_url
|
||||
end
|
||||
|
||||
it "should return the redirection url if there is one (ie: for https)" do
|
||||
https_login_url = login_url.gsub(/^http:/, "https:")
|
||||
|
||||
stub_request(:get, login_url).to_return(:status => 302, :headers => {:location => https_login_url})
|
||||
|
||||
@wp_target.login_url.should === https_login_url
|
||||
end
|
||||
end
|
||||
|
||||
describe "#error_404_hash" do
|
||||
it "should return the md5sum of the 404 page" do
|
||||
stub_request(:any, /.*/).
|
||||
to_return(:status => 404, :body => "404 page !")
|
||||
|
||||
@wp_target.error_404_hash.should === Digest::MD5.hexdigest("404 page !")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#wp_content_dir" do
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_TARGET_DIR + "/wp_content_dir" }
|
||||
|
||||
after :each do
|
||||
@wp_target = WpTarget.new(@target_url) if @target_url
|
||||
stub_request_to_fixture(:url => @wp_target.url, :fixture => @fixture) if @fixture
|
||||
|
||||
@wp_target.wp_content_dir.should === @expected
|
||||
end
|
||||
|
||||
it "should return the string set in the initialize method" do
|
||||
@wp_target = WpTarget.new("http://example.localhost/", :wp_content_dir => "hello-world")
|
||||
@expected = "hello-world"
|
||||
end
|
||||
|
||||
it "should return 'wp-content'" do
|
||||
@target_url = "http://lamp/wordpress-3.4.1"
|
||||
@fixture = fixtures_dir + "/wordpress-3.4.1.htm"
|
||||
@expected = "wp-content"
|
||||
end
|
||||
|
||||
it "should find the default 'wp-content' dir even if the target_url is not the same (ie : the user supply an IP address and the url used in the code is a domain)" do
|
||||
@target_url = "http://192.168.1.103/wordpress-3.4.1/"
|
||||
@fixture = fixtures_dir + "/wordpress-3.4.1.htm"
|
||||
@expected = "wp-content"
|
||||
end
|
||||
|
||||
it "should return 'custom-content'" do
|
||||
@target_url = "http://lamp/wordpress-3.4.1-custom"
|
||||
@fixture = fixtures_dir + "/wordpress-3.4.1-custom.htm"
|
||||
@expected = "custom-content"
|
||||
end
|
||||
|
||||
it "should return 'custom content spaces'" do
|
||||
@target_url = "http://lamp/wordpress-3.4.1-custom"
|
||||
@fixture = fixtures_dir + "/wordpress-3.4.1-custom-with-spaces.htm"
|
||||
@expected = "custom content spaces"
|
||||
end
|
||||
|
||||
it "should return 'custom-dir/subdir/content'" do
|
||||
@target_url = "http://lamp/wordpress-3.4.1-custom"
|
||||
@fixture = fixtures_dir + "/wordpress-3.4.1-custom-subdirectories.htm"
|
||||
@expected = "custom-dir/subdir/content"
|
||||
end
|
||||
|
||||
it "should also check in src attributes" do
|
||||
@target_url = "http://lamp/wordpress-3.4.1"
|
||||
@fixture = fixtures_dir + "/wordpress-3.4.1-in-src.htm"
|
||||
@expected = "wp-content"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "#wp_plugins_dir" do
|
||||
after :each do
|
||||
@wp_target.stub(:wp_content_dir => @stub_value) if @stub_value
|
||||
|
||||
@wp_target.wp_plugins_dir.should === @expected
|
||||
end
|
||||
|
||||
it "should return the string set in the initialize method" do
|
||||
@wp_target = WpTarget.new("http://example.localhost/", :wp_plugins_dir => "custom-plugins")
|
||||
@expected = "custom-plugins"
|
||||
end
|
||||
|
||||
it "should return 'wp-content/plugins'" do
|
||||
@stub_value = "wp-content"
|
||||
@expected = "wp-content/plugins"
|
||||
end
|
||||
end
|
||||
end
|
||||
149
spec/lib/wpscan/wp_theme_spec.rb
Normal file
149
spec/lib/wpscan/wp_theme_spec.rb
Normal file
@@ -0,0 +1,149 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + "/wpscan_helper")
|
||||
|
||||
describe WpTheme do
|
||||
|
||||
before :all do
|
||||
@target_uri = URI.parse("http://example.localhost/")
|
||||
|
||||
Browser.instance(
|
||||
:config_file => SPEC_FIXTURES_CONF_DIR + "/browser/browser.conf.json",
|
||||
:cache_timeout => 0
|
||||
)
|
||||
end
|
||||
|
||||
describe "#to_s" do
|
||||
it "should return the theme name and the version if there is one" do
|
||||
wp_theme = WpTheme.new("bueno", :version => "1.2.3")
|
||||
|
||||
wp_theme.to_s.should === "bueno v1.2.3"
|
||||
end
|
||||
|
||||
it "should not add the version if there is not" do
|
||||
style_url = @target_uri.merge("wp-content/themes/hello-world/style.css").to_s
|
||||
|
||||
stub_request(:get, style_url).to_return(:status => 200, :body => "")
|
||||
|
||||
wp_theme = WpTheme.new("hello-world", :style_url => style_url)
|
||||
|
||||
wp_theme.to_s.should === "hello-world"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_from_css_link" do
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_THEME_DIR + "/find/css_link" }
|
||||
|
||||
it "should return nil if no theme is present" do
|
||||
stub_request(:get, @target_uri.to_s).to_return(:status => 200, :body => "")
|
||||
|
||||
WpTheme.find_from_css_link(@target_uri).should be_nil
|
||||
end
|
||||
|
||||
it "should return a WpTheme object with .name = twentyeleven" do
|
||||
stub_request_to_fixture(:url => @target_uri.to_s, :fixture => fixtures_dir + "/wordpress-twentyeleven.htm")
|
||||
|
||||
wp_theme = WpTheme.find_from_css_link(@target_uri)
|
||||
wp_theme.should be_a WpTheme
|
||||
wp_theme.name.should === "twentyeleven"
|
||||
end
|
||||
|
||||
# http://code.google.com/p/wpscan/issues/detail?id=131
|
||||
# Theme name with spaces raises bad URI(is not URI?)
|
||||
it "should not raise an error if the theme name has spaces or special chars" do
|
||||
stub_request_to_fixture(:url => @target_uri.to_s, :fixture => fixtures_dir + "/theme-name-with-spaces.html")
|
||||
|
||||
wp_theme = WpTheme.find_from_css_link(@target_uri)
|
||||
wp_theme.should be_a WpTheme
|
||||
wp_theme.name.should === "Copia di simplefolio"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_from_wooframework" do
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_THEME_DIR + "/find/wooframework" }
|
||||
|
||||
after :each do
|
||||
stub_request_to_fixture(:url => @target_uri.to_s, :fixture => @fixture)
|
||||
|
||||
wp_theme = WpTheme.find_from_wooframework(@target_uri)
|
||||
|
||||
wp_theme.should be_a WpTheme unless wp_theme.nil?
|
||||
wp_theme.should === @expected_theme
|
||||
end
|
||||
|
||||
it "should return a WpTheme object with .name 'Editorial' and .version '1.3.5'" do
|
||||
@fixture = fixtures_dir + "/editorial-1.3.5.html"
|
||||
@expected_theme = WpTheme.new("Editorial", :version => "1.3.5")
|
||||
end
|
||||
|
||||
it "should return a WpTheme object with .name 'Merchant'" do
|
||||
@fixture = fixtures_dir + "/merchant-no-version.html"
|
||||
@expected_theme = WpTheme.new("Merchant")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find" do
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_THEME_DIR + "/find" }
|
||||
|
||||
after :each do
|
||||
stub_request_to_fixture(:url => @target_uri.to_s, :fixture => @fixture)
|
||||
|
||||
wp_theme = WpTheme.find(@target_uri)
|
||||
|
||||
if @expected_name
|
||||
wp_theme.should be_a WpTheme
|
||||
wp_theme.name.should === @expected_name
|
||||
else
|
||||
wp_theme.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
it "should return nil if no theme is found" do
|
||||
@fixture = SPEC_FIXTURES_DIR + "/empty-file"
|
||||
@expected_name = nil
|
||||
end
|
||||
|
||||
it "should return a WpTheme object with .name 'twentyeleven'" do
|
||||
@fixture = fixtures_dir + "/css_link/wordpress-twentyeleven.htm"
|
||||
@expected_name = "twentyeleven"
|
||||
end
|
||||
|
||||
it "should a WpTheme object with .name 'Merchant'" do
|
||||
@fixture = fixtures_dir + "/wooframework/merchant-no-version.html"
|
||||
@expected_name = "Merchant"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#version" do
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_THEME_DIR + "/version" }
|
||||
let(:theme_style_url) { @target_uri.merge("wp-content/themes/spec-theme/style.css").to_s }
|
||||
|
||||
after :each do
|
||||
if @fixture
|
||||
stub_request_to_fixture(:url => theme_style_url, :fixture => @fixture)
|
||||
|
||||
wp_theme = WpTheme.new('spec-theme', :style_url => theme_style_url)
|
||||
|
||||
wp_theme.version.should === @expected
|
||||
end
|
||||
end
|
||||
|
||||
it "should return nil if the version is not found" do
|
||||
@fixture = fixtures_dir + "/twentyeleven-unknow.css"
|
||||
@expected = nil
|
||||
end
|
||||
|
||||
it "should return nil if the style_url is nil" do
|
||||
WpTheme.new("hello-world").version.should be_nil
|
||||
end
|
||||
|
||||
it "should return 1.3" do
|
||||
@fixture = fixtures_dir + "/twentyeleven-1.3.css"
|
||||
@expected = "1.3"
|
||||
end
|
||||
|
||||
it "should return 1.5.1" do
|
||||
@fixture = fixtures_dir + "/bueno-1.5.1.css"
|
||||
@expected = "1.5.1"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
123
spec/lib/wpscan/wp_version_spec.rb
Normal file
123
spec/lib/wpscan/wp_version_spec.rb
Normal file
@@ -0,0 +1,123 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/wpscan_helper')
|
||||
|
||||
describe WpVersion do
|
||||
|
||||
before :all do
|
||||
@target_uri = URI.parse('http://example.localhost/')
|
||||
@browser = Browser.instance(:config_file => SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf.json')
|
||||
end
|
||||
|
||||
describe "#find_from_meta_generator" do
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_VERSION_DIR + "/meta-generator" }
|
||||
|
||||
after :each do
|
||||
stub_request_to_fixture(:url => @target_uri.to_s, :fixture => @fixture)
|
||||
|
||||
WpVersion.find_from_meta_generator(@target_uri.to_s).should === @expected
|
||||
end
|
||||
|
||||
it "should return nil if the meta-generator is not found" do
|
||||
@fixture = fixtures_dir + "/no-meta-generator.htm"
|
||||
@expected = nil
|
||||
end
|
||||
|
||||
it "should return 3.3.2" do
|
||||
@fixture = fixtures_dir + "/3.3.2.htm"
|
||||
@expected = "3.3.2"
|
||||
end
|
||||
|
||||
it "should return 3.4-beta4" do
|
||||
@fixture = fixtures_dir + "/3.4-beta4.htm"
|
||||
@expected = "3.4-beta4"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_from_rss_generator" do
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_VERSION_DIR + "/rss-generator" }
|
||||
|
||||
after :each do
|
||||
@status_code ||= 200
|
||||
stub_request_to_fixture(:url => @target_uri.merge("feed/").to_s, :status => @status_code, :fixture => @fixture)
|
||||
|
||||
WpVersion.find_from_rss_generator(@target_uri).should === @expected
|
||||
end
|
||||
|
||||
it "should return nil on a 404" do
|
||||
@status_code = 404
|
||||
@fixture = SPEC_FIXTURES_WPSCAN_WP_VERSION_DIR + "/404.htm"
|
||||
@expected = nil
|
||||
end
|
||||
|
||||
it "should return nil if the rss-generator is not found" do
|
||||
@fixture = fixtures_dir + "/no-rss-generator.htm"
|
||||
@expected = nil
|
||||
end
|
||||
|
||||
it "should return nil if the version is not found (but the rss-generator is present)" do
|
||||
@fixture = fixtures_dir + "/no-version.htm"
|
||||
@expected = nil
|
||||
end
|
||||
|
||||
it "shuld return 3.3.2" do
|
||||
@fixture = fixtures_dir + "/3.3.2.htm"
|
||||
@expected = "3.3.2"
|
||||
end
|
||||
|
||||
it "should return 3.4-beta4" do
|
||||
@fixture = fixtures_dir + "/3.4-beta4.htm"
|
||||
@expected = "3.4-beta4"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_from_sitemap_generator" do
|
||||
after :each do
|
||||
stub_request(:get, @target_uri.merge("sitemap.xml").to_s).
|
||||
to_return(:status => 200, :body => @body)
|
||||
|
||||
WpVersion.find_from_sitemap_generator(@target_uri).should === @expected
|
||||
end
|
||||
|
||||
it "should return nil if the generator is not found" do
|
||||
@body = ''
|
||||
@expected = nil
|
||||
end
|
||||
|
||||
it "should return the version : 3.3.2" do
|
||||
@body = "<!-- generator=\"wordpress/3.3.2\" -->"
|
||||
@expected = "3.3.2"
|
||||
end
|
||||
|
||||
it "should return nil if it's not a valid version, must contains at least one '.'" do
|
||||
@body = "<!-- generator=\"wordpress/5065\" -->"
|
||||
@expected = nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#find_from_readme" do
|
||||
let(:fixtures_dir) { SPEC_FIXTURES_WPSCAN_WP_VERSION_DIR + '/readme' }
|
||||
|
||||
after :each do
|
||||
@status_code ||= 200
|
||||
stub_request_to_fixture(:url => @target_uri.merge("readme.html").to_s, :status => @status_code, :fixture => @fixture)
|
||||
|
||||
WpVersion.find_from_readme(@target_uri).should === @expected
|
||||
end
|
||||
|
||||
it "should return nil on a 404" do
|
||||
@status_code = 404
|
||||
@fixture = SPEC_FIXTURES_WPSCAN_WP_VERSION_DIR + "/404.htm"
|
||||
@expected = nil
|
||||
end
|
||||
|
||||
it "should return nil if the version number is not present" do
|
||||
@fixture = fixtures_dir + "/empty-version.html"
|
||||
@expected = nil
|
||||
end
|
||||
|
||||
it "should return 3.3.2" do
|
||||
@fixture = fixtures_dir + "/readme-3.3.2.html"
|
||||
@expected = "3.3.2"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
33
spec/lib/wpscan/wpscan_helper.rb
Normal file
33
spec/lib/wpscan/wpscan_helper.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
||||
|
||||
require WPSCAN_LIB_DIR + '/wpscan_helper'
|
||||
|
||||
SPEC_FIXTURES_WPSCAN_DIR = SPEC_FIXTURES_DIR + '/wpscan'
|
||||
SPEC_FIXTURES_WPSCAN_MODULES_DIR = SPEC_FIXTURES_WPSCAN_DIR + '/modules'
|
||||
SPEC_FIXTURES_WPSCAN_WP_TARGET_DIR = SPEC_FIXTURES_WPSCAN_DIR + '/wp_target'
|
||||
SPEC_FIXTURES_WPSCAN_WPSCAN_OPTIONS_DIR = SPEC_FIXTURES_WPSCAN_DIR + '/wpscan_options'
|
||||
SPEC_FIXTURES_WPSCAN_WP_THEME_DIR = SPEC_FIXTURES_WPSCAN_DIR + '/wp_theme'
|
||||
SPEC_FIXTURES_WPSCAN_WP_PLUGIN_DIR = SPEC_FIXTURES_WPSCAN_DIR + '/wp_plugin'
|
||||
SPEC_FIXTURES_WPSCAN_WP_VERSION_DIR = SPEC_FIXTURES_WPSCAN_DIR + '/wp_version'
|
||||
|
||||
class WpScanModuleSpec
|
||||
attr_reader :uri
|
||||
attr_accessor :error_404_hash
|
||||
|
||||
def initialize(target_url)
|
||||
@uri = URI.parse(add_http_protocol(target_url))
|
||||
Browser.instance(
|
||||
:config_file => SPEC_FIXTURES_CONF_DIR + '/browser/browser.conf.json',
|
||||
:cache_timeout => 0
|
||||
)
|
||||
end
|
||||
|
||||
def url
|
||||
@uri.to_s
|
||||
end
|
||||
|
||||
def login_url
|
||||
@uri.merge("wp-login.php").to_s
|
||||
end
|
||||
end
|
||||
|
||||
301
spec/lib/wpscan/wpscan_options_spec.rb
Normal file
301
spec/lib/wpscan/wpscan_options_spec.rb
Normal file
@@ -0,0 +1,301 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/wpscan_helper')
|
||||
|
||||
describe "WpscanOptions" do
|
||||
|
||||
before :each do
|
||||
@wpscan_options = WpscanOptions.new
|
||||
end
|
||||
|
||||
describe "#initialize" do
|
||||
|
||||
end
|
||||
|
||||
describe "#url=" do
|
||||
it "should raise an error if en empty or nil url is supplied" do
|
||||
expect { @wpscan_options.url = '' }.to raise_error
|
||||
expect { @wpscan_options.url = nil }.to raise_error
|
||||
end
|
||||
|
||||
it "should add the http protocol if not present" do
|
||||
@wpscan_options.url = "example.com"
|
||||
@wpscan_options.url.should === "http://example.com"
|
||||
end
|
||||
|
||||
it "should not add the http protocol if it's already present" do
|
||||
url = "http://example.com"
|
||||
@wpscan_options.url = url
|
||||
@wpscan_options.url.should === url
|
||||
end
|
||||
end
|
||||
|
||||
describe "#threads=" do
|
||||
it "should convert an integer in a string into an integr" do
|
||||
@wpscan_options.threads = "10"
|
||||
@wpscan_options.threads.should be_an Integer
|
||||
@wpscan_options.threads.should === 10
|
||||
end
|
||||
|
||||
it "should set to correct number of threads" do
|
||||
@wpscan_options.threads = 15
|
||||
@wpscan_options.threads.should be_an Integer
|
||||
@wpscan_options.threads.should === 15
|
||||
end
|
||||
end
|
||||
|
||||
describe "#wordlist=" do
|
||||
it "should raise an error if the wordlist file does not exist" do
|
||||
expect { @wpscan_options.wordlist = "/i/do/not/exist.txt" }.to raise_error
|
||||
end
|
||||
|
||||
it "should not raise an error" do
|
||||
wordlist_file = "#{SPEC_FIXTURES_WPSCAN_WPSCAN_OPTIONS_DIR}/wordlist.txt"
|
||||
|
||||
@wpscan_options.wordlist = wordlist_file
|
||||
@wpscan_options.wordlist.should === wordlist_file
|
||||
end
|
||||
end
|
||||
|
||||
describe "#proxy=" do
|
||||
it "should raise an error" do
|
||||
expect { @wpscan_options.proxy = 'invalidproxy' }.to raise_error
|
||||
end
|
||||
|
||||
it "should not raise an error" do
|
||||
proxy = "127.0.0.1:3038"
|
||||
@wpscan_options.proxy = proxy
|
||||
@wpscan_options.proxy.should === proxy
|
||||
end
|
||||
end
|
||||
|
||||
describe "#enumerate_plugins=" do
|
||||
it "should raise an error" do
|
||||
@wpscan_options.enumerate_only_vulnerable_plugins = true
|
||||
expect { @wpscan_options.enumerate_plugins = true }.to raise_error
|
||||
end
|
||||
|
||||
it "should not raise an error" do
|
||||
@wpscan_options.enumerate_only_vulnerable_plugins = false
|
||||
@wpscan_options.enumerate_plugins = true
|
||||
|
||||
@wpscan_options.enumerate_plugins.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#enumerate_only_vulnerable_plugins=" do
|
||||
it "should raise an error" do
|
||||
@wpscan_options.enumerate_plugins = true
|
||||
expect { @wpscan_options.enumerate_only_vulnerable_plugins = true }.to raise_error
|
||||
end
|
||||
|
||||
it "should not raise an error" do
|
||||
@wpscan_options.enumerate_plugins = false
|
||||
@wpscan_options.enumerate_only_vulnerable_plugins = true
|
||||
|
||||
@wpscan_options.enumerate_only_vulnerable_plugins.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_h" do
|
||||
it "should return an empty hash" do
|
||||
@wpscan_options.to_h.should be_a Hash
|
||||
@wpscan_options.to_h.should be_empty
|
||||
end
|
||||
|
||||
it "should return a hash with :verbose = true" do
|
||||
expected = {:verbose => true}
|
||||
@wpscan_options.verbose = true
|
||||
|
||||
@wpscan_options.to_h.should === expected
|
||||
end
|
||||
end
|
||||
|
||||
describe "#has_options?" do
|
||||
it "should return false" do
|
||||
@wpscan_options.has_options?.should be_false
|
||||
end
|
||||
|
||||
it "should return true" do
|
||||
@wpscan_options.verbose = false
|
||||
@wpscan_options.has_options?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#clean_option" do
|
||||
after :each do
|
||||
WpscanOptions.clean_option(@option).should === @expected
|
||||
end
|
||||
|
||||
it "should return 'url'" do
|
||||
@option = "--url"
|
||||
@expected = "url"
|
||||
end
|
||||
|
||||
it "should return 'u'" do
|
||||
@option = "-u"
|
||||
@expected = 'u'
|
||||
end
|
||||
|
||||
it "should return 'follow_redirection'" do
|
||||
@option = "--follow-redirection"
|
||||
@expected = "follow_redirection"
|
||||
end
|
||||
end
|
||||
|
||||
describe "#option_to_instance_variable_setter" do
|
||||
after :each do
|
||||
WpscanOptions.option_to_instance_variable_setter(@argument).should === @expected
|
||||
end
|
||||
|
||||
it "should return @url" do
|
||||
@argument = "--url"
|
||||
@expected = :url=
|
||||
end
|
||||
|
||||
it "should return @verbose" do
|
||||
@argument = "-v"
|
||||
@expected = :verbose=
|
||||
end
|
||||
|
||||
it "should return nil for -U" do
|
||||
@argument = "-U"
|
||||
@expected = nil
|
||||
end
|
||||
|
||||
it "should return nil for --enumerate" do
|
||||
@argument = "--enumerate"
|
||||
@expected = nil
|
||||
end
|
||||
|
||||
it "should return nil for -e" do
|
||||
@argument = "-e"
|
||||
@expected = nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#is_long_option?" do
|
||||
it "should return true" do
|
||||
WpscanOptions.is_long_option?("--url").should be_true
|
||||
end
|
||||
|
||||
it "should return false" do
|
||||
WpscanOptions.is_long_option?("hello").should be_false
|
||||
WpscanOptions.is_long_option?("--enumerate").should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#enumerate_options_from_string" do
|
||||
after :each do
|
||||
if @argument
|
||||
wpscan_options = WpscanOptions.new
|
||||
wpscan_options.enumerate_options_from_string(@argument)
|
||||
wpscan_options.to_h.should === @expected_hash
|
||||
end
|
||||
end
|
||||
|
||||
it "should raise an error if p and p! are " do
|
||||
expect { @wpscan_options.enumerate_options_from_string("pp!") }.to raise_error
|
||||
end
|
||||
|
||||
it "should set enumerate_plugins to true" do
|
||||
@argument = 'p'
|
||||
@expected_hash = {:enumerate_plugins => true}
|
||||
end
|
||||
|
||||
it "should set enumerate_only_vulnerable_plugins to tue" do
|
||||
@argument = "p!"
|
||||
@expected_hash = {:enumerate_only_vulnerable_plugins => true}
|
||||
end
|
||||
|
||||
it "should set enumerate_timthumbs to true" do
|
||||
@argument = 't'
|
||||
@expected_hash = {:enumerate_timthumbs => true}
|
||||
end
|
||||
|
||||
it "should set enumerate_usernames to true" do
|
||||
@argument = 'u'
|
||||
@expected_hash = {:enumerate_usernames => true}
|
||||
end
|
||||
|
||||
it "should set enumerate_usernames to true and enumerate_usernames_range to (1..20)" do
|
||||
@argument = "u[1-20]"
|
||||
@expected_hash = {:enumerate_usernames => true, :enumerate_usernames_range => (1..20)}
|
||||
end
|
||||
|
||||
# Let's try some multiple choices
|
||||
it "should set enumerate_timthumbs to true, enumerate_usernames to true, enumerate_usernames_range to (1..2)" do
|
||||
@argument = "u[1-2]t"
|
||||
@expected_hash = {
|
||||
:enumerate_usernames => true, :enumerate_usernames_range => (1..2),
|
||||
:enumerate_timthumbs => true
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe "#set_option_from_cli" do
|
||||
it "should raise an error with unknow option" do
|
||||
expect { @wpscan_options.set_option_from_cli("hello", "") }.to raise_error
|
||||
end
|
||||
|
||||
it "should set @url to example.com" do
|
||||
@wpscan_options.set_option_from_cli("--url", "example.com")
|
||||
@wpscan_options.url.should === "http://example.com"
|
||||
end
|
||||
|
||||
it "should set @enumerate_plugins to true" do
|
||||
@wpscan_options.set_option_from_cli("--enumerate", "p")
|
||||
@wpscan_options.enumerate_plugins.should be_true
|
||||
@wpscan_options.enumerate_only_vulnerable_plugins.should be_nil
|
||||
end
|
||||
|
||||
it "should set @enumerate_only_vulnerable_plugins, @enumerate_timthumbs and @enumerate_usernames to true if no argument is given" do
|
||||
@wpscan_options.set_option_from_cli("--enumerate", '')
|
||||
@wpscan_options.enumerate_only_vulnerable_plugins.should be_true
|
||||
@wpscan_options.enumerate_timthumbs.should be_true
|
||||
@wpscan_options.enumerate_usernames.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "#load_from_arguments" do
|
||||
after :each do
|
||||
set_argv(@argv)
|
||||
wpscan_options = WpscanOptions.load_from_arguments
|
||||
wpscan_options.to_h.should === @expected_hash
|
||||
end
|
||||
|
||||
it "should return {}" do
|
||||
@argv = ''
|
||||
@expected_hash = {}
|
||||
end
|
||||
|
||||
it "should return {:url => 'example.com'}" do
|
||||
@argv = "--url example.com"
|
||||
@expected_hash = {:url => "http://example.com"}
|
||||
end
|
||||
|
||||
it "should return {:url => 'example.com'}" do
|
||||
@argv = "-u example.com"
|
||||
@expected_hash = {:url => "http://example.com"}
|
||||
end
|
||||
|
||||
it "should return {:username => 'admin'}" do
|
||||
@argv = "--username admin"
|
||||
@expected_hash = {:username => "admin"}
|
||||
end
|
||||
|
||||
it "should return {:username => 'Youhou'}" do
|
||||
@argv = "-U Youhou"
|
||||
@expected_hash = {:username => "Youhou"}
|
||||
end
|
||||
|
||||
it "should return {:url => 'example.com', :threads => 5, :force => ''}" do
|
||||
@argv = "-u example.com --force -t 5"
|
||||
@expected_hash = {:url => "http://example.com", :threads => 5, :force => ""}
|
||||
end
|
||||
|
||||
it "should return {:url => 'example.com', :enumerate_plugins => true, :enumerate_timthumbs => true}" do
|
||||
@argv = "-u example.com -e pt"
|
||||
@expected_hash = {:url => 'http://example.com', :enumerate_plugins => true, :enumerate_timthumbs => true}
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
4
spec/lib/wpstools/wpstools_helper.rb
Normal file
4
spec/lib/wpstools/wpstools_helper.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
||||
|
||||
require WPSTOOLS_LIB_DIR + '/wpstools_helper'
|
||||
|
||||
Reference in New Issue
Block a user