Skip to content

Exploiting Kaseya Unitrends Backup Appliance – Part 1

Exploiting Kaseya Unitrends Backup Appliance – Part 1

Versions Tested:

  • Unitrends Backup Appliance 10.5.1-2.202103162241.CentOS7
  • Unitrends Windows Agent 10.5.1-1.0950_64 bit
  • Unitrends Linux Agent 10.5.0-3.202102101927


Security Advisories:

CVE Numbers:


Multiple vulnerabilities were discovered in the Unitrends Backup appliance and client software. An attacker with network access to the management interface or backup ports on the client or server could be exploited to compromise the machine. Both suffer from critical remote code execution vulnerabilities.

The following vulnerabilities will be discussed in this blog and will outline an attack chain showing how an undocumented low privileged PostgreSQL with a weak password resulted in a full system compromise. Several additional critical vulnerabilities were also discovered during this research and will be published in another blog.

  • CVE-2021-43039 – SMB Null Sessions Allowed with Read/Write
  • CVE-2021-43036 – Weak PostgreSQL Account wguest
  • CVE-2021-43038 – PostgreSQL Trigger Command Injection
  • CVE-2021-43040 – Privilege Escalation – Arbitrary File Create – vaultServer


Because the Unitrends Backup appliance server holds a privileged position in the network, a compromise could potentially extend to all computers configured as a backup client. Also, the Unitrends backup client software for Windows and Linux contains a critical unpatched vulnerability which allows for unauthenticated remote code execution as root/SYSTEM. It is strongly recommended to not expose the client ports directly to the Internet and internally. Follow the vendors guidance at

CyberOne’s offensive security team TeamARES can perform a penetration test of your company’s Unitrends backup infrastructure and internal environment to assess your organizations current security posture. For information, please contact at .


During an internal penetration test I ran a network sweep looking for servers that allow null SMB sessions to discover exposed network shares. This can be done using various tools but my favorites are smbmap and smbclient. After running this job, one server was found which allowed the anonymous listing of shares which piqued my interest.

The following example shows a simple manual way to check for null sessions using smbclient. It’s possible an anonymous listing could be allowed but access to the individual shares could be restricted to authenticated users so additional verification was needed.

A picture containing textDescription automatically generated

Manual verification can be done with smbclient but that can be time consuming if there are many servers. The smbcacls utility can be used to remotely check ACLs.

TextDescription automatically generated

The smbmap tool can also quickly identify share permissions. It verifies write permission by creating a temporary file. Similar tools use the same approach so keep this in mind for OPSEC considerations.

TextDescription automatically generated

Connecting to the shares did not result in sensitive files being disclosed and most of the shares were empty. It appears this specific appliance was recently setup and not actually in production. The virtual failover writable share contained several files, but it is unknown how these files are used.

A screenshot of a computerDescription automatically generated with medium confidence

Several services are running including the web management application. Visiting the server in a web browser yields a login screen. Authenticated testing was not performed during the research.

Graphical user interface, applicationDescription automatically generated

The server looked interesting but there was not enough time to look for additional vulnerabilities during the test. A research project was created after the assessment completed and several issues were discovered. The focus was primarily on unauthenticated vulnerabilities outside of the web management.

The Unitrends backup appliance uses PostgreSQL for the backend database. An undocumented limited account “wguest” with the password “wguest” was discovered. The purpose of this account is unknown. An upgrade is required to resolve this issue as there are no supported methods for a customer to remove or disable the account. CVE-2021-43036 was created for this issue.

TextDescription automatically generated

The wguest account is not a superuser and appeared to have very limited privileges on the bp schema which is where most of the application tables reside. Two high value target tables identified were bp.users and bp.client_credentials. The bp.users table contains the username and hashed password for the web management accounts. The bp.client_credentials contain usernames and base64 encoded plaintext passwords for remote client computers. Gaining access to the client_credentials table could potentially allow for lateral movement of a high privileged user, but this table is restricted to the postgres user.

TextDescription automatically generated with medium confidence

The goal was to find a path to escalate privileges from the low privilege wguest account to the postgres superuser. The wguest account had read access to a few application tables and the USAGE privilege on the bp.* schema.

The USAGE privilege allowed wguest to execute any user defined functions (UDF) in the bp schema. While reviewing the attack surface in the 60+ UDFs, two Perl trigger functions stood out amongst the rest. One of the functions will be discussed in this blog. A trigger function is a special type of PostgreSQL function that executes based on a database event. The plperl extension extends the functionality of the database by supporting the Perl programming language.

