~8 min read
The Key to COMpromise - Writing to the Registry (again), Part 4

In this final part of our series on COM hijacking, we will examine a custom-named pipe IPC protocol implemented by Bitdefender Total Security and detail our approach to reverse engineering it.
We will explore how we could use COM hijacking and this custom communication to gain SYSTEM
privileges (CVE-2023-6154).
Additionally, we will examine how to mitigate the vulnerabilities discussed throughout this series of blog posts.
Lastly, we will demonstrate how COM hijacking can be exploited to perform a Denial-of-Service (DoS) attack on security products.
COM Hijacking
Once again, the targeted product accesses the COM interface for the dataexchange.dll
upon launching the front-end UI. We hijacked this COM interface as described in part one of this series. After hijacking the COM Interface, a DLL we provided was loaded into a front-end process, allowing us to communicate with the back-end processes out of the context of a trusted process.

Our DLL being loaded into the front-end process
To exploit this primitive, we needed a deeper understanding of the communication between the front and back end. The next section details our reverse engineering process.
Reverse engineering the communication
Similar to other security products we analyzed and exploited, the seccenter.exe
(front-end process) communicates with a high-privileged back-end process. However, with Bitdefender, high-level interfaces implemented the communication, so we didn’t have to analyze RPC calls in depth.
During our analysis of the seccenter.exe
, we quickly identified the loaded DLL safeelevatedrun.dll
, which contains some plugin-like interfaces written in C++. Three intriguing strings caught our attention:
CEleveatedOperationsClient
CRegistryOperationsClient
CFileOperationsClient
The strings seem to reference classes implemented within the safeelevatedrun.dll
and provide the high-level interfaces already mentioned for communication with the back-end service.

Initialization of the CRegistryOperationsClient instance in the safeelevatedrun.dll
The CRegistryOperationsClient
class seemed especially interesting, as its name implies it deals with registry operations, which could be a vector to escalate our privileges. Our suspicions were confirmed when we saw the front-end process, seccenter.exe, using the CSecurityCenterApp::SaveRegValue
with reference to a Registry operations client
class object.
This strongly suggested a connection to the CRegistryOperationsClient
class mentioned above.

