Brute Ratel v0.9.0 (Checkmate) is biggest release for Brute Ratel till date. This release brings major changes to the Brute Ratel’s loader, reflective DLL, shellcode and the internal APIs being called. As detailed in the previous version, where several syscall injection techniques were added for evasion, but they were limited to the reflective DLL’s loader of BRc4 and the VEH (Vectored Exception Handler) API of Windows. This version uses an updated version of Syscalls for almost everything except a few of those which I was pretty sure would never be hooked since they are too noisy. This release was built after reverse engineering several top tier EDR and Antivirus DLLs. A quick summary of the changes can be found in the release notes.
The biggest highlight of this release is the self-debugging mini-debugger called ‘Checkmate’ which was written purely in assembly (x64 only). I wrote this console application debugger sometime back which allowed me to hook several functions and syscalls in order to enumerate the page memories, traverse back and forth to hunt for a specific set of instructions. This was written without using any Windows or Native API in order to avoid any type of hook that can be added to the Badger. In the previous release, the Badger used the VEH (Vectored Exception Handler) which tracked the NTAPIs hooked by the EDRs, however this used the AddVectoredExceptionHandler
WinAPI. I wanted to avoid using this WinAPI altogether since it is uncommon for legitimate applications to use this API call. This API call is mostly found in debuggers and any EDR which hook this WinAPI can possibly tag it as a direct anomaly.
Since this was bugging me, I spent sometime reversing the DLLs of severals EDR, understanding their hooking pattern and optimizing the debugger at the same time while trying to avoid the use of AddVectoredExceptionHandler. After spending a few sleepless nights and lots of coffee, I was able to write a full fledged debugger which does not use any WINAPI call. Checkmate now has ability to track the short and long jumps, function calls, parameters passed to the functions, find base memory address of newly allocated regions, and search for a specific set of instructions while walking the memory.
The miniature debugger pauses the current execution when any syscall is made, eg.: NtOpenProcess, NtReadVirtualMemory and so on, it traces the jump calls made by NTAPI and follows the trampoline jump instructions added by the EDR. Post finding the jumps, it identifies the opcodes manually and traces the exact location of the syscall which is either stored in the EDR’s memory, or sometimes in the memory of a random DLL which was loaded by your process. The below figure shows the debugger which hunts down the syscalls stored anywhere in the current process memory. And you can see the jumps it found which it iterates over and walks through the opcodes till it finds the exact location of the syscall.
The below example shows a hook placed by an EDR which stores the hooked syscalls in the memory space of the main executable PE itself instead of storing them in it’s own memory. This becomes more fun when the EDR sometimes randomly selects a loaded DLL and places the hooked instructions in them.
While building this technique, it was found that some EDRs store the syscalls in a READONLY region with guard pages enabled, whose memory permissions are changed by the EDR’s DLL itself, if it finds the call is legitimate. However, if ‘CheckMate’ finds any such pages, it will automatically point itself to the guard removal code in the EDR’s dll, execute those instructions and then point the RIP to the syscall found. Once the syscall is found, it overwrites its own RIP instructions and points itself to the found syscall, making sure that the execution is performed at the place where the EDR saved the original instructions instead of modifying and removing the syscall hooks. It auto-manages the stack and the registers to call the syscall, while preserving the existing information in the registers. All of this was done in order to avoid tampering the EDR DLL’s memory or removing the hooks, since removing the hook itself is monitored sometimes by the EDR. I like to call these as Traced Syscalls instead of unhooked syscalls since we are not unhooking them anymore.
All of this basically means the Syscalls are now totally free from any type of hooks performed by EDR’s DLL which get loaded as a System DLL instead of a normally injected DLL (because system DLLs can be loaded before kernel32.dll or kernebase.dll in order to add a Kernel trap). All the Native APIs mentioned below are the ones which are now replaced with Syscall Tracing using Checkmate:
NtAllocateVirtualMemory | NtQueueApcThread | NtGetContextThread | NtCreateTransaction |
NtFlushInstructionCache | NtResumeThread | NtSetContextThread | NtOpenFile |
NtProtectVirtualMemory | NtAlertResumeThread | NtWaitForSingleObject | NtCreateFile |
NtWriteVirtualMemory | NtOpenProcess | NtClose | NtQuerySystemInformation |
NtCreateSection | NtSetInformationProcess | NtTerminateThread | NtReadVirtualMemory |
NtMapViewOfSection | NtQueryInformationProcess | NtCreateEvent | NtReadFile |
NtCreateThreadEx | NtDuplicateObject | NtSignalAndWaitForSingleObject | NtQueryInformationFile |
Shadowcloak was one of the special features of Brute Ratel which was released in version 0.7 - Tsukuyomi. It used a unique technique to dump the lsass memory without touching the disk or calling MiniDumpWriteDump. This release enhances ShadowCloak by using syscalls for all of it’s WINAPI/NTAPI calls including opening process handles and reading virtual memory. Another command was built on top of Shadowcloak
in this release which is memdump
. The memdump
command uses the same technique as Shadowcloak, but instead of dumping lsass.exe, it can dump the memory of any other process too and doesn’t necessarily require you to be privileged if the target process running has the same privilege of your Badger. The below figure shows dumping the memory of explorer.exe and exfiltrating it directly to your Ratel server without dropping it to disk.
Another feature which I missed having in Badger was the token privilege modification command. This is added in the current release with the addpriv
command. An operator can use it to enable any privilege they want in the badger. The below example shows the privilege for SeLoadDriverPrivilege acquired by the badger. A detailed list of privileges which can be enabled can be found in the microsoft documentation.
The applist
command was added to enumerate a list of installed applications on the host. Everything that usually shows up in the Add or Remove Programs of Control Panel will be shown over here.
File preview is a feature that a customer requested to read the first few bytes of the file from disk. At times, there are scenarios where you are in a Red Team engagement, and the customer doesn’t want you to download the file due to confidentiality issue, but wants the operator to prove that they have the ability to read the file. This command preview
does exactly that. It reads the first 8192 bytes of a file from disk and displays the contents on to the screen. If you want to read the whole file however, then you would need to download it and view it offline. This also evades any sorts of DLP that might’ve been installed since it uses the Checkmate’s syscall techniques to open a file HANDLE and read the file.
Along with the file preview feature, I thought it would be a good addition to show if a file on disk was modifed, or who it actually belonged to by reading the metadata of the file. The fileinfo
command reads the size, creation time, last access time, last write time, change time, company name and the description of the file and prints it to screen.
The lookup
is another command which is extremely handy when you want to check the DNS cache on your host and might want to know which IP it belongs to.
That’s all with this release for now. Almost every API being called is basically a Syscall in the badger and all future releases will be using the Checkmate technique i.e syscalls henceforth. This release was heavily tested with multiple EDRs before release and it is highly recommended to upgrade to this release if you want to avoid some extremely low level detections.