TrickBot Variant Using DNS Tunneling for C2

31204934889?profile=RESIZE_400xFortiGuard Labs recently captured several malicious samples that were sending malformed DNS queries.  After conducting an in-depth analysis, researchers determined that these samples are TrickBot variants that use DNS tunneling to communicate with their command-and-control (C2) servers.

TrickBot is a modular malware family that FortiGuard Labs has repeatedly captured over the past decade.  Its modular architecture enables it to extend its capabilities by downloading and executing additional modules on compromised devices.  Previously observed TrickBot variants primarily relied on HTTP to communicate with its C2 servers.[1]

Affected Platforms: Microsoft Windows

Impacted Users: Windows Users

Impact: Fully Control the Victim’s Computer

Severity Level: High

In this analysis, analysts used one of these samples to demonstrate the obfuscation techniques the TrickBot variant employs to protect itself from analysis.  An analyst examined the persistence mechanisms it establishes on compromised devices, the process of generating malformed DNS queries for C2 communication, and the method used to transport command-and-control data through DNS packets.

Static Analysis - Figure 1 shows the captured TrickBot sample files, with one of the samples analyzed using a PE inspection tool.  The sample is identified as a 64-bit executable and is not protected by a packer.

31204934895?profile=RESIZE_400xFigure 1- Captured samples and analysis in a PE tool.

Although these samples have different file hashes, they exhibit identical PE characteristics, startup code, and overall behaviors.  This suggests they originate from the same TrickBot campaign.

Obfuscation Techniques - To protect itself from static analysis, TrickBot employs several obfuscation techniques.  Constant strings in this TrickBot variant are encrypted and then decrypted at runtime.  Most constant numbers are dynamically calculated at runtime.  Figure 2 shows how the malware defines and decrypts the constant string “Kernel32.dll”.  The decryption method includes executing SUB or XOR instructions.
31204935657?profile=RESIZE_584xFigure 2- Decrypting the constant strings “Kernel32.dll”.

All Windows APIs are resolved at runtime using hash-based lookups.  Named was the function responsible for this operation Get_API_By_Hash().  Figure 3 shows that the malware passes the hash C8AC8026 to the function at 0x14004990, which returns the API address of LoadLibraryA() in the RAX register.  TrickBot then calls this API to load the “Kernel32.dll” file, whose name was a previously decrypted constant string.

31204935668?profile=RESIZE_710xFigure 3- Dynamically retrieving the LoadLibraryA() API.

A partial list of the APIs used in this TrickBot variant, along with their hash codes, can be found in the Appendix.

Maintain Persistence - This TrickBot maintains persistence on the victim’s computer by leveraging the Windows Task Scheduler.

The malware variant accepts several command-line parameters, such as “-u”, “-s”, “--log,” and “-i”.

When the TrickBot executable is launched with no parameters or without the “-u” flag, it executes the persistence maintenance workflow to create a new task that runs every several minutes.

The task’s name is formed using a randomly selected folder name from the %AppData% folder, the decrypted constant string “ autoupdate #” and a random numeric value.  As shown in Figure 4, it calls a function to generate a task name, such as “Wireshark autoupdate #72784”.  This time, TrickBot disguises the scheduled task as an automatic Wireshark update.

31204935471?profile=RESIZE_710xFigure 4- Calling a function to generate a random task name.

To create the scheduled task, the malware instantiates an ITaskService COM object that implements the Task Scheduler automation interface.  The API CoCreateInstance() is called with the ProgID “Schedule.Service.1” to create the COM object.  Subsequently, it uses several interfaces of the COM object to configure the task properties, including the task name, task action, and task triggers.

31204935068?profile=RESIZE_710xFigure 5 illustrates a successfully installed task with the following configuration-

The Task Name- “Wireshark autoupdate #72784”.

The Task Action- Execute the command “E-\4d99f6b.exe” with parameter “-u”.

Triggers- Runs at the device startup and repeats the task action every 5 minutes.

Figure 5- Task created in the Task Scheduler.

TrickBot stores the task name and the full path of its executable file in two NTFS Alternate Data Streams (ADS).  The stream named “$TASK” contains the Base64-encoded task name, while the stream named “$FILE” holds the Base64-encoded full path of the TrickBot executable file.

