What is NoEscape Ransomware?
NoEscape ransomware emerged in May 2023 as a financially motivated ransomware group that operates RaaS (Ransomware-as-a-Service). The operators claim to have developed the ransomware and the infrastructure from scratch, though it is believed that their ransomware is a rebranding of the Avaddon ransomware. Additionally, NoEscape operators provide affiliates with a complete platform designed to create and manage payloads customized for both Windows and Linux operating systems.
NoEscape is known for its multi-extortion operations, using a TOR-based blog to list victims and host exfiltrated data from those who refuse to meet their demands.
Targets of NoEscape Ransomware
NoEscape ransomware tends to avoid targeting CIS countries, a trend often observed among ransomware groups originating from Russia. This ransomware group has been active across various industries and sectors.
NoEscape Attacks: A Timeline of Cyber Threats
Explore the timeline of NoEscape ransomware attacks spanning from June to December 2023, revealing the striking impact on 123 victims.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/victims-1024x486.png)
The United States emerged as the primary target, representing 26% of all affected entities.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/countries-victims-1024x486.png)
Further examination reveals the sectors most affected by the ransomware group: manufacturing, education, and construction. With nine manufacturing companies impacted, followed closely by educational institutions and construction firms.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/sectors-1024x486.png)
NoEscape DLS (Data Leak Site)
NoEscape ransomware operators are leveraging a TOR-based platform, they list victims and host exfiltrated data from non-compliant targets and also, to contact the actors to know how recover the encrypted data.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/Pasted-image-20240505235434-648x1024.png)
Source: ransomware.live
Subsequently, it drops a ransom note labeled as “HOW_TO_RECOVER_FILES.txt,” that guiding victims to access their TOR website and also it contains the victim’s Personal ID, which a unique ID for each victim so they login and contact the actors for additional directives.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/Pasted-image-20240506000633-1024x500.png)
Technical Analysis
Let’s dive in to the technical analysis. First, NoEscape has some changes in the code development, the malware core is based on switch cases, and each switch case has a wrapper function for other functions, this wrapper function also has switch cases inside it, and each switch case leads to a function that makes a specific behavior so, to call the malware core function, we should base it 2 numbers, first number to go to the wrapper function and the second number to be applied in the switch cases inside the wrapper function, so the passed argument is an array of 2 numbers, based on these numbers a path will be chosen.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/AcRB4Wl-Imgur.png)
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/077vlsw-Imgur.png)
Ransomware Configuration
Ransomware Configuration is divided into two parts, each part has its own RC4 Decryption key, the decryption process is simple and easy just base64 decodes and then RC4 decrypts it using the appropriate RC4 key.
Part one
The first part is related to some used commands and registry keys, as well as some configurations related to ransomware internals. It first defines an array of pointers of base64 encoded streams and then obtains a pointer to this array and saves it in a global variable. The function responsible for obtaining pointers for all streams is sub_422170(), which we have renamed to mw_Get_ptr_to_encoded_streams().
It is the first function to be called upon malware execution.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/iw0kRAX-Imgur.png)
inside sub_422170() it goes through all part one configuration saves it in a local variable and then saves a pointer to it in array pointers discussed before, it uses function sub_409A30() for this task, it passed a pointer to a global variable for base64 stream and stream length and a local variable that will hold the new pointer which will be saved in pointers array, we have renamed this function to mw_save_ptr_to_1st_arg(), the first processed stream is the RC4 key for part one configuration.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/9NTrgBY-Imgur-1024x393.png)
so each time the malware wants to decrypt a specific stream it passes the index for sub_40BDD0() which we have renamed to mw_w_rc4() because this function wraps RC4 decryption operation and base64 decoding.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/kXffDNW-Imgur.png)
To handle this decryption stuff, we wrote a Python script to automate decryption and just pass it the
index and it will return you the decrypted stream.
#!/usr/bin/python3
import base64
import pefile
def Get_data_and_Key(FilePath):
pe = pefile.PE(FilePath)
for section in pe.sections:
if b'rdata' in section.Name:
key = section.get_data() [0xBAF8:0xBAF8 + 0x10]
data = section.get_data() [0xBB10:0xBB10 + 0x23A0]
key2 = section.get_data() [0xB8AC:0xB8AC + 0x10]
data2 = section.get_data() [0xFA94:0xFA94 + 0x940]
return key,data,key2,data2
def rc4_decrypt(ciphertext, key):
# Initialization
S = list(range(256))
j = 0
key_length = len(key)
plaintext = bytearray(len(ciphertext))
# Key-scheduling algorithm (KSA)
for i in range(256):
j = (j + S[i] + key[i % key_length]) % 256
S[i], S[j] = S[j], S[i]
# Pseudo-random generation algorithm (PRGA) and decryption
i = j = 0
for idx, byte in enumerate(ciphertext):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
keystream_byte = S[(S[i] + S[j]) % 256]
if byte == 0x00 :
continue
else :
plaintext[idx] = byte ^ keystream_byte
return bytes(plaintext)
key,data,key2,data2 = Get_data_and_Key(r"File Path")
part1_decoded = base64.b64decode(data)
part1_decrypted_stream = rc4_decrypt(part1_decoded,key)
part2_streams_list =data2.split(b'\x00\x00\x00\x00')
part2_decrypted_streams=[]
for stream in part2_streams_list :
if stream:
b64decoded=base64.b64decode(stream)
rc4_decrypted = rc4_decrypt(b64decoded,key2)
part2_decrypted_streams.append(rc4_decrypted)
print(part1_decrypted_stream.decode('utf-8'))
for decrypted_stream in part2_decrypted_streams :
print(decrypted_stream.decode('utf-8'))
Part Two
This part involves public keys, ransomware notes, and also some Boolean values like the maximum size for a file to be encrypted, or whether to print the note and change the wallpaper, avoided paths and files, etc. The decryption key for this part resides above the configuration itself.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/PZxgGV0-Imgur-1024x598.png)
Decrypting it using CyberChef results in a JSON formatted configuration containing some file paths, locker keys (iv_key, mp_keyā¦), extensions, and settings. Additionally, there is a reference for processes and services to be killed and terminated, along with a ransomware note.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/3hRVWhC-Imgur-1024x457.png)
Cryptography Flow
As we already have seen the Locker keys part in the above figure the key named mp_key is the RSA public key which will be used later for encrypting session keys or encrypting AES keys or whatever symmetric algorithm is used.
this RSA public key is base64 encoded, and it first Calls CryptAcquireContextW to get a handle to a key container, next it will call CryptStringToBinaryA twice to first get the required size and allocate it and then to decode the public key into bytes.
using the decoded buffer it will import this RSA public to the key container created before or we can
call it CSP using CryptImportKey API.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/CAaYvEF-Imgur-1024x418.png)
next it will generate public RSA session keys using CryptGenKey API, followed by using CryptExportKey to export public and private keys .
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/ri7kMDx-Imgur-1024x128.png)
![](https://i.imgur.com/s2RQrnQ.png)
the RSA Public Exported key, the key handle is saved in eax which is pushed as the fifth argument for CryptExportKey API call, if the function succeeded the return value will be saved in eax it will be 1.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/9APHjwf-Imgur-1024x486.png)
also after generating the private key using the same API, it will use CryptEncrypt API to encrypt the generated private key using the mp_key that was delivered by the malware configuration.
![](https://blog-wp.darkatlas.io/wp-content/uploads/2024/05/2lhqUh51-1024x473.png)
then it will import the public generated key using CryptImportKey API to convert this key from ASCII
format to byte format.
![](https://i.imgur.com/Rds7dmT.png))
Data Collection
After initializing keys and encrypting session keys using public RSA key, NoEscape starts allocating some information about the machine, like iv_key, Generated Extension, Logical Drivers, Remote Drivers, Driver Spaces, it uses GetLogicalDirver which its return value is a bitmask representing the currently available disk drives. Bit position 0 (the least-significant bit) is drive A, bit position 1 is drive B, bit position 2 is drive C, and so on, and then it uses WNetGetConnectionW to get Remote Server names.
![](https://i.imgur.com/tcPlEqP.png)
it also gets the User Language, and Desktop name, and saves all of that in JSON format.
![](https://i.imgur.com/NB5N1bm.png)
![](https://i.imgur.com/kqaHvdP.png)
next, all of these data are encrypted using AES, The AES key is the public key-driven through malware configuration and iv_key also, the Encryption applies CBC mode for padding.
![](https://i.imgur.com/bSt7oVY.png)
then this data is base64 encoded twice to add layers of obfuscation and appended to the Ransom note.
Abusing Restart Session Manager
NoEscape ransomware abuses restart session manager to terminate any process appended to thefile that is going to be encrypted using these techniques.
Abusing Restart Session Manager explanation: CrowdStrike.
Basically, when attempting to open or delete a file that is currently in use by another process, amessage box will appear, informing the user that the file cannot be accessed or modified at that timedue to its association with an active process.
![](https://i.imgur.com/S4fO6Mw.png)
so when the ransomware process is trying to encrypt a file attached to another process it may alert the user of suspicious behavior, and to avoid that it will for each file try to get a list of all registered processes or services and terminate them.
It initiates a new Restart Manager session by invoking the RmStartSession API, obtaining the session handle in the designated argument pSessionHandle. Subsequently, it proceeds to invoke RmRegisterResources, providing the file it seeks to associate with applications that are currently impeding access to this resource.
![](https://i.imgur.com/ncvzOZO.png)
Now the file has been registered as a resource for the created session, it will call RmGetList to get alist of all applications and services that are currently using resources that have been registered withthe Restart Manager session, and it will check the return value if it is not equal to 234 which is aENUM for ERROR_MORE_DATA and if it is it will end the function and will not complete.
Next, it will check dwRebootReason which is an ENUM if it is equal to 0x00 which means a system restart is not required.
and if this value is equal to 0x00 it will terminate all processes and applications on the list that block access for the registered resource on this session and after all of that it will end the session using RmEndSession.
![](https://i.imgur.com/miHotAj.png)
Cheating Window
NoEscape can Create a window to trick the user into a running process if he stops it his files will be damaged.
it first defines the Window Class Structure and fills in its elements, one of its elements is a class name, and the malware assigns the string “ShutdownBlockReasonClassName” to the class name.
next it will load Icon by using LoadIconW and passing the module address on memory (Malware base address in memory) and Icon name which is 0x7F00, so after building class structure it then will Register the class using RegisterClassExW and pass the created structure.
![](https://i.imgur.com/lfHnBD6.png)
Mutex Creation
Next, it will resolve a mutant name using the Machine GUID value appended to string “// Global\” it first will try to open the mutex using OpenMutexW and if the mutex is already created it will not recreate it again to ensure that there is only one instance of NoEscape ransomware is running on the system at the time of execution, if not it will create it using CreateMutexW.
![](https://i.imgur.com/jcWVS11.png)
Anti-Debugging
NoEscape applies an anti-debugging method to detect if it is being debugged or not using DR registers which are CPU registers that hold addresses of Hardware breakpoints created by the analyst and it only created using a user debugger, there are 4 Register mean that there are only 4 Hardware breakpoints allowed per thread to be created, NoEscape checks all of these registers.
It also checks using Direct Win APIs like Is DebuggerPresesnt which returns 1 if its, and CheckRemoteDebuggerPresent to check for remote debugging sessions.
![](https://i.imgur.com/CLjec3H.png)
Anti-CIS Countries
The Ransomware checks if any of the installed input languages on the system correspond to CIS countries to prevent the NoEscape execution. So, upon examining function sub_426270, it first calls GetUserDefaultLangID and then It performs AND operation with the returned value against 0x3FF, the result of the AND operation will be measured to many cases, each case is relative to a specific country, If doesn’t match any case it will go through the default case which calls GetUserDefaultUILanguage and perform the same AND operation and Switch cases, if no case hit it will return to alter that this machine is allowed to be ransomed.
![](https://i.imgur.com/EHYNh3D.png)
Disabling UAC
NoEscape then will try to Disable UAC (User Access Control) to prevent showing or altering the user of any program needs to be allowed for execution, Disabling UAC and consent prompts can pose serious security risks, as it allows any program or process to run with full administrative privileges without user intervention.
It first decrypts 2 strings
- ‘EnableLUA’
- ‘SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System’
Then it Open a handle to this key using RegOpenKeyExW, the handle related to HKEY_LOCAL_MACHINE no the user, Next it will manipulate EnableLUA subkey, this key specifies whether Windows User Account Controls (UAC) notifies the user when programs try to make changes to the computer. UAC was formerly known as Limited User Account (LUA).
It sets this value with 0 using RegSetValueExW which means Windows doesn’t notify the user when programs try to install software or make changes to the computer.
![](https://i.imgur.com/yAXg1Ki.png)
It will do the same but this time with another subkey named ConsentPromptBehaviorAdmin, it will
set this key value with 0x0000000 and this option allows the Consent Admin to perform an operation
that requires elevation without consent or credentials.
![](https://i.imgur.com/42cFTx1.png)
Abusing COM for persistence
After disabling UAC, the malware will try to use COM (Component Object Model) to create a scheduled task.
creating the scheduled task using direct APIs may alter the defensive solutions into a malicious behavior so NoEscape uses COM for this function, so Let’s dive deep into how this is done.
- It uses GetEnvironmentVariableW to get ‘APPDATA\Roaming’ path, it then extracts the file name and extension using GetModuleFileNameW and then copy it to this path using CopyFileW.
![](https://i.imgur.com/913Y07F.png)
- Next It will create a COM instance from ITaskService interface using CoCreateInstance This interface provides access to the Task Scheduler service for managing registered tasks, the Instance handle or ppv is returned in the last argument, Next it will call ITaskService_interface->Connect t start operating with Task Scheduler service manager, if the return value of Connect method is 0 — S_OK that’s mean that the operation completed successfully.
![](https://i.imgur.com/DssTQh2.png)
![](https://i.imgur.com/aZbBEcn.png)
- Next it will call ITaskService::GetFolder, This method retrieves a folder from the Task Scheduler service. Folders in the Task Scheduler provide a way to organize tasks. the third argument will hold a handle or instance for ITaskFolder object, according to MSDN this interface provides the method that are used to register (create) tasks in the folder, remove tasks from the folder, and create o remove subfolders from the folder.
![](https://i.imgur.com/oNZm6C6.png)
- NoEscape is preparing to register its task with “SystemUpdate” to trick the normal users if the applied some normal investigation, so it deletes any registered task before with this nam “SystemUpdate”, it uses ITaskFolder::DeleteTask to delete a task from the folder.
![](https://i.imgur.com/h2NuJs5.png)
- Next it will register a new task using ITaskService::NewTask and it returns an empty tas definition object to be filled in with settings and properties, the third argument for this API will outpu with a handle to ITaskDefinition object, This interface represents a task definition, which contains al the settings and properties needed to define a task
HRESULT NewTask(
[in] DWORD flags,
[out] ITaskDefinition * ppDefinition
);
- it will then call ITaskDefinition::get_principal, This method retrieves the principal object associated with the task definition. The principal object contains information about the security context, including the user account, logon type, and other authentication settings, that the task will run under, the return value is saved in the second argument and it will hold IPrincipal object handle which is used to defines the basic functionality of a principal object.
![](https://i.imgur.com/8UkJkIp.png)
- Next it will call IPrincipal::put_RunLevel , This method sets the run level for the task’s security principal. The run level determines the privilege level at which the task will run. It takes an argumen that specifies the run level, it uses TASK_RUNLEVEL_HIGHEST as run level value to run the tas with the highest privileges, followed by calling ITaskDefinition::get_Triggers This method retrieve the collection of triggers that are configured for the task. Triggers determine when a task will b executed.
- The returned collection typically contains instances of trigger objects ITriggerCollection, each representing a specific type of trigger configured for the task. These triggers define the conditions under which the task should be triggered, such as a specific time, event, or system state change.
![](https://i.imgur.com/JGsOhaq.png)
- by using ITriggerCollection interface object it will call ITriggerCollection::Create twice to create two different Triggers.
TASK_TRIGGER_DAILY, Triggers the task on a daily schedule. For example, the task starts at a specific time every day, every other day, every third day, and so on.
TASK_TRIGGER_LOGON , Triggers the task when a specific user logs on.
this function returns an ITrigger interface that represents the new trigger, so we have two objects of ITrigger interface one for Daily Trigger and another for Login Trigger.
![](https://i.imgur.com/eivlr5g.png)
- Next it will call IUnknown::QueryInterface to query 2 interfaces objects IDailyTrigger (Represents a trigger that starts a task based on a daily schedule. For example, the task starts a a specific time every day, every other day, every third day, and so on) and ILogonTrigge (Represents a trigger that starts a task when a user logs on. When the Task Schedule service starts, all logged-on users are enumerated and any tasks registered with logon trigger that match the logged-on user are run)
![](https://i.imgur.com/q6v80Kn.png)
- Next It will set the ID and Activation time for the Daily trigger using ITrigger::put_Id and ITrigger::put_StartBoundary
![](https://i.imgur.com/33GXsxh.png)
![](https://i.imgur.com/2l4u4PH.png)
it then will call IDailyTrigger::put_DaysInterval, This method sets the number of days between each occurrence of the task. It specifies how often the task should repeat, measured in days, it uses 1 day as an interval time between task occurrences.
![](https://i.imgur.com/NlsXmFX.png)
Next, it will call ITrigger::get_Repetition to get an object from IRepetitionPattern interface, This method retrieves the repetition pattern associated with the trigger. The repetition pattern defines how many times the task should be repeated and the time interval between repetitions.
![](https://i.imgur.com/UNzdG4G.png)
next, it will call IRepetitionPattern::put_Interval, This method is used to set the time intervalbetween repetitions. You can specify the interval in milliseconds, seconds, minutes, hours, or days,depending on the requirements of your task, and it sets it to PT10M.
“PT” indicates that the following characters represent a time duration.
“10M” indicates 10 minutes.
![](https://i.imgur.com/b1wRQYj.png)
- it will use the same step done for Daily Trigger which is identified by “Trigger1”, The logon Trigger will be identified by “Trigger2”, the difference thing here is that i will call IRepetitionPattern::put_StopAtDuration with Logon Trigger “Trigger2” to get or set Boolean value that indicates if a running instance of the task is stopped at the end of the repetition pattern duration, it set it to False (0).
HRESULT ( *put_StopAtDurationEnd)
(
IRepetitionPattern *This,
VARIANT_BOOL stop
);
![](https://i.imgur.com/JdeV4zB.png)
- Next it will call ITaskDefinition::get_Actions method and it is used to retrieve a collection of actions associated with a task definition. In the context of Windows Task Scheduler programming, it allows you to access the actions that the task performs when triggered, so it returns IActionCollection object, and it uses it to call IActionCollection::Create and it sets the type of the action to TASK_ACTION_EXEC , This action performs a command-line operation. For example, the action could run a script, or start an executable.
![](https://i.imgur.com/F6JlYxR.png)
- here we come to the most important phase NoEscape assigns the dropped ransomware path to the created tasks, it uses IExecAction::put_Path to set the task path.
![](https://i.imgur.com/VgbXv0B.png)
Command Execution
NoEscape for the second time takes advantage of COM interfaces but this time it abuses COM for Command execution, it executes some WMI commands that pave the way for file encryption andremoves backups or shadow copies, so let’s delve into this functionality as we did before.
- it first decrypts the commands it wants to execute using decryption the appropriate index for each command.
![](https://i.imgur.com/IM4vMJP.png)
- Next it calls CoCreateInstance to create an object of IWbemLocator, the interface object handle is saved in the last argument for this API.
![](https://i.imgur.com/vFNGUKk.png)
- Then NoEscape decrypts a string “ROOT\CIMV2” and then gets a pointer toIWbemLocator::ConnectServer, The IWbemLocator::ConnectServer method creates aconnection through DCOM to a WMI namespace on the computer specified in thestrNetworkResource parameter, this function returns a object handle to IWbemServicesinterface, The IWbemServices interface is used by clients and providers to access WMIservices. The interface is implemented by WMI and WMI providers and is the primary WMIinterface.
The WMI namespace “ROOT\CIMV2” is the default namespace and contains classes for computer
hardware and configuration.
![](https://i.imgur.com/OgiqPIk.png)
- Next it decrypts 2 strings to be used later (‘Create’ , ‘Win32_Porcess’), and then it calls IWbemServices::GetObjectA , This method provided by the Windows Management Instrumentatio (WMI) API, which is used for retrieving a single instance of a managed object from the WMI repository
HRESULT GetObject(
[in] const BSTR strObjectPath,
[in] long lFlags,
[in] IWbemContext *pCtx,
[out] IWbemClassObject * ppObject,
[out] IWbemCallResult * ppCallResult
);
this function retrieves an object of a class, but you need to pass it the object path in the first argument (strObjectPath), and in our case, it passes Win32_Process (CIM class definition) as a class name.
The Win32_Process class is a part of the Windows Management Instrumentation (WMI) infrastructure, which provides a standardized way for administrators to query and interact with various aspects of a Windows operating system.
The Win32_Process class represents a running process on a Windows system. It containsinformation about processes currently executing on the system, such as their process ID, executablepath, command line arguments, and more.
the object is returned in the fourth argument ppObject and its type is IWbemClassObject interface.
![](https://i.imgur.com/hmRA03B.png)
- next it will execute a call to IWbemClassObject::GetMethod to get information about a method, The method in our case is ‘Create’ this method related to Win32_Process Class, so it will get information about Create method and all of that is saved in the fourth argument which will result in IWbemClassObject interface, so to process with Create method it needs to operate with th newly IWbemClassObject object, it then Spawn this object using IWbemClassObject::SpawnInstance to create a new instanc of a class.
![](https://i.imgur.com/c4ybjh1.png)
- Next it will call IWbemClassObject::Put to set set the property name to ‘CommandLine’ and then to set the command line to be executed by Create Method.
![](https://i.imgur.com/0o4hwi2.png)
- Then NoEscape will call IWbemServices::ExecMethod to execute Create Method from Win32_Process Class, and it passes the object path which is Win32_Process and the las spawned IWbemClassObject which holds information about Create Method.
(IWebmService_interface->lpVtbl->ExecMethod)(
IWebmService_interface,
Win32_process_string, // Win32_Process
0,
7,
0,
IWbemClassObject_interface_ref,
&Zero,
0);
so when ExecMethod is executed it will execute a call to Create Method, this function creates a new
process with the property name specified on Step7, which is the command line that holds the
command line NoEscape wants to execute.
uint32 Create(
[in] string CommandLine,
[in] string CurrentDirectory,
[in] Win32_ProcessStartup ProcessStartupInformation,
[out] uint32 ProcessId
);
and that is how NoEscape Abuses COM and WMI to execute commands stealthily. and here is a list of executed commands.
SHADOWCOPY DELETE /nointeractive
wmic SHADOWCOPY DELETE /nointeractive
wbadmin DELETE SYSTEMSTATEBACKUP -deleteOldes
wbadmin DELETE SYSTEMSTATEBACKUP -keepVersions:0
'wbadmin DELETE BACKUP -deleteOldest
wbadmin DELETE BACKUP -keepVersions:0
vssadmin Delete Shadows /All /Quiet
bcdedit /set {default} recoveryenabled No
bcdedit /set {default} bootstatuspolicy ignoreallfailures
Stopping and Deleting Services
When files are actively used by Windows services, accessing them for encryption may fail. To address this, NoEscape maintains a list of services to terminate and delete. The presence of these services on the system can hinder NoEscape’s operations.
- It first gets a handle to Service Control Manager using OpenSCManagerW , this API Establishes a connection to the service control manager on the specified computer and opens the specifie service control manager database, Next it gets a handle to the service using OpenServiceW.
![](https://i.imgur.com/JdTLQu2.png)
- Then it execute a call to QueryServiceStatusEx to get the current statues for the service, The statues statue is saved in a passed structure called SERVICE_STATUS_PROCESS, accessing dwCurrentState from this structure and comparing it against 1 (SERVICE_STOPPED) , which means that this service is stopped right now, so it closes the handle and do nothing.
![](https://i.imgur.com/ZzcTBgc.png)
- If the service’s current state is not SERVICE_STOPPED , It will check if it is SERVICE_STOP_PENDING which means that this service is stopping, Based on that it wil calculate the required time for the pending status to be SERVICE_STOPPED , To do this it access another element on SERVICE_STATUS_PROCESS called dwWaitHint , it expresses the estimated time required for a pending start, stop, pause, or continue operation, in millisecond, And after calculating the required time it executes a sleep call with this value., and it will loop until pending time ends.
![](https://i.imgur.com/Dhqgq0S.png)
- So all steps were related SERVICE_STOPPED, SERVICE_STOP_PENDING , but what if the service is running and there are other services there execution is dependent on this service, the malware is paving the way to stop the service but can’t do that without stopping services that require this service to be active, So it execute a call to EnumDependentServicesW to retrieve the name and status of each service that depends on the specified service.
![](https://i.imgur.com/PEk5Zak.png)
- The LpService argument is an array of ENUM_SERVICE_STATUSA that holds a structure for each enumerated service, And for each service, it will first get a handle using OpenService and then it uses ControlService to stop the service by passing SERVICE_CONTROL_STOP in the second argument, it will check if the service is stopped already after this call through Do While Loop, and when is get the service statue is SERVICE_CONTROL_STOP, it breaks the loop.
![](https://i.imgur.com/KBc83vs.png)
- After doing this for each dependent service on our specific service it will do the same with our service itself it will use ControlService to state the service with SERVICE_CONTROL_STOP Flag, inside a Do While loop it will call QueryServiceStatusEx and check for service statue until it becomes SERVICE_STOPPED if it is it will break the loop.
![](https://i.imgur.com/Rv9cxo8.png)
- So Now the service is ready to be deleted after stopping it, it will get a handle to service controlmanager and to the service and then execute a call to DeleteService by passing the servicehandle.
![](https://i.imgur.com/jLgNGFX.png)
and here is a list of services to be deleted using this explained way.
Culserver | DefWatch | GxBlr | GxCIMgr | GxCVD |
GxFWD | GxVss | QBCFMonitorService | QBIDPService | RTVscan |
SavRoam | VMAuthdService | VMUSBArbService | VMnetDHCP | VMwareHostd |
backup | ccEvtMgr | ccSetMgr | dbeng8 | dbsrv12 |
memtas | mepocs | msexchange | msmdsrv | sophos |
sql | sqladhlp | sqlagent | sqlbrowser | sqlservr |
sqlwriter | svc | tomcat6 | veem | vmware-converter |
vmware-usbarbitator64 | vss |
Process Termination
There is a list of processes that prevent NoEscape file encryption process, this list contains some Anti-Virus agents or office processes and other services and applications that may make getting file handles impossible, so NoEscape handles this by getting a snapshot of all running processes in the machine using CreateToolHelpSnapShot , using this snapshot it iterates over each process in the snapshot using Process32FirstW to get a PROCESSENTRY32W for the first process in the snapshot and then it uses Process32NextW to get the structure for the next process in the snapshot.
for each process, it gets its name by accessing PROCESSENTRY32W.szExeFile which holds the
name of the executable file for the process, and then it compares it against an kill_processes list in
the malware configuration.
if the comparison result it an equality it will get a handle to this process using OpenProcess and then
using this handle it calls TerminateProcess to kill this process.
![](https://i.imgur.com/itDsQtt.png)
![](https://i.imgur.com/eCI3PbA.png)
Processes List
360doctor | 360se | Culture | Defwatch | GDscan |
MsDtSrvr | QBCFMonitorService | QBDBMgr | QBIDPSerice | QBW32 |
RAgui | RTVscn | agntsvc | agntsvcencsvc | agntsvcisqlplussvc |
anvir | anvir64 | apache | axlbridge | backup |
ccleaner | ccleaner64 | dbeng50 | dbsnmp | encsvc |
excel | far | fdhost | fdlauncher | httpd |
infopath | isqlplussvc | java | kingdee | msaccess |
msftesql | mspub | mydesktopqos | mydesktopservice | mysqld-nt |
mysqld-opt | mysqld | ncsvc | ocautoupds | ocomm |
ocssd | onedrive | onenote | oracle | outlook |
powerpnt | procexp | qbpdate | sqbcoreservice | sql |
sqlagent | sqlbrowser | sqlmangr | sqlserver | sqlservr |
sqlwriter | steam | supervise | synctime | taskkill |
tasklist | tbirdconfig | thebat | thunderbird | tomcat |
tomcat6 | u8 | ufida | visio | wdswfsafe |
winword | wordpad | wuauclt | wxServer | wxServerView |
xfssvccon | vmcompute | vmwp | vmms | vds |
Deleting Event Logs
NoEscape tries to prevent an investigation by accessing Windows logs and deleting them.
it first decrypts 4 strings that represent 4 elements in Windows log collection sections,Application, Security, Setup, and System .
![](https://i.imgur.com/fIzRGfr.png)
next it gets a handle for each log source using OpenEventLogW and it uses the returned handle to clear the logs for this source using ClearEventLogW and it sets 0 in the second argument to indicate that this event log is not backed up.
![](https://i.imgur.com/ArDkYCO.png)
next it executes for /F “tokens=*” %1 in (\’wevtutil.exe el\’) DO wevtutil.exe cl “%1 , which iterates over the list of event logs on the system using wevtutil.exe el , and for each event log found, it clears the log using wevtutil.exe cl
MITRE ATT&CK
TACTIC | TECHNIQUE TITLE | MITRE ATT&CK ID |
Initial Access | Valid Accounts | T1078 |
Initial Access | External Remote Services | T1133 |
Initial Access | Phishing | T1566 |
Execution | Inter-Process Communication: Component Object Model | T1559.001 |
Persistence | Scheduled Task/Job: Scheduled Task | T1053.005 |
Privilege Escalation | Scheduled Task/Job: Scheduled Task | T1053.005 |
Privilege Escalation | Access Token Manipulation | T1134 |
Defense Evasion | Abuse Elevation Control Mechanism: Bypass User Account Control | T1548.002 |
Defense Evasion | Indicator Removal: Clear Windows Event Logs | T1070.001 |
Defense Evasion | Impair Defenses: Disable or Modify Tools | T1562.001 |
Defense Evasion | Debugger Evasion | T1622 |
Defense Evasion | Modify Registry | T1112 |
Credential Access | OS Credential Dumping | T1003 |
Discovery | Network Share Discovery | T1135 |
Discovery | Query Registry | T1012 |
Discovery | System Service Discovery | T1007 |
Collection | Archive Collected Data: Archive via Utility | T1560.001 |
Impact | Data Encrypted for Impact | T1471 |
Impact | Inhibit System Recovery | T1490 |
Impact | Service Stop | T1489 |
Indicators of Compromise
IOC | Type |
68ff9855262b7a9c27e349c5e3bf68b2fc9f9ca32a9d2b844f2265dccd2bc0d8 | SHA256 |
68e5caa3f0fd4adc595b1163bf0dd30ca621c5d7a6ad0a20dfa1968346daa3c8 | SHA256 |
8FAF3B4047CD810CA30A6D7174542DC1E1270AD63662AE2F53D222A8A9113AF8 | SHA256 |
Yara Rule
rule NoEscape_Ransomware
{
meta:
author = "Aziz Farghly - Dark Atlas Squad"
description = "Detects NoEscape Ransomware"
sharing = "TLP:WHITE"
hash = "68ff9855262b7a9c27e349c5e3bf68b2fc9f9ca32a9d2b844f2265dccd2bc0d8"
hash2 ="68e5caa3f0fd4adc595b1163bf0dd30ca621c5d7a6ad0a20dfa1968346daa3c8"
hash3 ="68e5caa3f0fd4adc595b1163bf0dd30ca621c5d7a6ad0a20dfa1968346daa3c8"
hash4 ="8FAF3B4047CD810CA30A6D7174542DC1E1270AD63662AE2F53D222A8A9113AF8"
date = "04/05/2024"
strings:
$op1= {83 F8 01 75 0A E8 [4] 5? 8B E5 5D C3 83 F8 02 75 0A E8 [4] 5? 8B E5 5D C3 83 F8 03 75 0A E8 [4] 5? 8B E5 5D C3
83 F8 04 74 ?? 83 F8 05 75 0A E8 [4] 5? 8B E5 5D C3 83 F8 06 75 ?? E8 [4] 8B ?? E8 [4] 8B ?? E8 [4] 8B ??
E8 [4] 8B ?? E8 [4] 5? 8B E5 5D C3
} // switch cases used in malware core function that determine which method to execute
$s1 = "Trigger1" wide ascii
$s2 = "Trigger2" wide ascii
condition:
uint16(0) == 0x5A4D and all of them
}