EDR, or Endpoint Detection and Response, refers to an integrated endpoint security solution that continuously monitors devices to prevent malicious actors from gaining access to the system. Along with Detection and Prevention, an EDR solution also provides features such as Threat Hunting and Forensic Analysis. An EDR is an essential tool for a security team today allowing them to build defensive capability with detection rules, queries to hunt for specific threats, inspect assets remotely and even respond to threats in real-time by isolating systems from the network or quarantining malicious programs.
In this blog, we are going to look at the foundations of an EDR, how it gains visibility into malicious activities and what are ways to bypass it so that you are not detected.
As detection software, an EDR gathers logs and telemetry from all configured sources, such as event log files, running applications, network connections, authentication attempts, RPC calls etc.
The EDR agent usually has two components for gathering data, a user-mode application and a kernel-mode driver. These components then collect data using a variety of methods. This data is stored for future investigation, proactive threat hunting, and sometimes used for establishing baselines using Machine learning.
The data is then correlated based on existing rules and signatures to find any anomaly. On detection, corresponding alerts are pushed to security dashboards, and a response is initiated depending on predetermined triggers.
Most Modern EDRs use a combination of Signature and Behaviour Based Detection.
Signature Based Detection utilises a unique set of data specific to a threat. It is based on the latest threat intelligence, where people have submitted known malicious bytes or IOCs to quickly flag and stop a threat.
It is easy to change these signatures are hence they are not hard to bypass. However, it still adds an initial security layer that quickly detects any threats without looking at the behaviour.
Behaviour-based detection, on the other hand, evaluates an executable during runtime based on the actions. An executable's behaviour, or in some cases its potential behaviour, is analysed for suspicious activities. For example, attempts to perform abnormal or unauthorised actions indicate the object is malicious or at least suspicious.
Behaviour-based detections are harder to bypass as it requires mimicking the system and performing activities which don't seem abnormal. An EDR sees the behaviour of the process by using the telemetry provided to it by the OS. So to defeat behaviour-based detections, we have to take away these sources.
Signature-based detections are based on a set of bytes or IOCs which are known to be malicious. These bytes and IOCs are stored in a database and can be quickly compared when a file is dropped to disk.
There are two primary methods for creating signatures for threats.
Yara Rules are a way of identifying malware by creating some rules which looks for certain character in a binary, An example yara rule looks like this:
1import "pe" 2 3rule IndiaGolf 4{ 5 meta: 6 copyright = "2015 Novetta Solutions" 7 author = "Novetta Threat Research & Interdiction Group - trig@novetta.com" 8 Source = "3dda69dfb254dcaea2ba6e8323d4b61ab1e130a0694f4c43d336cfb86a760c50" 9 10 strings: 11 /* 12 FF D6 call esi ; rand 13 8B F8 mov edi, eax 14 C1 E7 10 shl edi, 10h 15 FF D6 call esi ; rand 16 03 F8 add edi, eax 17 89 7C 24 20 mov [esp+2A90h+var_2A70], edi 18 FF D6 call esi ; rand 19 8B F8 mov edi, eax 20 C1 E7 10 shl edi, 10h 21 FF D6 call esi ; rand 22 03 F8 add edi, eax 23 89 7C 24 24 mov [esp+2A90h+var_2A6C], edi 24 */ 25 26 $generateRandomID = {FF ?? 8B ?? C1 ?? 10 FF ?? 03 F8 89 [3] FF ?? 8B ?? C1 ?? 10 FF ?? 03 ?? 89} 27 28 condition: 29 $generateRandomID in ((pe.sections[pe.section_index(".text")].raw_data_offset)..(pe.sections[pe.section_index(".text")].raw_data_offset + pe.sections[pe.section_index(".text")].raw_data_size)) 30}
This Yara rule looks for random id generation for a malware family.
Yara rules can be more complicated than just matching specific bytes. You can match byte patterns, various types of encoding, module imports(imphash) etc.
To bypass a brittle signature like yara rule, you can check for these bytes and replace them with alternatives. You can also use cryptors and obfuscators to change these bytes or store them in an encrypted manner to bypass these signatures
An Indicator of Compromise (IOC) is a piece of digital artefact that suggests a compromise has happened. As with physical evidence, this digital evidence can quickly identify malicious activities.
IOCs looked at by EDRs are File Hashes, Domains Names, and IP Addresses. If any binary has a known malicious hash or communicates with a malicious IP/Domain, it is an instant detection opportunity.
You cannot bypass IOC signatures; instead, you need to build new binaries with different hashes, acquire other domains that are not categorised as malicious, and run your operation using the new infrastructure.
Behaviour-based detections are runtime detections based on actions which are not typical for that application or are known malicious behaviours. An EDR gains visibility on these actions by loading various modules in the process space when the process starts. The EDR also monitors events from the kernel using its kernel driver, and these events are then correlated to decide if the behaviour is malicious or benign.
Every executable uses the API calls present in the operating system to perform any action. For example, if you have to write to a file on Windows OS, you use the API WriteFile
. To determine whether an action is malicious, it is crucial to monitor these API calls and check the parameters to decide if the API call is for a malicious or benign purpose.
This is done using a procedure known as Userland Hooking. Every EDR solution injects a module into every process on the endpoint. This Module, upon loading, hooks the API calls so that they can be monitored. The EDRs do this by modifying the executable bytes of the actual API in memory to redirect the call to the EDR Monitoring component. This component analyses the parameter and considers various other factors to pass a decision. If the call is deemed to be benign, it is sent to the actual API, and if it is deemed to be malicious, the process is killed, and an alert is raised.
To bypass Userland Hooking, we can call the Kernel function directly by setting up appropriate registers and using the syscall instruction. This will avoid the userland hooks, and our parameters won't be scrutinized by the EDR, allowing us to perform malicious actions.
But wait, this creates an anomaly. If a syscall is made using a module from which it is not expected, the EDR can flag this behaviour as suspicious and stop it. EDRs have two ways to identify this anomaly.
Process Instrumentation Callback is an undocumented feature which can be used to trace the API calls. Just like the kernel component, using PIC, you can determine the source of the syscall and take decisions accordingly. Since the callback is set in the address space of the process, and we always have full control over our own process, you can easily remove it by calling the Undocumented API
NtSetInformationProcess
with Callback set toNULL
.
Event Tracing for Windows (ETW) provides a mechanism to trace and log events that are raised by user-mode applications and kernel-mode drivers. ETW is implemented in the Windows operating system and provides developers with a fast, reliable, and versatile set of event-tracing features.
ETW can also be used to detect threats, as the EDRs can monitor these events. Taking an example of the Microsoft .NET runtime provider, the provider sends event logs in JSON format to any subscriber of the runtime provider. An EDR can use these logs to flag and stop malicious actions.
These ETW functions are loaded in the process's address space so they can send the relevant logs from the process. Since we control our address space, we can patch these functions to return without sending any logs. For example, in ntdll.dll, we have the function
EtwEventWrite
, which is called right after .Net Runtime is loaded in a process. We can patch the function so that no logs are sent on runtime loading.
AMSI, or Antimalware Scan Interface, is a standard that allows an EDR to scan various applications and services for malicious activities. AMSI is integrated into Powershell, Wscript, Cscript, JavaScript, VBScript and VBA Macros. The amsi.dll is loaded into these processes, and using the dll; the EDR can see what is potentially being performed.
Just the ETW, AMSI is also loaded in the process's address space can also be patched so that there is no detection.
As you can notice, the userland components can be evaded trivially. The bypasses may create anomalies which can be detected, but there are methods to avoid those anomalies. such as Patchless Patching using Hardware Breakpoints
and Thread Stack Spoofing to spoof CallStacks
.
Since data from User mode cannot be trusted, EDR vendors are transitioning towards the kernel data source for their detections, namely callbacks and minifilters. The purpose of Minifilters is to intercept file system I/O requests and extend or replace the native functionalities. Meanwhile, callbacks are the one needed to intercept process/threads creation and image loading.
A Minifilter Driver is a driver that runs in Kernel Mode and can look at I/O operations from Kernel. For each I/O operation, callbacks can be registered, which will notify the driver of specific actions, such as Process Creation, Registry Modification, etc. The Minifilter component of the EDR registers these callbacks to get untampered data directly from Kernel.
Some of these callbacks are:
PspCreateProcessNotifyRoutine
For process creationPspCreateThreadNotifyRoutine
For thread creationPspLoadImageNotifyRoutine
For image loadingCmRegisterCallbackEx
For registry callbacksObRegisterCallbacks
For object creation callbacks.The PspCreateProcessNotifyRoutine notification triggers the EDR to load its user-mode dll into any created processes.
These callbacks and mini filters are also responsible for protecting the EDR components from tampering, as any attempt to tamper can be seen and blocked directly on the kernel.
The Kernel is the source of all truth, and it is crucial to blind the EDR of this data. To remove the Minifilter driver, you can use the fltMC.exe
, a built-in tool of windows to manage mini-filter drivers. Using an elevated shell, you can use fltMC.exe
to unload the Minifilter driver. Though, the EDR can detect and block this activity.
Another option is to use a vulnerable driver to gain access to kernel mode and remove the mini-filter from the Kernel side. You can also remove the registered callbacks, and now the EDR doesn't inject any monitoring Dlls into your newly created processes.
From the previous section on Kernel Mode, you might get the wrong impression that the Kernel components are only responsible for preventing tampering, whereas the actual detections are happening in userland. Not quite so; the kernel also has another data source like ETW, known as ETW-Ti.
Modern EDRs utilise ETW-Ti to receive logs from the kernel. The Kernel Patch Protection periodically checks to ensure that the kernel's protected system structures have not changed. If a change is detected, the result is a blue screen and/or a restart.
Since the functions responsible for sending logs are defined in the kernel itself, and you cannot patch the kernel, you cannot patch these functions. Instead, it is better to disable the EDR component from Kernel Mode so that you are not detected while performing malicious actions.
Anomaly Detection for an EDR is the identification of rare occurrences or events of concern due to their differing characteristics from the majority of the processed data. These outliers can represent security issues since it is not seen during normal operations. Red Teams should avoid these common pitfalls so that they are not caught.
Network connections are made by processes which require a network connection to perform some tasks. In any organisation, only some executables would open network connections; however, if you are making network connections ensure that you are making them from the process that usually does make those connections.
If you utilise a paint.exe DLL hijacking and start making network connections to random domains, a credible blue team will instantly have an alert for this detection.
If you are making SMB connections, ensure you do it from a process that does make SMB connections.
There are more examples of these behaviours so ensure that you don't stick out like a sore thumb.
During a routine operation, some executables create child executables, and some executables don't create child executables. For example, a parent-child relationship of Word.exe spawning cmd.exe is suspicious since word never spawns cmd.exe. It can be indicative of an exploit or maldoc.
Named Pipes are a way of interprocess communication. Two processes can exchange information over named pipes. Red Team tools also require exchanging information between various instances for communication.
It is crucial to give a name to your named pipe which matches the process you are impersonating. In Cobalt Strike, the named pipes are of the format msagent_##, but if you have migrated to the Chrome binary, then the named pipes must follow the chrome named pipe regex mojo\.%d+\.%d+\.%d+
otherwise, this anomaly can be easily detected
As the detections on PowerShell tooling have matured, attackers have been moving towards C-Sharp tooling for their needs. However, c-Sharp tools don't run directly; they load the CLR or Common Language Runtime to run the C-Sharp bytecode. This loading of CLR in processes is an anomaly as the runtime DLL(clr.dll) Module Load notification and CLR Load notification are sent to EDR for scrutiny. It is crucial to inject your tooling only in those processes which are known to load CLR so that you don't trigger the anomaly detections.
EDR Vendors keep updating their detections based on the current threat landscape, and similarly, the Red Teams also need to stay on their toes to stay one step ahead. It's a cat-and-mouse game, but the goal is to keep the organization safe against threats in the wild. Understanding the fundamental working of a defensive solution is crucial to understand its limitations and fulfilling those gaps using some other strategy. We have tackled the knowns. The next step is to be Proactive and tackle the unknowns.