Code42 Backup solution Agent takeover & OS Priviledge Escalation
Code42 is an endpoint backup solution used by over 50,000 organizations worldwide, establishing itself as one of the leading backup solutions.
My friends and I collaborated to audit Code42 last year, and their great skills enabled us to discover a vast number of critical vulnerabilities. The vulnerabilities include Agent takeover, Arbitrary file read in Linux, and Privilege escalation in Windows. The vulnerable version is <= 12.0.0, users are recommended to update to the version >= 12.0.1.
When the application is installed, it consists of two components: the Code42 application for the user, and Code42Services, which runs with root/system permissions on port 4244.
Let’s explore some of them further.
I. Agent takeover
With Code42, the endpoint is auto-backed up when user input is the valid credential into the application, or in other words, the service is authenticated.
It needs to provide a username, password, and a domain backup server address for this account. I am not sure how they designed it before, it would have a separate backup server for each organization, but even if an endpoint is logged in or not, an attacker still can take over it.
The rationale behind is that, beyond the conventional direct input mechanism within the application, an alternative authentication pathway exists in the form of an API facilitated by Code42Service.
However, when the API is triggered, it automatically backs up the entire endpoint to the cloud associated with the account. This happens even if the API is called without user interaction or without the user having previously logged into the application (by another credential).
Unfortunately, this service was only running on the localhost interface, if it was not, an attacker with network access to the target machine can take over it. However, the attack scenario seems feasible because it was vulnerable to CSRF also.
An attacker crafts a malicious HTML link that contains a request to the Code42Service endpoint and the attacker credential. When users that installed Code42 on their machines click on that link, it auto logins into the attacker account and everything from the user machine will be backed up into the attacker cloud server (whether they have ever logged into another account or not, and no matter about the cloud server, just need the internet).
That person can pwn the whole world by his account (an account can be self registered in Code42 server).
II. Privilege escalation via deserialization
Code42 application is a combination, with ElectronJS as the front end and Java as the back end. A user can start the app to use Code42 as a normal user, but Code42Service was running as SYSTEM/root.
I will talk about Windows first. When backing up, a user has 2 options. The first one is backing up to the cloud, and the second is to a local folder.
In the local, it creates a bunch of files
In com.code42.backup.manifest.ManifestManager#getRemoteRetentionPolicy
, it reads the data from “cprp
” file and deserializes it
The readObject
function called com.code42.io.CompressUtility#uncompressObject
which the data is unzipped from the GZip string stream and deserialized, leading to arbitrary deserialization of untrusted data vulnerability. If we can make it deserialize a gadget that runs a shell command, it will run as the Code42Service permission, which is SYSTEM.
The last piece of this vulnerability is a valid gadget. CommonsBeanutils1 worked perfectly. We just needed to wrap it up with GZip input and make the cprp file deserializable. Because we can choose the backup location, we had permission to overwrite the cprp files. Each time we clicked on Run maintenance, the deserialization process happened.
As we can make it run any command we want, every command inherits the permission of Code42Service, which is NT AUTHORITY\SYSTEM.
But in Linux, somehow we can’t overwrite the cprp file
So we have the bug there but we can’t exploit it in Linux. At the time I wrote this article, I found another spot that led to deserialization vulnerability.
In com.backup42.service.upgrade.platform.PlatformUpgradeFileUtility#loadServiceModel
, it took the data from the model file in <app_installation>/conf/service.model
, decrypted and deserialized it. But the decryption key is hardcoded in the source code so we just need a small piece of code to make it done
However, as mentioned, we still need high privileges to write the values of this file.
Code42 developer fixed the vulnerability by adding whitelist classes for deserializing in com.code42.io.C42WhitelistObjectInputStream#C42WhitelistObjectInputStream
Basically, if we can find a valid gadget from these classes, it is again exploitable. In a pure initial effort, I couldn’t find the legitimate one, as the classes are quite limited. Will try harder next time.
III. Read arbitrary files
As we saw, in Linux we didn’t exploit it. We ended up with an arbitrary file read in Linux.
In the get logs command, it took all files that end with .log inside ~/.code42/log/ folder (via getOnlyLogFilesFilter()
function)
And then added them into a zip file inside /usr/local/crashplan/log/
We can create a symlink to the file we want to read to the .log file inside ~/.code42/log
and let its content be copied into the zip file, but the server checked and ignored if it is a symlink inside the getOnlyLogFilesFilter()
function
It wouldn’t easily work, but we combined it with a Time-of-check to time-of-use (TOCTOU) vulnerability, by creating a normal aa1.log file to bypass the symlink check, then removing and replacing it with a symlink to the file we want to read (e.g. /etc /shadow
). Winning the race was what we expected.
*/ Bonus: Another PE in Windows
When we backup, we can set it to run the ScanState.exe command in every folder we want
Unfortunately, it needs a valid digital signature from Microsoft. ScanState is a tool from the USMT tool of Microsoft.
Again, we can leverage the TOCTOU, using a valid ScanState.exe file to bypass the check and then replace it with our malicious ScanState.exe file. At the time I wrote this article, I couldn’t create the POC because it needed a VIP plan to use the USMT function.
Shoutout to yeuchimse!