A Deep Dive into Brute Ratel C4 payloads – Part 2

Summary

Brute Ratel C4 is a Red Team & Adversary Simulation software that can be considered an alternative to Cobalt Strike. In this blog post, we’re presenting a technical analysis of a Brute Ratel badger/agent that doesn’t implement all the recent features of the framework. There aren’t a lot of Brute Ratel samples available in the wild. This second part of the analysis presents the remaining commands executed by the agent. The commands include: user impersonation, inject shellcode into processes, create and stop processes, extract information about the processes and services, create TCP listeners, block keyboard and mouse input events, extract Windows registry keys and values, and others. You can consult the first part of the analysis here.

Technical analysis

SHA256: d71dc7ba8523947e08c6eec43a726fe75aed248dfd3a7c4f6537224e9ed05f6f

We continue to describe the commands that can be used by the Brute Ratel agent.

0x0703 ID – Stop the current process

The malware stops the current process by calling the ExitProcess API:

Figure 1

0x6BAE/0x6F39 ID – User impersonation

The binary retrieves a pseudo handle for the current process using GetCurrentProcess:

Figure 2

OpenProcessToken is utilized to open the access token associated with the process (0x28 = TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY):

Figure 3

The process extracts the locally unique identifier (LUID) for the “SeDebugPrivilege” privilege (Figure 4).

Figure 4

The executable enables the above privilege via a function call to AdjustTokenPrivileges:

Figure 5

The running processes are enumerated using the Process32FirstW and Process32NextW functions:

Figure 6
Figure 7

The agent is looking for the “LogonUI.exe”, “winlogon.exe”, and “lsass.exe” processes:

Figure 8

It opens the first process found using the OpenProcess method (0x400 = PROCESS_QUERY_INFORMATION):

Figure 9

ImpersonateLoggedOnUser is used to impersonate the security content of the user extracted from the process identified above:

Figure 10

In order to confirm that the operation was successful, the malware calls the GetUserNameW API (see Figure 11).

Figure 11

The message displayed in Figure 12 will be sent to the C2 server:

Figure 12

On another branch, the binary calls the DuplicateTokenEx method in order to duplicate the access token extracted from “winlogon.exe” or “lsass.exe”. Finally, a new process is created using CreateProcessWithTokenW.

0xA86A ID – Inject code into a remote process

The malicious executable converts the process ID passed as a parameter using atoi:

Figure 13

The shellcode to be executed is Base64-decoded by calling the CryptStringToBinaryA API (0x1 = CRYPT_STRING_BASE64):

Figure 14

The badger opens the target process using OpenProcess (0x1F0FFF = PROCESS_ALL_ACCESS):

Figure 15

VirtualAllocEx is utilized to allocate a new memory area in the remote process (0x3000 = MEM_COMMIT | MEM_RESERVE, 0x4 = PAGE_READWRITE):

Figure 16

The malware writes the shellcode to the above area via a function call to WriteProcessMemory, as shown in Figure 17.

Figure 17

The page’s protection is changed using the VirtualProtectEx API (0x20 = PAGE_EXECUTE_READ):

Figure 18

Finally, the binary creates a thread in the remote process that executes the shellcode:

Figure 19

0xE9B0 ID – Create a process and read its output via a pipe

The agent creates an anonymous pipe using the CreatePipe method:

Figure 20

The pipe is set to be inherited via a call to SetHandleInformation (0x1 = HANDLE_FLAG_INHERIT):

Figure 21

The malicious executable creates a process specified by the C2 server using the CreateProcessA API, as shown in the figure below.

Figure 22

The process’ output that resides in the anonymous pipe is copied into a buffer by calling PeekNamedPipe (Figure 23).

Figure 23

The output is read using ReadFile and then transmitted to the C2 server:

Figure 24

0x91B3 ID – Inject code into the current process

The CryptStringToBinaryA method is utilized to decode from Base64 the shellcode that will be executed:

Figure 25

The agent creates a named pipe (0x80000003 = FILE_FLAG_WRITE_THROUGH | PIPE_ACCESS_DUPLEX):

Figure 26

A new thread is created using the CreateThread function. In this thread, the malware connects to the pipe and reads data using the ConnectNamedPipe and ReadFile methods:

Figure 27
Figure 28

VirtualAllocEx is used to allocate a new memory area in the current process:

Figure 29

The shellcode is copied into the new area and its page is made executable, as highlighted below:

Figure 30

A new thread runs the shellcode copied earlier:

Figure 31

