# CVE-2021-27075: Microsoft Azure Vulnerability Allows Privilege Escalation
and Leak of Private Data
Written by Paul Litvak \- 11 May 2021
![](https://images.seebug.org/1620874220103-w331s)
In this post I will explain how the [Microsoft Azure Virtual Machine (VM)
extension](https://docs.microsoft.com/en-us/azure/virtual-
machines/extensions/overview) works and how we found a fatal vulnerability in
the extension mechanism affecting Azure VM Linux systems. As part of the
responsible disclosure policy, we reported the vulnerability to Microsoft
Security Response Center (MSRC). They soon patched and assigned it
[CVE-2021-27075](https://msrc.microsoft.com/update-
guide/vulnerability/CVE-2021-27075).
This vulnerability would have allowed an unprivileged user to leak any Azure
VM extension's private data. Paired with the design of the VMAccess extension,
an official Azure extension built for assisting system admins, we will
demonstrate how this could have been used to achieve **privilege escalation**
and possibly **lateral movement**.
![](https://images.seebug.org/1620874227300-w331s)![](https://images.seebug.org/1620874228174-w331s)
_Proof of Concept_
## Azure VM Extensions
Azure VM offers developers and admins an integrated plugin system to install
additional components onto their machines. Both first party (e.g., Microsoft
Azure Diagnostics and Microsoft Azure Network Watcher) and third party apps
(like Datadog Agent) are offered through this mechanism.
To manage extension installations and keep them up to date, Microsoft Azure
Guest Agent is installed on the system. This component is open-source and
hosted on [GitHub](https://github.com/Azure/WALinuxAgent). This agent, along
with Azure extensions, is installed at _/var/lib/waagent_. This directory is
inaccessible for non-root users as it contains extension-related secrets.
Extensions are installed in this directory in their own sub directories, e.g.,
_/var/lib/waagent/Microsoft.Azure.NetworkWatcher.NetworkWatcherAgentLinux-1.4.1587.1_
Many shared configurations are laid out in the root extension directory
_/var/lib/waagent_.
Here is an example of the directory layout:
![](https://images.seebug.org/1620874229186-w331s)![](https://images.seebug.org/1620874229928-w331s)
_/var/lib/waagent directory structure_
When an extension is added to the VM, the extension's configuration file is
updated behind the scenes in the Azure VM manager, also known as the [Fabric
Controller](https://azure.microsoft.com/en-us/resources/videos/fabric-
controller-internals-building-and-updating-high-availability-apps/). The
WAAgent constantly polls the Fabric Controller for this file, and once
updated, the extension is downloaded and deployed. In Microsoft Azure Cloud,
the WAAgent communicates with the 'Wire Server,' an HTTP service belonging to
the Fabric Controller.
WAAgent communicates with the Fabric Controller by accessing a special IP
address: [168.63.129.16](https://docs.microsoft.com/en-us/azure/virtual-
network/what-is-ip-address-168-63-129-16). Through some testing, we discovered
that this endpoint is the same as 169.254.169.254, better known as the [Azure
Instance Metadata Service](https://docs.microsoft.com/en-us/azure/virtual-
machines/windows/instance-metadata-service) IP address.
The WAAgent receives the extension configuration URL by parsing the
'GoalState.'
![](https://images.seebug.org/1620874230743-w331s)![](https://images.seebug.org/1620874231431-w331s)
_GoalState endpoint request_
A response looks like this:
![](https://images.seebug.org/1620874232127-w331s)![](https://images.seebug.org/1620874234005-w331s)
![](https://images.seebug.org/1620874234759-w331s)![](https://images.seebug.org/1620874236025-w331s)
![](https://images.seebug.org/1620874236960-w331s)![](https://images.seebug.org/1620874237682-w331s)
_GoalState endpoint response_
The GoalState contains URLs to all relevant configurations available to the
Wire Server. Using the GoalState we can query the **ExtensionsConfig** file
ourselves:
![](https://images.seebug.org/1620874238472-w331s)![](https://images.seebug.org/1620874239566-w331s)
_ExtensionsConfig endpoint request_
Here is an example of how the LinuxDiagnostic extension configuration might
look:
![](https://images.seebug.org/1620874240380-w331s)![](https://images.seebug.org/1620874241839-w331s)
_ExtensionsConfig endpoint response_
The _protectedSettings_ field holds sensitive extension configurations such as
private keys and is additionally protected with an encryption scheme. The
_protectedSettingsCertThumbprint_ field holds the filename of the key used to
decrypt the protectedSettings. This key is stored in
_/var/lib/waagent/F54265F38F8D16C35C0E1FD3190882831A6C4384.prv_ with its
certificate stored in
_/var/lib/waagent/F54265F38F8D16C35C0E1FD3190882831A6C4384.crt_.
The private key and certificate pair are not supplied by the ExtensionConfig
file. So, how do they get deployed to the server?
For this deployment, the **Certificates** endpoint is used. After reverse
engineering the WAAgent communication with the Wire Server, we observed that
the Certificates endpoint requires a 'transport' certificate which is used to
supply the _F542 … _extension key:
![](https://images.seebug.org/1620874242908-w331s)![](https://images.seebug.org/1620874243902-w331s)
_Certificates endpoint request_
The Wire Server returns an encrypted form of the extension key which can be
decrypted via the Transport Certificate's private key.
![](https://images.seebug.org/1620874245139-w331s)![](https://images.seebug.org/1620874247809-w331s)
_Certificates endpoint response_
## Leaking Azure VM Extensions' Private Data
## Flaw #1: Certificates Endpoint Does Not Validate Transport Certificate
An attacker can create their own Transport Private Key and its corresponding
Transport Certificate. Using the Certificate endpoint, the attacker supplies
their own Transport Certificate and receives an encrypted form of the keys
from the Wire Server (in our example this is the
_F54265F38F8D16C35C0E1FD3190882831A6C4384_ key _)_.
Finally, the encrypted keys are decrypted via the Transport Key and the
attacker can proceed to decrypt the protectedSettings:
![](https://images.seebug.org/1620874248627-w331s)![](https://images.seebug.org/1620874249916-w331s)
![](https://images.seebug.org/1620874251020-w331s)![](https://images.seebug.org/1620874252736-w331s)
To our surprise, after developing the PoC with the root user, it would not
work with an unprivileged user. It seems that packets destined to the Wire
Server endpoint at 168.63.129.16 were not sent out by the server. This is
because of an iptables rule that drops packets which aren't from user ID 0
(root) to the endpoint:
![](https://images.seebug.org/1620874254193-w331s)![](https://images.seebug.org/1620874254927-w331s)
_Azure VM IPTables_
## Flaw #2: Bypassing Wire Server Unprivileged Access Defense
As mentioned earlier, we discovered that 164.254.164.254 is the same machine
as 168.63.129.16. We replaced every request to 168.63.129.16 with
164.254.164.254 and this allowed us to communicate with the Wire Server
without a privileged user.
In addition, this iptables defense did not apply to processes that run in
Docker containers (even when the PoC ran as an unprivileged user), allowing
containers to leak information about their host through the Wire Server. This
issue was fixed by MSRC as well.
## Combining the Flaws
Utilizing both flaws, an unprivileged user can leak any Azure VM extension's
private settings. This is especially dangerous when paired with extensions
that handle sensitive data.
A particularly severe example is the
[VMAccess](https://azure.microsoft.com/nl-nl/blog/using-vmaccess-extension-to-
reset-login-credentials-for-linux-vm/) extension, an official Microsoft Azure
extension used for changing passwords conveniently on controlled machines.
[Guardicore](https://www.guardicore.com/2018/03/recovering-plaintext-
passwords-azure/) previously documented that VMAccess persists passwords in
the protectedSettings field even after it's done changing the user's password
and no longer needs to keep it on disk.
Combined with the vulnerability we found, an attacker would be able to elevate
themself to a higher privileged user by leaking the VMAccess admin password.
Also, in the event that the VMAccess password is shared with other Azure VMs
(as is often the case), the attacker could perform lateral movement across the
system. This is what the flow looks like:
![](https://images.seebug.org/1620874255889-w331s)![](https://images.seebug.org/1620874259209-w331s)
_Vulnerability flow_
And the proof of concept:
![](https://images.seebug.org/1620874260137-w331s)![](https://images.seebug.org/1620874260907-w331s)
_Leaking VMAccess extension data_
## Takeaways
The CVE issued by Microsoft also applies to other Azure products such as Azure
Spring Cloud, as discovered by researcher [Wouter ter
Maat](https://twitter.com/wtm_offensi) independently at a later date, who was
also credited in the CVE.
Microsoft fixed the issue after revamping the whole Linux extension mechanism
and no user interaction is needed to update VMs.
This research is meant to further the discussion around the relationship
between cloud service providers (CSPs) and their customers. Ultimately, the
customer is responsible for any data breach that occurs. For a more complete
cloud security strategy, Intezer recommends adopting a two-pronged approach.
Do the basics, like fixing known vulnerabilities and hardening your systems to
[reduce the likelihood of getting
attacked](https://www.intezer.com/blog/cloud-security/announcing-
configuration-checks-and-vulnerability-management/). You also need runtime
threat detection to identify and respond to attacks as they occur following
unknown vulnerability exploitation or a backdoor in the supply chain.
Intezer Protect can help reduce the attack surface while detecting and
responding to attacks in runtime. Try [Intezer
Protect](https://protect.intezer.com/signup) for free on up to 10 hosts.
暂无评论