Upon execution, the malware first reads data from the two streams, then executes the same code flow to recreate the task using the retrieved information.  This prevents TrickBot from creating multiple duplicate scheduled tasks under different task names.

Figure 6 displays the output of three commands used to examine and decode the Base64-encoded data stored in the “$TASK” and “$FILE” streams.

31204935696?profile=RESIZE_710xFigure 6- ADS streams and extracted data.

DNS Tunneling - DNS tunneling is a technique used to bypass network security controls by hiding non-DNS traffic inside standard Domain Name System (DNS) queries and responses.  Figure 7 illustrates the general DNS tunneling model.


31204935490?profile=RESIZE_584xFigure 7- DNS tunneling model.

Once the TrickBot executable is launched with the “-u” parameter, it communicates with its C2 server over DNS Tunneling.  Figure 8 shows that TrickBot sends malformed DNS queries over a public DNS server at 8.8.8.8.

31204936053?profile=RESIZE_710xFigure 8- DNS traffic between the TrickBot variant and a public DNS server.

TrickBot DNS Tunneling / DNS Query - The original C2 server was shut down when I analyzed the malware. Developed was a Python script to simulate the C2 server’s response, allowing the analysis to continue.  The data presented in this analysis is derived from the simulated C2 server.  TrickBot wraps its command-and-control request packets in encrypted DNS query packets.  This section details how TrickBot transfers the data across three types of packets.

Data Encoding and Domain Construction - The malware encrypts and formats control command data before embedding it in DNS traffic.  The process involves-

  • Encryption- The command data is XORed with the key 0xB9.
  • Hex Encoding- The encrypted data is converted into a hexadecimal string.
  • Subdomain Formatting- To mimic a legitimate domain structure, a period (.) is inserted into the hexadecimal string every 63 characters.
  • Domain Prepending- The formatted string is prepended to the decrypted constant domain “.westurn.in”.

8970D9E4F4BE8F88FD3394A2C57A1763E2B9BA96D8D7DAD1D6CBE6DDD7CA96F.DFCEAF2EDF6E994FC8 1F5FF81F3EDE6EE8F8B808B898997FF8EFF8BFF8D818B.FF8AFBFA8F8A8D8CF88D8DFC8DF88FFD8F8D8E 8E8A88F8FC968996EED0D7DDD.6CECA998199C18F8D968889898896899789978997.westurn.in

TrickBot calls the Windows API function getaddrinfo() to send malformed DNS queries and receive responses.

Packet Structure - The plaintext data of a packet is shown in Figure 9. All DNS query packets generated by this TrickBot variant follow this packet structure.
31204935859?profile=RESIZE_400xFigure 9- Plaintext data of a 0x30 packet.

The plaintext packet, shown in Figure 9, consists of the following fields-

  • Packet Type- 0x30, 0x31, and 0x32.
  • Packet Session ID- A 10H-byte-long UUID used to correlate packets belonging to the same session.
  • Fragmentation Header- The first byte indicates the fragment index, and the next byte indicates the total number of fragments. In this case, the fragment index is 0, and the total number is 3.

Note- If the 0x30 type packet size exceeds 96 bytes (0x60), TrickBot splits the packet into multiple smaller packets (max 96 bytes each).  This field appears only in 0x30 packets.

  • Packet Payload- The payload data of the control command.

Figure 10 shows logs from my Python DNS server illustrating how the three 0x30-fragment packets are received and reconstructed.

31204936070?profile=RESIZE_584xFigure 10- Display showing how 0x30 fragment packets are reconstructed.

Packet Type Functions - According to the data content carried by the three types of packets, they serve distinct roles-

  • Packet type 0x30 (Request)- Transport TrickBot’s control command requests data to the C2 server.
  • Packet type 0x31 (Size Query)- Request the packet size of the upcoming response. Upon receiving the size, TrickBot allocates the necessary memory buffer to store the incoming data, which will be transported in 0x32-byte packets.
  • Packet type 0x32 (Response Data)- Transport TrickBot’s control command response data. When TrickBot sends this type of packet, the payload contains two DWORDs- 
  • First DWORD- A value received in the response to the previous 0x30 packet.
  • Second DWORD- A data offset, instructing the C2 server from which point to transmit data.

