Persistent Exploitation of ASP.NET Components Fuels Remote Code Execution Attacks
Persistent Exploitation of ASP.NET Components Fuels Remote Code Execution Attacks
Context
During a recent incident response engagement in June, our team observed an unattributed adversary exploiting a public-facing ASP.NET application, immediately followed by hands-on-keyboard activity. The initial access vector aligns with the technique described by Microsoft in February, involving the use of a known MachineKey to craft and sign malicious __VIEWSTATE payloads. This allowed the attacker to achieve remote code execution on the vulnerable server.
Post-compromise activity included the usage of in-memory Godzilla webshell, as noted in Microsoft’s prior reporting, along with post-exploitation framework Cobalt Strike. Additionally, poor OPSEC was observed throughout the intrusion, indicating potential gaps in adversary tradecraft despite the effective initial access.
While the adversary’s motivation remained unclear, they attempted to enumerate files on a file share and successfully downloaded several files. We assess with low to medium confidence that the adversary may originate from China, based on the observed TTPs and certain technical indicators identified during the investigation. The targeting of the health sector is still consistent with prior reporting, including the HC3 analyst note on the Godzilla webshell published in November 2024.

Figure 1- ViewState code injection attack chain leading to Godzilla (src: Code injection attacks using publicly disclosed ASP.NET machine keys | Microsoft Security Blog)
_VIEWSTATE Deserialization
Although _VIEWSTATE deserialization exploits have been known for over a decade, adversaries continue to use them as an initial access vector, reflecting a widespread lack of visibility and effective mitigation of insecure configurations.
In practice, the __VIEWSTATE is a Base64-encoded string stored in a hidden field, used by ASP.NET Web Forms to persist the state of server-side controls across postbacks. This allows controls (like text boxes, dropdowns, etc.) to retain their values without the need for re-fetching from the server. Microsoft introduced protections to prevent malicious users from tampering with the contents of _VIEWSTATE. These protections include the use of a Message Authentication Code (MAC) to ensure integrity and encryption to ensure confidentiality. However, if an attacker gains possession of the MachineKey, which consists of both the ValidationKey (for the MAC) and the DecryptionKey (for encryption), they can craft malicious objects that will be accepted and deserialized by the server, potentially leading to code execution.
One key concept in .NET deserialization attacks is the use of a “gadget”, a class (or chain of classes) that already exists in the application or .NET framework and which executes code during deserialization. The final payload must be deserialized into an object of this class (or chain) to achieve remote code execution (RCE).
The Initial Access Vector
When our team started working on the case, the initial access vector was unclear. What we did know was that the w3wp.exe process had loaded suspicious .NET assemblies, and that webshells had been dropped on the affected server. Given this combination, the most likely explanation was exploitation of a vulnerability in the web application or the web server itself.
Among the .NET assemblies loaded, one particularly revealing artifact stood out, a .pdb path embedded in the binary metadata:
C:\Users\hbada\Desktop\ActivitySurrogateSelector\LoadLibrary\obj\Debug\LoadLibrary.pdb
The name ActivitySurrogateSelector refers to a known .NET serialization gadget that can be exploited to achieve arbitrary code execution during deserialization, especially when ViewState deserialization is misconfigured or MAC protection is bypassed.
Upon further investigation within the same time window, application logs revealed additional evidence of the attack. Specifically, Event ID 1316 was recorded with event value 4009, indicating that the adversary was attempting to inject malicious “__VIEWSTATE” payloads. This event is typically associated with ViewState validation failures, and in this context, it strongly suggested active tampering attempts using forged or manipulated serialized objects.

Figure 2- Application event log 1316
We then compared the application’s MachineKey values against a set of publicly known keys and discovered they were in fact already exposed. This confirmed that the application was using publicly available keys, a critical misconfiguration that enabled the attacker to forge valid ViewState payloads and bypass integrity validation.
Discovery and poor OPSEC
The deserialized payload enabled the adversary to execute a series of commands aimed at discovering and enumerating the environment:

