Knowing the Assembly Version of the API you’ve deployed on an environment may be helpful for many reasons. We’re gonna see why, how to retrieve it, and how to expose it with Endpoint Routing (bye-bye Controllers and Actions!)
Table of Contents
Just a second! 🫷 If you are here, it means that you are a software developer.
So, you know that storage, networking, and domain management have a cost .
If you want to support this blog, please ensure that you have disabled the adblocker for this site. I configured Google AdSense to show as few ADS as possible – I don’t want to bother you with lots of ads, but I still need to add some to pay for the resources for my site.
Thank you for your understanding. – Davide
Sometimes it can be useful to show the version of the running Assembly in one .NET Core API endpoint: for example, when you want to know which version of your code is running in an environment, or to expose a simple endpoint that acts as a “minimal” health check.
In this article, we’re going to see how to retrieve the assembly version at runtime using C#, then we will expose it under the root endpoint of a .NET Core API without creating an API Controller, and lastly we’ll see how to set the Assembly version with Visual Studio.
How to get Assembly version
To get the Assembly version, everything we need is this snippet:
The first step is to get the info about the running assembly:
Assembly assembly = Assembly.GetEntryAssembly();
The Assembly class is part of the System.Reflection namespace, so you have to declare the corresponding using statement.
The AssemblyInformationalVersionAttribute attribute comes from the same namespace, and contains some info for the assembly manifest. You can get that info with the second line of the snippet:
Next, we need to expose that value using .NET Core API.
Since we’re exposing only that value, we might not want to create a new Controller with a single Action: in this case, endpoint routing is the best choice!
In the Startup.cs file, under the Configure method, we can define how the HTTP request pipeline is configured.
By default, for ASP.NET Core APIs, you’ll see a section that allows the engine to map the Controllers to the endpoints:
In this section, we can configure some other endpoints.
The easiest way is to map a single path to an endpoint and specify the returned content. We can do it by using the MapGet method, which accepts a string for the path pattern and an async Delegate for the execution:
In this way, we will receive the message Hi there every time we call the root of our API (because of the first parameter, /), and it happens only when we use the GET HTTP Verb, because of the MapGet method.
Putting all together
Now that we have all in place, we can join the two parts and return the Assembly version on the root of our API.
You could just return the string as it is returned from the versionAttribute.InformationalVersion property we’ve seen before. Or you could wrap it into an object.
If you don’t want to specify a class for it, you can use an ExpandoObject instance and create new properties on the fly. Then, you have to serialize it into a string, and return it in the HTTP Response:
endpoints.MapGet("/", async context =>
{
// get assembly version Assembly assembly = Assembly.GetEntryAssembly();
AssemblyInformationalVersionAttribute versionAttribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
string assemblyVersion = versionAttribute.InformationalVersion;
// create the dynamic objectdynamic result = new ExpandoObject();
result.version = assemblyVersion;
// serialize the objectstring versionAsText = JsonSerializer.Serialize(result);
// return it as a stringawait context.Response.WriteAsync(versionAsText);
});
That’s it!
Of course, if you want only the version as a string without the dynamic object, you can simplify the MapGet method in this way:
endpoints.MapGet("/", async context =>
{
var version = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
await context.Response.WriteAsync(version);
});
But, for this example, let’s stay with the full object.
Let’s try it: update Assembly version and retrieve it from API
After tidying up the code, the UseEndpoints section will have this form:
WithAssemblyVersionOnRoot is an extension method I created to wrap that logic and make the UseEndpoints method cleaner. If you want to learn how to create extension methods with C#, and what are some gotchas, head to this article!
To see the result, open Visual Studio, select the API project and click alt + Enter to navigate to the Project properties. Here, under the Package tag, define the version in the Package version section.
In this screen, you can set the value of the package that will be built.
To double-check that the version is correct, head to the bin folder and locate the exe related to your project: right-click on it, go to properties and to the details tab. Here you can see the details of that exe:
Noticed the Product version? That’s exactly what we’ve set up on Visual Studio.
So, now it’s time to run the application.
Get back to Visual Studio, run the application, and navigate to the root of the API.
Finally, we can enjoy the result!
Quite simple, isn’t it?
Wrapping up
In this article, we’ve seen how to expose on a specific route the version of the assembly running at a specified URL.
This is useful to help you understand which version is currently running in an environment without accessing the CD pipelines to see which version has been deployed.
Also, you can use this information as a kind of health check, since the data exposed are static and do not depend on any input or database status: the simplest match for getting info about the readiness of your application.
What other info would you add to the exposed object? Let me know in the comment section 👇
Recent threat campaigns have revealed an evolving use of BAT-based loaders to deliver Remote Access Trojans, including XWorm and Remcos. These campaigns often begin with a ZIP archive, typically hosted on trusted looking platforms such as ImgKit, and are designed to appear as legitimate content to entice user interaction.
Upon extraction, the ZIP file contains a highly obfuscated BAT script that serves as the initial stage of the infection chain. These BAT files use advanced techniques to evade static detection and are responsible for executing PowerShell based loaders that inject the RAT payload directly into memory. This approach enables fileless execution, a growing trend in modern malware to bypass endpoint defences.
A notable development in this campaign is the use of SVG files to distribute the malicious BAT scripts. These SVGs contain embedded JavaScript that triggers the execution chain when rendered in vulnerable environments or embedded in phishing pages. This technique highlights a shift toward using non-traditional file formats for malware delivery, exploiting their scripting capabilities to evade detection.
Infection Chain:
Fig: Infection Chain
Process Tree:
Fig: Process Tree
Campaign 1:
During the analysis Campaign 1, we identified multiple BAT scripts associated with the campaign, indicating an evolving threat landscape. Some of these scripts appear to be in active development, containing partial or test-stage code, while others are fully functional and capable of executing the complete attack chain, including payload download, execution.
The image below showcases two BAT files:
Method 1: Delivered directly as an attachment via EML (email file).
Method 2: Downloaded via a URL hosted on the ImageKit platform.
This variation in delivery methods suggests that the threat actors are experimenting with different approaches to improve infection success rates and evade detection mechanisms.
Fig: Attachments
Persistence:
The malware achieves persistence by creating a BAT file in the Windows Startup folder. This ensures that the malicious script is automatically executed whenever the user starts the system or logs into their account.
Fig: Persistence Mechanism through startup Menu
BATCH files:
The figure below displays the BAT script in its obfuscated form alongside its de obfuscated version.
Fig: Obfuscated and deobfuscated bat files
PowerShell script:
Below, the figure shows the PowerShell process window and the command-line arguments used during execution. This provides insight into how the malware leverages PowerShell for in-memory payload delivery. We will analyze the PowerShell script in detail in the following sections to understand its role in the deployment of XWorm.
Fig: Process window of PWERSHELL with argument as PS script
Fig: Obfuscated Poershell script as an argument
This PowerShell command runs the script by decoding a Base64 encoded string and executing it in the memory. It uses -nop to avoid loading the user profile, -w hidden to hide the window, and iex (Invoke-Expression) to run the decoded content.
Deobfuscated Script:
Fig: Deobfuscted script
We divided the deobfuscated script into two parts. In first part of the PowerShell script; it is designed to locate and execute an obfuscated code embedded within a batch file (aoc.bat) located in the current user’s profile directory. Firstly, It retrieves the username from the environment variables to construct the full path to aoc.bat. It reads all lines using UTF-8 encoding and iterates through each line, specifically looking for lines that begin with a triple-colon comment prefix (:::), followed by a Base64-encoded string. Upon finding such a line, it attempts to decode the Base64 string into a byte array, then converts it into a Unicode string assigned to the variable $ttzhae. This decoded string ($ttzhae) contains an additional layer of PowerShell script, which is then executed in memory using Invoke-Expression. This allows the attacker to embed and execute complex or multi-stage malicious PowerShell logic covertly within a seemingly benign batch file comment, enabling stealthy and fileless execution.
Fig: First part of PS script
The script programmatically disables two key Windows security mechanisms AMSI (Antimalware Scan Interface) and ETW (Event Tracing for Windows) to evade detection. It leverages .NET reflection and dynamic delegate creation to resolve native functions such as GetProcAddress, GetModuleHandle, VirtualProtect, and AmsiInitialize. Using these, it locates and patches the AmsiScanBuffer function in memory with a instructions (mov eax, 0; ret), effectively bypassing AMSI scanning. Similarly, it disables event tracing by overwriting the beginning of EtwEventWrite with a return instruction. These in-memory modifications allow malicious PowerShell activity to execute stealthily, without being logged or scanned by endpoint protection solutions.
Fig: Output of First part of PS script
In the second part of the PowerShell script, it first retrieves the current user’s name from the environment and constructs the path to a file named aoc.bat located in the user’s profile directory. It proceeds to execute payloads embedded as encrypted and compressed .NET assemblies hidden within this batch file. The script specifically searches for a comment line prefixed with ::, which contains a Base64-encoded payload string. This string is then split into two parts using the backslash (\) as a delimiter. Each part undergoes Base64 decoding, AES decryption using a hardcoded key and IV (in CBC mode with PKCS7 padding), followed by GZIP decompression as illustrated in the accompanying figures. The result is two separate .NET assemblies, both loaded and executed directly in memory. The first assembly is invoked without any arguments, while the second is executed with ‘%*’ passed as a simulated command-line input.
Fig: Second Part of Script_ encryption function
The second payload plays a more critical role. it functions as a loader responsible for executing the final malware. which is XWorm remote access trojan (RAT).
Fig: Second Part of Script_ call to encryption function
Loader
The loader is designed to evade detection, disable event logging, and execute embedded payloads directly in the memory. It achieves this by either decrypting and running .NET executables via Assembly.Load or executing decrypted shellcode using VirtualProtect and delegates.
Fig: Loader which loads XWorm\
Fig: Resources and Features
Fig: Encrypted Resource containing XWorm/remcos
Loader Capabilities:
Extract and execute embedded payloads
Here, we identified multiple loaders that utilize in-memory execution techniques to evade detection and persist stealthily. Some of these loaders contain encrypted .NET executables, which are decrypted at runtime and executed directly from memory using Assembly.Load followed by .EntryPoint. Invoke, allowing the loader to run managed code without writing the executable to disk.
In contrast, other variants have encrypted shellcode instead of a binary. These variants decrypt the shellcode, modify the memory protections using VirtualProtect to make it executable, and then execute it using a delegate created via Marshal.GetDelegateForFunctionPointer. As shown in below figures,
Xworm
We have previously reported on XWorm and Remcos earlier this year, providing an in-depth analysis of its core functionality, advanced capabilities such as keylogging, remote command execution, data exfiltration, and its methods of persistence and evasion.
In addition to XWorm, several variants in the same campaign also utilized Remcos, a widely known commercial Remote Access Trojan (RAT) that offers a range of capabilities, including remote desktop access, keylogging, command execution, file manipulation, screenshot capture, and data exfiltration.
Campaign 2:
Campaign 2 introduces a notable shift in malware delivery by leveraging SVG (Scalable Vector Graphics) files embedded with JavaScript, which are primarily used in phishing attacks. These malicious SVGs are crafted to appear as legitimate image files and are either rendered in vulnerable software environments (such as outdated image viewers or email clients) or embedded within phishing web pages designed to lure unsuspecting users. Now, the embedded JavaScript within the SVG file acts as a trigger mechanism, initiating the automatic download of a ZIP archive when the SVG is opened or previewed.
This downloaded ZIP archive contains an obfuscated BAT script, which serves as the initial access vector for the malware. Once the BAT script is executed either manually by the user or through social engineering tactics, it initiates a multi-stage infection chain similar to that observed in Campaign 1. Specifically, the BAT script invokes PowerShell commands to decode and execute a loader executable (EXE) directly in memory. This loader is responsible for decrypting and deploying the final payload, which in this campaign is the XWorm Remote Access Trojan (RAT).
The use of SVG as a delivery mechanism represents a noteworthy evolution in attack methodology, as image files are typically considered benign and are often excluded from deep content inspection by traditional security tools. By exploiting the scripting capabilities of SVGs, threat actors can effectively bypass perimeter defences and deliver malicious payloads in a fileless, stealthy manner.
Conclusion:
These campaigns highlight a growing trend in the use of obfuscated scripts, fileless malware, and non-traditional file formats like SVGs to deliver Remote Access Trojans such as XWorm and Remcos. By embedding payloads in BAT files and executing them via PowerShell, attackers effectively bypass static defences. The shift from using SVGs in phishing attacks to malware delivery further emphasizes the need for behavioural detection, content inspection, and improved user awareness to counter such evolving threats.
IOCS:
MD5
File
EDA018A9D51F3B09C20E88A15F630DF5
BAT
23E30938E00F89BF345C9C1E58A6CC1D
JS
1CE36351D7175E9244209AE0D42759D9
LOADER
EC04BC20CA447556C3BDCFCBF6662C60
XWORM
D439CB98CF44D359C6ABCDDDB6E85454
REMCOS
Detections:
Trojan.LoaderCiR
Trojan.GenericFC.S29960909
MITRE ATTACK TTPs:
Tactic
Technique ID & Name
Description
Execution
T1059.001 – Command and Scripting Interpreter: PowerShell
PowerShell is used to interpret commands, decrypt data, and invoke payloads.
T1106 – Execution Through API
The script uses .NET APIs (e.g., Assembly.Load, Invoke) to execute payloads in memory.
Defense Evasion
T1027 – Obfuscated Files or Information
Payloads are Base64 encoded, AES-encrypted, and compressed to bypass static detections.
T1140 – Deobfuscate/Decode Files or Information
The script decodes and decompresses payloads before execution.
T1055.012 – Process Injection: .NET Assembly Injection
Payloads are loaded into memory
T1036 – Masquerading
The malicious content is hidden in batch file.
Persistence
T1053 – Scheduled Task/Job
Establish persistence through strartup menu.
Initial Access
T1204 – User Execution
Execution depends on a user manually running the batch file
Command and Control
T1132 – Data Encoding
Base64 and encryption are used to encode commands or payloads.
T1219 – Remote Access Software
Xworm provides full remote access and control over the infected host.
Credential Access
T1056.001 – Input Capture: Keylogging
XWorm includes keylogging functionality to steal user input and credentials.
Exfiltration
T1041 – Exfiltration Over C2 Channel
Stolen data is exfiltrated via the same C2 channel used by Xworm.
Earlier this year, we published a white paper detailing the VIP keylogger, a sophisticated malware strain leveraging spear-phishing and steganography to infiltrate victims’ systems. The keylogger is known for its data theft capabilities, particularly targeting web browsers and user credentials.
In a recently identified campaign, the threat actors have once again employed spear-phishing tactics to distribute the malware. However, unlike the previous iteration, this campaign uses an Auto-It-based injector to deploy the final payload VIP keylogger.
The malware is typically delivered through phishing emails containing malicious attachments or embedded links. Once executed, it installs the VIP keylogger, which is specifically designed to steal sensitive information by logging keystrokes, capturing credentials from widely used web browsers like Chrome, MS Edge, and Mozilla, and monitoring clipboard activity.
In this campaign, the AutoIt script is utilized to deliver and execute the malicious payload. Threat actors often leverage AutoIt due to its ease of obfuscation and ability to compile scripts into executables, which evade traditional AV solutions.
Infection chain and Process tree:
The campaign begins with a spear-phishing email carrying a ZIP file named “payment receipt_USD 86,780.00.pdf.pdf.z.”. This archive contains a malicious executable disguised as “payment receipt_USD 86,780.00 pdf.exe”, tricking users into believing it’s a harmless document. Once executed, the executable runs an embedded AutoIt script and drops two encrypted files leucoryx and avenes into the temp folder. These files are decrypted at runtime, and the final payload, VIP Keylogger, is injected into RegSvcs.exe using process hollowing techniques, as shown in the figures below.
Fig.: Infection chain
Fig.: Process Tree
Infiltration:
The campaign begins with a spear-phishing email carrying a ZIP file named “payment receipt_USD 86,780.00 pdf.pdf.z.” This archive contains a malicious executable disguised as “payment receipt_USD 86,780.00 pdf.exe,” tricking users into thinking it’s a harmless document. Once executed, the embedded AutoIt script runs and drops the VIP Keylogger onto the system, as shown in the images below.
Fig.: Email
Zip Attachments which further contains the executable.
Fig:Attachment
During execution, two files named leucorynx and aveness are dropped in the system’s Temp directory, as shown in the figure below.
AutoIt Script:
Fig.: AutoIt Script
This AutoIt script decrypts and executes the dropped payload in memory. It first checks the encrypted file leucoryx in the temp directory, reads its content, and decrypts it using a custom XOR function (KHIXTKVLO). The decrypted data is stored in a memory structure. It retrieves the pointer to the decrypted payload and uses DllCall to allocate executable memory and copy the payload into the allocated memory. A second DllCall triggers the execution and runs the payload in the memory.
The leucorynx contains the key to the decode file, as shown in the figure below.
Fig.: leucorynx
The malware drops a .vbs script in the Startup folder to maintain persistence. This script executes the primary payload located in the “AppData\Local” directory. The VB script ensures that the payload (definitiveness.exe) located in the “AppData\Local\Dunlop” directory is executed every time the user logs in, it to operate silently in the background after each reboot.
Fig.: Persistence
The dropped file avness is loaded into memory, as shown in the figures below. Once loaded, its contents are passed to a custom decryption routine, which is responsible for unpacking or decoding the embedded payload.
The figure below Shows the decryption function, which is takes the address of the encrypted payload and the XOR key as arguments.
Fig.:Decryption Function
The figure below highlights the decryption loop, where the payload is iteratively decoded. The memory dump shows the decrypted content of the payload.
Fig.: Decryption Loop
Decrypted payload is .NET VIP keylogger;
Process Hollowing:
The figure below demonstrates the use of process hollowing, where RegSvcs.exe is spawned in a suspended state using CreateProcess. This enables the malware to unmap the original code and inject its own payload into the process memory before resuming execution.
Fig: Targeted process RegSvcs.exe
As shown in the figures below, the decrypted payload is mapped into the address space of regsvc.exe. The memory dump has strings associated with the payload.
Fig: Injected code in RegSvcs.exe
Fig: Strings related to VIP Keylogger
Payload: VIP Keylogger
Fig. Exfiltrate data through SMTP
Fig. Exfiltrate data to c2
The final payload delivered in this campaign is VIP Keylogger, for which we have already provided a comprehensive analysis of its functionality, capabilities, and behaviour in our technical paper on VIP Keylogger.
During our recent investigation at Seqrite Labs, we identified a sophisticated variant of Masslogger credential stealer malware spreading through .VBE (VBScript Encoded) files. Initially, the variant appeared to be a typical script-based threat, but upon deeper analysis it turned out to be a multi-stage fileless malware that heavily relies on Windows Registry to store and execute its malicious payload.
In this blog post, we analyzed the internal flow of VBScript code, the obfuscation mechanism used, and how it manipulates system to remain fileless. Also, we have explained about the Stagers and the capabilities of the final Masslogger payload.
Initial Infection Vector:
The infection begins with .VBE file, likely distributed via spam email or drive-by downloads. .VBE file is a VBScript encoded with Microsoft’s built-in encoding scheme to detect casual inspection. Once decoded, the script reveals multiple layers of obfuscation, modular routines and true functionality.
Analysis of Decoded .VBS – [VBScript] File:
Initially, .VBS file prepares and writes multiple registry values under a specific key used by the malware. It sets up the execution environment for storing a fileless payload.
Registry Key and Value names are hard-coded and straightforward. However, few of the critical value data are kept encoded and are decoded during file execution.
-Registry Setup for Commands and Stager Configuration:
Subroutine AKAAU() is used to prepare keys and values before they are written to the registry. Value names and Value Data are stored as a separate array – “QORXG” and “ZBZLV” respectively. Both arrays are written to registry by using “RegWrite”.
Fig-1 : .VBS file prepares and writes multiple Windows Registries
Once system is infected, we can find these malicious registry entries in Registry Editor:
Fig-2: Malicious Registry entries, values and their probable Meaning
Here is the summary of Registry Entries written to the system at registry path “HKCU\Software\”:
Value Name
Value Data
Summary
cn
Stop-Process -Name conhost -Force
Forcefully kill conhost.exe process.
i
“AddInProcess32.exe”
Target process for code injection.
in
“0”
Control flag, checking if PowerShell command already run or not.
instant
LPICU
Obfuscated PowerShell commands. Deobfuscate and loads Stager-1 in memory.
Path
esBbIgyFlZcXjUl
Name of the registry key path. It is appended to “HKCU\Software\”.
r
WAJLA
.Net assembly, stored in reversed string format. Stager-2.
Obfuscated Commands for PowerShell. Deobfuscate and loads Stager-1 in memory. Specifically used as user input simulation.
Table-1: Summary of added registry entries
Before writing these registries, malware calls a subroutine “ZGYHW()” that checks if the file “C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe” is present at location.
Depending upon the presence, malware deploys different versions of Stagers. Specifically, Stager-2 in this scenario:
Fig-3: Check for MSBuild.exe file presence
– Registry Setup for Final Payload Deployment:
After above registries are configured and written, there is a call to another subroutine “XSSAY()”. This function is responsible for reading another larger string data (which is an actual Masslogger payload, kept encoded). This data is then split into 25,000-character chunks and writes them in another registry values in segmented form.
Fig-4: Malware splitting another large string data to chunks and writing it to registries
Each chunk is written to the registry at these paths:
Fig-5: New registries added as a chunks of string data
-Task scheduler:
Malware establishes persistence via a Windows scheduled task, ensuring that malware keeps running in the system. Trigger for the task starts on the date of infection (20xx-xx–xxT00:00:00) and repeats every 1 minute (PT1M). Task is scheduled to run ignoring the battery-related restrictions.
Fig-6: Task Scheduling
Task uses the same name as a created registry key i.e. esBbIgyFlZcXjUl and is triggered to run a .VBS file. This .VBS acts as a persistent execution loop that checks for a created registries indicating whether a payload should be executed.
-Task Scheduler Script – Capable of Simulating User Input:
As we can see in the image below:
It runs for around 10000 times, sleeping for 10 seconds between each cycle.
It reads registry value “i” to get the name of process and confirm if it is running or not.
Then it checks for registry value “in” set to 1,
if yes, it silently executes malicious command stored in registry “instant”.
When value in “in” is not set to 1.
It launches PowerShell in visible window mode and uses “.SendKeys” methods to input values of “v” and “cn” registries followed by “{ENTER}”.
This technique is like simulating user inputs to PowerShell.
Fig-7: esBbIgyFlZcXjUl.VBS file with user input simulation
As we saw in summary table,
“cn” registry is used to forcefully stop the running instance of conhost.exe process.
“instant” and “v” registries are used as a PowerShell to de-obfuscate, prepare and load Stager .Net assembly in memory, without touching the disk.
Check for System Protection Status:
Malware checks the protection status of the target system and possibly remain undetected during execution. It does so by querying some important registries. Below are a few of the registries where AV / Security products usually register their presence:
These registries are defined in the script in encoded format. Malware tries to enumerate through the subkeys of above keys and attempts to read “DisplayName” value. DisplayName holds the name of the installed AV / Security tool. If multiple security products are found to be installed on target system, malware halts its execution.
Fig-8: Check the presence of installed security tools
-Trigger for Stager:
The subroutine SQSKP() in .VBE file is a critical part of malware execution chain. It dynamically constructs and runs a PowerShell command that performs in-memory execution of a .NET stager retrieved from the Windows Registry.
Fig-9: Trigger for stager
Here, the decoded text is a de-obfuscated PowerShell commands, after replacing |path| with RVOYN.
Fig-10: Deobfuscated PowerShell command
As we can see in Fig-10 –
This PowerShell command is formed and assigned to variable “LPICU”.
The contents of variable are then written to registry value “\instant”, which is created inside registry key “Computer\HKEY_CURRENT_USER\SOFTWARE\esBbIgyFlZcXjUl”.
Function runs the constructed PowerShell command silently, where “0” – hides PowerShell window.
The PowerShell then reads registry key “HKCU\Software\esBbIgyFlZcXjUl\s” – This registry key contains the Stager-1, kept in revered Base64- encoded format.
Fig-11: Forming stager-1 by reversing and Base64 decoding
We have seen malware authors implementing this encoding combo in many of the recent credential stealers, including VIPKeylogger, Remcos, AsyncRAT etc.
The PowerShell command reverse the string, joining them, decodes base64 strings and load it as a .Net assembly using “[AppDomain]::CurrentDomain.Load ()” function in memory. This approach allows malware to:
Avoid writing actual malware files to disk (Evasive capability).
Dynamically construct and load payload at runtime.
Invokes entry method “[v.v]::v(‘esBbIgyFlZcXjUl’)”, that refers to the registry path.
We took the dump of deobfuscated stager-1 payload for further analysis. Our observations are as follows:
Analysis of Stager-1:
Stager-1 is a small executable kept encoded at registry “HKCU\Software\esBbIgyFlZcXjUl\s”. It is compiled in .Net and size is around ~14KB.
Analyzing its code, we found that the file is trying to read contents from another registry key with name “r” – [HKCU\Software\esBbIgyFlZcXjUl\r].
Those contents are reversed and another .Net compiled binary is formed – the stager-2.
This binary is then loaded in memory using “Assembly.Load()”. Stager-1 tries to locate method r() inside the class r inside the Stager-2 assembly. It is the entry point for the execution of stager-2.
Fig-12: Stager-1 trying to load Stager-2 and locate Method “r” in it
Analysis of Stager-2:
After Stager-1 completes its setup, malware proceeds to its Stager-2 loader. This stage of infection is focused on extracting actual Masslogger payload from registry and injecting it into target process.
Stager-2 initially constructs potential file paths to launch process and performing code injection.
It checks if a file (whose name is retrieved from the registry value “i”) exists in any of these paths.
In our case, we found the target file/process path is:
Fig-13: Constructing file/process path for code injection.
Further, malware extracts actual Masslogger payload which was previously written (by subroutine “XSSAY()”) in multiple registry subkeys under below registries, that we saw earlier “.
The BBX() function of class ‘r’ is responsible for collecting all value entries, concatenate them, reverses the combined string, and then decodes it from hexadecimal into raw bytes. This technique allows malware authors to hide a full PE binary across multiple registry keys. The decoded payload is then used for process hollowing. Process hollowing is performed using function .XGP()
It’s a clever way to keep everything stored in the registry and only use memory for execution.
Fig-14:Function performing payload deobfuscation and process hollowing
-France Specific Payload Delivery:
Geo-targeted payload delivery is now common in advanced malware to alter behavior based on the victim’s location. Stager-2 of this infection checks if current system’s input language is set to French “Fr” and whether locale contains “France”.
Fig-15: France specific payload delivery
If conditions are met, it tries to download specially crafted additional payload from hardcoded URL – hxxps://144.91.92.251/MoDi.txt. At the time of analysis, the URL was not accessible.
-Terminating Traces and Exiting:
At the end of its execution, the malware forcibly terminates running instances of conhost.exe and PowerShell.exe processes.
Fig-16: Process killing to hide traces
By killing these processes, malware likely aims to hide its activity traces. Finally, it exits application using ProjectData.EndApp(), completing stager-2 lifecycle.
Analysis of Masslogger Final Payload:
After successful deobfuscation of final payload from registry, Masslogger is injected to into target process – “AddInProcess32.exe”. We can see the marker of this malware in memory dump of the injected process as below:
Fig-17: Marker of Masslogger in memory
We took a memory dump of this payload representing the final stage in malware chain. It is responsible for executing the main credential – info stealing functionalities.
-Data Harvesting:
Just like many infostealer malware’s, this malware is also targeting multiple Web browsers and few email clients for stealing sensitive information, like saved Username, Passwords, autofill data, etc. Below are list of Web Browsers and few email clients Masslogger is trying to target.
Fig-18: Targeted browsers and email client for credential Harvesting
Let’s see one of the modules in detail where malware is trying to harvest saved login credentials from the Chrome browser.
Fig-19: Chrome browser specific module for credential harvesting
It locates the user’s login data by accessing its “Login Data” SQLite database. It extracts website URLs along with corresponding usernames and passwords and collects them for further use. If valid credentials are found, they are stored in a structured format like the website, username, and password.
Apart from targeting browsers and email clients for info stealing, Masslogger also possesses capabilities of:
Keylogger activity.
Take and clear snapshot files.
Retrieve clipboard data.
Try monitoring user activity by calling GetForegroundWindow, GetWindowText etc.
Read system details, like IP address and Country.
Uploading multiple files to server.
-Data Exfilteration:
The SpeedOffPWExport() method in final payload enables data exfiltration by sending collected credentials and system information to remote locations via multiple channels, like FTP, SMTP or Telegram.
If FTP is enabled, the method uploads the stolen data as a .txt file to a remote FTP server using hard-coded credentials.
Fig-20: Data exfilteration via FTP
For SMTP, it constructs an email containing the data in either the message body or as an attached text file and sends it using the specified mail server.
Fig-21: Data exfilteration via SMTP
If Telegram exfiltration is enabled, it sends the data as a document using the Telegram Bot API, including a caption with the victim’s username and IP.
Fig-22: Data exfilteration via Telegram
Conclusion:
The Masslogger fileless variant shows the evolving trend of info-stealing malware. Delivered via a .VBE script, it abuses Windows Registry to store actual executable payload and loads that payload directly in memory without touching the disk. It possesses capability to harvest stored credentials from multiple browsers and email clients and using multiple channels [FTP, SMTP, Telegram Bot] for data exfiltration.
This variant shows the shift of credential stealer malware towards fileless and operation in multiple stages (Stager-1, Stager-2). This challenges traditional AV and signature-based detection methods. To overcome this, security defenders must employ advanced detection mechanisms like behavioral detection, monitor registry anomalies etc.
SEQRITE Labs APT-Team has been tracking and has uncovered a campaign targeting the Baltic State Technical University, a well-known institution for various defense, aerospace, and advanced engineering programs that contribute to Russia’s military-industrial complex. Tracked as Operation HollowQuill, the campaign leverages weaponized decoy documents masquerading as official research invitations to infiltrate academic, governmental, and defense-related networks. The threat entity delivers a malicious RAR file which contains a .NET malware dropper, which further drops other Golang based shellcode loader along with legitimate OneDrive application and a decoy-based PDF with a final Cobalt Strike payload.
Key Targets
Industries Affected
Academic & Research Institutions
Military & Defense Industry.
Aerospace & Missile Technology
Government oriented research entities.
Geographical Focus
Infection Chain.
Initial Findings.
In the early months of 2025, our team found a malicious RAR archive file named as Исх 3548 о формировании государственных заданий на проведение фундаментальных и поисковых исследований БГТУ «ВОЕНМЕХ» им. Д.Ф. Устинова.rar , which translates to Outgoing 3548 on the formation of state assignments for conducting fundamental and exploratory research at BSTU ‘VOENMEKH’ named after D.F. Ustinov.rar surfaced on Virus Total. Upon investigation, we determined that this RAR has been used as a preliminary source of infection, containing a malicious .NET dropper which contains multiple other payloads along with a PDF based decoy.
The RAR archive contains a malicious .NET executable functioning as a dropper, named “Исх 3548 о формировании государственных заданий на проведение фундаментальных и поисковых исследований БГТУ «ВОЕНМЕХ» им. Д.Ф. Устинова” which also translates to Outgoing No. 3548 regarding the formation of state assignments for conducting fundamental and exploratory research at BSTU ‘VOENMEKH’ named after D.F. Ustinov. This dropper is responsible for deploying a legitimate OneDrive executable alongside a malicious shellcode loader written in Golang. Upon execution, the .NET executable performs several operations: one of them it deploys the Golang loader containing shellcode, injects the shellcode into the legitimate OneDrive process, and spawns a decoy document. Before delving into the technical details, let’s first examine the decoy document.
Looking into the decoy-document.
Upon looking into the decoy document, it turns out that this lure is a document related to the Ministry of Science and Higher Education of Russia, specifically concerning Baltic State Technical University “VOENMEKH” named after D.F. Ustinov. The document appears to be an official communication addressed to multiple organizations, potentially discussing state-assigned research projects or defense-related academic collaborations.
The above is a translated version of the initial sections of the decoy.
The contents and the entire decoy confirm that this PDF serves as a comprehensive guideline for the allocation of state-assigned research tasks, outlining the process for organizations to submit proposals for fundamental and applied research projects under the 2026-2028 budget cycle. It provides instructions for institutions, particularly those engaged in advanced scientific and technological research, on how to register their technological requests within the Unified State Information System for Scientific Research and Technological Projects (ЕГИСУ НИОКТР) before the specified deadline.
Now, looking into the later part of the decoy it can be seen that the decoy document provides additional information on the submission process for state-assigned research tasks, emphasizing that financial support for these projects will come from budgetary allocations through the Ministry of Science and Higher Education of Russia. Also, the document mentions contact details for inquiries of Bogdan Evgenyevich Melnikov, a senior researcher in the Department of Fundamental and Exploratory Research, with an email address for communication.
Well, at the end of this decoy, it can be seen that it has been signed by A.E. Shashurin, who is identified as a Doctor of Technical Sciences (д.т.н.), professor, and acting rector (и.о. ректора) of the institution. Overall, this lure document serves as an official communication from the Ministry of Science and Higher Education of Russia, providing guidelines for organizations regarding state-funded research initiatives.
Technical Analysis
We will divide our analysis into four main sections. First, we will examine the malicious RAR archive. Second, we will delve into the malicious .NET dropper. Third, we will focus on analyzing the working of the malicious Golang based shellcode injector and at the end, we will look into the malicious Cobalt Strike payload. This detailed exploration will shed light on the methodologies employed and provide insights into the threat actor’s tactics within this particular campaign.
Stage 1 – Malicious RAR File.
Upon examining the malicious RAR file, it contains another malicious executable named Исх 3548 о формировании государственных заданий на проведение фундаментальных и поисковых исследований БГТУ «ВОЕНМЕХ» им. Д.Ф. Устинова. After initial analysis of the file’s artefacts it was revealed it is a 32-bit .NET-based executable. In the next section, we will explore the functionality of this.NET executable.
Stage 2 – Malicious .NET malware-dropper.
Now, let us look into the workings of the .NET file which was compressed inside the RAR archive. As in the previous section we found that the binary is basically a 32-bit.NET executable, it is also renamed as SystemUpdaters.exe while we loaded it into analysis tools.
Upon looking inside, the sample, we found three interesting methods. Now let us dive deep into them.
Looking into the first method we can see that the Main function, we can see that it calls another method MyCustomApplicationContext . Let us analyze the method.
Next, looking into the method, we found that the code initially checks whether the decoy PDF is present inside the C:\Users\Appdata\Roaming\Documents location, in case the PDF file is not present, it goes ahead and copies the decoy, which is stored under the resources section, and writes it into the location.
Next, looking into the code further, we found that it checks if the file OneDrive.exe which is basically the legitimate OneDrive application exists, in case it does not find it on the desired location, it goes ahead and copies the legitimate application stored under the resource section, and writes it into the location.
Looking into the later part of code, we found that it checks for a file named as OneDrives_v2_1.exe under the location C:\Users\Appdata\Roaming\Driver , in case it did not find the file, just like similar files, it copies the executable from the resources section and writes it to the location.
Then looking into one of the most intriguing aspects of this dropper is its use of a shortcut (.lnk) file named X2yL.lnk as a persistence mechanism by placing it in the Windows Startup folder to ensure execution upon system boot. Upon analyzing the H3kT7fXw method, we observed that it is responsible for creating this shortcut file. The method utilizes WshShell to generate the .lnk file and assigns it a Microsoft Office-based icon, making it less suspicious. Additionally, the target path of the shortcut is set to the location where the malicious payload I.e., OneDrives_v2_1.exe is stored, ensuring its execution whenever the shortcut is triggered upon booting.
At the end, it goes ahead and spawns the decoy PDF into the screen. As, we conclude the analysis of the malicious .NET dropper, in the next sections, we will analyze the malicious executable dropped by this dropper.
Stage 3 – Malicious Golang Shellcode loader.
Initially, upon looking into the sample inside analysis tools. we can confirm that this executable is programmed using Golang. Next, we will look into the working of the shellcode loader and its injection mechanism.
Looking into the very first part of this shellcode loader, we found that the binary executes time_now function to initially capture the current system time, then it calls time_sleep which is also a Golang function with a hardcoded value, then again it calls the time_now function, which checks for the timestamp after the sleep. Then, it calls time_Time_Sub which checks the difference between the timestamp captured by the function and goes ahead and checks if the total sleep time is less then 6 seconds, in case the sleep duration is shorter, the program exits, this acts as a little anti-analysis technique.
Next, moving ahead and checking the code, we found that the legitimate OneDrive executable, which was dropped by the.NET dropper, that similar process is being created using the CreateProcess API in Golang, and the process is being created in a suspended mode.
Then, the shellcode which is already embedded in this loader binary is being read by using Golang function embed_FS_ReadFile which returns the shellcode.
Next, the shellcode which was returned by the previous function in a base64 encoded format is being decoded using Golang native function base64.StdEncoding.DecodeString and returned.
Then, the code basically uses a hardcoded 13-byte sized key, which is basically used to decode the entire shellcode.
Then finally, the code performs APC Injection technique to inject the shellcode inside the memory, by first starting with the process in a suspended state, followed by decoding and decrypting the shellcode, followed by allocating memory on the suspended OneDrive.exe process, then once the memory is allocated, it goes ahead and writes the shellcode inside the memory using WriteProcessMemory , then it uses QueueUserAPC API to queue a function call inside the main thread of the suspended OneDrive.exe process. Finally using ResumeThread which causes the queued APC function (containing the shellcode) to execute, effectively running the injected malicious code within the context of OneDrive.exe. Now, let us analyze some key artifacts of the shellcode.
Stage 4 -Shellcode overview.
Upon looking inside, the malicious shellcode and analyzing it we found that the shellcode is actually a loader, which works by initially loading a Windows wwanmm.dll library.
Once, the DLL is loaded it zeroes out the .text section of the DLL. It uses a windows API DllCanUnloadNow which helps to prepare the beacon in memory. Thus, further facilitating the working of the shellcode which is a Cobalt Strike beacon.
Further analyzing it becomes quite evident that the beacon is connecting to the C2-server, hosted by the attacker using certain user-agent. As, this tool is quite commonly used, therefore, we will not delve in-depth on the workings of the malicious beacon. The configuration of the beacon can be extracted as follows.
Extracted Configuration:
Method : GETHost[Command & Control] : phpsympfony.comUser-Agent : “Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko”
Hunting and Infrastructure.
Upon analysis of the shellcode injector programmed in Golang, we found little OPSEC related mistakes from the threat actor such as leaving Go-build ID along with the injector, which helped us to hunt for similar payloads, used by the same threat actor. The Go-build ID is as follows:
Now, looking into the infrastructural artefacts, the malicious command-and-control server which has been hosted at the domain phpsymfony[.]com , has been rotating the domain across multiples ASN services. Also, there has been a unique HTTP-Title which has also been rotated multiple times across the C2-server.
Looking into the response across the history we can see that the title Coming Soon – pariaturzzphy.makebelievercorp[.]com has been set up multiple times.
Upon further searching for the same HTTP-Title, we found that a lot of hosts are serving the same title, out of which some of them are serving malicious binaries such as ASyncRAT and much more.
Looking into the ASNs, the C2 server has been rotating since the date of activation. The list is as follows.
ASN
Geolocation
Owner
AS13335
United States
Cloudflare Net
AS35916
United States
MULTA-ASN1
AS135377
Hong Kong
UCLOUD-HK-AS-AP UCLOUD INFORMATION TECHNOLOGY HK LIMITED
AS174
United States
COGENT-174
AS47846
Germany
SEDO-AS
AS8560
🌍 Unknown
IONOS-AS
Conclusion
We have found that a threat actor is targeting the Baltic Technical University using research themed lure where they have been using a.NET dropper to shellcode loader finally delivering a Cobalt Strike in-memory implant. Analyzing the overall campaign and TTPs employed by the threat actor, we can conclude that the threat actor has started targeting few months back since December 2024.
SEQRITE Protection.
Trojan.Ghanarava.1738100518c73fdb
Trojan.Ghanarava.1735165667615275
IOCs.
MD5
Filename
ab310ddf9267ed5d613bcc0e52c71a08
Исх 3548 о формировании государственных заданий на проведение фундаментальных и поисковых исследований БГТУ «ВОЕНМЕХ» им. Д.Ф. Устинова.rar
fad1ddfb40a8786c1dd2b50dc9615275
SystemsUpdaters.exe
cac4db5c6ecfffe984d5d1df1bc73fdb
OneDrives_v2_1.exe
C2
phpsymfony[.]com
hxxps://phpsymfony[.]com/css3/index2.shtml
MITRE ATT&CK.
Tactic
Technique ID
Name
Initial Access
T1566.001
Phishing: Spear phishing Attachment
Execution
T1204.002
T1053.005
User Execution: Malicious File
Scheduled Task.
Persistence
T1547.001
Registry Run Keys / Startup Folder
Defense Evasion
T1036 T1027.009 T1055.004 T1497.003
Masquerading Embedded Payloads. Asynchronous Procedure Call Time Based Evasion