0x1719 ID – Enable SeDebugPrivilege

The malicious process calls the LookupPrivilegeValueA function with the “SeDebugPrivilege” parameter:

Figure 32

The PrivilegeCheck API is utilized to determine if the above privilege is enabled in the access token:

Figure 33

The message displayed in Figure 34 will be sent to the C2 server as a confirmation.

Figure 34

0x4FFE ID – Extract the status of the token’s privileges

The badger obtains the TOKEN_PRIVILEGES structure that contains the privileges of the token using GetTokenInformation (see Figure 35).

Figure 35

It retrieves the name of the privileges represented by a locally unique identifier (LUID) via a function call to LookupPrivilegeNameW:

Figure 36

The list of privileges and their status is written in the memory. The following statuses can be specified: “[+] %-50ls Enabled (Default)”, “[+] %-50ls Enabled (Adjusted)”, “[+] %-50lsDisabled\n”, “[+] Elevated”, or “[+] Restricted”.

Figure 37

0x9DE0 ID – Extract Username, PPID, PID, and Executable path for every running process

The binary obtains a snapshot of all processes in the system using CreateToolhelp32Snapshot. It enumerates them using the Process32FirstW and Process32NextW methods:

Figure 38
Figure 39

The agent tries to open the local process object using OpenProcess (0x410 = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ):

Figure 40

For each of the access token extracted from the processes, the executable calls the GetTokenInformation function and retrieves the user account of the token (Figure 41).

Figure 41

The malware extracts the name of the account for the security identifier (SID) and the first domain on which the SID is found:

Figure 42

0xEBC0 ID – Kill processes

The target process is opened via a function call to OpenProcess (0x1 = PROCESS_TERMINATE):

Figure 43

The process is killed using the TerminateProcess API:

Figure 44

0xF584 ID – Create a new process using the Domain, Username, and Password received from the C2 server

The binary spawns a new process using the CreateProcessWithLogonW method. The parameters are modified according to the command’s arguments:

Figure 45

0xBED0 ID – Execute the “open”, “runas”, or “print” command

The first parameter is compared with the above commands, as shown in Figure 46.

Figure 46

We could use the runas command to spawn a cmd.exe process:

Figure 47

GetProcessId is utilized to obtain the PID of the newly created process:

Figure 48

0xE2EA ID – Copy bytes into memory

The second parameter is Base64-decoded by calling the CryptStringToBinaryA API:

Figure 49

The address containing the resulting bytes is stored in a table that contains functions pointers (see Figure 50).

Figure 50

Depending on the number of bytes, the malware will send the “[+] Imported %d bytes” message to the C2 server:

Figure 51

0x6154 ID – Free the pointer storing the address of the imported bytes

The agent calls the free function with the pointer displayed in the above command. The message shown below is transmitted to the C2 server.

Figure 52

0x699A ID – Create a TCP listener

The process creates a new thread that is responsible for the listener creation:

Figure 53

It calls the getaddrinfo method with the port number and the first parameter being NULL, which returns all registered addresses on the local machine:

Figure 54

The badger creates a TCP socket (0x2 = AF_INET, 0x1 = SOCK_STREAM, 0x6 = IPPROTO_TCP):

Figure 55

The bind function is used to associate the local address with the socket, as highlighted below:

Figure 56

The malware starts listening on the port specified in the command’s arguments (in our case, 8888):

Figure 57

Finally, the accept method is utilized to allow incoming connection attempts (Figure 58).

Figure 58

The IP address from the connection is converted into an ASCII string in dotted-decimal format:

Figure 59

A new thread that handles the receive operation is created:

Figure 60
Figure 61

0xB458 ID – Extract information about Windows services

The binary opens the service control manager on the local machine using OpenSCManagerA (0x4 = SERVICE_QUERY_STATUS):

Figure 62

EnumServicesStatusW is used to enumerate all services in the database (0x30 = SERVICE_WIN32, 0x3 = SERVICE_STATE_ALL):

Figure 63

For every service, the malware calls the OpenServiceW API (0x1 = SERVICE_QUERY_CONFIG):

Figure 64

The agent extracts the configuration parameters of the service using QueryServiceConfigW. The following fields are relevant: display name, service name, service state, service path, service user, and service type.

Figure 65

0xE3CB ID – Retrieve information about Domain Controllers and policies

The malicious executable obtains the name of a domain controller via a function call to DsGetDcNameW, as displayed in Figure 66.

Figure 66