Note the mistyped commands such as “gorup” instead of “group” and “teamssix” value (a likely reference to the well-known cybersecurity blog Teamssix, which primarily targets Chinese-speaking audiences). These patterns, combined with the operational behavior, suggest that the adversary is likely Chinese-speaking and operating in a hands-on-keyboard manner.
Persistence through webshells
Our adversary subsequently re-exploited the vulnerability to deploy password-protected webshells in multiple locations within the application including the “/Images” directory, in-memory Godzilla webshell, along with other post-exploitation tools such Cobalt Strike. Many of these attempts were blocked by the antivirus solution.

Figure 3- Failed attempt to load CobaltStrike implant
When the malicious .aspx webshell were uploaded and accessed, ASP.NET dynamically compiled it into a .NET assembly, resulting in a corresponding .dll file written to the Temporary ASP.NET Files directory under:
C:\Windows\Microsoft.NET\Framework64\<dotnet_version>\Temporary ASP.NET Files\root\< random >\<random>\App_Web_< random >.dll
This compiled DLL were then loaded into the IIS worker process (w3wp.exe) and executed as part of the normal request pipeline. The presence of these DLLs, serves as forensic artifact, indicating that the webshell was not only uploaded but also requested and executed by the server. In many cases, these DLLs can be reverse engineered to recover the webshell source code and capabilities when the source file is lost or cleaned.
In-memory Godzilla webshell
We were able to get hands on the in-memory Godzilla-injected assembly, and analysis showed that it uses two main blocks:
- Dynamic Assembly Loading and Execution:
The webshell gets the context of the actual requests and retrieves a base64-encoded .NET assembly from the HTTP request parameter (__FIXEDPATH). It then decrypts the AES encrypted value and dynamically loads it into memory without touching the disk. This approach allows execution of arbitrary code embedded inside the transmitted assembly, making the webshell highly flexible and stealthy since no executable files are written to disk, and all execution happens within the context of the hosting application.

Figure 4- In-memory webshell and assembly loading
- AMSI Bypass via Hardware Breakpoints:
The AMSI bypass code uses basic obfuscation to hide the names of parameters used to call the Windows API functions “LoadLibraryA” and “GetProcAddress”. It then loads the specified “amsi.dll” and retrieves the address of “amsi.dll!AmsiScanBuffer”. The bypass sets up a hardware breakpoint on the address of the AmsiScanBuffer function, which is responsible for scanning memory buffers for malicious scripts. When the breakpoint triggers due to AMSI invoking this function, a custom exception handler intervenes. This handler manipulates the CPU context to skip the scanning process by modifying the instruction pointer and clearing certain CPU registers. The exception handler effectively disables the AMSI scan without crashing the process, allowing malicious code to execute without being detected by AMSI.

Figure 5- AMSI bypass via hardware breakpoint
Privilege escalation
The attacker attempted to reflectively load the Juicy Potato tool, a well-known privilege escalation tool allowing local privilege escalation from a Windows Service account to “NT AUTHORITY\SYSTEM”. This attempt failed as the AMSI still detected the loading attempt and the antivirus blocked its execution.

Figure 6- JuicyPotato detected by AMSI
Lateral movement
Using the capabilities of the post-exploitation frameworks, the attacker attempted to pivot laterally via RDP, but these attempts were unsuccessful as only failed logons were recorded on the target host, indicating that the credentials used were invalid.
The adversary’s brief intrusion ended there, as their implants were removed and the affected host was contained.
Early detection and response enabled us to stop the adversary before the attack could escalate, potentially preventing a far more severe breach.
However, these are two takeaways from this incident that should be considered going forward:
- Implement an External Attack Surface Management (EASM) program
This incident highlights the critical need for continuous External Attack Surface Management to identify and proactively remediate publicly exposed or misconfigured assets, before attackers exploit them. - Actively incorporate vendor and industry threat warnings into your processes
Microsoft’s February advisory was a clear warning that should have prompted immediate review and remediation efforts. Organizations must take such threat intelligence alerts seriously, integrating them promptly into their vulnerability management and patching workflows to proactively defend against known exploitation techniques.
IOC list
Observed TTPs
References
- https://www.microsoft.com/en-us/security/blog/2025/02/06/code-injection-attacks-using-publicly-disclosed-asp-net-machine-keys/
- https://www.aha.org/system/files/media/file/2024/11/hc3-tlp-clear-analyst-note-the-godzilla-webshell-11-12-2024.pdf