TrickBot DNS Tunneling / DNS Response - Normal DNS response packets typically contain the IP addresses associated with the queried domain.  This section explains how TrickBot hides the malicious data within the IP addresses of these responses.

The 0x32 response packets illustrate how the C2 server transports data through the DNS tunnel.  These packets are responsible for delivering control command response data to the TrickBot, corresponding to the requests previously sent in 0x30 packets.

IP Indexing and Data Encoding - TrickBot reserves the high 6 bits of the first octet of each IPv4 address for an index value (IP index) that starts at 1, leaving the low 2 bits unused. Consequently, the IP index is obtained by right-shifting the first octet by 2 bits (equivalent to dividing it by 4), as shown in Figure 11.
31204935884?profile=RESIZE_584xFigure 11- Display of a 0x32-type response packet.

The first two IPv4 addresses are also reserved as detailed in Figure 11-

First IP- Data offset (e.g., 0x9F2B8)

Second IP- Size of the payload data (e.g., 183) in the current DNS packet.

The maximum 6-bit index value is 0x3F (63). Since the first two IP addresses are reserved, the remaining 61 addresses can carry payload data. Each address can carry 3 bytes of payload. Therefore, the maximum payload size that can be transferred in a single 0x32 response packet is (63-2)*3 = 183 bytes.

Data Reassembly - While DNS protocols allow multiple IPv4 addresses in a response packet, some middle DNS resolvers may randomly reorder them before returning the response, causing the encoded payload to be out of order.  To address this issue, TrickBot implements a sorting function that reorders the received IPs in their original order based on the IP index (the high 6 bits of the first octet).  To reassemble the original payload data, TrickBot needs to read the 3 payload bytes from each IP address (starting with the third IP address) and store them in a previously allocated memory buffer.

31204935884?profile=RESIZE_584xFigure 12 examines how the sorted IP addresses are reassembled into the original payload data
31204936252?profile=RESIZE_584xFigure 12- Data reassembled from sorted IP addresses.

Performance Analysis - In my test environment, it took 40 seconds to transfer a 1.2 MB file via TrickBot DNS tunneling to the TrickBot variant. The transfer speed of DNS tunneling is about 30.7 KB/s.

TrickBot Control Commands - I will next elaborate on the structure and functionality of TrickBot’s control commands.

The data structure for the commands used in the DNS tunnel is the same as that used in TrickBot’s HTTP protocol-based version.  The following sections examine the control commands in chronological order.

Requesting Command “0”

The initial request command sent to the C2 server follows this format-

/anchor_dns/DESKTOP-E8LF8JT_W629200.F7F2F482F3BC6345A44E4A6D647731AE/0/Windows 8 x64/1001/0.0.0.0/4E2D56B35DDF7C44B2E42B7B33AADD57EFC3411D262559337CE94D86BA6D76 F5/EjR6pa0ELV59E8K2mR8PUbI80DlEaxyb/

Structure breakdown-

"/anchor_dns"- The campaign or group name.

"/DESKTOP-E8LF8JT_W629200.F7F……31AE"- It’s the victim Client_ID, composed of the computer name, OS version, and hardware ID.

"/0"- The request command number.

"/Windows 8 x64/1001"- System information. Notably, the malware incorrectly parses Windows 10 as "Windows 8."

"/0.0.0.0"- Intended to represent the public IP of the compromised device. However, this value is hardcoded as “0.0.0.0” within the malware payload.

"4E2D56......76F5"-  A random 64 bytes (0x40) hexadecimal data.

"EjR6pa0……axyb"- Verification data (like Session ID). This is a random 32-byte (0x20) string. It is unique and only available in a command session.

Command “0” is the first command sent to the C2 server, serving to register the victim on the C2 server.

Based on the behavior of the HTTP version, I crafted a simulated response command (replying to the request command “0”) in my DNS server-

"/1/anchor_dns/DESKTOP-E8LF8JT_W629200.F7F2F482F3BC6345A44E4A6D647731AE/EjR6pa0ELV59E8K2mR8PUbI80DlEaxyb"

