diff --git a/app/finders/interesting_findings/backup_db.rb b/app/finders/interesting_findings/backup_db.rb index 7e742143..c6358b81 100644 --- a/app/finders/interesting_findings/backup_db.rb +++ b/app/finders/interesting_findings/backup_db.rb @@ -8,13 +8,12 @@ module WPScan # @return [ InterestingFinding ] def aggressive(_opts = {}) path = 'wp-content/backup-db/' - url = target.url(path) - res = Browser.get(url) + res = target.head_and_get(path, [200, 403]) return unless [200, 403].include?(res.code) && !target.homepage_or_404?(res) Model::BackupDB.new( - url, + target.url(path), confidence: 70, found_by: DIRECT_ACCESS, interesting_entries: target.directory_listing_entries(path), diff --git a/app/finders/interesting_findings/duplicator_installer_log.rb b/app/finders/interesting_findings/duplicator_installer_log.rb index c84dfc04..4b12e6f3 100644 --- a/app/finders/interesting_findings/duplicator_installer_log.rb +++ b/app/finders/interesting_findings/duplicator_installer_log.rb @@ -7,13 +7,12 @@ module WPScan class DuplicatorInstallerLog < CMSScanner::Finders::Finder # @return [ InterestingFinding ] def aggressive(_opts = {}) - url = target.url('installer-log.txt') - res = Browser.get(url) + path = 'installer-log.txt' - return unless res.body =~ /DUPLICATOR INSTALL-LOG/ + return unless target.head_and_get(path).body =~ /DUPLICATOR INSTALL-LOG/ Model::DuplicatorInstallerLog.new( - url, + target.url(path), confidence: 100, found_by: DIRECT_ACCESS, references: { url: 'https://www.exploit-db.com/ghdb/3981/' } diff --git a/app/finders/interesting_findings/emergency_pwd_reset_script.rb b/app/finders/interesting_findings/emergency_pwd_reset_script.rb index 4f37c2e8..f4efa291 100644 --- a/app/finders/interesting_findings/emergency_pwd_reset_script.rb +++ b/app/finders/interesting_findings/emergency_pwd_reset_script.rb @@ -7,13 +7,13 @@ module WPScan class EmergencyPwdResetScript < CMSScanner::Finders::Finder # @return [ InterestingFinding ] def aggressive(_opts = {}) - url = target.url('/emergency.php') - res = Browser.get(url) + path = 'emergency.php' + res = target.head_and_get(path) return unless res.code == 200 && !target.homepage_or_404?(res) Model::EmergencyPwdResetScript.new( - url, + target.url(path), confidence: res.body =~ /password/i ? 100 : 40, found_by: DIRECT_ACCESS, references: { diff --git a/app/finders/interesting_findings/readme.rb b/app/finders/interesting_findings/readme.rb index d5436569..b382d3a1 100644 --- a/app/finders/interesting_findings/readme.rb +++ b/app/finders/interesting_findings/readme.rb @@ -7,14 +7,14 @@ module WPScan class Readme < CMSScanner::Finders::Finder # @return [ InterestingFinding ] def aggressive(_opts = {}) - potential_files.each do |file| - url = target.url(file) - res = Browser.get(url) + potential_files.each do |path| + res = target.head_and_get(path) - if res.code == 200 && res.body =~ /wordpress/i - return Model::Readme.new(url, confidence: 100, found_by: DIRECT_ACCESS) - end + next unless res.code == 200 && res.body =~ /wordpress/i + + return Model::Readme.new(target.url(path), confidence: 100, found_by: DIRECT_ACCESS) end + nil end diff --git a/app/finders/interesting_findings/upload_sql_dump.rb b/app/finders/interesting_findings/upload_sql_dump.rb index 19185d8a..302c21ca 100644 --- a/app/finders/interesting_findings/upload_sql_dump.rb +++ b/app/finders/interesting_findings/upload_sql_dump.rb @@ -9,22 +9,17 @@ module WPScan # @return [ InterestingFinding ] def aggressive(_opts = {}) - head_res = browser.forge_request(dump_url, target.head_or_get_request_params).run + path = 'wp-content/uploads/dump.sql' + res = target.head_and_get(path, [200], get: { headers: { 'Range' => 'bytes=0-3000' } }) - return unless head_res.code == 200 - - return unless Browser.get(dump_url, headers: { 'Range' => 'bytes=0-3000' }).body =~ SQL_PATTERN + return unless res.body =~ SQL_PATTERN Model::UploadSQLDump.new( - dump_url, + target.url(path), confidence: 100, found_by: DIRECT_ACCESS ) end - - def dump_url - @dump_url ||= target.url('wp-content/uploads/dump.sql') - end end end end diff --git a/spec/app/finders/interesting_findings/backup_db_spec.rb b/spec/app/finders/interesting_findings/backup_db_spec.rb index 412c5871..00cdb89a 100644 --- a/spec/app/finders/interesting_findings/backup_db_spec.rb +++ b/spec/app/finders/interesting_findings/backup_db_spec.rb @@ -8,31 +8,38 @@ describe WPScan::Finders::InterestingFindings::BackupDB do let(:wp_content) { 'wp-content' } let(:dir_url) { target.url("#{wp_content}/backup-db/") } - before { expect(target).to receive(:content_dir).at_least(1).and_return(wp_content) } + before do + expect(target).to receive(:content_dir).at_least(1).and_return(wp_content) + expect(target).to receive(:head_or_get_params).and_return(method: :head) + end describe '#aggressive' do - before { stub_request(:get, dir_url).to_return(status: status, body: body) } - - let(:body) { '' } - context 'when not a 200 or 403' do - let(:status) { 404 } + it 'returns nil' do + stub_request(:head, dir_url).to_return(status: 404) - its(:aggressive) { should be_nil } + expect(finder.aggressive).to eql nil + end end context 'when 200 and matching the homepage' do - before { expect(target).to receive(:homepage_or_404?).and_return(true) } + it 'returns nil' do + stub_request(:head, dir_url) + stub_request(:get, dir_url) - let(:status) { 200 } + expect(target).to receive(:homepage_or_404?).and_return(true) - its(:aggressive) { should be_nil } + expect(finder.aggressive).to eql nil + end end context 'when 200 or 403' do - before { expect(target).to receive(:homepage_or_404?).and_return(false) } + before do + stub_request(:head, dir_url) + stub_request(:get, dir_url).and_return(body: body) - let(:status) { 200 } + expect(target).to receive(:homepage_or_404?).and_return(false) + end after do found = finder.aggressive @@ -47,6 +54,8 @@ describe WPScan::Finders::InterestingFindings::BackupDB do end context 'when no directory listing' do + let(:body) { '' } + it 'returns an empty interesting_findings attribute' do @expected_entries = [] end diff --git a/spec/app/finders/interesting_findings/duplicator_installer_log_spec.rb b/spec/app/finders/interesting_findings/duplicator_installer_log_spec.rb index 334bb9b3..9e7ec17d 100644 --- a/spec/app/finders/interesting_findings/duplicator_installer_log_spec.rb +++ b/spec/app/finders/interesting_findings/duplicator_installer_log_spec.rb @@ -11,24 +11,39 @@ describe WPScan::Finders::InterestingFindings::DuplicatorInstallerLog do describe '#aggressive' do before do expect(target).to receive(:sub_dir).at_least(1).and_return(false) - stub_request(:get, log_url).to_return(body: body) + expect(target).to receive(:head_or_get_params).and_return(method: :head) end - context 'when the body does not match' do - let(:body) { '' } + context 'when not a 200' do + it 'return nil' do + stub_request(:head, log_url).to_return(status: 404) - its(:aggressive) { should be_nil } + expect(finder.aggressive).to eql nil + end end - context 'when the body matches' do - let(:body) { File.read(fixtures.join(filename)) } + context 'when a 200' do + before do + stub_request(:head, log_url) + stub_request(:get, log_url).to_return(body: body) + end - it 'returns the InterestingFinding' do - expect(finder.aggressive).to eql WPScan::Model::DuplicatorInstallerLog.new( - log_url, - confidence: 100, - found_by: described_class::DIRECT_ACCESS - ) + context 'when the body does not match' do + let(:body) { '' } + + its(:aggressive) { should be_nil } + end + + context 'when the body matches' do + let(:body) { File.read(fixtures.join(filename)) } + + it 'returns the InterestingFinding' do + expect(finder.aggressive).to eql WPScan::Model::DuplicatorInstallerLog.new( + log_url, + confidence: 100, + found_by: described_class::DIRECT_ACCESS + ) + end end end end diff --git a/spec/app/finders/interesting_findings/emergency_pwd_reset_script_spec.rb b/spec/app/finders/interesting_findings/emergency_pwd_reset_script_spec.rb index 93a20103..64c16c02 100644 --- a/spec/app/finders/interesting_findings/emergency_pwd_reset_script_spec.rb +++ b/spec/app/finders/interesting_findings/emergency_pwd_reset_script_spec.rb @@ -4,9 +4,69 @@ describe WPScan::Finders::InterestingFindings::EmergencyPwdResetScript do subject(:finder) { described_class.new(target) } let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) } let(:url) { 'http://ex.lo/' } + let(:file_url) { url + 'emergency.php' } let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'emergency_pwd_reset_script') } + before do + expect(target).to receive(:sub_dir).at_least(1).and_return(false) + expect(target).to receive(:head_or_get_params).and_return(method: :head) + end + describe '#aggressive' do - xit + context 'when not a 200' do + it 'returns nil' do + stub_request(:head, file_url).to_return(status: 404) + + expect(finder.aggressive).to eql nil + end + end + + context 'when 200 and matching the homepage' do + before { stub_request(:head, file_url) } + + context 'when matching the homepage' do + it 'returns nil' do + stub_request(:get, file_url) + + expect(target).to receive(:homepage_or_404?).and_return(true) + + expect(finder.aggressive).to eql nil + end + end + + context 'when 200' do + before do + stub_request(:get, file_url).and_return(body: body) + + expect(target).to receive(:homepage_or_404?).and_return(false) + end + + after do + found = finder.aggressive + + expect(found).to eql WPScan::Model::EmergencyPwdResetScript.new( + file_url, + confidence: @expected_confidence, + found_by: described_class::DIRECT_ACCESS + ) + end + + context 'when body matches /password/' do + let(:body) { File.read(fixtures.join('emergency.php')) } + + it 'returns with a confidence of 100' do + @expected_confidence = 100 + end + end + + context 'when body does not match /password/' do + let(:body) { 'maybe, maybe not' } + + it 'returns with a confidence of 40' do + @expected_confidence = 40 + end + end + end + end end end diff --git a/spec/app/finders/interesting_findings/readme_spec.rb b/spec/app/finders/interesting_findings/readme_spec.rb index 01f00daf..f4da18db 100644 --- a/spec/app/finders/interesting_findings/readme_spec.rb +++ b/spec/app/finders/interesting_findings/readme_spec.rb @@ -9,9 +9,10 @@ describe WPScan::Finders::InterestingFindings::Readme do describe '#aggressive' do before do expect(target).to receive(:sub_dir).at_least(1).and_return(false) + expect(target).to receive(:head_or_get_params).at_least(1).and_return(method: :head) finder.potential_files.each do |file| - stub_request(:get, target.url(file)).to_return(status: 404) + stub_request(:head, target.url(file)).to_return(status: 404) end end @@ -24,7 +25,10 @@ describe WPScan::Finders::InterestingFindings::Readme do let(:file) { finder.potential_files.sample } let(:readme) { File.read(fixtures.join('readme-3.9.2.html')) } - before { stub_request(:get, target.url(file)).to_return(body: readme) } + before do + stub_request(:head, target.url(file)) + stub_request(:get, target.url(file)).to_return(body: readme) + end it 'returns the expected InterestingFinding' do expected = WPScan::Model::Readme.new( diff --git a/spec/app/finders/interesting_findings/upload_sql_dump_spec.rb b/spec/app/finders/interesting_findings/upload_sql_dump_spec.rb index 3916f58a..0ba4280c 100644 --- a/spec/app/finders/interesting_findings/upload_sql_dump_spec.rb +++ b/spec/app/finders/interesting_findings/upload_sql_dump_spec.rb @@ -4,20 +4,21 @@ describe WPScan::Finders::InterestingFindings::UploadSQLDump do subject(:finder) { described_class.new(target) } let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) } let(:url) { 'http://ex.lo/' } + let(:dump_url) { url + 'wp-content/uploads/dump.sql' } let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'upload_sql_dump') } let(:wp_content) { 'wp-content' } describe '#aggressive' do before do expect(target).to receive(:content_dir).at_least(1).and_return(wp_content) - expect(target).to receive(:head_or_get_request_params).and_return(method: :head) + expect(target).to receive(:head_or_get_params).and_return(method: :head) end after { expect(finder.aggressive).to eql @expected } context 'when not a 200' do it 'returns nil' do - stub_request(:head, finder.dump_url).to_return(status: 404) + stub_request(:head, dump_url).to_return(status: 404) @expected = nil end @@ -25,9 +26,9 @@ describe WPScan::Finders::InterestingFindings::UploadSQLDump do context 'when a 200' do before do - stub_request(:head, finder.dump_url).to_return(status: 200) + stub_request(:head, dump_url).to_return(status: 200) - stub_request(:get, finder.dump_url) + stub_request(:get, dump_url) .with(headers: { 'Range' => 'bytes=0-3000' }) .to_return(body: File.read(fixtures.join(fixture))) end @@ -45,7 +46,7 @@ describe WPScan::Finders::InterestingFindings::UploadSQLDump do it 'returns the interesting findings' do @expected = WPScan::Model::UploadSQLDump.new( - finder.dump_url, + dump_url, confidence: 100, found_by: described_class::DIRECT_ACCESS ) diff --git a/spec/fixtures/finders/interesting_findings/emergency_pwd_reset_script/emergency.php b/spec/fixtures/finders/interesting_findings/emergency_pwd_reset_script/emergency.php new file mode 100644 index 00000000..75aebb40 --- /dev/null +++ b/spec/fixtures/finders/interesting_findings/emergency_pwd_reset_script/emergency.php @@ -0,0 +1,30 @@ + + + +WordPress Emergency PassWord Reset + + + + +
+
+

WordPress Emergency PassWord Reset

+

Your use of this script is at your sole risk. All code is provided "as -is", without any warranty, whether express or implied, of its accuracy, completeness. Further, I shall not be liable for any damages you may sustain by using this script, whether direct, indirect, special, incidental or consequential.

+

This script is intended to be used as a last resort by WordPress administrators that are unable to access the database. +Usage of this script requires that you know the Administrator's user name for the WordPress install. (For most installs, that is going to be "admin" without the quotes.)

+

+ +
+WordPress Administrator + +
+
+Password + +
+ +

+
+