There are several methods to query the logic of a UDF. A simple method is to use the psql cli utility to execute df+ bp.*elk*. The bp.run_elk_alert_script() function simply calls the Perl system() function to execute a shell script passing various parameters. The $_TD->{new}{column} represents the new value of a column. The function blindly passes new or modified data from a table row. The following code for run_elk_alert_script() was formatted for readability purposes.

TextDescription automatically generated

I wanted to find a path to inject commands into this function but the wguest account had minimal privileges. Since the function is a trigger function, I would need a “mock” event to fire the trigger but wguest did not have access to create a table in the bp schema. Thankfully by default, all PostrgreSQL users have access to the built-in public schema.

I could have created a table from scratch based on the UDF logic but to make it easier I looked for existing tables with the trigger defined. The bp.alerts table had the triggered defined but was disabled for unknown reasons. To craft an exploit, we only need the table definition.

TableDescription automatically generated

At this stage the following conditions make the custom PostgreSQL UDF vulnerable to command injection.

  1. Remote access to the undocumented limited wguest PostgreSQL account.
  2. Privilege to execute a custom UDF trigger that shells out to the operating system.
  3. Privilege to create a table in the public schema.

The following exploit creates a table with a trigger to call the vulnerable UDF when a row is inserted or updated. A crafted malicious row is then inserted by injecting shell metacharacters into the alert_text column. The result is remote command execution as the postgres Linux account. The entire exploit is inside of a transaction. The trigger executes asynchronously and then ABORT is called which forces any changes to be rolled back. The table is never visible to any other connected application.

TextDescription automatically generated

The IP.ADDRESS and PORT values should be changed to a netcat listener of the attacking computer. Using the psql command, execute the SQL with the following command.

TextDescription automatically generated

Once the trigger executes, a postgres reverse shell is received. The ps commands were executed to show the process hierarchy of the reverse shell. With access to postgres the bp.client_credentials table can be queried resulting in all base64 encoded secrets disclosed.

TableDescription automatically generated with medium confidence

Compromising the postgres account is significant and it’s pretty much a game over scenario but let’s see if root access can be achieved. Several opportunities for privilege escalation were found but only one method will be discussed in this blog. A custom setuid root binary was found which created a log file based on a path influenced by a user-controlled environment variable. The log file is created with write permissions to the postgres group. This issue was found using the strace(1) utility while testing in the safe offline test environment.

Using a classic symbolic link attack, arbitrary files can be created on the system. There are several methods to gain root access with an arbitrary file create vulnerability. For this proof of concept, a malicious shared object file is created that the sudo privileged command will load. Note this is not a vulnerability in sudo. The sudo binary along with other privileged binaries search for libraries to load from various paths. For additional details of how this works check, review my write-up on CVE-2019-3466 Debian / Ubuntu Privilege Escalation via pg_ctlcluster. This exploit simply places a crafted library in a path that is searched prior to the real library being loaded and results in arbitrary code execution as the root account. Important: Attacking sudo in this manor will break sudo. The PoC should not be blindly used on real production system.

TextDescription automatically generated

The source code for the trojan library executes a shell. Some binaries require functions from the target library. If these functions don’t exist, the binary will fail to execute and the attack will fail. Sudo requires audit_open() and audit_log_user_message() so stub functions were created to ensure the symbols can be found when the library is loaded.

TextDescription automatically generated

Executing the script produces a root shell completing the compromise of the entire system.

Text, letterDescription automatically generated

Chaining the above issues together is easily automated to receive a root reverse shell. The exploit injects several commands into the vulnerable UDF to download and execute the LPE exploit. The full exploit can be found at the TeamARES Github repo

TextDescription automatically generated


When beginning the research, I could not have anticipated the various issues uncovered. The discovery of the undocumented wguest PostgreSQL account ultimately led to the full compromise of the server. Had access to wguest account been properly hardened, the following attack chain would not have been possible. The fix for wguest was to remove the account. The Perl UDFs have also been removed. Stay tuned for part two where I discuss several unauthenticated remote code execution vulnerabilities.

DiagramDescription automatically generated


05/25/2021 – Email sent to requesting a contact.

05/26/2021 – Email sent to requesting a contact.

06/02/2021 – Requested contact from @unitrends on Twitter.

06/02/2021 – Created Unitrends Zendesk ticket. Received human reply from 5/25 email.

06/02/2021 – Sent vulnerability report via email.

06/25/2021 – 03/09/2022 Various email exchanges and conference call with vendor.


Discovered by Rich Mirch of CyberOne, TeamARES