TrickBot parses the response packet by directly locating the fourth “/”.  It then compares the subsequent 32-byte verification data against the one sent in the request command packet.
31204936453?profile=RESIZE_584xFigure 13- TrickBot verifies the 32-byte verification data.

As shown in Figure 13, TrickBot calls a memcmp-like function to compare the verification code.  The lower portion of the figure displays the received response packet.  The “/1/” at the beginning can be replaced with any other valid command number for this response packet because TrickBot ignores the entire data field preceding the verification data.

Requesting Command “1”

TrickBot next sends the command “1” to the C2 server to request tasks to execute on the victim’s device. An example of a Command “1” request packet is shown below-

/anchor_dns/DESKTOP-E8LF8JT_W629200.F7F2F482F3BC6345A44E4A6D647731AE/1/ZQqRydar6QBCEYo4IMWUodsgQ7AzJhHc/

As with previous commands, the final 32-byte (0x20) string serves as a verification code. The C2 server must echo this value back in the command response packet for TrickBot to authenticate.

A corresponding response packet for the request command “1” appears as follows-

/{response command number}/anchor_dns/DESKTOP-E8LF8JT_W629200.F7F2F482F3BC6345A44E4A6D647731AE/ ZQqRydar6QBCEYo4IMWUodsgQ7AzJhHc/96322307/bWFsaWNpb3VzX2V4ZV9tb2R1bGUgcGFyYW1ldGVy

The 32-byte-long string after the fourth “/” is the verification code, just as it is for the other commands explained earlier.  The following “96322307” is a unique command string ID that identifies the command string in this packet.  The final part (“bWFsaWNp…”) is the command string encoded in Base64.

Decoding the Base64 string reveals the command structure- “malicious_exe_module parameter”.  The command is split by the space into two components-

Module Name (Required)- The name of the module to download and execute (e.g., “malicious_exe_module”).  It is included in request commands, such as in command “5”.

Parameters (Optional)- Arguments passed to the module during execution (e.g., parameter).

This TrickBot variant supports 12 response control commands, listed in the table below.

Response Command Number

Description

“0”

Executes a Windows command-line command.

“1”, “2”

Downloads an EXE module to be executed on the victim’s device.

“3”, “4”

Downloads a module and executes it using rundll32.exe, invoking the module’s “Control_RunDLL” export function.

“5”, “6”

Downloads a module and injects it into a randomly selected process using process hollowing technique.

“7”, “8”

Downloads a module and injects it in a randomly selected process using process doppelgänging.

“9”

Executes Windows commands via anonymous pipes connected to cmd.exe.

“10”

Executes PowerShell codes through anonymous pipes connected to cmd.exe.

“11”

Executes raw machine code (ASM code) directly within TrickBot’s memory.

Requesting Command “5”

TrickBot sends a request command “5” to the C2 server to download an executable module.  This action is typically triggered by the command handler functions for response commands “1”, “3”, “4”, “5”, and “7”.

Below is an example of a request command “5” packet-

/anchor_dns/DESKTOP-E8LF8JT_W629200.F7F2F482F3BC6345A44E4A6D647731AE/5/test_dll/

“5”- The request command number.

“test_dll”- The name of a module to download from the C2 server.  The name was previously Base64-encoded in the response packet for command “1”.

The response packet contains the module data, which is delivered separately across multiple 0x32-type packets.
31204936470?profile=RESIZE_400xFigure 14- Downloading a module by requesting the command “5”.

Figure 14 shows the handler function for the response command “3”, which sends a request command “5” packet to download the DLL module shown in memory.  TrickBot saves the DLL module to a randomly named temporary file.

The malware then launches rundll32.exe to execute the downloaded DLL module, invoking the CreateProcessW() API, as shown in Figure 15.  The malicious DLL module (tcp469A.dll) then executes within the rundll32.exe process, starting at its “Control_RunDLL” export function.
31204936479?profile=RESIZE_584xFigure 15- Execute a downloaded DLL module on the victim’s device.

Conclusion - This analysis examined a TrickBot variant that uses DNS tunneling for command-and-control (C2) communication instead of the HTTP protocol used by earlier variants.  DNS tunneling is achieved by embedding specially encoded data in DNS queries and responses.

