{"id":26145,"date":"2026-09-21T13:06:18","date_gmt":"2026-09-21T21:06:18","guid":{"rendered":"https:\/\/www.palada.net\/index.php\/2026\/09\/21\/inside-a-trickbot-variant-using-dns-tunneling-for-c2-3\/"},"modified":"2026-09-21T13:06:18","modified_gmt":"2026-09-21T21:06:18","slug":"inside-a-trickbot-variant-using-dns-tunneling-for-c2-3","status":"publish","type":"post","link":"http:\/\/www.palada.net\/index.php\/2026\/09\/21\/inside-a-trickbot-variant-using-dns-tunneling-for-c2-3\/","title":{"rendered":"Inside a TrickBot Variant Using DNS Tunneling for C2"},"content":{"rendered":"<div class=\"Table-Content aem-GridColumn aem-GridColumn--default--12\">\n<div class=\"blog-toc\">\n<div class=\"b3-blog-list__row\">\n<div class=\"b3-blog-list__column-left table-content-wrapper automatic\">\n<ul class=\"table-of-content\">\n<li class=\"header\"><img decoding=\"async\" alt=\"\" class=\"toc-icon\" src=\"\/content\/dam\/fortinet\/images\/toc-icon.jpg\"\/>Article Contents<\/li>\n<\/ul>\n<\/div>\n<div class=\"aem-GridColumn aem-GridColumn--default--8 b3-blog-list__column-right scrolling-content automatic\">\n<div class=\"b15-blog-meta__container text-container\">\n<span>By <\/span><br \/>\n<span class=\"b15-blog-meta__author\"><br \/>\n<a href=\"\/blog\/search?author=Xiaopeng+Zhang\">Xiaopeng Zhang<\/a><br \/>\n<\/span><br \/>\n<span class=\"b15-blog-meta__\"><br \/>\n<\/span><br \/>\n<span class=\"b15-blog-meta__date\"> | July 22, 2026<\/span>\n<\/div>\n<div class=\"C875-Disclaimer\">\n<\/div>\n<div class=\"raw-import\">\n<div class=\"text-container\"><\/div>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p style=\"\tmargin-left: 80.0px;\n\"><b>Affected Platforms: <\/b>Microsoft Windows<br \/>\n<b>Impacted Users: <\/b>Windows Users<br \/>\n<b>Impact: <\/b>Fully Control the Victim\u2019s Computer<br \/>\n<b>Severity Level: <\/b>High<\/p>\n<h2>Background<\/h2>\n<p>FortiGuard Labs recently observed several malicious samples that were sending malformed DNS queries. After conducting an in-depth analysis, I determined that these samples are TrickBot variants that use DNS tunneling to communicate with their command-and-control (C2) servers.<\/p>\n<p>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.<\/p>\n<p>While DNS-based TrickBot variants, including Anchor DNS, have been publicly documented previously, this analysis focuses on recently observed samples and provides an in-depth technical analysis of their implementation and behavior.<\/p>\n<p>In this analysis, I use one of these samples to demonstrate the obfuscation techniques the TrickBot variant employs to protect itself from analysis. I examine 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.<\/p>\n<h2>Static Analysis<\/h2>\n<p>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.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 1: Captured samples and analysis in a PE tool.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>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.<\/p>\n<h2>Obfuscation Techniques<\/h2>\n<p>To protect itself from static analysis, TrickBot employs several obfuscation techniques.<\/p>\n<p>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 \u201cKernel32.dll\u201d. The decryption method includes executing SUB or XOR instructions.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 2: Decrypting the constant strings \u201cKernel32.dll\u201d.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>All Windows APIs are resolved at runtime using hash-based lookups. I have named 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 \u201cKernel32.dll\u201d file, whose name was a previously decrypted constant string.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 3: Dynamically retrieving the LoadLibraryA() API.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>A partial list of the APIs used in this TrickBot variant, along with their hash codes, can be found in the Appendix.<\/p>\n<h2>Maintain Persistence<\/h2>\n<p>This TrickBot maintains persistence on the victim\u2019s computer by leveraging the Windows Task Scheduler.<\/p>\n<p>The malware variant accepts several command-line parameters, such as \u201c-u\u201d, \u201c-s\u201d, \u201c&#8211;log,\u201d and \u201c-i\u201d.<\/p>\n<p>When the TrickBot executable is launched with no parameters or without the \u201c-u\u201d flag, it executes the persistence maintenance workflow to create a new task that runs every several minutes.<\/p>\n<p>The task\u2019s name is formed using a randomly selected folder name from the %AppData% folder, the decrypted constant string \u201c autoupdate #\u201d and a random numeric value. As shown in Figure 4, it calls a function to generate a task name, such as \u201cWireshark autoupdate #72784\u201d. This time, TrickBot disguises the scheduled task as an automatic Wireshark update.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 4: Calling a function to generate a random task name.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>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 \u201cSchedule.Service.1\u201d to create the COM object.<\/p>\n<p>Subsequently, it uses several interfaces of the COM object to configure the task properties, including the task name, task action, and task triggers.<\/p>\n<p>Figure 5 illustrates a successfully installed task with the following configuration:<\/p>\n<ul>\n<li>The Task Name: \u201cWireshark autoupdate #72784\u201d.<\/li>\n<li>The Task Action: Execute the command \u201cE:\\4d99f6b.exe\u201d with parameter \u201c-u\u201d.<\/li>\n<li>Triggers: Runs at the device startup and repeats the task action every 5 minutes.<\/li>\n<\/ul>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 5: Task created in the Task Scheduler.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>TrickBot stores the task name and the full path of its executable file in two NTFS Alternate Data Streams (ADS). The stream named \u201c$TASK\u201d contains the Base64-encoded task name, while the stream named \u201c$FILE\u201d holds the Base64-encoded full path of the TrickBot executable file.<\/p>\n<p>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.<\/p>\n<p>Figure 6 displays the output of three commands used to examine and decode the Base64-encoded data stored in the \u201c$TASK\u201d and \u201c$FILE\u201d streams.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 6: ADS streams and extracted data.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<h2>DNS Tunneling<\/h2>\n<p>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.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 7: DNS tunneling model.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>Once the TrickBot executable is launched with the \u201c-u\u201d 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.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 8: DNS traffic between the TrickBot variant and a public DNS server.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<h2>TrickBot DNS Tunneling \u2013 DNS Query<\/h2>\n<p>The original C2 server was shut down when I analyzed the malware. I developed a Python script to simulate the C2 server\u2019s response, allowing the analysis to continue. The data presented in this analysis is derived from the simulated C2 server.<\/p>\n<p>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.<\/p>\n<h3>Data Encoding and Domain Construction<\/h3>\n<p>The malware encrypts and formats control command data before embedding it in DNS traffic. The process involves:<\/p>\n<ol>\n<li><b>Encryption<\/b>: The command data is XORed with the key 0xB9.<\/li>\n<li><b>Hex Encoding<\/b>: The encrypted data is converted into a hexadecimal string.<\/li>\n<li><b>Subdomain Formatting<\/b>: To mimic a legitimate domain structure, a period (.) is inserted into the hexadecimal string every 63 characters.<\/li>\n<li><b>Domain Prepending<\/b>: The formatted string is prepended to the decrypted constant domain \u201c.westurn.in\u201d.<\/li>\n<\/ol>\n<p><span style=\"\tbackground-color: yellow;\n\">8970D9E4F4BE8F88FD3394A2C57A1763E2B9BA96D8D7DAD1D6CBE6DDD7CA96F.DFCEAF2EDF6E994FC8 1F5FF81F3EDE6EE8F8B808B898997FF8EFF8BFF8D818B.FF8AFBFA8F8A8D8CF88D8DFC8DF88FFD8F8D8E 8E8A88F8FC968996EED0D7DDD.6CECA998199C18F8D968889898896899789978997.westurn.in<\/span><\/p>\n<p>TrickBot calls the Windows API function getaddrinfo() to send malformed DNS queries and receive responses.<\/p>\n<h3>Packet Structure<\/h3>\n<p>The plaintext data of a packet is shown in Figure 9. All DNS query packets generated by this TrickBot variant follow this packet structure.<\/p>\n<p>\u00a0<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 9: Plaintext data of a 0x30 packet.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>The plaintext packet, shown in Figure 9, consists of the following fields:<\/p>\n<ul>\n<li><b>Packet Type<\/b>: 0x30, 0x31, and 0x32.<\/li>\n<li><b>Packet Session ID<\/b>: A 10H-byte-long UUID used to correlate packets belonging to the same session.<\/li>\n<li><b>Fragmentation Header<\/b>: 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.<\/li>\n<\/ul>\n<p><b>Note<\/b>: 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.<\/p>\n<ul>\n<li><b>Packet Payload<\/b>: The payload data of the control command.<\/li>\n<\/ul>\n<p>Figure 10 shows logs from my Python DNS server illustrating how the three 0x30-fragment packets are received and reconstructed.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 10: Display showing how 0x30 fragment packets are reconstructed.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<h3>Packet Type Functions<\/h3>\n<p>According to the data content carried by the three types of packets, they serve distinct roles:<\/p>\n<ul>\n<li>Packet type 0x30 (<b>Request<\/b>): Transport TrickBot\u2019s control command requests data to the C2 server.<\/li>\n<li>Packet type 0x31 (<b>Size Query<\/b>): 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.<\/li>\n<li>Packet type 0x32 (<b>Response Data<\/b>): Transport TrickBot\u2019s control command response data. When TrickBot sends this type of packet, the payload contains two DWORDs:\u00a0\n<ul>\n<li>First DWORD: A value received in the response to the previous 0x30 packet.<\/li>\n<li>Second DWORD: A data offset, instructing the C2 server from which point to transmit data.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>TrickBot DNS Tunneling \u2013 DNS Response<\/h2>\n<p>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.<\/p>\n<p>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.<\/p>\n<h3>IP Indexing and Data Encoding<\/h3>\n<p>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.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 11: Display of a 0x32-type response packet.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>The first two IPv4 addresses are also reserved as detailed in Figure 11:<\/p>\n<ul>\n<li><b>First IP<\/b>: Data offset (e.g., 0x9F2B8)<\/li>\n<li><b>Second IP<\/b>: Size of the payload data (e.g., 183) in the current DNS packet.<\/li>\n<\/ul>\n<p>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.<\/p>\n<h3>Data Reassembly<\/h3>\n<p>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).<\/p>\n<p>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.<\/p>\n<p>Figure 12 examines how the sorted IP addresses are reassembled into the original payload data.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 12: Data reassembled from sorted IP addresses.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<h3>Performance Analysis<\/h3>\n<p>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.<\/p>\n<h2>TrickBot Control Commands<\/h2>\n<p>I will next elaborate on the structure and functionality of TrickBot\u2019s control commands.<\/p>\n<p>The data structure for the commands used in the DNS tunnel is the same as that used in TrickBot\u2019s HTTP protocol-based version.\u00a0 The following sections examine the control commands in chronological order.<\/p>\n<h3>Requesting Command \u201c0\u201d<\/h3>\n<p>The initial request command sent to the C2 server follows this format:<\/p>\n<p style=\"\tmargin-left: 40.0px;\n\">\/anchor_dns\/DESKTOP-E8LF8JT_W629200.F7F2F482F3BC6345A44E4A6D647731AE\/<span style=\"\tbackground-color: yellow;\n\">0<\/span>\/Windows 8 x64\/1001\/0.0.0.0\/4E2D56B35DDF7C44B2E42B7B33AADD57EFC3411D262559337CE94D86BA6D76 F5\/EjR6pa0ELV59E8K2mR8PUbI80DlEaxyb\/<\/p>\n<p>Structure breakdown:<\/p>\n<ul>\n<li><b>&#8220;\/anchor_dns&#8221;<\/b>: The campaign or group name.<\/li>\n<li><b>&#8220;\/DESKTOP-E8LF8JT_W629200.F7F\u2026\u202631AE&#8221;<\/b>: It\u2019s the victim Client_ID, composed of the computer name, OS version, and hardware ID.<\/li>\n<li><b>&#8220;\/0&#8221;<\/b>: The request command number.<\/li>\n<li><b>&#8220;\/Windows 8 x64\/1001&#8221;<\/b>: System information. Notably, the malware incorrectly parses Windows 10 as &#8220;Windows 8.&#8221;<\/li>\n<li><b>&#8220;\/0.0.0.0&#8221;<\/b>: Intended to represent the public IP of the compromised device. However, this value is hardcoded as \u201c0.0.0.0\u201d within the malware payload.<\/li>\n<li><b>&#8220;4E2D56&#8230;&#8230;76F5&#8221;<\/b>:\u00a0 A random 64 bytes (0x40) hexadecimal data.<\/li>\n<li><b>&#8220;EjR6pa0\u2026\u2026axyb&#8221;<\/b>: Verification data (like Session ID). This is a random 32-byte (0x20) string. It is unique and only available in a command session.<\/li>\n<\/ul>\n<p>Command \u201c0\u201d is the first command sent to the C2 server, serving to register the victim on the C2 server.<\/p>\n<p>Based on the behavior of the HTTP version, I crafted a simulated response command (replying to the request command \u201c0\u201d) in my DNS server:<\/p>\n<p style=\"\tmargin-left: 40.0px;\n\">&#8220;\/1\/anchor_dns\/DESKTOP-E8LF8JT_W629200.F7F2F482F3BC6345A44E4A6D647731AE\/EjR6pa0ELV59E8K2mR8PUbI80DlEaxyb&#8221;<\/p>\n<p>TrickBot parses the response packet by directly locating the fourth \u201c\/\u201d. It then compares the subsequent 32-byte verification data against the one sent in the request command packet.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 13: TrickBot verifies the 32-byte verification data.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>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 \u201c\/1\/\u201d 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.<\/p>\n<h3>Requesting Command \u201c1\u201d<\/h3>\n<p>TrickBot next sends the command \u201c1\u201d to the C2 server to request tasks to execute on the victim\u2019s device. An example of a Command \u201c1\u201d request packet is shown below:<\/p>\n<p style=\"\tmargin-left: 40.0px;\n\">\/anchor_dns\/DESKTOP-E8LF8JT_W629200.F7F2F482F3BC6345A44E4A6D647731AE\/<span style=\"\tbackground-color: yellow;\n\">1<\/span>\/ZQqRydar6QBCEYo4IMWUodsgQ7AzJhHc\/<\/p>\n<p>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.<\/p>\n<p>A corresponding response packet for the request command \u201c1\u201d appears as follows:<\/p>\n<p style=\"\tmargin-left: 40.0px;\n\">\/{<!-- --><i>response command number<\/i>}\/anchor_dns\/DESKTOP-E8LF8JT_W629200.F7F2F482F3BC6345A44E4A6D647731AE\/ ZQqRydar6QBCEYo4IMWUodsgQ7AzJhHc\/96322307\/bWFsaWNpb3VzX2V4ZV9tb2R1bGUgcGFyYW1ldGVy<\/p>\n<p>The 32-byte-long string after the fourth \u201c\/\u201d is the verification code, just as it is for the other commands explained earlier. The following \u201c96322307\u201d is a unique command string ID that identifies the command string in this packet. The final part (\u201cbWFsaWNp\u2026\u201d) is the command string encoded in Base64.<\/p>\n<p>Decoding the Base64 string reveals the command structure: \u201cmalicious_exe_module parameter\u201d. The command is split by the space into two components:<\/p>\n<ul>\n<li><b>Module Name (Required):<\/b> The name of the module to download and execute (e.g., \u201cmalicious_exe_module\u201d). It is included in request commands, such as in command \u201c5\u201d.<\/li>\n<li><b>Parameters (Optional):<\/b> Arguments passed to the module during execution (e.g., parameter).<\/li>\n<\/ul>\n<p>This TrickBot variant supports 12 response control commands, listed in the table below.<\/p>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" class=\"details-tbl\" width=\"100%\">\n<tbody>\n<tr>\n<td width=\"33%\"><b>Response Command Number<\/b><\/td>\n<td width=\"67%\"><b>Description<\/b><\/td>\n<\/tr>\n<tr>\n<td>\u201c0\u201d<\/td>\n<td>Executes a Windows command-line command.<\/td>\n<\/tr>\n<tr>\n<td>\u201c1\u201d, \u201c2\u201d<\/td>\n<td>Downloads an EXE module to be executed on the victim\u2019s device.<\/td>\n<\/tr>\n<tr>\n<td>\u201c3\u201d, \u201c4\u201d<\/td>\n<td>Downloads a module and executes it using rundll32.exe, invoking the module\u2019s \u201cControl_RunDLL\u201d export function.<\/td>\n<\/tr>\n<tr>\n<td>\u201c5\u201d, \u201c6\u201d<\/td>\n<td>Downloads a module and injects it into a randomly selected process using process hollowing technique.<\/td>\n<\/tr>\n<tr>\n<td>\u201c7\u201d, \u201c8\u201d<\/td>\n<td>Downloads a module and injects it in a randomly selected process using process doppelg\u00e4nging.<\/td>\n<\/tr>\n<tr>\n<td>\u201c9\u201d<\/td>\n<td>Executes Windows commands via anonymous pipes connected to cmd.exe.<\/td>\n<\/tr>\n<tr>\n<td>\u201c10\u201d<\/td>\n<td>Executes PowerShell codes through anonymous pipes connected to cmd.exe.<\/td>\n<\/tr>\n<tr>\n<td>\u201c11\u201d<\/td>\n<td>Executes raw machine code (ASM code) directly within TrickBot\u2019s memory.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Requesting Command \u201c5\u201d<\/h3>\n<p>TrickBot sends a request command \u201c5\u201d to the C2 server to download an executable module. This action is typically triggered by the command handler functions for response commands \u201c1\u201d, \u201c3\u201d, \u201c4\u201d, \u201c5\u201d, and \u201c7\u201d.<\/p>\n<p>Below is an example of a request command \u201c5\u201d packet:<\/p>\n<p style=\"\tmargin-left: 40.0px;\n\">\/anchor_dns\/DESKTOP-E8LF8JT_W629200.F7F2F482F3BC6345A44E4A6D647731AE\/<span style=\"\tbackground-color: yellow;\n\">5<\/span>\/test_dll\/<\/p>\n<ul>\n<li>\u201c5\u201d: The request command number.<\/li>\n<li>\u201ctest_dll\u201d: The name of a module to download from the C2 server. The name was previously Base64-encoded in the response packet for command \u201c1\u201d.<\/li>\n<\/ul>\n<p>The response packet contains the module data, which is delivered separately across multiple 0x32-type packets.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 14: Downloading a module by requesting the command \u201c5\u201d.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<p>Figure 14 shows the handler function for the response command \u201c3\u201d, which sends a request command \u201c5\u201d packet to download the DLL module shown in memory. TrickBot saves the DLL module to a randomly named temporary file.<\/p>\n<p>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 \u201cControl_RunDLL\u201d export function.<\/p>\n<\/div>\n<div class=\"cmp cmp-image\">\n<p><!--\n\n<div class=\"enlarge-btn\" data-sly-test=\"\">\n\n<div class=\"gg-maximize-alt\"><\/div>\n\n \n\n<div>Click to Enlarge<\/div>\n\n<\/div>\n\n--><br \/>\n<span class=\"cmp-image--title\">Figure 15: Execute a downloaded DLL module on the victim\u2019s device.<\/span>\n<\/div>\n<div class=\"cmp cmp-text\">\n<h2>Conclusion<\/h2>\n<p>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.<\/p>\n<p>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.<\/p>\n<p>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.<\/p>\n<h2>Fortinet Protections<\/h2>\n<p>Fortinet customers are already protected from this campaign with FortiGuard\u2019s AntiSPAM, Web Filtering, IPS, and AntiVirus services as follows:<\/p>\n<p>The C2 server domain associated with this malicious campaign is rated as <b>Malicious Websites<\/b> by the FortiGuard Web Filtering service.<\/p>\n<p>The domain is also covered by FortiGuard\u2019s Botnet Domain DB service.<\/p>\n<p>FortiGate and FortiNDR detect the TrickBot DNS Tunneling with the IPS signature:<\/p>\n<p><b>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Trick.Botnet<\/b><\/p>\n<p>FortiNDR Cloud detects TrickBot DNS tunneling through behavioral analysis of DNS traffic. For more details, please refer to <a href=\"https:\/\/community.fortinet.com\/blogs-103\/fortindr-cloud-dns-based-threat-detection-and-response-202903\" rel=\"noopener noreferrer\" target=\"_blank\">FortiNDR Cloud: DNS Based Threat Detection and Response<\/a>.<\/p>\n<p>FortiGuard Antivirus service detects these TrickBot sample files with the following AV signature:<\/p>\n<p style=\"\tmargin-left: 40.0px;\n\"><b>W64\/TrickBot.WC!tr<\/b><\/p>\n<p>Fortinet FortiGate, FortiMail, FortiClient, and FortiEDR support the FortiGuard AntiVirus service, and the FortiGuard AntiVirus engine is part of each solution. As a result, customers using these products already have up-to-date protections.<\/p>\n<p>To stay informed of new and emerging threats, you can <a aria-label=\"FortiGuard\" href=\"\/fortiguard\/labs\" title=\"FortiGuard\">sign up<\/a> to receive future alerts.<\/p>\n<p>We also suggest that our readers complete the free <a aria-label=\"NSE training\" href=\"https:\/\/training.fortinet.com\/?utm_source=blog&amp;utm_campaign=2019-q3-nse-institute\" rel=\"noopener noreferrer\" target=\"_blank\" title=\"NSE training\">NSE training<\/a>: <a aria-label=\"NSE 1 \u2013 Information Security Awareness\" href=\"https:\/\/training.fortinet.com\/local\/staticpage\/view.php?page=nse_1&amp;utm_source=blog&amp;utm_campaign=2020-q2-nse-1\" rel=\"noopener noreferrer\" target=\"_blank\">NSE 1 \u2013 Information Security Awareness<\/a>, which includes information on Internet threats and is designed to help end users identify and protect themselves against phishing attacks.<\/p>\n<p>The <a aria-label=\"FortiPhish Phishing Simulation Service\" href=\"\/products\/phishing-simulation?utm_source=blog&amp;utm_medium=blog&amp;utm_campaign=fglab-phishing\" title=\"FortiPhish Phishing Simulation Service\">FortiPhish Phishing Simulation Service<\/a>, together with <a aria-label=\"Fortinet\u2019s Security Awareness and Training Service\" href=\"\/training\/security-awareness-training\">Fortinet\u2019s Security Awareness and Training Service<\/a>, uses real-world phishing scenarios to train and test employees against common social engineering tactics. By improving users\u2019 ability to recognize and respond to suspicious content\u2014especially during high-risk periods of distraction or urgency\u2014these services help reduce the risk of successful phishing and malware attacks.<\/p>\n<p>If you believe this or any other cybersecurity threat has impacted your organization, please contact our <a aria-label=\"Global FortiGuard Incident Response Team\" href=\"\/corporate\/about-us\/contact-us\/experienced-a-breach\" title=\"Global FortiGuard Incident Response Team\">Global FortiGuard Incident Response Team<\/a>.<\/p>\n<h2>MITRE ATT&amp;CK Techniques<\/h2>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" class=\"details-tbl\" width=\"60%\">\n<tbody>\n<tr>\n<td width=\"33%\"><b>Technique ID<\/b><\/td>\n<td width=\"67%\"><b>Technique Name<\/b><\/td>\n<\/tr>\n<tr>\n<td>T1071.004<\/td>\n<td>Application Layer Protocol: DNS<\/td>\n<\/tr>\n<tr>\n<td>T1572<\/td>\n<td>Protocol Tunneling<\/td>\n<\/tr>\n<tr>\n<td>T1053.005<\/td>\n<td>Scheduled Task\/Job<\/td>\n<\/tr>\n<tr>\n<td>T1564.003<\/td>\n<td>Hide Artifacts: NTFS File Attributes<\/td>\n<\/tr>\n<tr>\n<td>T1055.002<\/td>\n<td>Process Injection: Process Hollowing<\/td>\n<\/tr>\n<tr>\n<td>T1055.005<\/td>\n<td>Process Injection: Process doppelg\u00e4nging<\/td>\n<\/tr>\n<tr>\n<td>T1218.011<\/td>\n<td>Signed Binary Proxy Execution: Rundll32<\/td>\n<\/tr>\n<tr>\n<td>T1059.001<\/td>\n<td>Command and Scripting Interpreter: PowerShell<\/td>\n<\/tr>\n<tr>\n<td>T1105<\/td>\n<td>Ingress Tool Transfer<\/td>\n<\/tr>\n<tr>\n<td>\u00a0T1059<\/td>\n<td>Command and Scripting Interpreter<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>IOCs<\/h2>\n<h3>C2 Server Domain:<\/h3>\n<p>westurn.in<\/p>\n<h3>Associated Sample SHA-256:<\/h3>\n<p>[TrickBot Samples]<\/p>\n<p>DF527A5C2FBDE43816CD02F4CD49EEE4BB82FB4A3C7045021360888C7D504C98<br \/>\n6C677EB2B3FFD288083C59A13D7BB712D4754AF61A5563873F76C440962346F4<br \/>\n105F652E6B8F31C371F2385877E43B6772AFF5D3168D5D4635F8A1FCBB321421<br \/>\n33C331EDEDBF8EE9829895424423CE3FD17E359D2E784FCBCE396AACFF458CF5<br \/>\n3B19A82E1354AC14A3DA7C840CBDD0CE50DB38432D78E767B36F08E45024C23D<br \/>\nBF80245BA792992FBFE24ABAC33F8FD66F24CDEB5F0F21CFDF45A29D107C8D3B<\/p>\n<h2>Appendix:<\/h2>\n<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" class=\"details-tbl\" width=\"60%\">\n<tbody>\n<tr>\n<td width=\"33%\"><b>Hash Code<\/b><\/td>\n<td width=\"67%\"><b>API Name<\/b><\/td>\n<\/tr>\n<tr>\n<td>1297812C<\/td>\n<td>GetLastError<\/td>\n<\/tr>\n<tr>\n<td>1FC0EAEE<\/td>\n<td>GetProcAddress<\/td>\n<\/tr>\n<tr>\n<td>223296ED<\/td>\n<td>GetShortPathNameA<\/td>\n<\/tr>\n<tr>\n<td>279DEAC1<\/td>\n<td>FindNextFileW<\/td>\n<\/tr>\n<tr>\n<td>2CA1B5E6<\/td>\n<td>lstrcat<\/td>\n<\/tr>\n<tr>\n<td>2D40B8E6<\/td>\n<td>lstrlenA<\/td>\n<\/tr>\n<tr>\n<td>32432452<\/td>\n<td>FindFirstFileW<\/td>\n<\/tr>\n<tr>\n<td>3287EC73<\/td>\n<td>RtlInitUnicodeString<\/td>\n<\/tr>\n<tr>\n<td>3D9972F5<\/td>\n<td>Sleep<\/td>\n<\/tr>\n<tr>\n<td>475587A1<\/td>\n<td>GetFileAttributesW<\/td>\n<\/tr>\n<tr>\n<td>4B935B8E<\/td>\n<td>FreeLibrary<\/td>\n<\/tr>\n<tr>\n<td>052AC19C<\/td>\n<td>IsWow64Process<\/td>\n<\/tr>\n<tr>\n<td>58FE7ABE<\/td>\n<td>GetTempPathA<\/td>\n<\/tr>\n<tr>\n<td>5AA7E70B<\/td>\n<td>MultiByteToWideChar<\/td>\n<\/tr>\n<tr>\n<td>5CB5EF72<\/td>\n<td>FreeSid<\/td>\n<\/tr>\n<tr>\n<td>5E7EE0D0<\/td>\n<td>SetEvent<\/td>\n<\/tr>\n<tr>\n<td>69260152<\/td>\n<td>GetTickCount<\/td>\n<\/tr>\n<tr>\n<td>723EB0D5<\/td>\n<td>CloseHandle<\/td>\n<\/tr>\n<tr>\n<td>774393E8<\/td>\n<td>GetModuleFileNameA<\/td>\n<\/tr>\n<tr>\n<td>774393FE<\/td>\n<td>GetModuleFileNameW<\/td>\n<\/tr>\n<tr>\n<td>7B4842C1<\/td>\n<td>FindClose<\/td>\n<\/tr>\n<tr>\n<td>81F0F0DF<\/td>\n<td>DeleteFileA<\/td>\n<\/tr>\n<tr>\n<td>8D5A50DC<\/td>\n<td>CreateEventA<\/td>\n<\/tr>\n<tr>\n<td>08F8F114<\/td>\n<td>CreateFileA<\/td>\n<\/tr>\n<tr>\n<td>8FB8B5BD<\/td>\n<td>WSACleanup<\/td>\n<\/tr>\n<tr>\n<td>9ABFB8A6<\/td>\n<td>VirtualAllocEx<\/td>\n<\/tr>\n<tr>\n<td>9C480E24<\/td>\n<td>GetVersionExA<\/td>\n<\/tr>\n<tr>\n<td>9E6FA842<\/td>\n<td>TerminateProcess<\/td>\n<\/tr>\n<tr>\n<td>A48D6762<\/td>\n<td>GetModuleHandleA<\/td>\n<\/tr>\n<tr>\n<td>B8538A52<\/td>\n<td>InitializeSecurityDescriptor<\/td>\n<\/tr>\n<tr>\n<td>BEA0BF35<\/td>\n<td>WriteProcessMemory<\/td>\n<\/tr>\n<tr>\n<td>C09D5D66<\/td>\n<td>TerminateThread<\/td>\n<\/tr>\n<tr>\n<td>C54374F3<\/td>\n<td>WaitForSingleObject<\/td>\n<\/tr>\n<tr>\n<td>C8AC8026<\/td>\n<td>LoadLibraryA<\/td>\n<\/tr>\n<tr>\n<td>CCD03C3A<\/td>\n<td>SetSecurityDescriptorDacl<\/td>\n<\/tr>\n<tr>\n<td>0D89AD05<\/td>\n<td>GetCurrentProcess<\/td>\n<\/tr>\n<tr>\n<td>0E91A280<\/td>\n<td>GetProcessId<\/td>\n<\/tr>\n<tr>\n<td>EF48E03A<\/td>\n<td>SetFilePointer<\/td>\n<\/tr>\n<tr>\n<td>0FA4F502<\/td>\n<td>GetTempFileNameA<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Affected Platforms: Microsoft Windows<br \/>\nImpacted Users: Windows Users<br \/>\nImpact: Fully Control the Victim\u2019s Computer<br \/>\nSeverity Level: High<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[10424,10378,32774],"tags":[],"class_list":["post-26145","post","type-post","status-publish","format-standard","hentry","category-fortinet","category-security","category-threats"],"_links":{"self":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/26145","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/comments?post=26145"}],"version-history":[{"count":0,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/26145\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/media?parent=26145"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/categories?post=26145"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/tags?post=26145"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}