For the complete documentation index, see llms.txt. This page is also available as Markdown.

SakDriver: Reversing a Kernel Driver Rootkit

Cobalt Strike is a paid penetration testing product that allows an attacker to deploy an agent named 'Beacon' on the victim machine. Beacon includes a lot of functionality to the attacker, including, but not limited to command execution, key logging, file transfer, SOCKS proxying, privilege escalation, mimikatz, port scanning and lateral movement. Beacon is in-memory/file-less, in that it consists of stageless or multi-stage shellcode that once loaded by exploiting a vulnerability or executing a shellcode loader, will reflectively load itself into the memory of a process without touching the disk. It supports C2 and staging over HTTP, HTTPS, DNS, SMB named pipes as well as forward and reverse TCP.

The Beacon implant has become popular amongst targeted attackers and criminal users as it is well written, stable, and highly customizable.

Technical Analysis

Upon having the cobalt strike beacon sample I ran basic checks and tools to gather initial information about the agent. It uncovered that what i am looking at is not a user land beacon but a kernel rootkit loading as a driver.

It actively hooks and patches the ETW(Event Tracing for Windows) structure in kernel which blinds the defense system before it even logs an event. It also hides and unhides process via DKOM(Direct Kernel Object Manipulation), hides the C2 communication port NSI_HIDE_PORT and unblocks IP WFP_UNBLOCK_IP using the WFP(Windows Filtering Platform) which is the core architecture behind the windows firewall.

It also has to do something with the time stamp counter in hypervisor likely when the rootkit is in a sandbox environment. The driver is named as SakDriver with a PDB path pointing to E:\tools\oldfilelaoda\x64\Release\CrackerDrv.pdb .

After loading it in IDA, in DriverEntry function which is the main entry function for a driver, it uses the DriverObject, created by I/O manager for each driver that has been installed and loaded which contains storage for entry points of driver routines such as DriverEntry, Unload, MajorFunction etc. and also information like DriverName .

Now further in function, it use the member DriverSection (pointer to _KLDR_DATA_TABLE_ENTRY in kernel mode containing information about the loaded module) and sets the unload routine to DriverUnload after which it loads the DLL name from offset 0x48 .

Now if the driver is already present in system it then iterates through the FullDllName->Buffer to find string \SystemRoot\System32\Drivers using custom loop rather than using kernel API’s and search for driver’s name.

Then it calls a function which takes the driver name and opens a handle to the \\Registry\\Machine\\System\\CurrentControlSet\\Services (store information about each service), allocating a Non-Paged memory region with NX(No-Execute) of 0x218 bytes with tag CvrD and then iterates over each subkey under Services and fills the PoolWithTag region with KEY_BASIC_INFORMATION .

It then opens handle for the intended driver and query its ImagePath (points to location of file) and stores path into a global state then it registers the driver as a minifilter driver (type of driver used to monitor, intercept and modify file system I/O requests) and sets IRP_MJ_DIRECTORY_CONTROL as MajorFunction to have control over directory I/O request to evade scans by AV softwares.

It then fingerprints OS information of the victimized user and prepares a POST request to send this info to a C2 server(43.160.247.24) at /api/event.php endpoint with a custom user-agent SakDriver 1.0.

In case, if it’s a fresh installation then it installs the driver into system at one of the paths\\Device\\HarddiskVolume%lu\\Windows\\System32\\drivers\\DRIVER_NAME , \\??\\C:\\Windows\\System32\\drivers\\DRIVER_NAME with naming sak_XXX.sys and the XXX is a random seed containing XOR’s of a memory region, frequency performance counter, PID and TID. Also it registers the service as msXXXX in registry at \\Registry\\Machine\\System\\CurrentControlSet\\Services\\SERVICE_NAME as Microsoft Player Service display name and Provides support for %04X operations as description to camouflage itself as a legitimate windows service and in case of error registers itself as SakDriver ( Not OPSec friendly :) ) and if everything goes right it sends install_success mark to C2 and deletes the dropper.

Now it queries system to get the memory address of ntoskrnl.exe , and then build its own Import Address Table(IAT) in memory to use kernel API’s by deobfuscating API names and resolving their address during runtime using sub_14000E34C which will take address of ntoskrnl and decrypted API name to manually parse PE header to find the Export Directory which will be used to get address of those API’s , it will also help to bypass EDR’s static scanning.

