Cmdguard.sys not only filters file/registry I/O, but also keeps track of running processes by registering a CREATE_PROCESS_NOTIFY_ROUTINE (using PsSetCreateProcessNotifyRoutine). As a process runs, containment status, trust level, and other Comodo relevant attributes are kept track of in a kernel-stored process list. Cmdguard.sys exposes “filter ports” that user-mode Comodo components can talk to. Containment status is set by sending a specific message to its filterport named “cmdAuthPort”. The target process specified in the message then has its “containment” flag set by the kernel mode driver.

Guard64.dll (which is injected into just about every running process) is responsible for sending these containment message from user-mode after contained process creation. For example, Guard64.dll will hook Explorer.exe’s CreateProcessInternalW API so that when a user executes an untrusted process, the hook sends a “containment” message to Cmdguard.sys filter port. Now when untrusted process starts, it is deemed “contained” by the driver and file/registry I/O is prevented. Also, Cmdguard.sys will inject a Guard64.dll into the contained process, which will perform aggressive user-mode hooking.

Figure 2 —Cmdguard.sys’ dll Injection Routine

Below, we can see just a few of user-mode hooks Guard64.dll will set.

Figure 3 — Guard64.dll Usermode Hooks

A common role these hooks play is preventing contained processes from connecting to existing securable objects created by non-contained processes. For this, it will append a “!comodo_6” tag to each object name created or opened by a contained process, preventing name collision (or connection) with existing securable objects on the OS.

In fact, this is how its RPC/ALPC containment works! RPC/ALPC traffic is diverted to contained Svchost.exe instances (seen in the first diagram above). This is because “!comodo_6” is appended to port names contained processes attempt to connect to, and the contained Svchost.exe instances happened to create port names with “!comodo_6” appended to them since they themselves are contained. Here we can see a contained MSI installer trying to run and ends up with a sandboxed MSIexec.exe service component created (under cmdvirth.exe) after issuing its RPC calls.

Figure 4 — Contained ALPC Spawns Contained MSIExec Instance

Bypassing these user mode hooks is trivial, but containment escaping through that is not easy. It was not possible, for example, to simply patch ALPC related hooks and escape via WMI, as these were also monitored and blocked by CmdAgent.exe. Now that I have provided a small primer on Comodo containment, let’s look into how we can achieve an escape and escalation.

Making a Comodo COM Client

Comodo uses many IPC mechanisms between its various AV components: Filter Ports, Shared Memory, LPC, and COM. COM is what we will focus on here. A good primer for COM can be found here, but in short it stands for “Component Object Model” and is a Microsoft technology to allow different modules to create and interface with various objects defined by the COM server. COM servers can be local (just a COM server dll loaded in current process) or remote, a COM server running as a remote process and interacted with over ALPC. Exploitation-wise, remote provides a much more interesting scenario.

We happen to know Comodo has the capability to invoke scan jobs from low-privilege processes such as explorer.exe (via it’s Context Shell Handler — (the menu that appears when user right clicks)) or Cis.exe (Comodo client GUI). These scan jobs are executed by invoking routines in CAVWP.exe which runs as SYSTEM.

If we can understand how to connect ourselves to this service (as they do), then perhaps we can uncover a new attack surface for ourselves and may find even more interesting functions than just “scanning”. This remote interaction with CAVWP.exe happens to be through COM, as CAVWP.exe is an out-of-proc COM server as we see in the registry.