How to Break Out of Hyper-V and Compromise your Admins

In this blog post we will explain novel attacks scenarios that affects the widely used protocols PowerShell Remoting and PowerShell Direct. Are you using PowerShell Remoting to manage your environment? Are you using PowerShell Direct to manage virtual machines in your hypervisor platform? Then you need to read this and take action to ensure you are not affected.

This blog post is a high-level overview. If you are looking for the full technical details, please see this article Attacking PowerShell CLIXML Deserialization – Truesec.

PowerShell Remoting and PowerShell Direct are widely used solutions, used to manage enterprise IT environment. They both have a feature to share objects between computers and this is implemented with a serialization format called CLIXML. The issue is that they put trust the remote system to always provide legitimate CLIXML data. This is a vulnerability known as CWE-502: Deserialization of Untrusted Data. In this attack scenario we do not target the server, instead, the target is the client of the connection. Anyone who use these solutions to connect to a compromised computer is thus exposed.

Privilege Escalation and Lateral Movement

The PowerShell Remoting attack scenario is illustrated in the figure below. The unsuspecting administrator connects to a compromised server. However, as the server is compromised, the threat actor can control what data to return. This scenario would thus result in a compromise of the administrator’s computer. Note that this also affects many popular admin solutions because rely on PowerShell Remoting.

This scenario is very interesting because PowerShell Remoting is usually used by administrators with high privileges to remotely manage computers. If a threat actor manages to compromise for example a web server, they could use this technique to escalate their privileges as soon as an admin connects to the compromised server. This concept of internal escalation is a vital part of most cyber attacks.

In the video below, we show what this attack could look like in practice. In this case, an unsuspecting domain admin uses PowerShell Remoting to run a simple command on the compromised server. We see that as soon as the command is executed, the threat actor manages to steal the network password hash (Net-NTLMv2) of the domain admin.

Breaking out of a Hyper-V virtual machine

The PowerShell Direct scenario is very similar. The victim connect to a compromised virtual machine using PowerShell Direct. The threat actor can control the data returned to the hypervisor host. This leads to a compromise of the underlying hypervisor host. This scenario is very interesting because the hypervisor security barrier is critical for most organizations. For example, cloud hosting providers rely on this security barrier to provide separation between customers. If a threat actor manages to compromise the host-layer, they would go from compromising one victim into all victims hosted by the same provider.

In the video below, we see a scenario where a virtual machine is already compromised. An unsuspecting Hyper-V admin uses PowerShell Direct to run a simple command in the compromised machine. In this case, we do it manually, but note that for example backup solutions could be configured to run recurring PowerShell Direct commands automatically.

As soon as a PowerShell Direct command is executed, the threat actor is able to exploit this and break out of the virtual machine. In the demo we spawn a remote access malware on the underlying host.

What is the impact of these vulnerabilities?

This is not very straight forward as the impact of the vulnerability will depend on a variaty of factors. Essentially, it depends on what gadgets are available in the victim’s PowerShell session. By default, only a few gadgets are available. The concept of gadgets are fairly involved, we recommend that you read our technical article if you want to fully understand the impact.

GADGET IMPACTDEPENDENCIES
Arbitrary DNS lookupThreat actor can perform domain name lookup to any domain. Useful to find vulnerabilitites.None
Remote Code ExecutionExecute any code to for example spawn a malware.The victim must use the attribute ‘action’ on the result object, as an argument to a cmdlet.
Steal Net-NTLMv2 hashesThreat actor can steal the Net-NTLMv2 hash which contains the victim’s password.None
XXE (XML External Entity)Not detailed here.< .NET 4.5.2
Remote Code ExecutionExecute any code to for example spawn a malware.CVE-2017-8565
Remote Code ExecutionExecute any code to for example spawn a malware.Affects hundreds of modules, including three official Microsoft modules. One of these modules must be installed and available.
Other impacts Not detailed here.Not detailed here.

Note that these gadgets (impacts) are what I have found in my research. There are likely more gadgets to be discovered.

Reporting the vulnerability

I submitted my research on March 18th, 2024 to Microsoft Security Response Center (MSRC). MSRC closed the case as “fixed” on July 22nd and a month later my research was publicly acknowledged. However, it is still possible to perform this attack and therefore organizations need to take propriate precautions to mitigate the risks.