Usage of the registry operations client from the seccenter.exe`
We needed to obtain an instance of this class to interact with CRegistryOperationsClient
from within the front-end process.
The object was dynamically created via a plugin-like system that passed an internal GUID to a dynamic creation method.

Dynamic plugin instantiation of the CRegistryOperationsClient
Eventually, after some additional (and not so interesting) reverse engineering, we created the following flow to create an instance of the CRegistryOperationsClient
class. This class, we hoped, would allow us to interact with the registry. Unrestricted write interaction with the registry would allow us to escalate our privileges.
- The
seccenter.exe
(and the internalsafeelevatedrun.dll
) dynamically create theCEleveatedOperationsClient
andCRegistryOperationsClient
objects using an internal GUID. - The newly instantiated
CRegistryOperationsClient
object exposed an interface for passing aregistry_ops
structure to the back-end service. - The
CSecurityCenterApp::SaveRegValue
provides a high-level interface to perform the low-level RPC calls to the service.
Or, more detailed:

Abstract flow of the CRegistryOperationsClient object creation and eventual SaveRegValue call
For our exploit, we needed to reverse engineer the essential fields of the registry_ops
structure:
typedef struct {
DWORD hive;
DWORD unknown;
wchar_t key[100];
wchar_t value[100];
DWORD regtype;
wchar_t value2[522];
DWORD value_len_qq;
} registry_ops_t;
One key parameter, DWORD hive
, specifies the registry hive where the registry key would be written.
To target HKEY_LOCAL_MACHINE
, the key’s value had to be set to 0x80000002
, as documented in some Windows internals documentation.
The final exploit call was constructed using the dynamically created registry client object and the crafted registry_ops
structure.
A simplified implementation of this exploit is provided below:
typedef DWORD_PTR(WINAPI* SaveRegvalue_Orig_t)(__int64 this_ptr, registry_ops_t* a2);
// [...]
registry_ops_t ops = { 0 };
ops.hive = 0x80000002;
ops.unknown = 0xFFFFFFFF;
wcscpy_s(ops.key, 0x64ui64, L"SYSTEM\\CurrentControlSet\\Services\\NetSetupSvc");
wcscpy_s(ops.value, 0x64ui64, L"ImagePath");
wcscpy_s(ops.value2, 0x64ui64, L"C:\\poc\\SpawnSystemShell.exe");
ops.regtype = REG_SZ;
ops.value_len_qq = strlen("C:\\poc\\SpawnSystemShell.exe") * 2 + 1;
SaveRegvalue_Orig_t saveRegValue = (SaveRegvalue_Orig_t)((uint64_t)seccenter + 0x10DCF0);
uint64_t global_reg_handler = (uint64_t)((uint64_t)seccenter + 0x198DC0);
saveRegValue(global_reg_handler, &ops);
Escalating our privileges
After understanding the back-end communication, we could write a registry key without restrictions on its path. We aimed to exploit this capability without requiring an admin login or system restart.
We decided to modify the binary path of a service to point to an executable we controlled.
Although many services could be used for this purpose, most required a system restart.
We ultimately chose NetSetupService
because it was not started by default, ran as SYSTEM, and could be started by a low-privileged user.
We created a COM DLL that used the above-mentioned functionality to instruct the back end to change this service’s ImagePath
to a controlled path.
Once the modification was made, we could start the service, which then executed our binary as SYSTEM
.
Our binary then spawned a cmd.exe
process with SYSTEM
privileges on our desktop.
Put together, our exploit worked as follows:
- We hijacked the COM interface for
dataexchange.dll
. - We started the front-end UI to trigger the COM interface and load our DLL into the front end.
- Our DLL would communicate with the back end and instruct the back end to write to the registry.
- The back-end would change the
ImagePath
for theNetSetupService
service. - We place our executable under the new
ImagePath
and start the service. - Our executable is started as
SYSTEM
and spawns acmd.exe
process running asSYSTEM
on our desktop.
Preventing COM hijacking vulnerabilities
To mitigate COM hijacking as an attack vector for privilege escalation, vendors should refrain from giving special privileges to applications running in low-privileged user contexts. Microsoft does not enforce a security boundary between processes running in the same user context, so the vendor is likely to always play catch-up to new techniques being used to inject into other processes. Products requiring administrator privileges for all critical actions, such as setting exclusions, were found to be more resistant to similar exploits.
Vendors may allow users to trigger certain actions without admin privileges for usability. However, they should implement measures to prevent code injection into these processes. The most effective way to do this would be to make the front-end process a Protected Process Light (PPL). Unfortunately, Microsoft does not support PPL for processes providing a UI, according to Microsoft’s documentation.
Therefore, if special permissions are given to the front-end process, the vendor must try to prevent code injection into this process. Most vendors currently do this by using a filter driver. Another measure is hooking the functions involved in DLL loading to enforce signature verification and an allow list. If implemented correctly, this would help against COM hijacking, as described in our posts. However, these methods require ongoing updates to counter new injection techniques that might allow an attacker to execute code in the trusted front-end process.
Denial of Service via COM Hijacking
During this research, we stumbled upon another interesting question: We can inject a DLL into a front-end process of an Endpoint Detection and Response (EDR) via COM. Could we do the same for the back end and, thus, potentially create a Denial of Service (DoS) attack against security solutions?
We often struggle with permanently deactivating the security solution in place on a system so that it does not interfere with our tooling.
Note: You do not want to do this on production systems. However, we often use dedicated systems set up just for a project and get wiped afterwards. Deactivating security solutions on specific systems in penetration testing scenarios can be justified, as it increases the efficiency of the pentesters’ work and allows testing of blue team responses.
COM hijacking enabled us to inject a DLL into a central back-end process of the security solution. The most direct approach was to terminate the process upon DLL load, effectively disabling the security software. A more advanced method could involve suspending specific process functions to make the solution appear functional while neutralizing its effectiveness.
So, do the back-end processes even use COM?
Some of our targeted products did.
We found two EDR products whose back-end processes utilized COM interfaces, which we were able to hijack.
For our proof of concept, we terminated the process every time our DLL was loaded by one of the security vendors’ processes.
This effectively disabled the security solution and allowed us to execute tools like mimikatz
without interference.
As this requires SYSTEM
privileges and is only a DoS issue rather than a privilege escalation issue, both vendors we reported this to declined to issue a fix. Thus, this might remain a viable technique for the next time you want to get rid of an EDR and do not need to be too stealthy.
Conclusion
In this final part of the series, we detailed the reverse engineering of a custom IPC protocol and demonstrated how we combined it with COM hijacking to gain SYSTEM
privileges.
We also explored mitigation techniques to prevent similar vulnerabilities and discussed how COM hijacking can facilitate DoS attacks against security products.
This concludes our series of blog posts on COM hijacking. We hope that you enjoyed reading it and gained some insights from it.