COM Hijacking: How a Registry Lookup Order Lets a Standard User Replace System Components
Introduction
COM hijacking is one of those vulnerabilities that doesn't come from a coding mistake in the traditional sense — it comes from a design decision in how Windows resolves component lookups, combined with default permissions that favor convenience over security. The result is that a completely standard, unprivileged user can quietly redirect a trusted application into loading a DLL of their choosing, with no admin rights and no UAC prompt involved anywhere in the process.
What COM Hijacking is?
COM (Component Object Model) is a Windows system that lets applications borrow features from each other without needing to know where those features actually live on disk. An application essentially says "give me the PDF renderer," and Windows looks up a registry key called a CLSID to determine which DLL provides that feature, then loads it.
What Is a CLSID?
A CLSID is a unique 128-bit identifier (a GUID) assigned to every COM component. It looks something like {D3E34B21-9D75-101A-8C3D-00AA001A1652}. Windows uses this identifier to figure out exactly which DLL to load whenever a component is requested.
Where Is It Stored?
CLSID registrations live in the Windows registry, under two separate hives: HKLM (system-wide, writable only by administrators) and HKCU (per-user, writable by any standard user). Windows checks HKCU first — and that ordering is the entire vulnerability.
If the HKCU entry for a given CLSID doesn't exist, a standard user can simply create it and point it to any DLL of their choosing. Windows will then load that DLL inside the thick client's process, every single time the application launches.
The Registry Lookup Order - Why HKCU Wins
When an application calls CoCreateInstance({CLSID}), Windows searches two locations, in this order, and uses whichever one it finds a match in first:
|
Location |
Path |
Notes |
|
HKCU |
Software\Classes\CLSID\{GUID}\InProcServer32 |
Checked first — user writable |
|
HKLM |
SOFTWARE\Classes\CLSID\{GUID}\InProcServer32 |
The real, legitimate entry lives here |
|
|
|
|
HKCU is completely writable by any standard domain user — no admin rights required, no UAC prompt triggered. If the HKCU key is absent for a given CLSID, the attacker simply creates it. If it already exists, they may be able to modify it. Either way, Windows loads whichever DLL path the HKCU key points to, without question.
What the attacker's planted key actually looks like:
HKCU\Software\Classes\CLSID\{TARGET-GUID}\InProcServer32
(Default) =
C:\Users\attacker\AppData\Local\evil.dll
ThreadingModel = Apartment
Any standard user can create this with a single reg add command. No elevation, no UAC, no warning shown to anyone.
Steps to Reproduce:
Step 1 — Capture CLSID lookups that fail in HKCU
Open Process Monitor and apply the following filters:
Process Name =
target.exe
Operation = RegOpenKey
Path contains InprocServer32
Result contains NAME NOT FOUND
Run the application and capture the trace. This surfaces every CLSID the application looks for in HKCU but doesn't find there.
Step 2 — Confirm the CLSID resolves via HKLM/HKCR
From the captured CLSIDs, identify one that resolves successfully via HKCR/HKLM. This confirms the entry genuinely exists in HKLM and is currently being served from there as a fallback.
Step 3 — Check write access on the target DLL's directory
Since the payload needs to be planted somewhere on disk, check whether the existing DLL's directory is writable:
icacls "C:\Program Files\test\abc\gateway"
Step 4 — Place the malicious DLL in that directory
copy malicious.dll "C:\Program Files\test\abc\gateway\malicious.dll"
Step 5 — Register the planted DLL under the target CLSID in HKCU
This makes it take priority over the legitimate HKLM entry:
reg add "HKCU\Software\Classes\CLSID\{7EB885F2-6277-4257-932E-4C4C65C1240A}\InprocServer32" /ve /t REG_SZ /d "C:\Program Files\test\abc\gateway\malicious.dll" /f
Step 6 — Verify the registry entry was created correctly
reg query "HKCU\Software\Classes\CLSID\{7EB885F2-6277-4257-932E-4C4C65C1240A}\InprocServer32" /s
Step 7 — Launch the application and confirm execution
Confirm the malicious DLL executes instead of the legitimate COM server — visible via a popup or other observable marker from the test payload.
Step 8 — Re-check Process Monitor
Confirm the same CLSID now resolves successfully from HKCU, instead of returning NAME NOT FOUND as it did in Step 1.
Impact
|
Scenario |
Impact |
|
Persistence |
The malicious DLL loads every time the application starts or the COM object is instantiated — surviving reboots without requiring any elevated privileges. |
|
Privilege Escalation |
If the calling process runs as SYSTEM, LocalService, or any other elevated context, the attacker's code executes at that same higher privilege level. |
|
Code Execution |
The attacker gains arbitrary code execution within the context of the target application, which may have access to sensitive data, network resources, or other system functions. |
|
Lateral Movement |
The compromised host can subsequently be used as a pivot point within the broader network. |
Remediation:
Immediate (Application Vendor)
1. Harden directory permissions. Remove Modify/Write access for BUILTIN\Users from C:\Program Files\abc\xyzapp\gateway\ and all of its subdirectories. Standard users should only ever have Read & Execute (RX) access under Program Files:
icacls
"C:\Program Files\abc\gateway" /inheritance:e
icacls "C:\Program Files\abc\gateway" /remove "Users"
icacls "C:\Program Files\abc\gateway" /grant
"Users:(OI)(CI)(RX)"
2. Remove dependency on external COM objects. If the application does not genuinely require the CLSID in question — for example {4590F811-...} (cdfview.dll, a legacy Windows component for Channel Definition Format that is now deprecated) — remove the dependency entirely. If the dependency is required, the application should not rely on HKCU-resolvable COM lookups for anything security-sensitive.
3. Migrate away from unsafe COM patterns. Register required CLSIDs with explicit path validation, or use strong-named assemblies with digital signature verification performed at load time, rather than trusting whatever the registry resolution happens to return.
Detection/Monitoring (Defenders)
4. Monitor HKCU COM registrations. Deploy detection rules (Sigma, EDR) for registry writes under:
HKCU\Software\Classes\CLSID\{*}\InprocServer32
This is especially important for known hijackable CLSIDs — {4590F811-1D3A-11D0-891F-00AA004B2E24} is included in the hayabusa-rules Sigma detection list specifically for COM hijacking.
5. Alert on anomalous DLL loads. Correlate HKCU CLSID registry modifications with subsequent DLL loads from non-standard paths, such as ProgramData, Temp, or user profile directories.
Closing Thoughts
COM hijacking is a reminder that a security boundary is only as strong as its weakest checked location — and here, Windows checks the user-writable location first. The fix isn't really about patching a bug in target.exe; it's about removing the gap between where the application trusts a component to come from and where a standard user is actually allowed to write. Tight directory ACLs, reduced reliance on legacy COM dependencies, and active monitoring of HKCU registry writes together close most of the practical exposure here.
Thanks for reading ๐
Feel free to point out any mistakes or let me know if there is anything I should add ๐
Keep Learning, Keep growing ๐
Comments
Post a Comment