TimeWhoDescription
2024-03-18 23:57Alex to MSRCReported findings with working PoCs to Microsoft (MSRC)
2024-03-21 17:33MSRCCase opened
2024-04-15 19:03MSRC to Alex“We confirmed the behavior you reported”
2024-05-06 17:53Alex to MSRCAsked for status update
2024-05-07 21:09MSRCClosed the case
2024-05-26 23:33Alex to MSRCAsked for resolution details
2024-05-30AlexStarted escalating via contacts at MS and MVP friends
2024-06-04Microsoft to AlexAsked for a copy of my SEC-T presentation
2024-06-04Alex to MicrosoftSent my SEC-T presentation
2024-06-26 15:55MSRCOpened the case
2024-07-22 23:02  MSRC to Alex“Thank you[…] The issue has been fixed.”
2024-07-22 23:04MSRC Closed the case
2024-07-22 Alex to MSRCOffered to help validate the fix and for resolution details.
2024-08-14Alex to MicrosoftSent reminder asking if they want to give feedback on the presentation
2024-08-19  Alex to PSFrameworkStarted reachout to PSFramework.
2024-08-28PSFrameworkFirst contact.
2024-08-29MSRC Public acknowledgment.
2024-09-13AlexPresented at SEC-T.
2024-09-14AlexPublished blog post.
Response from MSRC saying they have fixed the issue.

To me, it is still unclear what MSRC means with “The issue has been fixed” as they have not shared any resolution details. While it is obvious that PSRP and PSDirect still deserializes untrusted data, it appears that they also did not fix the remote code execution (due to PSFramework dependency) in Microsoft’s own PowerShell modules, although they are covered under MSRC according to their security.md files (Azure/AzOps, Azure/AzOps-Accelerator, Azure/AVDSessionHostReplacer, PAWTools).

On 2024-08-19 I decided to contact the Microsoft employee behind PSFramework myself. He instantly understood the issue and did a great job starting to resolve it. Make sure to update to v1.12.345 in case you have PSFramework installed.

This research was publicly released 2024-09-14, which is 180 days after the initial private disclosure.

What can you do about it?

PowerShell Remoting (PSRP) is still a recommended method for managing your environment. You should not go back to RDP (Remote Desktop Protocol) or similar for lots of reasons. However, before using PSRP or PSDirect, there are a few things you need to keep in mind.

1. Ensure that the computer you are remoting from is fully patched. As you see in the table above, this will solve some of the problems, but not all.

2. Never use remoting from a computer that is littered with third-party PowerShell modules. In other words, you probably shouldn’t remote from your all-in-one admin PC.

3. Use a privileged access workstation that is dedicated for admin tasks.

4. Review your PowerShell modules
Check the modules loaded on startup by starting a fresh PowerShell prompt and run:

get-module

Note however that modules will be implicitly loaded as soon as you use one of their cmdlets. So you should also check the available modules on your system.

get-module -ListAvailable

5. Reduce your PowerShell Modules
When you install a PowerShell module, it may introduce a new deserialization gadget on your system and your system will be exposed as soon as you use PSRP, PSDirect, or use any script that imports untrusted CLIXML.

Being restrictive with PowerShell modules is good practice in general, as third-party modules comes with other risks as well (e.g. supply chain attacks).

This is however not as easy as it may sound. Lots of software ships with their own set of PowerShell modules that will be installed on your system. You need to ensure that these don’t introduce gadgets.

6. Mitigate impact and disable gadgets
As long as PSRP and PSDirect still relies on untrusted CLIXML deserialization, there will be a constant battle to find and defuse deserialization gadgets.

As an example, the “password stealing gadget” can be mitigated with a simple if statement. Find the following code in C:\Windows\System32\WindowsPowerShell\v1.0\Registry.format.ps1xml:

<ScriptBlock>
$result = (Get-ItemProperty -LiteralPath $_.PSPath | Select * -Exclude PSPath,PSParentPath,PSChildName,PSDrive,PsProvider | Format-List | Out-String | Sort).Trim()
$result = $result.Substring(0, [Math]::Min($result.Length, 5000) )
if($result.Length -eq 5000) { $result += "..." }
$result
</ScriptBlock>

Then add validation that ensures the PSPath property is legitimate. The updated formatter could look something like this:

<ScriptBlock>
$result = ""
if($_.PSPath.startswith("Microsoft.PowerShell.Core\Registry")){
$result = (Get-ItemProperty -LiteralPath $_.PSPath | Select * -Exclude PSPath,PSParentPath,PSChildName,PSDrive,PsProvider | Format-List | Out-String | Sort).Trim()
$result = $result.Substring(0, [Math]::Min($result.Length, 5000) )
if($result.Length -eq 5000) { $result += "..." }
}
$result
</ScriptBlock>