Updates finders to use new methods

This commit is contained in:
erwanlr
2019-03-26 21:10:14 +00:00
parent cfab2a9cd7
commit 743ba0541b
11 changed files with 169 additions and 57 deletions

View File

@@ -8,13 +8,12 @@ module WPScan
# @return [ InterestingFinding ] # @return [ InterestingFinding ]
def aggressive(_opts = {}) def aggressive(_opts = {})
path = 'wp-content/backup-db/' path = 'wp-content/backup-db/'
url = target.url(path) res = target.head_and_get(path, [200, 403])
res = Browser.get(url)
return unless [200, 403].include?(res.code) && !target.homepage_or_404?(res) return unless [200, 403].include?(res.code) && !target.homepage_or_404?(res)
Model::BackupDB.new( Model::BackupDB.new(
url, target.url(path),
confidence: 70, confidence: 70,
found_by: DIRECT_ACCESS, found_by: DIRECT_ACCESS,
interesting_entries: target.directory_listing_entries(path), interesting_entries: target.directory_listing_entries(path),

View File

@@ -7,13 +7,12 @@ module WPScan
class DuplicatorInstallerLog < CMSScanner::Finders::Finder class DuplicatorInstallerLog < CMSScanner::Finders::Finder
# @return [ InterestingFinding ] # @return [ InterestingFinding ]
def aggressive(_opts = {}) def aggressive(_opts = {})
url = target.url('installer-log.txt') path = 'installer-log.txt'
res = Browser.get(url)
return unless res.body =~ /DUPLICATOR INSTALL-LOG/ return unless target.head_and_get(path).body =~ /DUPLICATOR INSTALL-LOG/
Model::DuplicatorInstallerLog.new( Model::DuplicatorInstallerLog.new(
url, target.url(path),
confidence: 100, confidence: 100,
found_by: DIRECT_ACCESS, found_by: DIRECT_ACCESS,
references: { url: 'https://www.exploit-db.com/ghdb/3981/' } references: { url: 'https://www.exploit-db.com/ghdb/3981/' }

View File

@@ -7,13 +7,13 @@ module WPScan
class EmergencyPwdResetScript < CMSScanner::Finders::Finder class EmergencyPwdResetScript < CMSScanner::Finders::Finder
# @return [ InterestingFinding ] # @return [ InterestingFinding ]
def aggressive(_opts = {}) def aggressive(_opts = {})
url = target.url('/emergency.php') path = 'emergency.php'
res = Browser.get(url) res = target.head_and_get(path)
return unless res.code == 200 && !target.homepage_or_404?(res) return unless res.code == 200 && !target.homepage_or_404?(res)
Model::EmergencyPwdResetScript.new( Model::EmergencyPwdResetScript.new(
url, target.url(path),
confidence: res.body =~ /password/i ? 100 : 40, confidence: res.body =~ /password/i ? 100 : 40,
found_by: DIRECT_ACCESS, found_by: DIRECT_ACCESS,
references: { references: {

View File

@@ -7,14 +7,14 @@ module WPScan
class Readme < CMSScanner::Finders::Finder class Readme < CMSScanner::Finders::Finder
# @return [ InterestingFinding ] # @return [ InterestingFinding ]
def aggressive(_opts = {}) def aggressive(_opts = {})
potential_files.each do |file| potential_files.each do |path|
url = target.url(file) res = target.head_and_get(path)
res = Browser.get(url)
if res.code == 200 && res.body =~ /wordpress/i next unless res.code == 200 && res.body =~ /wordpress/i
return Model::Readme.new(url, confidence: 100, found_by: DIRECT_ACCESS)
end return Model::Readme.new(target.url(path), confidence: 100, found_by: DIRECT_ACCESS)
end end
nil nil
end end

View File

@@ -9,22 +9,17 @@ module WPScan
# @return [ InterestingFinding ] # @return [ InterestingFinding ]
def aggressive(_opts = {}) 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 res.body =~ SQL_PATTERN
return unless Browser.get(dump_url, headers: { 'Range' => 'bytes=0-3000' }).body =~ SQL_PATTERN
Model::UploadSQLDump.new( Model::UploadSQLDump.new(
dump_url, target.url(path),
confidence: 100, confidence: 100,
found_by: DIRECT_ACCESS found_by: DIRECT_ACCESS
) )
end end
def dump_url
@dump_url ||= target.url('wp-content/uploads/dump.sql')
end
end end
end end
end end

View File

@@ -8,31 +8,38 @@ describe WPScan::Finders::InterestingFindings::BackupDB do
let(:wp_content) { 'wp-content' } let(:wp_content) { 'wp-content' }
let(:dir_url) { target.url("#{wp_content}/backup-db/") } 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 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 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 end
context 'when 200 and matching the homepage' do 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 end
context 'when 200 or 403' do 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 after do
found = finder.aggressive found = finder.aggressive
@@ -47,6 +54,8 @@ describe WPScan::Finders::InterestingFindings::BackupDB do
end end
context 'when no directory listing' do context 'when no directory listing' do
let(:body) { '' }
it 'returns an empty interesting_findings attribute' do it 'returns an empty interesting_findings attribute' do
@expected_entries = [] @expected_entries = []
end end

View File

@@ -11,6 +11,20 @@ describe WPScan::Finders::InterestingFindings::DuplicatorInstallerLog do
describe '#aggressive' do describe '#aggressive' do
before do before do
expect(target).to receive(:sub_dir).at_least(1).and_return(false) 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
context 'when not a 200' do
it 'return nil' do
stub_request(:head, log_url).to_return(status: 404)
expect(finder.aggressive).to eql nil
end
end
context 'when a 200' do
before do
stub_request(:head, log_url)
stub_request(:get, log_url).to_return(body: body) stub_request(:get, log_url).to_return(body: body)
end end
@@ -33,3 +47,4 @@ describe WPScan::Finders::InterestingFindings::DuplicatorInstallerLog do
end end
end end
end end
end

View File

@@ -4,9 +4,69 @@ describe WPScan::Finders::InterestingFindings::EmergencyPwdResetScript do
subject(:finder) { described_class.new(target) } subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) } let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
let(:url) { 'http://ex.lo/' } let(:url) { 'http://ex.lo/' }
let(:file_url) { url + 'emergency.php' }
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'emergency_pwd_reset_script') } 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 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
end end

View File

@@ -9,9 +9,10 @@ describe WPScan::Finders::InterestingFindings::Readme do
describe '#aggressive' do describe '#aggressive' do
before do before do
expect(target).to receive(:sub_dir).at_least(1).and_return(false) 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| 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
end end
@@ -24,7 +25,10 @@ describe WPScan::Finders::InterestingFindings::Readme do
let(:file) { finder.potential_files.sample } let(:file) { finder.potential_files.sample }
let(:readme) { File.read(fixtures.join('readme-3.9.2.html')) } 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 it 'returns the expected InterestingFinding' do
expected = WPScan::Model::Readme.new( expected = WPScan::Model::Readme.new(

View File

@@ -4,20 +4,21 @@ describe WPScan::Finders::InterestingFindings::UploadSQLDump do
subject(:finder) { described_class.new(target) } subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) } let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
let(:url) { 'http://ex.lo/' } 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(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'upload_sql_dump') }
let(:wp_content) { 'wp-content' } let(:wp_content) { 'wp-content' }
describe '#aggressive' do describe '#aggressive' do
before do before do
expect(target).to receive(:content_dir).at_least(1).and_return(wp_content) 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 end
after { expect(finder.aggressive).to eql @expected } after { expect(finder.aggressive).to eql @expected }
context 'when not a 200' do context 'when not a 200' do
it 'returns nil' 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 @expected = nil
end end
@@ -25,9 +26,9 @@ describe WPScan::Finders::InterestingFindings::UploadSQLDump do
context 'when a 200' do context 'when a 200' do
before 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' }) .with(headers: { 'Range' => 'bytes=0-3000' })
.to_return(body: File.read(fixtures.join(fixture))) .to_return(body: File.read(fixtures.join(fixture)))
end end
@@ -45,7 +46,7 @@ describe WPScan::Finders::InterestingFindings::UploadSQLDump do
it 'returns the interesting findings' do it 'returns the interesting findings' do
@expected = WPScan::Model::UploadSQLDump.new( @expected = WPScan::Model::UploadSQLDump.new(
finder.dump_url, dump_url,
confidence: 100, confidence: 100,
found_by: described_class::DIRECT_ACCESS found_by: described_class::DIRECT_ACCESS
) )

View File

@@ -0,0 +1,30 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>WordPress Emergency PassWord Reset</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="http://wp.lab/wp-admin/wp-admin.css?version=5.1.1" type="text/css" />
</head>
<body>
<div class="wrap">
<form method="post" action="">
<h2>WordPress Emergency PassWord Reset</h2>
<p><strong>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.</strong></p>
<p>This script is intended to be used as <strong>a last resort</strong> 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.)</p>
<p class="submit"><input type="submit" name="update" value="Update Options" /></p>
<fieldset class="options">
<legend>WordPress Administrator</legend>
<label>Enter Username:<br />
<input type="text" name="e-name" id="e-name" class="input" value="" size="20" tabindex="10" /></label>
</fieldset>
<fieldset class="options">
<legend>Password</legend>
<label>Enter New Password:<br />
<input type="text" name="e-pass" id="e-pass" class="input" value="" size="25" tabindex="20" /></label>
</fieldset>
<p class="submit"><input type="submit" name="update" value="Update Options" /></p>
</form>
</div></body></html>