diff --git a/lib/common/collections/wp_timthumbs/detectable.rb b/lib/common/collections/wp_timthumbs/detectable.rb index dd6c9e08..aec16b7e 100644 --- a/lib/common/collections/wp_timthumbs/detectable.rb +++ b/lib/common/collections/wp_timthumbs/detectable.rb @@ -4,28 +4,37 @@ class WpTimthumbs < WpItems module Detectable # No passive detection + # + # @param [ WpTarget ] wp_target + # @param [ Hash ] options + # # @return [ WpTimthumbs ] def passive_detection(wp_target, options = {}) new end - def targets_items(wp_target, options = {}) - unless options[:file] - raise 'A file must be supplied' - end + protected + # @param [ WpTarget ] wp_target + # @param [ Hash ] options + # @option options [ String ] :file The path to the file containing the targets + # @option options [ String ] :theme_name + # + # @return [ Array ] + def targets_items(wp_target, options = {}) targets = options[:theme_name] ? theme_timthumbs(options[:theme_name], wp_target) : [] - File.open(options[:file], 'r') do |f| - f.readlines.collect do |path| - targets << create_item(wp_target, path.strip) - end + if options[:file] + targets += targets_items_from_file(options[:file], wp_target) end targets.uniq { |i| i.url } end - # @return [ WpTimthumb Array ] + # @param [ String ] theme_name + # @param [ WpTarget ] wp_target + # + # @return [ Array ] def theme_timthumbs(theme_name, wp_target) targets = [] wp_timthumb = create_item(wp_target) @@ -41,6 +50,24 @@ class WpTimthumbs < WpItems targets end + # @param [ String ] file + # @param [ WpTarget ] wp_target + # + # @return [ Array ] + def targets_items_from_file(file, wp_target) + targets = [] + + File.open(file, 'r') do |f| + f.readlines.collect do |path| + targets << create_item(wp_target, path.strip) + end + end + targets + end + + # @param [ WpTarget ] wp_target + # @option [ String ] path + # # @return [ WpTimthumb ] def create_item(wp_target, path = nil) options = { diff --git a/lib/common/models/wp_timthumb.rb b/lib/common/models/wp_timthumb.rb index 6261b94a..dcaa12e1 100755 --- a/lib/common/models/wp_timthumb.rb +++ b/lib/common/models/wp_timthumb.rb @@ -8,4 +8,11 @@ class WpTimthumb < WpItem include WpTimthumb::Versionable include WpTimthumb::Existable include WpTimthumb::Output + + # @param [ WpTimthumb ] other + # + # @return [ Boolean ] + def ==(other) + url == other.url + end end diff --git a/spec/lib/common/collections/wp_timthumbs/detectable_spec.rb b/spec/lib/common/collections/wp_timthumbs/detectable_spec.rb new file mode 100644 index 00000000..c1d22579 --- /dev/null +++ b/spec/lib/common/collections/wp_timthumbs/detectable_spec.rb @@ -0,0 +1,123 @@ +# encoding: UTF-8 + +require 'spec_helper' +require WPSCAN_LIB_DIR + '/wp_target' + +describe 'WpTimthumbs::Detectable' do + subject(:wp_timthumbs) { WpTimthumbs } + let(:fixtures_dir) { COLLECTIONS_FIXTURES + '/wp_timthumbs/detectable' } + let(:targets_items_file) { fixtures_dir + '/targets.txt' } + let(:wp_content_dir) { 'wp-content' } + let(:wp_plugins_dir) { wp_content_dir + '/plugins' } + let(:wp_target) { WpTarget.new(url, wp_content_dir: wp_content_dir, wp_plugins_dir: wp_plugins_dir) } + let(:url) { 'http://example.com/' } + let(:uri) { URI.parse(url) } + let(:empty_file) { SPEC_FIXTURES_DIR + '/empty-file' } + + let(:expected) do + { + targets_from_file: [WpTimthumb.new(uri, path: 'timthumb.php'), + WpTimthumb.new(uri, path: '$wp-content$/timthumb.php'), + WpTimthumb.new(uri, path: '$wp-plugins$/a-gallery/timthumb.php'), + WpTimthumb.new(uri, path: '$wp-content$/themes/theme-name/timthumb.php')] + + } + end + + def expected_targets_from_theme(theme_name) + expected = [] + %w{ + timthumb.php lib/timthumb.php inc/timthumb.php includes/timthumb.php + scripts/timthumb.php tools/timthumb.php functions/timthumb.php + }.each do |file| + path = "$wp-content$/themes/#{theme_name}/#{file}" + expected << WpTimthumb.new(uri, path: path) + end + expected + end + + describe '::passive_detection' do + it 'returns an empty WpTimthumbs' do + subject.passive_detection(wp_target).should == subject.new + end + end + + describe '::targets_items_from_file' do + after do + targets = subject.send(:targets_items_from_file, file, wp_target) + + targets.map { |t| t.url }.should == @expected.map { |t| t.url } + end + + context 'when an empty file' do + let(:file) { empty_file } + + it 'returns an empty Array' do + @expected = [] + end + end + + context 'when a non empty file' do + let(:file) { targets_items_file } + + it 'returns the correct Array of WpTimthumb' do + @expected = expected[:targets_from_file] + end + end + end + + describe '::theme_timthumbs' do + it 'returns the correct Array of WpTimthumb' do + theme = 'hello-world' + targets = subject.send(:theme_timthumbs, theme, wp_target) + + targets.map { |t| t.url }.should == expected_targets_from_theme(theme).map { |t| t.url } + end + end + + describe '::targets_items' do + let(:options) { {} } + + after do + targets = subject.send(:targets_items, wp_target, options) + + targets.map { |t| t.url }.should == @expected.sort.map { |t| t.url } + end + + context 'when no :theme_name' do + context 'when no :file' do + it 'returns an empty Array' do + @expected = [] + end + end + + context 'when :file' do + let(:options) { { file: targets_items_file } } + + it 'returns the targets from the file' do + @expected = expected[:targets_from_file] + end + end + end + + context 'when :theme_name' do + let(:theme) { 'theme-name'} + + context 'when no :file' do + let(:options) { { theme_name: theme } } + + it 'returns targets from the theme' do + @expected = expected_targets_from_theme(theme) + end + end + + context 'when :file' do + let(:options) { { theme_name: theme, file: targets_items_file } } + + it 'returns merged targets from theme and file' do + @expected = (expected_targets_from_theme('theme-name') + expected[:targets_from_file]).uniq { |i| i.url } + end + end + end + end +end diff --git a/spec/samples/common/collections/wp_timthumbs/detectable/targets.txt b/spec/samples/common/collections/wp_timthumbs/detectable/targets.txt new file mode 100644 index 00000000..33f019f2 --- /dev/null +++ b/spec/samples/common/collections/wp_timthumbs/detectable/targets.txt @@ -0,0 +1,4 @@ +timthumb.php +$wp-content$/timthumb.php +$wp-plugins$/a-gallery/timthumb.php +$wp-content$/themes/theme-name/timthumb.php diff --git a/spec/shared_examples/wp_items_detectable.rb b/spec/shared_examples/wp_items_detectable.rb index c95c8a83..0b4f54a4 100644 --- a/spec/shared_examples/wp_items_detectable.rb +++ b/spec/shared_examples/wp_items_detectable.rb @@ -104,7 +104,7 @@ shared_examples 'WpItems::Detectable' do if @expected results = subject.send(:targets_items, wp_target, options) - results.map { |i| i.name }.sort.should == @expected.map { |i| i.name }.sort + results.sort.map { |i| i.name }.should == @expected.sort.map { |i| i.name } end end @@ -137,10 +137,10 @@ shared_examples 'WpItems::Detectable' do after do stub_request_to_fixture(url: wp_target.url, fixture: @fixture) - result = subject.passive_detection(wp_target) + results = subject.passive_detection(wp_target) - result.should be_a subject - result.map { |i| i.name }.should == @expected.map { |i| i.name }.sort + results.should be_a subject + results.map { |i| i.name }.should == @expected.sort.map { |i| i.name } end context 'when the page is empty' do @@ -171,7 +171,7 @@ shared_examples 'WpItems::Detectable' do result = subject.aggressive_detection(wp_target, options) result.should be_a subject - result.map { |i| i.name }.should == @expected.map { |i| i.name }.sort + result.sort.map { |i| i.name }.should == @expected.sort.map { |i| i.name } end context 'when :only_vulnerable' do