~/f4n6 $ grep -r "Unknown APT uses NetamLoader to compromise Asian government Windows builds via supply chain" ./investigations/ --include="*.md"

Unknown APT uses NetamLoader to compromise Asian government Windows builds via supply chain

Jeff Davies 29 Oct 2026 10 min read

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:

  1. PatchMyPC-ScriptRunner.exe starts and the CLR reads PatchMyPC-ScriptRunner.exe.config from the same directory before the executable's entry point runs. The config sets appDomainManagerAssembly to Microsoft.HostIntegration.Connectors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 and appDomainManagerType to Microsoft.ApplicationServer.Caching.DataCacheFactoryConfiguration. Both are Microsoft-signed.
  2. DataCacheFactoryConfiguration is the Windows Server AppFabric Cache Client configuration class. On instantiation it looks for fabric.config in the same directory and reads it. The planted fabric.config sets className to System.Resources.ResXResourceSet, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089(Resources.resx), so a ResXResourceSet is constructed against Resources.resx.
  3. Resources.resx holds a Base64-encoded object serialised with BinaryFormatter. Parsing it calls BinaryFormatter.Deserialize(), which Kaspersky describes as a TypeConfuseDelegate deserialization attack. The delegate invokes XamlReader.Parse() on an embedded XAML payload (XAML-1).
  4. 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.
  5. XAML-2 carries two Base64-encoded, ZIP-compressed XAML files, XAML-2-1 and XAML-2-2, each loaded in memory with XamlReader.Load().
  6. XAML-2-1 is 796 lines whose only job is AMSI bypass. It checks IntPtr.Size == 8 and aborts if the host is not 64-bit. It patches Console.Clear() in memory with the bytes 41 C7 00 01 00 00 00 33 C0 C3. It then walks the IUnknown virtual method table of the AMSI object, adds 0x18 to reach the CAmsiAntimalware::Scan pointer, calls VirtualProtect() to make it writable, and overwrites it with the address of a patched routine returning AMSI_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.
  7. 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 its m.C() method.
  8. .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 field tp set to * (any certificate accepted, so certificate pinning is disabled), the AES master key 9fT04e03tAiZAPogcDWt0w==, and the encrypted XAML-3 template set in ibi with its key in ibk.
  9. .NET 1 Loader reads SusClientId from HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate and derives a per-victim identifier si from it. It sets the environment variable COMPlus_ETWEnabled to 0 through WScript.Shell (CLSID 41904400-BE18-11D3-A28B-00104BD35090), which stops the CLR registering the .NET ETW provider and hides the associated events.
  10. XAML-3 is decrypted from the ibi/ibk material and loaded in a new process, dllhost.exe, reached through COM. The plugin writes DllSurrogate = "" under HKCU\Software\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2}, creates the COM object, and calls CoLockObjectExternal() so the surrogate is not released. The AMSI bypass from XAML-2-1 is re-applied in the new process through the __P1__ placeholder.
  11. The .NET 2 Plugin (hash CFB8B281BDF5D9390E64B10C312FB2C1) runs in dllhost.exe. It collects host reconnaissance: the .NET Framework version from HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full value Version, and the build string from HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion value BuildLab (the example given is 4.7.03190\n17763.rs5_release.180914-1434). Failed queries are replaced with a hyphen.
  12. 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 to https://openaigpt4v[.]com/model_v4/<si>?b=<encrypted>&c=<si> with a ServerCertificateValidationCallback that accepts any certificate because tp is *.

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 e4537a1762fcafd2fd96bfc825bad34f9db9a24d and for any .config file in C:\Windows\SoftwareDistribution\Download\ or its Install\ subdirectory that contains appDomainManagerAssembly or appDomainManagerType. Legitimate Windows update packages do not ship CLR AppDomainManager configuration there.
  • Block openaigpt4[.]com and 104.18.14[.]219 at 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.exe making outbound HTTPS to a host it has no COM activation history with, and on dllhost.exe writing to HKCU\Software\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2}.
  • If Patch My PC is deployed, confirm the publisher's binaries and their .config files against a known-good hash set from the vendor. Any PatchMyPC-ScriptRunner.exe.config that 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-DotNETRuntime events off-host; the loader sets COMPlus_ETWEnabled=0 to 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, .resx and .cab files under SoftwareDistribution and 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 from ResXResourceSet parsing in processes that should never deserialise untrusted .resx files. .NET 4.6 does not enable the safer BinaryFormatter switch by default; where the application allows it, set Switch.System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization to false in runtimeconfig or via AppContext, 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.


Read the original source →

Published via PulseTrace — Adverse Trace threat intelligence.

Post this to LinkedIn
Formatting is converted automatically — headings, bullets, a link back & hashtags. Paste straight in.
J
Jeff Davies