1. Executive summary
Kaspersky has published analysis of NetamLoader, a .NET assembly-loading framework delivered through a tampered Patch My PC update package that sat in the Windows update download directory (C:\Windows\SoftwareDistribution\Download\) of a single victim in Asia. The loader chains AppDomainManager injection, a BinaryFormatter deserialization flaw in a Microsoft-signed assembly, and multiple XAML stages to reach a final .NET plugin that beacons to openaigpt4v[.]com over AES-128-CBC with HMAC-SHA256. Kaspersky assesses the target as a Windows build customised for government use in Asia and states it could not link the activity to any known APT group. No CVE has been assigned and no entry exists in NVD, EPSS or CISA KEV, so there is no patch to apply and no exploitation deadline to track. The direct risk to EMEA financial services is low: no victim, no targeting and no infrastructure overlap with the sector has been reported. The exposure that matters is architectural. The chain runs entirely through signed Microsoft binaries and a legitimate patch-management tool, so signature-based controls do not see it, and any firm running third-party patch tooling inside SoftwareDistribution should assume the same delivery path is available to it.
2. Regulatory framing
No specific DORA/NIS2 article is directly engaged by this item.
3. Technical analysis & attack chain
Kaspersky did not observe delivery. The first artefact is a CAB archive named e4537a1762fcafd2fd96bfc825bad34f9db9a24d sitting in C:\Windows\SoftwareDistribution\Download\, the directory Windows uses for operating system update packages. The archive extracts seven files to C:\Windows\SoftwareDistribution\Download\Install\, and the chain begins when PatchMyPC-ScriptRunner.exe runs with the arguments -updatepackage -applicationid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Six of the seven files are clean. Only Resources.resx carries the payload. The rest are legitimate Patch My PC components and Microsoft-signed .NET assemblies, which is why the initial triage of the CAB found nothing.
The confirmed execution sequence:
PatchMyPC-ScriptRunner.exestarts and the CLR readsPatchMyPC-ScriptRunner.exe.configfrom the same directory before the executable's entry point runs. The config setsappDomainManagerAssemblytoMicrosoft.HostIntegration.Connectors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35andappDomainManagerTypetoMicrosoft.ApplicationServer.Caching.DataCacheFactoryConfiguration. Both are Microsoft-signed.DataCacheFactoryConfigurationis the Windows Server AppFabric Cache Client configuration class. On instantiation it looks forfabric.configin the same directory and reads it. The plantedfabric.configsetsclassNametoSystem.Resources.ResXResourceSet, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089(Resources.resx), so aResXResourceSetis constructed againstResources.resx.Resources.resxholds a Base64-encoded object serialised withBinaryFormatter. Parsing it callsBinaryFormatter.Deserialize(), which Kaspersky describes as a TypeConfuseDelegate deserialization attack. The delegate invokesXamlReader.Parse()on an embedded XAML payload (XAML-1).- XAML-1 acts as a loader for XAML-2 and then calls
Environment.Exit(0)to kill the host process before any error dialog can appear. - XAML-2 carries two Base64-encoded, ZIP-compressed XAML files, XAML-2-1 and XAML-2-2, each loaded in memory with
XamlReader.Load(). - XAML-2-1 is 796 lines whose only job is AMSI bypass. It checks
IntPtr.Size == 8and aborts if the host is not 64-bit. It patchesConsole.Clear()in memory with the bytes41 C7 00 01 00 00 00 33 C0 C3. It then walks theIUnknownvirtual method table of the AMSI object, adds0x18to reach theCAmsiAntimalware::Scanpointer, callsVirtualProtect()to make it writable, and overwrites it with the address of a patched routine returningAMSI_RESULT_CLEAN(0). Sensitive strings are split into short fragments and reassembled at parse time. One patch lands in the memory of an existing legitimate module and the other only alters AMSI virtual tables, so code integrity checks pass. - XAML-2-2 carries the .NET 1 Loader assembly and a JSON configuration (JSON-1), both ZIP-compressed and Base64-encoded. The loader is instantiated with
Assembly.CreateInstance()and JSON-1 is passed to itsm.C()method. - .NET 1 Loader parses JSON-1, which contains a nested configuration (JSON-1-p) with the C2 URL
https://openaigpt4v.com/model_v4/, a trusted certificate thumbprint fieldtpset to*(any certificate accepted, so certificate pinning is disabled), the AES master key9fT04e03tAiZAPogcDWt0w==, and the encrypted XAML-3 template set inibiwith its key inibk. - .NET 1 Loader reads
SusClientIdfromHKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdateand derives a per-victim identifiersifrom it. It sets the environment variableCOMPlus_ETWEnabledto0throughWScript.Shell(CLSID41904400-BE18-11D3-A28B-00104BD35090), which stops the CLR registering the .NET ETW provider and hides the associated events. - XAML-3 is decrypted from the
ibi/ibkmaterial and loaded in a new process,dllhost.exe, reached through COM. The plugin writesDllSurrogate = ""underHKCU\Software\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2}, creates the COM object, and callsCoLockObjectExternal()so the surrogate is not released. The AMSI bypass from XAML-2-1 is re-applied in the new process through the__P1__placeholder. - The .NET 2 Plugin (hash
CFB8B281BDF5D9390E64B10C312FB2C1) runs indllhost.exe. It collects host reconnaissance: the .NET Framework version fromHKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\fullvalueVersion, and the build string fromHKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersionvalueBuildLab(the example given is4.7.03190\n17763.rs5_release.180914-1434). Failed queries are replaced with a hyphen. - The plugin resolves proxy configuration three ways (WinHTTP,
WebProxy.GetDefaultProxy(), and impersonation of the current user) so it can reach the internet from proxied networks. It then beacons tohttps://openaigpt4v[.]com/model_v4/<si>?b=<encrypted>&c=<si>with aServerCertificateValidationCallbackthat accepts any certificate becausetpis*.
Traffic is AES-128-CBC with Encrypt-then-MAC: a random 16-byte IV, the ciphertext, then a 32-byte HMAC-SHA256 over IV plus ciphertext. Per-direction keys are derived from the master key with HMAC using single-byte seeds 0 to 3. The C2 response is parsed by a second-stage XAML loaded through a CrossAppDomainDelegate whose _invocationList is rewritten by reflection to point at XamlReader.Parse(), keeping the downloaded payload out of the main AppDomain.
Timing is deliberate. The plugin waits 100801 seconds (about 28 hours) before its first callback and then exits. If the C2 does not answer, polling backs off to 79200 to 100800 seconds (22 to 28 hours). The initial connection delay is 1200 to 2400 seconds (20 to 40 minutes). These intervals defeat sandboxes that run for minutes.
Persistence is not described in the source. Kaspersky documents the loader chain and the C2 protocol but does not state a run key, scheduled task or service. Treat persistence as unknown rather than absent.
The C2 domain openaigpt4[.]com resolved to 104.18.14[.]219, first seen 27 September 2023, registered through Cloudflare and hosted on Cloudflare's CDN (ASN 15169). Kaspersky notes the use of commercial hosting infrastructure.
Confidence caveats. All of the above is single-sourced to Kaspersky. Kaspersky reports one victim in Asia identified from KSN telemetry and infers government targeting from the customised Windows build, not from confirmed victim identity. The attribution is unconfirmed: Kaspersky states it could not link the TTPs, code or infrastructure to any known APT group, and no MITRE ATT&CK profile exists for this activity. The tp field is described by Kaspersky as suspected to be a trusted SSL certificate thumbprint. The delivery vector is unknown; the CAB's presence in SoftwareDistribution is consistent with a supply-chain or update-path compromise but Kaspersky does not confirm how it got there.
4. Mitigation & containment
P1 (within 24 hours)
- Hunt for the CAB filename
e4537a1762fcafd2fd96bfc825bad34f9db9a24dand for any.configfile inC:\Windows\SoftwareDistribution\Download\or itsInstall\subdirectory that containsappDomainManagerAssemblyorappDomainManagerType. Legitimate Windows update packages do not ship CLR AppDomainManager configuration there. - Block
openaigpt4[.]comand104.18.14[.]219at egress proxy, DNS and firewall. The domain is Cloudflare-fronted, so block by full hostname and by the resolved address rather than by CDN range. - Alert on
dllhost.exemaking outbound HTTPS to a host it has no COM activation history with, and ondllhost.exewriting toHKCU\Software\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2}. - If Patch My PC is deployed, confirm the publisher's binaries and their
.configfiles against a known-good hash set from the vendor. AnyPatchMyPC-ScriptRunner.exe.configthat is not the vendor's own file is a compromise indicator.
P2 (within 72 hours)
- Audit which accounts and processes can write to
C:\Windows\SoftwareDistribution\Download\. Restrict write access to SYSTEM and the Windows Update service. A non-Microsoft process placing files there is the precondition for this chain. - Enable PowerShell script block logging, module logging and AMSI logging to a collector that does not depend on the local AMSI provider, since the loader patches AMSI in memory. Forward
Microsoft-Windows-DotNETRuntimeevents off-host; the loader setsCOMPlus_ETWEnabled=0to suppress them locally, so local-only collection will be blind. - Deploy the YARA rule in §6 to EDR and file-scanning tiers, scoped to
.config,.resxand.cabfiles underSoftwareDistributionand to user-writable paths.
P3 (within 7 days)
- Review third-party patch-management tooling for update integrity: signed manifests, hash verification before execution, and execution from a directory the tool controls rather than from
SoftwareDistribution. - Add a detection for
BinaryFormatter.Deserialize()reachable fromResXResourceSetparsing in processes that should never deserialise untrusted.resxfiles. .NET 4.6 does not enable the saferBinaryFormatterswitch by default; where the application allows it, setSwitch.System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerializationtofalseinruntimeconfigor viaAppContext, and test that Patch My PC and other managed tools still function. - No vendor fix exists for this chain. There is no CVE, so there is no patch to schedule. The controls above are the remediation.
5. Indicators of compromise
All indicators are single-sourced to Kaspersky; verify before enforcement. Hashes are MD5 as published.
| type | value | confidence | source |
|---|---|---|---|
| md5 | f2458ed133f8d0ca19e22c10f577e98e | high | Kaspersky Securelist |
| md5 | e4537a1762fcafd2fd96bfc825bad34f9db9a24d | high | Kaspersky Securelist |
| md5 | e1dc6f1ed193594f2284be22ae08dfa4 | high | Kaspersky Securelist |
| md5 | ab81564bcb8ca7e710c66832de747556 | high | Kaspersky Securelist |
| md5 | cfb8b281bdf5d9390e64b10c312fb2c1 | high | Kaspersky Securelist |
| md5 | 67e3617f8709d34f806f8e02badba8a5 | high | Kaspersky Securelist |
| md5 | 514ac0d73b8a1b73488ef5e2e55a75c3 | high | Kaspersky Securelist |
| md5 | 514117d536e347560d049cfe0c609632 | high | Kaspersky Securelist |
| md5 | 9000820d8153c24cd60d53001d3a97b6 | high | Kaspersky Securelist |
| md5 | b3c4a635179680edafb5d006cf0cffc6 | high | Kaspersky Securelist |
| md5 | 4f28622c5e60c01319bf48cf742fe1a5 | high | Kaspersky Securelist |
| md5 | c86d53392a87dd3f3e62d62c9b92a9bd | high | Kaspersky Securelist |
| domain | openaigpt4[.]com | high | Kaspersky Securelist |
| ipv4 | 104.18.14[.]219 | high | Kaspersky Securelist |
| url | hxxps://openaigpt4[.]com/model_v4/ | high | Kaspersky Securelist |
| filepath | C:\Windows\SoftwareDistribution\Download\e4537a1762fcafd2fd96bfc825bad34f9db9a24d | high | Kaspersky Securelist |
| filepath | C:\Windows\SoftwareDistribution\Download\Install\PatchMyPC-ScriptRunner.exe.config | high | Kaspersky Securelist |
| filepath | C:\Windows\SoftwareDistribution\Download\Install\fabric.config | high | Kaspersky Securelist |
| filepath | C:\Windows\SoftwareDistribution\Download\Install\Resources.resx | high | Kaspersky Securelist |
| registry | HKCU\Software\Classes\appid{ff259bcd-2f0a-44de-b34a-0092fec1d8a2} | high | Kaspersky Securelist |
The hash-to-file mapping published by Kaspersky is: f2458ed133f8d0ca19e22c10f577e98e is the CAB archive e4537a1762fcafd2fd96bfc825bad34f9db9a24d; e1dc6f1ed193594f2284be22ae08dfa4 is Resources.resx; ab81564bcb8ca7e710c66832de747556 is the .NET 1 Loader; cfb8b281bdf5d9390e64b10c312fb2c1 is the .NET 2 Plugin; 67e3617f8709d34f806f8e02badba8a5 is fabric.config; 514ac0d73b8a1b73488ef5e2e55a75c3 is PatchMyPC-ScriptRunner.exe.config; 514117d536e347560d049cfe0c609632 is XAML-1; 9000820d8153c24cd60d53001d3a97b6 is XAML-2; b3c4a635179680edafb5d006cf0cffc6 is XAML-2-1; 4f28622c5e60c01319bf48cf742fe1a5 is XAML-2-2; c86d53392a87dd3f3e62d62c9b92a9bd is XAML-3.
md5 f2458ed133f8d0ca19e22c10f577e98e
md5 e4537a1762fcafd2fd96bfc825bad34f9db9a24d
md5 e1dc6f1ed193594f2284be22ae08dfa4
md5 ab81564bcb8ca7e710c66832de747556
md5 cfb8b281bdf5d9390e64b10c312fb2c1
md5 67e3617f8709d34f806f8e02badba8a5
md5 514ac0d73b8a1b73488ef5e2e55a75c3
md5 514117d536e347560d049cfe0c609632
md5 9000820d8153c24cd60d53001d3a97b6
md5 b3c4a635179680edafb5d006cf0cffc6
md5 4f28622c5e60c01319bf48cf742fe1a5
md5 c86d53392a87dd3f3e62d62c9b92a9bd
domain openaigpt4[.]com
ipv4 104.18.14[.]219
url hxxps://openaigpt4[.]com/model_v4/
filepath C:\Windows\SoftwareDistribution\Download\e4537a1762fcafd2fd96bfc825bad34f9db9a24d
filepath C:\Windows\SoftwareDistribution\Download\Install\PatchMyPC-ScriptRunner.exe.config
filepath C:\Windows\SoftwareDistribution\Download\Install\fabric.config
filepath C:\Windows\SoftwareDistribution\Download\Install\Resources.resx
registry HKCU\Software\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2}
Behavioural indicators, since the atomic set above is small and the loader's value is in its behaviour:
| behaviour | where to observe | confidence |
|---|---|---|
CLR AppDomainManager configuration in a .config file under SoftwareDistribution |
file creation events, EDR file telemetry | high |
PatchMyPC-ScriptRunner.exe spawning dllhost.exe that then makes outbound HTTPS |
process creation and network telemetry | high |
dllhost.exe writing DllSurrogate under HKCU\Software\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2} |
registry auditing | high |
COMPlus_ETWEnabled set to 0 in a process environment |
process environment capture, EDR | high |
Console.Clear() and AMSI Scan patched in memory |
memory scanning, not file scanning | high |
outbound HTTPS to openaigpt4[.]com with a path of /model_v4/<GUID> and query parameters b and c |
proxy and TLS logs | high |
reads of SusClientId under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate by a non-Windows-Update process |
registry auditing | medium |
%LOCALAPPDATA%\Microsoft\CLR_v4.0\UsageLogs\PatchMyPC-ScriptRunner.exe.log and %WINDIR%\Prefetch\PATCHMYPC-SCRIPTRUNNER.EXE-*.pf created on a host that does not run Patch My PC |
file creation telemetry | medium |
6. Detection
The YARA rule targets the loader's configuration artefacts and the AMSI patch bytes. The strings are exact values from the Kaspersky report. The PatchMyPC-ScriptRunner.exe.config and fabric.config strings are specific to the malicious files, not to the legitimate Patch My PC tool, but test against your own Patch My PC deployment before enabling in blocking mode.
rule APT_NetamLoader_AppDomainManager_Chain
{
meta:
author = "Adverse Trace"
date = "2026-10-29"
reference = "https://securelist.com/netamloader/121676/"
description = "Detects NetamLoader AppDomainManager injection config, fabric.config loader and AMSI patch bytes"
tlp = "AMBER"
strings:
$adm_type = "Microsoft.ApplicationServer.Caching.DataCacheFactoryConfiguration" ascii wide
$adm_asm = "Microsoft.HostIntegration.Connectors, Version=1.0.0.0" ascii wide
$fabric = "System.Resources.ResXResourceSet, System.Windows.Forms" ascii wide
$resx = "Resources.resx" ascii wide
$amsi_patch = { 41 C7 00 01 00 00 00 33 C0 C3 }
$etw_off = "COMPlus_ETWEnabled" ascii wide
$c2_path = "/model_v4/" ascii wide
$c2_host = "openaigpt4" ascii wide
$appid = "{ff259bcd-2f0a-44de-b34a-0092fec1d8a2}" ascii wide nocase
condition:
uint16(0) == 0x5A4D and
(
(2 of ($adm_type, $adm_asm, $fabric, $resx)) or
$amsi_patch or
(2 of ($etw_off, $c2_path, $c2_host, $appid))
)
}
The Sigma rule covers the process and registry behaviour. It assumes Sysmon with process creation, network and registry events, or equivalent EDR telemetry.
title: NetamLoader dllhost COM surrogate with AppDomainManager config and C2 beacon
id: 7c1e4b2a-9f3d-4a61-8b0e-2d5c6f7a8b91
status: experimental
description: Detects NetamLoader behaviour - PatchMyPC-ScriptRunner spawning dllhost.exe, DllSurrogate registry write, and outbound HTTPS to openaigpt4 domain
author: Adverse Trace
date: 2026/10/29
references:
- https://securelist.com/netamloader/121676/
tags:
- attack.defense_evasion
- attack.t1218
- attack.t1055
logsource:
product: windows
category: process_creation
detection:
selection_parent:
ParentImage|endswith: '\PatchMyPC-ScriptRunner.exe'
Image|endswith: '\dllhost.exe'
selection_cmdline:
CommandLine|contains:
- '-updatepackage'
- '-applicationid='
condition: selection_parent or selection_cmdline
fields:
- Image
- ParentImage
- CommandLine
- User
falsepositives:
- Legitimate Patch My PC update runs spawning COM surrogates
level: high
---
title: NetamLoader DllSurrogate registry write
id: 3a8d5e1f-6b2c-4c7d-9e0a-1f2b3c4d5e6f
status: experimental
description: Detects write of DllSurrogate under the NetamLoader appid CLSID
author: Adverse Trace
date: 2026/10/29
references:
- https://securelist.com/netamloader/121676/
logsource:
product: windows
category: registry_set
detection:
selection:
TargetObject|contains: '\SOFTWARE\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2}'
Details: ''
condition: selection
falsepositives:
- Unknown
level: high
---
title: Outbound connection to NetamLoader C2 host
id: 9b4c2d1e-8a7f-4e3b-b6c5-0d9e8f7a6b5c
status: experimental
description: Detects network connections to openaigpt4 domain or 104.18.14.219 used as NetamLoader C2
author: Adverse Trace
date: 2026/10/29
references:
- https://securelist.com/netamloader/121676/
logsource:
category: network_connection
product: windows
detection:
selection_domain:
DestinationHostname|endswith: 'openaigpt4.com'
selection_ip:
DestinationIp: '104.18.14.219'
condition: selection_domain or selection_ip
falsepositives:
- None expected; the domain is not a legitimate service
level: critical
7. Sources
- Kaspersky Securelist, "Unknown APT uses NetamLoader to attack a Win10 OS customized for governments in Asia", https://securelist.com/netamloader/121676/, 2026-10-29.
8. Adverse Trace position
Adverse Trace assesses this as a targeted, single-victim intrusion against an Asian government platform, not a sector-wide campaign. No CVE has been assigned, nothing appears in NVD, EPSS or CISA KEV, and there is no exploitation deadline to track. The attribution is unconfirmed: Kaspersky could not link the activity to any known APT group and no MITRE ATT&CK profile exists for it, so we do not attribute it to a named actor. The technical significance for EMEA financial services is the delivery path, not the victim. A legitimate patch-management binary executed from SoftwareDistribution, a Microsoft-signed assembly abused for AppDomainManager injection, and an in-memory AMSI patch together defeat file-signature and local AMSI controls. Firms running third-party patch tooling should confirm that tooling verifies update integrity and does not execute from the Windows Update download directory. We will monitor for further Kaspersky reporting, for any CVE assignment against the DataCacheFactoryConfiguration or ResXResourceSet deserialization path, and for reuse of the openaigpt4[.]com infrastructure, and will reissue this advisory if any of those appear. All indicators here are single-sourced to Kaspersky; verify before blocking.
Published via PulseTrace — Adverse Trace threat intelligence.