Files
metasploit-gs/lib/msf/core/exploit/http/drupal.rb
T
2019-03-05 18:52:27 -06:00

106 lines
2.5 KiB
Ruby

# -*- coding: binary -*-
module Msf
module Exploit::Remote::HTTP::Drupal
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super
register_options([
OptString.new('TARGETURI', [true, 'Path to Drupal install', '/'])
])
end
def setup
super
# Ensure we don't hit a redirect (e.g., /drupal -> /drupal/)
# XXX: Naughty datastore modification instead of send_request_cgi!
datastore['TARGETURI'] = normalize_uri(datastore['TARGETURI'], '/')
end
# Determine Drupal version
#
# @return [Gem::Version] Version as Gem::Version
def drupal_version
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path)
)
return unless res && res.code == 200
# Check for an X-Generator header
version = version_match(res.headers['X-Generator'])
return version if version
# Check for a <meta> tag
generator = res.get_html_document.at(
'//meta[@name = "Generator"]/@content'
)
return unless generator
version_match(generator.value)
end
# Return CHANGELOG.txt
#
# @param version [Gem::Version] Gem::Version or version string
# @return [String] CHANGELOG.txt as a string
def drupal_changelog(version)
return unless version && Gem::Version.correct?(version)
uri = Gem::Version.new(version) < Gem::Version.new('8') ?
normalize_uri(target_uri.path, 'CHANGELOG.txt') :
normalize_uri(target_uri.path, 'core/CHANGELOG.txt')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
return unless res && res.code == 200
res.body
end
# Check CHANGELOG.txt for patch level
#
# @param changelog [String] CHANGELOG.txt to search
# @param patch [String] Patch to check for (example: SA-CORE-2019-003)
# @return [Boolean, nil] Whether or not the patch was found or unknown
def drupal_patch(changelog, patch)
return unless changelog && patch
# HACK: Patch level removed since undetermined 8.x release
if changelog.include?('For a full list of fixes in the latest release')
return nil
elsif changelog.include?(patch)
return true
end
false
end
# Match a Drupal version
#
# @param string [String] String to match against
# @return [Gem::Version] Version as Gem::Version
def version_match(string)
return unless string
# Perl devs love me; Ruby devs hate me
string =~ /^Drupal ([\d.]+)/
return unless $1 && Gem::Version.correct?($1)
Gem::Version.new($1)
end
end
end