It then call CmRegisterCallbackEx to register a RegistryCallback routine, which is called every time a thread performs an operation on the registry. The registry callback function named Function performs function like If an AV software tries to modify the registry keys of rootkit, it catches that modification and throws STATUS_ACCESS_DENIED which will abort registry modification.

Here’s the interesting part, now what author did is, it is using its own registry callback to receive C2 commands from a user-mode agent. So if a user-mode agent writes the command in benign registry using user-land API’s it completely evades EDR scans, although for every write driver checks for a specific magic bytes 0x2625B7146B and extracts commands from it.

Command ID
What It Does

22661

Arbitrary Read/Write Process memory (attaches kernel thread to address space of target process, locks and map the memory to kernel then reads or writes into process memory)

13592

Performs KVA Shadowing bypass to inject and steal information from user-land process.

13129

Allocates memory in the victim process to perform Process Injection

13128

Free the allocated memory after thread finish execution

12937

Copies data between 2 different process i.e. rootkit and user-land

10246

Attach to user-land process and parse the dll to locate the API names address ex. VirtualAlloc.

9072

Forcefully deletes the protected or executing files

8784

Kernel to User-mode DLL injection via Kernel APC queuing (parses PEB to locate kernel32.dll and finds address of LoadLibrary by parsing dll)

8306

Defensive measure by setting a callback whenever system does OpenProcess or OpenThread and intercept handle, threads opened for rootkit and strips out permissions like PROCESS_TERMINATE, PROCESS_QUERY_INFORMATION and also it bypass access rights for low privilege process to higher ones(setting access to PROCESS_ALL_ACCESS) specifically for v8(still need to find out).

16964

Query memory for basic information about the region

22323

Read/Write to any physical memory address by read/writing to its virtual pointer which is obtained by building a custom page table with RW permissions and injecting that into empty space in PML4. Also copies data directly from physical address

13831

Resolves PID by process name

13664

Spoofs hardware to send packets in form of mouse or PS2 keyboard/mouse data and execute the callback with forged input. \\Driver\\mouhid and \\Driver\\i8042prt

37720

Reads the memory of a process by querying PFN database and mapping addresses

39029

Changes the protection of page

38536

Returns process section base address from EPROCESS structure

38435

Walks PEB of a process to loop through loaded DLLs and match it with attacker supplied name eg. kernel32.dll and returns base address of DLL

37973

Extracts driver name

29557

Deobfuscate APIs and gets their address also applies system wide hooks on CKCL, ETWP, Syscall Table, HvlGetQpcBias, GetCpuClock. Else it scans win32kfull.sys for a specific pattern in text section to get address of undocumented function

29556

Spoofs hardware to send packets in form of keyboard or PS2 keyboard/mouse data and execute the callback. \\Driver\\kbdhid and \\Driver\\i8042prt

25736

Perform Hardware spoofing for Disk, Nvidia GPU, SMBIOS

25897

Executes a user thread with attackers DLL/ malicious function

29462

Reflective PE loading

It then applies a stealth layer on the registry to avoid any read or write query on the drivers service by AV and EDRs.

These are the things it perform as a callback function, and now coming back to Main entry it now perform Network filtering by blocking the requests made by security solutions to C2 IP and port. It also hides some ports like 6891, 12341, 12342, 12343, 6543, 7543, 9199 by hooking NSI driver.

Then it tries to create a WFP device object so that it can observe the network stack and adds just-do-it.icu and 91.99.165.207 to the blocking table.

IOCs

  • Domain and IP: just-do-it.icu, 91.99.165.207, 43.160.247.24 and these domain and IPs haven’t been flagged by VirusTotal yet and infra is still working.

  • Ports: 6891, 12341, 12342, 12343, 6543, 7543, 9199

  • Endpoint: /api/event.php

  • Hash: 4e95aba17c1a423cda5cc9f9f04f7cf8db17e294eb31ed1aa85063601b82fe8d

  • Driver name: SakDriver, sak_xxx.sys, ms_xxxx

Yara Rule

Last updated

Was this helpful?