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 ]
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),

View File

@@ -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/' }

View File

@@ -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: {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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(

View File

@@ -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
)

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>