The malware establishes persistence via Windows Task Scheduler, stores its configuration in NTFS Alternate Data Streams, and uses encrypted strings and runtime API resolution to hinder analysis.

Its modular architecture enables in-memory module execution and supports functions such as command execution, process injection, and PowerShell execution. Despite adopting DNS tunneling, this TrickBot variant retains the modular design and capabilities that make the malware family a persistent threat.

MITRE ATT&CK Techniques

Technique ID

Technique Name

T1071.004

Application Layer Protocol- DNS

T1572

Protocol Tunneling

T1053.005

Scheduled Task/Job

T1564.003

Hide Artifacts- NTFS File Attributes

T1055.002

Process Injection- Process Hollowing

T1055.005

Process Injection- Process doppelgänging

T1218.011

Signed Binary Proxy Execution- Rundll32

T1059.001

Command and Scripting Interpreter- PowerShell

T1105

Ingress Tool Transfer

 T1059

Command and Scripting Interpreter

IOCs / C2 Server Domain-

westurn.in

Associated Sample SHA-256-

[TrickBot Samples]

DF527A5C2FBDE43816CD02F4CD49EEE4BB82FB4A3C7045021360888C7D504C98
6C677EB2B3FFD288083C59A13D7BB712D4754AF61A5563873F76C440962346F4
105F652E6B8F31C371F2385877E43B6772AFF5D3168D5D4635F8A1FCBB321421
33C331EDEDBF8EE9829895424423CE3FD17E359D2E784FCBCE396AACFF458CF5
3B19A82E1354AC14A3DA7C840CBDD0CE50DB38432D78E767B36F08E45024C23D
BF80245BA792992FBFE24ABAC33F8FD66F24CDEB5F0F21CFDF45A29D107C8D3B

Appendix-

Hash Code

API Name

1297812C

GetLastError

1FC0EAEE

GetProcAddress

223296ED

GetShortPathNameA

279DEAC1

FindNextFileW

2CA1B5E6

lstrcat

2D40B8E6

lstrlenA

32432452

FindFirstFileW

3287EC73

RtlInitUnicodeString

3D9972F5

Sleep

475587A1

GetFileAttributesW

4B935B8E

FreeLibrary

052AC19C

IsWow64Process

58FE7ABE

GetTempPathA

5AA7E70B

MultiByteToWideChar

5CB5EF72

FreeSid

5E7EE0D0

SetEvent

69260152

GetTickCount

723EB0D5

CloseHandle

774393E8

GetModuleFileNameA

774393FE

GetModuleFileNameW

7B4842C1

FindClose

81F0F0DF

DeleteFileA

8D5A50DC

CreateEventA

08F8F114

CreateFileA

8FB8B5BD

WSACleanup

9ABFB8A6

VirtualAllocEx

9C480E24

GetVersionExA

9E6FA842

TerminateProcess

A48D6762

GetModuleHandleA

B8538A52

InitializeSecurityDescriptor

BEA0BF35

WriteProcessMemory

C09D5D66

TerminateThread

C54374F3

WaitForSingleObject

C8AC8026

LoadLibraryA

CCD03C3A

SetSecurityDescriptorDacl

0D89AD05

GetCurrentProcess

0E91A280

GetProcessId

EF48E03A

SetFilePointer

0FA4F502

GetTempFileNameA

 

 

This article is shared at no charge for educational and informational purposes only.

Red Sky Alliance is a Cyber Threat Analysis and Intelligence Service organization.  We provide indicators of compromise information (CTI) via a notification service (RedXray) or an analysis service (CTAC).  For questions, comments or assistance, please contact the office directly at 1-844-492-7225, or feedback@redskyalliance.com    

  • Reporting- https-//www.redskyalliance.org/
  • Website- https-//www.redskyalliance.com/
  • LinkedIn- https-//www.linkedin.com/company/64265941 

Weekly Cyber Intelligence Briefings
REDSHORTS - Weekly Cyber Intelligence Briefings
https://attendee.gotowebinar.com/register/7855487668891299929

 

[1] https://www.fortinet.com/blog/threat-research/inside-a-trickbot-variant-using-dns-tunneling-for-c2?lctg=141970831

E-mail me when people leave their comments –

You need to be a member of Red Sky Alliance to add comments!