This vulnerability was discovered by Tomer Peled, Netanel Cohen and Amir Shen from Bugsec Security Research team
Plex Media Server is a global streaming media service and a client–server media player platform.
The media server is used by millions of people across the world, both as a cloud service and as an on-premises platform for their media.
Since the platform is so widely used as a platform, we’ve decided to explore and see if we can tinker with it and find some exploits.
While surveying the attack surface of the application we discovered that MS-RPC was a main function within the update functionality.
“RPC is a powerful, robust, efficient, and secure inter–process communication (IPC) mechanism that enables data exchange and invocation of functionality residing in a different process. That different process can be on the same machine, on the local area network, or across the Internet. “
We confirmed the existence of RPC by reverse engineering the update service executable:
Further inspection using RPCView revealed the RPC interfaces and endpoints that are registered with the operating system.
After getting the function signatures, protocol UUID and endpoint names we had everything we needed to customize our own RPC client and communicate with the Plex Update Service.
Looking at the address given by RPCView and a little bit of reverse-engineering we found two functions of interest: Install() and CheckBundle().
- CheckBundle() checks the file specified by a given path is a legitimate plex update file (Check is performed by digital signatures).The given path to the update file is controlled by the caller of the RPC.
- The Install() function will first call CheckBundle() and if the file is a legitimate update file it will execute the file, which in turn is responsible for updating the plex server.
In order for an exploit to work, we needed to make sure that when Install() executes the update file it is executed as SYSTEM (since the actual process that executes it is the updater, which is a service that runs under SYSTEM).
In order to do that, we made sure that the update client did not use the RPCImpersonateClient() or CreateProcessAsUser() WinApi calls, which would have forced the RPC call to run under the user context, instead of SYSTEM.
Once we realized that the update file is indeed executed as SYSTEM, and no security measures are in place to prevent a regular non-privileged user from controlling the update file path – we saw the opportunity for the exploit.
TOCTOU using CreateFileMapping:
The main culprit in this vulnerability is a gap between CheckBundle() validating the update file, and the actual execution of the update file – Two distinct CreateFile() calls are made on the file.
This means that even if the first call actually got the correct update file and validated it there was still a chance to replace the original update file with a malicious one for the second CreateFile() call – a classical TOCTOU attack.
As with any TOCTOU there is a race condition for the execution of this attack.
In order to ensure we win the race condition every time, we will utilize the “SetOpLock” tool by James Forshaw  which allows us to control access to a file.
In order to further harden our exploit and make it even more reliable, we chose to create the malicious “update” file on a separate computer then the Plex Media Server itself.
Since we control the computer that the malicious “update” file is on, we have more control over the behavior of the race condition.
Note that it is also possible to run this exploit using a local path, meaning the malicious “update” file resides on the same computer as the Plex Media Server.
On the Plex Media Server machine the attacker needs to start a simple RPC communicator and call the RPC endpoint function Install() from “Plex Update Service.exe” using the malicious “update” file as the path parameter.
If the malicious file resides on a different computer, the path should be the SMB path to the file.
On the Attacker computer We will use SetOpLock to lock and notify us when someone attempts to access the file:
Once the “Plex Update Service” attempts to access the update file because of the Install() RPC call we made, we will allow it to access the file for a set number of times– exactly enough for it to validate the file via CheckBundle().
Once the file is validated, we lock it again and get notified when Install() is attempting to read the file in order to execute it.
At this point we use the legitimate update files’ handle to replace its content with our malicious content via the File Mapping WinApi –
CreateFileMapping -> MapViewOfFile -> CopyMemory WinAPI’s
With our malicious payload now in place the program will release the file handle and allow the Plex Update Service to execute our malicious file:
TOCTOU using Mount Points:
Further research revealed another technique to perform our TOCTOU exploit.
We noticed that the access order to the update bundle (After calling Install() ) is as follows:
- Read the update file to check its digital signature
- Read CACERT.pem
- Read the update file again
- Execute the bundle from the location
The other technique we used to implement TOCTOU was to create a junction folder 
which was first linked to a folder that contained a valid update file.
In order to always win the race condition, we set an OpLock on CACERT.pem with a callback function (Since we know that as soon as the update service requests an handle to CACERT.crt it has already finished its validity check).
The callback function creates a new mount point (on the junction folder) to the folder containing the malicious update.
This will cause the filesystem to serve the malicious file to the Plex server since the symbolic link points to the malicious directory, not the original directory.
As we’ve seen, RPC provides an attack surface ripe for exploits – it is only a matter of understanding the functionality of the RPC endpoints and customizing the calls.
From a security perspective it is possible for a vendor to eliminate much of the RPC attack surface, but this requires fairly deep understanding of RPC mechanisms, and thus many vendors do not implement these mitigations.
14/10/21 – First Contact with Plex Security Team
15-28/10/21 – Communication with Plex team to resolve this issue
25/10/21 – CVE was assigned by MITRE
01/12/21 – Plex issued a patch fixing this vulnerability