Malware of the Day – ZetaSwitch – DNS/HTTP Multi-Modal C2
What is Malware of the Day?
Lab Setup
Malware: Custom Go-based C2 (ZetaSwitch)
MITRE Tactics: TA0011 Command and Control, T1071.004 Application Layer Protocol: DNS, T1573 Encrypted Channel, T1027 Obfuscated Files or Information, T1568.002 Dynamic Resolution: Domain Generation Algorithms
Traffic Type: DNS (UDP port 53), HTTP/1.1 (TCP port 8080), ICMP Type 3
Connection Type: UDP, TCP, ICMP
C2 Platform: Custom Go-based C2 (ZetaSwitch)
Origin of Sample: Active Countermeasures Threat Hunting Lab
Host Payload Delivery Method: Malicious browser extension
Target Host/Victim: 192.168.2.115 (Windows x64)
Adversary Host: 172.208.51.75 (Windows 11 x64)
Beacon Delay: 5 seconds (DNS heartbeat)
Jitter: 50%
Malware of the Day Mission
To identify and share examples of post-compromise network activity in order to better detect and respond to potential network threats. Specifically we are looking for Command and Control (C2) communication channels used by attackers to obtain intelligence, issue commands, and exfiltrate data through a compromised host or hosts.
Background
In our previous article titled “DNS Packet Inspection for Network Threat Hunters“, we examined how threat actors can leverage DNS beyond the traditional subdomain-based data exfiltration that we’re all familiar with. Today’s investigation builds on those concepts, demonstrating how attackers combine multiple DNS abuse techniques into a cohesive, multi-modal C2 framework.
The conventional wisdom in threat hunting suggests that C2 over DNS is relatively easy to detect, since all we really need to do is look out for high volumes of unique and unusual subdomains. This pattern emerges when attackers chunk large amounts of data, encode each piece, and transmit them as DNS queries. The resulting avalanche of garbled subdomains is typically trivial to tease out against a backdrop of normal DNS traffic.
However, this detection paradigm rests on a flawed assumption: that DNS will always be used for bulk data transfer. In reality, DNS was never designed for bulk data transfer. Thus, using it for this purpose is essentially just a case of using the wrong tool for a job. It’s a poor architectural choice that creates excessive noise and is thus easy to detect. Consequently, malware developers have recognized this limitation and adapted accordingly.
So instead of forcing DNS to do everything, threat actors can use it selectively for what it excels at: providing a low-bandwidth, highly reliable, and universally permitted communication channel. DNS is thus ideally leveraged for stealthy heartbeats and state management, reserving other protocols for heavy lifting when needed.
Evolution of DNS Abuse Techniques
Let’s examine how real-world adversaries have pushed the boundaries of DNS as a covert channel.
SUNBURST: The State Machine Pioneer
The SUNBURST backdoor revolutionized DNS C2 by treating the protocol not as a data pipe, but as a signaling mechanism. Rather than generating floods of random domains, SUNBURST’s algorithm produced a single unique subdomain per victim, encoding host identifiers in a way that appeared almost legitimate.
The true innovation lay in its activation sequence. The malware used DNS responses semantically-specific IP ranges and CNAME records served as commands to transition the agent between states. An A record resolving to 184.72.0.0/15 followed by a CNAME record signaled the agent to activate its HTTPS channel. This created an elegant state machine where minimal DNS traffic could orchestrate complex multi-protocol operations.
DNS Sandwich: Hiding in the Headers
Security researcher Spencer Walden’s DNS Sandwich technique demonstrates how attackers can abuse overlooked protocol fields. The technique exploits two commonly ignored elements:
The Z-bits: Three reserved bits in the DNS header that “must be zero” according to RFC 1035. Since most security tools ignore these bits entirely, they can carry covert signals. Values from 0-7 can encode different commands or states without triggering alerts.
The QClass field: Almost always set to IN (Internet), this 16-bit field is effectively ignored by most monitoring tools. It can be repurposed as a sequence number for reassembling fragmented payloads or encoding additional command data.
Request ID Tunneling
Offensive researcher Joff Thyer developed an unpublished tool that chunks data across multiple DNS queries using the 16-bit Transaction ID field. While maintaining superficially normal domain lookups, the technique exfiltrates data through carefully crafted request IDs. Though limited in bandwidth, it remains virtually invisible to traditional DNS monitoring, giving a DNS channel some ability to transfer data beyond subdomains.
The Multi-Modal Advantage
These techniques share a common thread: they recognize DNS’s strengths and limitations. Rather than forcing the protocol to handle all C2 requirements, they leverage DNS as one tool in a larger toolkit. DNS provides the persistent, low-noise heartbeat that maintains access, while other protocols handle bandwidth-intensive operations when needed.
This multi-modal approach presents a significant challenge for defenders. We can no longer rely solely on detecting high volumes of unique subdomains. Instead, we must look for subtle behavioral anomalies, unusual field values, and patterns that emerge only when examining traffic holistically.
The investigation that follows demonstrates exactly this type of multi-modal DNS abuse in action. As we’ll see, the attackers leveraged DNS not for bulk data transfer, but as a control channel that orchestrated a complex, multi-protocol compromise.
Scenario and Setup
The compromise at GenericCompany Inc. began through a supply chain attack targeting their development team. A popular browser extension used for API testing had been compromised upstream, and when several developers updated to the latest version, they unknowingly installed a backdoored variant.
The malicious extension contained a ZetaSwitch C2 agent that immediately established its primary channel, which utilized DNS in an unconventional manner. It utilized a minimalist heartbeat pattern, checking in with the C2 server with little subdomain variation. This behavior was deliberately crafted to avoid triggering traditional DNS tunneling detections that look for high levels of subdomain entropy.
In what could perhaps be considered somewhat of an OPSEC blunder, the agent did not resolve the DNS recursively via the local DNS resolver, but communicated directly with an authoritative nameserver at 172.208.51.75. This was likely an attempt to avoid caching issues and thus maintain high-frequency communication.
Every 5 seconds (with 50% jitter), the agent would send a simple DNS query to resolve the A-record for www.timeserversync.com. Drawing inspiration from the DNS Sandwich technique, the server’s response used the reserved Z-bits in the DNS header to issue commands:
- Z=0: Continue normal beaconing (default state)
- Z=1: Enter stealth mode (1-hour communication pause)
- Z=2: Run pre-programmed profiling commands
- Z=3: Transition to HTTP Channel
When the attackers needed to exfiltrate data, they would send a Z=3 response, causing the agent to establish an HTTP connection on port 8080, a technique likely inspired by SUNBURST. This ensuing persistent connection, lasting nearly 3 hours in this compromise, facilitated the transfer of approximately 28 MB of sensitive data through a series of POST requests to an /upload endpoint.
The sophistication of this approach lay not in its individual components, but in their orchestration. The DNS channel provided a reliable command and control heartbeat channel with minimal noise, while the HTTP channel handled bandwidth-intensive operations.
Network Traffic Analysis with RITA
Our investigation began during routine threat hunting when RITA flagged an unusual connection pattern. The initial findings immediately warranted deeper investigation – see Image 1 below.
Several characteristics immediately stood out:
- High Threat Severity: RITA classified this connection as “High” severity with a beacon score of 97.50%, indicating highly regular, automated communication.
- Unusual Protocol Mix: The connection utilized three different protocols-ICMP Type 3/3 (Destination Port Unreachable), UDP port 53 (DNS), and TCP port 8080 (HTTP).
- Sustained Duration: A cumulative connection duration of 4h36m56s suggested a fairly high level of persistent communication.
- Extreme Connection Volume: 11,804 connections in 24 hours far exceeded normal DNS query patterns.
- Recent Appearance: First seen only 23 hours ago, indicating this was new behaviour on the network.
Interestingly, we spotted a separate entry in RITA for the HTTP-specific connection which revealed additional anomalies – see Image 2 below.
The absence of a beacon score made sense given this was a single, continuous connection that persisted for 2h58m42s. Further, RITA flagged the “Go-http-client/1.1” User Agent as unique on this network, meaning no other hosts used it.
This specific user agent is the default string from Go’s net/http package. The fact that this was never changed to align with the actual application suggested either a hastily developed tool or sloppy craftsmanship. Either way, in most circumstances we don’t expect legitimate tools to retain default library values for User Agent strings, further reinforcing our resolve to look closer at this connection.
Let’s pivot to AC-Hunter to see what we can learn there.
Network Traffic Analysis with AC-Hunter
Loading our data into AC-Hunter provided the visualization needed to understand the connection’s behavior patterns – see Image 3 below.
As we can see in the hourly-connection graph below, the graph maintained an overall “flat-top”, indicating that the connections per hour remained fairly consistent. But there is of course a notable exception to this trend – four distinct gaps (at 22:07, 09:06, 15:06, and 17:06). It thus appears the communication was consistent, but at certain points in time, for whatever reason, the communication ceased.
Since we know the connection also utilized DNS, let’s pivot to AC-Hunter’s DNS module to see what insights we can gather there – see Image 4 below.
Surprisingly, we don’t see any results in the DNS module. This is however because as per default we’ll only see results that had more than 100 subdomains. This is of course because in “normal” DNS tunnelling, a high volume of unique subdomains are generated. Since we’re not interested in that in this case per se, let’s change the tolerance to 0 so that all DNS connections are displayed regardless of the amount of subdomains – see Image 5 below.
Scrolling through the results, we can see a finding that is highly unusual. The domain timeserversync.com was queried 11,793 times, but with only 3 unique subdomains. This completely inverted the typical C2 over DNS pattern. Rather than thousands of unique subdomains, we had thousands of repeated queries for the same subdomains.
This also reveals another insight regarding the nature of these connections. Given that most local resolvers would cache responses for at least 300 seconds, achieving 11,793 queries in 24 hours was impossible through normal recursive resolution. This suggested that rather than going through the local DNS resolver, the application communicated directly with the authoritative nameserver.
Though all of this is highly unusual, we’re left at present with two prominent unanswered questions.
First, are these direct DNS requests resolving timeserversync.com to the same IP (172.208.51.75) from our other suspicious entries? At present we have not definitively connected them yet.
Second, what exactly are the three subdomains associated with timeserversync.com, and what insights could they potentially offer us regarding the nature of this communication.
Fortunately, we can answer both these questions in one fell swoop by looking at Zeek’s dns.log.
Inspecting Network Traffic with Zeek
To see which specific domains are being queried, as well as which IP resolved them, let’s run the following command in Zeek
cat dns.log | zeek-cut id.resp_h query | grep "timeserversync.com" | sort | uniq -c
(see Image 6 below).
We can immediately confirm that all the DNS requests were indeed sent directly to the IP (172.208.51.75) belonging to the same external host we identified earlier as being suspicious. This is as we expected, but now provides concrete proof that we’re dealing with a single potential compromise.
Further, we can see that among the 3 subdomains we have www.*, which was responsible for the large majority of requests (11791/11793). The other 2 domains are however more unusual and interesting.
These both appeared to be Base64-encoded data, however attempting to decode them yielded non-ASCII characters, suggesting either corruption or custom encoding – see Image 7 below.
While our investigation has uncovered numerous red flags pointing to malicious activity, one puzzling aspect demands further scrutiny. Here we identified two unusual subdomains that appear to contain encoded data, yet the volume is conspicuously low. Traditional DNS data exfiltration would generate hundreds or thousands of unique encoded subdomains as attackers chunk and transmit large datasets. The fact that we’re seeing only two suggests this DNS channel serves a different purpose.
This paradox – clear indicators of compromise without the expected data transfer patterns – alludes to a heterodox architecture. Rather than using DNS for bulk data movement, the attackers may have implemented a state machine system where DNS serves as a low-bandwidth control channel.
To test this hypothesis, we need to examine aspects of the DNS protocol that could carry covert commands without generating suspicious subdomain volumes. Specifically, we’ll analyze the Z-bit values in the DNS headers, as these reserved fields could be repurposed to transmit control signals between the C2 server and agent.
Z-Value Analysis: Uncovering the Hidden Control Channel
Suspecting a potential state machine architecture, we analyzed the DNS traffic for anomalous Z-bit values using a custom analysis tool I created that can be found here. Installation and usage instructions are available in the repo’s readme.
Essentially, the tool examines DNS packets between specified hosts, flagging non-zero Z-values that indicate potential covert channel activity. Running the analysis on our capture file produces the following output – see image 8 below.
Once our tool has processed our trace file we can open the resulting *.csv in any appropriate tool. I’ll be using Zui, which provides intuitive data wrangling capabilities through Zed syntax, though standard tools like Microsoft Excel or Google Sheets work equally well for this analysis.
Our first priority is to examine the distribution of Z-values present in the captured traffic. Since the Z-bits are reserved and must be zero according to RFC specifications, any non-zero values would immediately indicate potential covert channel activity. By aggregating and counting each unique Z-value, we can get more insight into the presence of any non-0 values – see Image 9 below.
Interestingly, we can see that though the majority of traffic (23554 packets) did contain the expected 0 as the Z-value, there were also packets with Z-values of 1, 2, and 3. Since it’s really only these that interest us for the moment, let’s look at those packet details in ascending order – Image 10 below.
The analysis reveals a clear pattern of anomalous Z-values: 3 packets with Z=1, 10 packets with Z=2, and a single packet with Z=3. Significantly, all non-zero Z-values appear exclusively in DNS response packets – communication flowing from the external nameserver back to our compromised host. This directionality suggests these values represent server-issued commands rather than client-initiated signals.
Examining the Z=2 packets (red) provides our first clue. Both queries containing the suspicious encoded subdomains received responses with Z=2, suggesting this value might signal successful data receipt, or serve as a trigger for enumeration activities.
However, this interpretation is complicated by the fact that 8 of the 10 Z=2 responses were for standard queries to www.timeserversync.com, not the encoded subdomains. This inconsistency could indicate failed transmission attempts or a more complex signaling mechanism we don’t yet fully understand.
The true revelation comes when we analyze the packets with Z=1 (green) and Z=3 (blue) values. These responses appear to serve a distinctly different purpose, one that becomes clear when we correlate their timestamps with our earlier observations regarding the hourly-connection graph from AC-Hunter – see Image 11 below.
Looking at the timestamps in the csv-file and comparing it to the gaps in the hourly-connection graph we observed earlier presents a clear correlation. The three packets with Z=1 (color-coded with green, turquoise, and fuchsia in the image above) each preceded exactly one-hour breaks in communication, while the single response packet with Z=3 (color-coded with orange) initiated a three-hour communication pause.
This correlation is too precise to be coincidental. These Z-values appear to function as server-issued commands instructing the agent to enter dormancy periods of predetermined lengths. The pattern suggests a simple but effective control mechanism: Z=1 triggers a one-hour sleep cycle, while Z=3 commands a three-hour hibernation. This allows the attackers to reduce their footprint on demand, potentially evading time-based detection systems or manual monitoring during specific periods.
While Z=0 is the normal and expected value for legitimate DNS traffic, it’s worth examining these packets as well, given they constitute the vast majority of the communication between these hosts. The sheer volume – over 23,000 packets – is itself anomalous and merits at the very least a cursory glance – Image 12.
We can see all the initial request-response pairs here. Though nothing beyond the frequency stands out as unusual, we can observe that each subsequent pair is separated by approximately 4 to 7 seconds, revealing a clear cyclical pattern.
This timing suggests the DNS queries function as a heartbeat mechanism, with the agent checking in at regular intervals. The server’s consistent Z=0 responses likely represent the default “no action required” state – the most common scenario that deliberately uses the least suspicious value to maintain cover.
We’ve now assembled compelling evidence pointing to a sophisticated compromise. The anomalous Z-values, the extreme query volume, the encoded subdomains, and the temporal patterns all paint a picture of deliberate C2 activity.
However, one crucial piece of the puzzle remains unexplained – how does the 2h58m HTTPS connection we discovered in RITA fit into this DNS-based command structure? To answer this final question and solidify our understanding of the attack chain, we need to examine the packet-level details in Wireshark.
Deep Packet Inspection with Wireshark
To understand how the HTTP session fits into this pattern, let’s examine the non-DNS traffic in Wireshark using the filter ip.addr == 192.168.2.115 && ip.addr == 172.208.51.75 && !dns – see Image 13 below.
We can see the first few packets follow the expected pattern for TCP connection establishment – SYN, SYN-ACK, ACK – followed by the GET request to the external server that initiates the HTTP/1.1 connection.
The pieces fall into place when we examine the time_human column showing when this connection was established. The connection began on August 4th at 17:08, the precise moment the server sent the DNS response packet with Z=3, and exactly when the hourly connection graph showed that precipitous drop in DNS communication, leading to a 3-hour gap in our hourly-connection graph.
This timing reveals that, despite what we suspected earlier, Z=3 serves a fundamentally different purpose than Z=1. While Z=1 seems to simply instruct the agent to pause communications, Z=3 commands a protocol switch from DNS to HTTP. This technique bears a striking resemblance to SUNBURST’s activation sequence, where DNS responses orchestrated transitions to higher-bandwidth channels. The attackers likely determined this was the optimal moment to begin data exfiltration, leveraging HTTP’s superior bandwidth capabilities for bulk data transfer.
To confirm this hypothesis, we can refine our Wireshark filter to examine only the HTTP packets (ip.addr == 192.168.2.115 && ip.addr == 172.208.51.75 && http), which provides the final piece of supporting evidence – see Image 14 below.
We can see here that, shortly after the HTTP connection was established, the client sent a series (27 chunks in total, as can be seen in the info column) of POST requests to the server’s /upload endpoint, strongly suggesting some data was being exfiltrated.
Indeed if we open the data flow in WireShark’s “Follow Stream” feature, we can see a giant blob of encoded data, as well as the fact that approximately 28 MB was transferred from the agent to the server – see Images 15 and 16, below.
As we can see, approximately 28 MB of encoded data was exfiltrated during this session – far more than DNS could handle without generating a deluge of garbled subdomains.
With this last bit of evidence we now have a reasonably clear picture of the attacker’s modus operandi, as well as the custom C2’s functionality. As threat hunters we have built a formidable case with numerous lines of valuable supportive evidence to present to the Response Team. This will not only serve as iron-clad validation regarding our premise, but also to help the Response Team initiate their remediation efforts with valuable information regarding the attacker’s behavior.
Conclusion
This investigation highlights several critical lessons for modern threat hunting.
DNS Abuse Has Evolved Beyond Subdomain Tunneling
The assumption that DNS C2 always generates numerous unique subdomains is outdated. This attack used just three unique subdomains across 11,793 queries, completely inverting traditional detection patterns. By using DNS as a control channel rather than a data pipe, attackers can maintain persistent access with minimal observable anomalies.
Protocol Semantics Matter More Than Content
The attackers didn’t hide data in DNS packets – they hid commands in the protocol itself. The Z-bits, which should always be zero, became a covert control channel. This technique bypasses content inspection entirely, as the malicious functionality exists in the metadata, not the payload.
Multi-Modal Frameworks Require Behavioral Analysis
No single protocol told the complete story. Only by correlating DNS beaconing patterns, HTTP sessions, and temporal anomalies could we understand the full scope of the compromise. This is where tools like RITA and AC-Hunter prove invaluable – they reveal the behavioral patterns that emerge across protocols and over time.
Direct Nameserver Communication Is a Red Flag
The extraordinarily high volume of queries could only occur through direct nameserver communication, bypassing the local resolver. This behavior is extremely unusual for legitimate applications and should trigger immediate investigation. Organizations should monitor for DNS queries that bypass internal resolvers.
Reserved Fields Are Not Benign
Every “reserved for future use” field in a protocol is a potential covert channel. The DNS Z-bits, the QClass field, even the Transaction ID can all carry hidden meanings. Security tools must examine these traditionally ignored fields.
The Power of Layered Detection
This investigation showcases why behavioral analysis tools like RITA and AC-Hunter remain essential in modern security operations. While encrypted payloads and protocol abuse can evade traditional signatures, the behavior of the communication – the beaconing patterns, the protocol mixing, the temporal anomalies – cannot be hidden.
RITA’s initial detection of the high beacon score and unusual protocol combination provided the crucial first alert. AC-Hunter’s visualizations revealed the distinct operational phases that would have been invisible in raw logs. Together, they enabled us to uncover a sophisticated attack that individual detection methods would have missed.
As attackers continue to evolve their techniques, our detection strategies must evolve as well. By combining automated behavioral analysis with deep protocol inspection and human intuition, we can successfully detect even the most sophisticated multi-modal C2 frameworks. The key is recognizing that modern threats don’t follow predictable patterns – they adapt, they hide in plain sight, and they abuse our assumptions about “normal” behavior.
In this case, what appeared to be a DNS anomaly was actually an elegant multi-protocol orchestration system. Only through methodical investigation, leveraging the strengths of tools like RITA and AC-Hunter, could we piece together the full narrative of the compromise. This reinforces the fundamental truth of network threat hunting: the adversaries may be sophisticated, but their network behavior, when properly analyzed, will always tell a story.
Capture Files
PCAPs
Because… PCAPs, or it didn’t happen. 😊
The following PCAP files are packet captures taken from the same lab environment over a 24-hour time frame. The files were generated using Wireshark from the target host and include normal Windows OS traffic and normal network broadcast traffic. They have not been edited. The PCAPs are safe, standard PCAP files and do not include any actual malware.
ZetaSwitch 24 Hour Capture
zetaswitch_24hr.pcapng
File Size: 347.4 MB
SHA-256 Hash: 3A476A29AA17337909C2DB4761E388E051A07EA7A419504FB9417F9713535824
Zeek Logs
If you are an AC-Hunter or RITA user, we are providing the 24-hour Zeek logs for you to import directly into AC-Hunter or RITA. The following Zeek Logs have been taken from the same lab environment over a 24-hour time frame and include normal Windows OS traffic and normal network broadcast traffic. They have not been edited. The Zeek logs are safe, standard log files and do not include any actual malware.
Importing Zeek logs into AC-Hunter or RITA example:
ssh into your AC-Hunter or RITA server and upload all the Zeek logs contained in the zip file below (all files that have the ‘.log’ extension) into a temporary directory on the server. In this example, we are uploading the Zeek logs into /tmp/zetaswitch_zeek/
Then run the following command:
For AC-Hunter v6.x and RITA v4.x and earlier:
rita import /tmp/zetaswitch_zeek/*.log zetaswitch
For RITA v5.x+:
rita import --logs=/tmp/zetaswitch_zeek/*.log --database=zetaswitch
You will now have a new database in the AC-Hunter UI/web interface or RITA CLI titled “zetaswitch” you can select and view.
ZetaSwitch 24 Hour Zeek Logs
zetaswitch_zeek.zip
Size: 1.7 MB
SHA256 Checksum: 247FC3AB1D2EE452A4A36473FA375377BFBF0E6DFDAF72760927BEBBF43F269B
Discussion
Want to talk about this or anything else concerning threat hunting? Want to share how good (or not so good) other detection tools were able to detect this sample?
You are welcome to join our Discord server titled “Threat Hunter Community” to discuss topics surrounding threat hunting. We invite you to join our server here.

Faan is a security researcher specializing in detecting post-exploitation malware, with a focus on network communication. He likes exploring threat hunting via a purple team approach by simulating adversarial activity to develop novel threat hunting detections. He also loves building covert channels and unusual malware communication methods, creating threat emulation tools that inform new detection vectors.