The DsGetDcOpenW API is utilized to open a new domain controller enumeration operation (0x2 = DS_NOTIFY_AFTER_SITE_RECORDS):

Figure 67

The badger extracts the global password parameters and lockout information by calling the NetUserModalsGet function. The information is organized using the following structure:

Figure 68

0x0105 ID – Extract data from the clipboard

The process opens the clipboard by calling the OpenClipboard method:

Figure 69

The data is obtained from the clipboard in the Unicode format (0xD = CF_UNICODETEXT):

Figure 70

0x0B06 ID – Convert the time of the last input event in minutes

The binary obtains the number of milliseconds elapsed since the system was started using GetTickCount:

Figure 71

GetLastInputInfo is used to retrieve the time of the last input event:

Figure 72

0xB63A ID – Block keyboard and mouse input events

The BlockInput method is used to perform the operation, as displayed in the figure below.

Figure 73

0x0391 ID – Lock the workstation’s display

LockWorkStation is utilized to lock the display (see Figure 74).

Figure 74

0xF999 ID – Impersonate the context of a logged-on user

The badger attempts to log a user on to the local machine via a call to LogonUserA (0x2 = LOGON32_LOGON_INTERACTIVE):

Figure 75

The binary impersonates the context of the above user using the ImpersonateLoggedOnUser function:

Figure 76

0xA959 ID – Retrieve information about users

The first parameter is compared with “user” and “users”. In the first case, the malware calls the NetUserGetInfo API to obtain information about the user account:

Figure 77

The information is organized in the following manner:

Figure 78

In the second case, the agent retrieves information about all user accounts on the local computer (0x2 = FILTER_NORMAL_ACCOUNT):

Figure 79

0x6C36 ID – Extract registry keys and values

The first argument can be “hklm”, “hkcu”, “root”, “config”, and “users”. These are Windows registry hives.

The registry key passed as the second argument is opened using the RegOpenKeyExA method (0x20019 = KEY_READ):

Figure 80

The malicious process retrieves information about the registry key by calling the RegQueryInfoKeyW function:

Figure 81

It enumerates the subkeys of the key using RegEnumKeyExW (Figure 82).

Figure 82

For each of the subkeys, the malware calls the RegEnumValueW API in order to enumerate the registry values:

Figure 83

Finally, the type and data for all registry values identified are extracted:

Figure 84

0x9C41 ID – Take a screenshot and send it to the C2 server

The GdiplusStartup function initializes Windows GDI+ (see Figure 85).

Figure 85

The agent retrieves a handle to the desktop window via a call to GetDesktopWindow:

Figure 86

It obtains the number of adjacent color bits for each pixel for the device context (DC) for the above window (0xC = BITSPIXEL):

Figure 87

The BitBlt method is used to capture the image:

Figure 88

The malware creates a Bitmap object based on a handle to a Windows GDI bitmap and a handle to a GDI palette:

Figure 89

The process calls the CLSIDFromString function with the “1d5be4b5-fa4a-452d-9cdd-5db35105e7eb” CLSID – Quality field:

Figure 90

GdipSaveImageToStream is utilized to save the screenshot to a stream (see Figure 91). The name of the image is derived from the current date and time.

Figure 91

0x3C4D ID – Read content from pipe and send it to the C2 server. Write server’s response to the pipe

The agent opens an existing pipe using the CreateFileA API (0xC0000000 = GENERIC_READ | GENERIC_WRITE, 0x3 = OPEN_EXISTING):

Figure 92

The malware modifies the read and the blocking mode via a function call to SetNamedPipeHandleState (0x0 = PIPE_READMODE_BYTE | PIPE_WAIT):

Figure 93

The pipe’s content is read using the ReadFile method:

Figure 94

The content is exfiltrated to the C2 server, and the server’s response is written back to the pipe.

0x2129 ID – Write two numbers into memory

The command takes two parameters and writes them in the following format:

Figure 95
Figure 96

INDICATORS OF COMPROMISE

SHA256: d71dc7ba8523947e08c6eec43a726fe75aed248dfd3a7c4f6537224e9ed05f6f

C2 server: 45.77.172.28

User-agent: trial@deloitte.com.cn

References

MSDN: https://docs.microsoft.com/en-us/windows/win32/api/

FakeNet-NG: https://github.com/mandiant/flare-fakenet-ng

Unit42: https://unit42.paloaltonetworks.com/brute-ratel-c4-tool/

MDSec: https://www.mdsec.co.uk/2022/08/part-3-how-i-met-your-beacon-brute-ratel/