Horizon3.ai
Horizon3.ai

Veeam Backup and Replication CVE-2023-27532 Deep Dive

by | Mar 23, 2023 | Attack Blogs

Introduction

Veeam has recently released an advisory for CVE-2023-27532 for Veeam Backup and Replication which allows an unauthenticated user with access to the Veeam backup service (TCP 9401 by default) to request cleartext credentials. Others, including Huntress, Y4er, and CODE WHITE , have provided insight into this vulnerability. In this post, we hope to offer additional insights and release our POC (found here) which is built on .NET Core and capable of running on Linux.

Examining the Vulnerable Port

We first determine what application is using vulnerable port 9401.

Find application using port 9401

Find application using port 9401

Now we can begin to reverse engineer the Veeam Backup Service. By default, we find the service binary and its associated assemblies in C:\Program Files\Veeam\Backup and Replication\Backup. The log file for the backup service is located at  C:\ProgramData\Veeam\Backup\Svc_VeeamBackup.log. Searching for the port in question in the log file gives a string that we can search for in the binary.

Find port in log file

Find port in log file

InitSslServerChannel

InitSslServerChannel

Next we dig into the call to CreateService and eventually find ourselves at a private constructor for CRemoteInvokeServiceHolder:

CRemoteInvokeServiceHolder

CRemoteInvokeServiceHolder

The use of ServiceHost, NetTcpBinding, and AddServiceEndpoint gives us enough context to know that this app is hosting a Windows Communication Foundation (WCF) service. The services exposes the IRemoteInvokeService interface to the client and the interface is implemented by CVbRestoreServiceStub on the server side.

The use of NetTcpBinding tells us that this service is using a binary protocol built on TCP intended for WCF to WCF communication. This restricts our client implementation to a .NET language as it would be rather difficult to write a custom WCF binary parser. We do not want our POC to be restricted to running on Windows so we will use .NET core for our POC.

Constructing a WCF Client

Before we are able to create a client, we need the service interface definition. Based on previous research, we know that we need a few credential based methods from the DatabaseManager scope. We end up with the following definition:

Now we can try to connect to the service:

Our first attempt is met with the following error:

/home/dev/RiderProjects/Veeam_CVE-2023-27532/CVE-2023-27532/bin/Debug/net6.0/CVE-2023-27532 net.tcp://192.168.1.139:9401/
Unhandled exception. System.ServiceModel.ProtocolException: The requested upgrade is not supported by 'net.tcp://192.168.1.139:9401/'. This could be due to mismatched bindings (for example security enabled on the client and not on the server).

If we look back at CRemoteInvokeServiceHolder, we see that the NetTcpBinding was created with parameter "invokeServiceBinding". We can find the configuration parameters for this binding in Veeam.Backup.Service.exe.config:

Veeam.Backup.Service.exe.config

Veeam.Backup.Service.exe.config

With this information, we can update our POC. After disabling certificate validation and setting the correct DNSIdentity, we have the following:

Running the POC we get:

/home/dev/RiderProjects/Veeam_CVE-2023-27532/CVE-2023-27532/bin/Debug/net6.0/CVE-2023-27532 net.tcp://192.168.1.139:9401/
Unhandled exception. System.ServiceModel.FaultException: Data at the root level is invalid. Line 1, position 1.

This indicates that we were able to successfully invoke the service. The error is a result of us passing invalid XML. Now we can begin to figure out how to extract credentials from this API.

Extracting Credentials

Based on previous research, we know that we can invoke CredentialsDbScopeGetAllCreds to get a binary blob containing credential information. If we look at the implementation of ExecuteCredentialsDbScopeGetAllCreds we see that this blob is a serialized C# object created by Veeam’s custom CProxyBinaryFormatter.

ExecuteCredentailsDbScopeGetAllCreds

ExecuteCredentailsDbScopeGetAllCreds

If we dump this data to a file we can see that there is username and password information, but it is not immediately obvious how to parse this information out of the binary blob. We don’t want to reimplement Veeam’s custom serialization class and also don’t want to have to reference their assemblies. So what can we do? It looks like there are some easily parseable guids prefixed by $.

CredentialsDbScopeGetAllCreds output

CredentialsDbScopeGetAllCreds output

We see that these guids match the id used for Credentials in the Veeam database:

Credentials in Veeam database

Credentials in Veeam database

We can now use the CredentialsDbScopeFindCredentials endpoint to get one credential at a time. Our code to extract the guids looks like:

The output from CredentialsDbScopeFindCredentials is still a binary blob, but at least we can work with one Credential at a time now instead of a list. We still have the problem of having to parse out the usernames and passwords. Luckily, we found a Stackoverflow post detailing how to use a custom serializer to get object properties as key value pairs. We can now extract the usernames an passwords with ease.

Running our POC we get the following output:

/home/dev/RiderProjects/Veeam_CVE-2023-27532/CVE-2023-27532/bin/Debug/net6.0/CVE-2023-27532 net.tcp://192.168.1.139:9401/
UserName = dev Password = Super Secret Password 
UserName = root Password = 
UserName = root Password = 
UserName = root Password = 
UserName = root Password =

Summary

In conclusion, CVE-2023-27532 allows an unauthenticated user with access to the Veeam backup service to request cleartext credentials. We have examined the vulnerable port, reverse engineered the Veeam Backup Service, and constructed a WCF client using .NET core. We have also shown how to extract credentials from the Veeam database by invoking the CredentialsDbScopeGetAllCreds and CredentialsDbScopeFindCredentials endpoints. Finally, we have released our POC on Github, which is built on .NET core and capable of running on Linux, making it accessible to a wider audience. It is important to note that this vulnerability should be taken seriously and patches should be applied as soon as possible to ensure the security of your organization.

How can NodeZero help you?

Let our experts walk you through a demonstration of NodeZero, so you can see how to put it to work for your company.