A STUNning Disguise: Cling Malware Masquerades as Google

A STUNning Disguise: Cling Malware Masquerades as Google

During routine monitoring of our customer telemetry, we observed multiple attempts to exploit CVE-2021-35394 affecting internet-exposed devices. Most of the activity resembled opportunistic scanning, but a subset led to a different finding: a botnet whose command-and-control design abuses legitimate-looking STUN traffic and public STUN infrastructure to register infected hosts, receive operator commands and make malicious activity less obvious from a network monitoring perspective.

Cling is notable not because it introduces a new propagation technique, but because it repurposes ordinary STUN behavior into a practical command-and-control channel. The result is a botnet whose traffic can resemble legitimate NAT-traversal activity while still supporting propagation, proxying, tunneling and denial-of-service commands.

Initial Access Through CVE-2021-35394 Exploitation

We constantly monitor anonymized telemetry from sensors deployed in customer networks around the world. This visibility helps us track exploitation trends and identify cases where routine-looking activity leads to more interesting malware behavior. In this case, we noticed a spike in attempts to exploit CVE-2021-35394, a remote code execution vulnerability affecting the Realtek Jungle SDK diagnostic component commonly compiled as UDPServer. Despite being a few years old, this vulnerability is widely abused in the wild because affected SDK components are embedded across many IoT and networking devices, including routers, access points, repeaters and other appliances, which often do not receive updates and remain unpatched and vulnerable for years.

Most of these hits were consistent with opportunistic probing commonly seen around older but still-exploited IoT vulnerabilities. However, a subset of the activity stood out because the exploitation chain retrieved and executed a malware sample that did not follow the typical communication patterns we often associate with Mirai-like botnets.

Figure 1: Large increase in telemetry hits for CVE-2021-35394

Exploiting the vulnerability is straightforward: the attacker sends UDP datagrams that start with orf;, followed by shell commands executed by the vulnerable system. In the captured attempt below, the threat actor uses BusyBox wget to download a binary from an HTTP server, marks it as executable, and runs it with the replication method passed as the first argument (realtek.selfrep in this case).

Figure 2: Example payload used to exploit CVE-2021-35394

Propagation via Scanning and Exploitation

Our analysis focused primarily on the MIPS sample 3b0ac6aaabb3bf8058ca14f9c8ccc613cfa3ea71, with supporting observations from related samples in the same activity cluster. Unless otherwise noted, the persistence, STUN C2 and command behavior described below refer to this sample.

In the analyzed sample, we found embedded exploit logic for several additional command-injection vulnerabilities, namely:

  • Realtek SDK RCE (CVE-2014-8361)
  • LB-LINK routers RCE (CVE-2023-26801)
  • TBK DVR RCE (CVE-2024-3721)
  • Linksys RCE (CVE-2025-34037)
  • Eir D1000 router RCE (CVE-2016-10372)
  • FiberHome SR1041F router / China Mobile HG6543C4 RCE (CVE-2023-41011)
  • MVPower CCTV DVR RCE (CVE-2016-20016)
Figure 3: Exploit payloads embedded in the sample

Persistence Through Init Scripts and wget Replacement  

The single-instance check to only run one copy involves binding a socket with SO_REUSEADDR to port 33957 and exiting cleanly if it fails. The sample copies itself to /root/.cling and /usr/local/bin/.cling. Both executables are appended to /etc/inittab, /etc/init.d/rcS, /etc/rc.d/rc.boot, thus achieving persistence on SysV and BusyBox init systems.

Figure 4: init persistence setup

Another persistence mechanism involves locating the wget binary, moving it to wget.r, writing its new location in wget.p and replacing the original wget binary with the malware itself. Symlinks, as is the case with BusyBox, are also handled. Upon future invocation of wget on the compromised system, which may be used by cron jobs, maintenance operations or other attackers, the malware is re-executed instead. The sample checks the name it was called by and if it is wget , it calls the legitimate wget binary by reading wget.p and passing its own argv. This way the malware can restart/reinstall itself whenever wget is called.

C2 Communication Masquerading as STUN

STUN, defined in RFC-8489, is a protocol used to support NAT traversal by allowing an endpoint to discover its public IP address and NAT-mapped port. It is commonly used as part of protocols and frameworks such as ICE, TURN, SIP, and real-time communication applications. As a result, STUN and related ICE/TURN traffic is common in enterprise networks, especially from applications such as Microsoft Teams, Zoom, Cisco Webex, and WebRTC-based browser applications.

What we noticed in this sample during our analysis is a list of embedded IPs associated with public STUN servers. While we have previously seen malware using this method to figure out the public IP of the infected host, Cling uses STUN-like exchanges as part of a registration and command-delivery flow.

Figure 5: Multiple connections to STUN servers

At a high level, the bot follows a four-step communication flow: it sends STUN Binding Request messages to a hardcoded list of STUN servers, records the externally observed ports returned by those servers, sends the servers a custom registration datagram that includes the mapped ports and the infection method tag, then waits for UDP packets that encode operator commands in the STUN transaction ID field. This flow lets the operator learn where to reach the bot while keeping much of the surrounding traffic shaped like ordinary STUN activity.

In more detail:

1. The sample periodically sends a STUN Binding Request to a list of 13 STUN servers (every ~5 seconds):

  • 74.125.250.129:19302
  • 145.249.115.184:3478
  • 216.93.246.18:3478
  • 85.17.88.164:3478
  • 77.72.169.213:3478
  • 77.72.169.211:3478
  • 5.39.72.109:3478
  • 81.187.30.115:3478
  • 212.227.67.34:3478
  • 212.227.67.33:3478
  • 207.38.82.134:3478
  • 83.211.9.232:3478
  • 212.53.40.43:3478

The transaction ID is set to all zeros instead of a random value, which does not follow the RFC. At the time of writing, the servers all have clean reputation on VirusTotal and the majority are present in public lists of STUN servers.

Figure 6: RFC-8489 guidelines for transaction ID
Figure 7: Binding request sent to 13 STUN servers

2. Each server responds with a Binding Success Response message containing the public IP of the endpoint and the source port seen from its perspective.

Figure 8: Temporary pinholes opened

3. The sample sends a custom UDP datagram, which serves as a registration message, to each STUN server. The registration message contains the argv[1] of the bot process or unknown if it is not present and each of the ports returned by the STUN bindings. argv[1] is used by the dropper to tag each bot by the method of infection that was used (e.g., realtek.selfrep,selfrep.router). This custom UDP payload falls outside the STUN protocol definition even though it is sent to the ports associated with STUN. As expected, conforming servers ignore it; in our testing, none of the servers responded.

Figure 9: Custom registration message sent to 13 STUN servers

4. The sample then polls for messages containing commands to execute from its operator sent via UDP to any of the previously mapped ports.

From a network monitoring perspective, the activity appears as innocuous interaction with STUN servers. Given that the custom registration message is sent to every STUN server in the list, it is apparent that the operator requires visibility into at least one of the servers, in order to track new bots joining the swarm to know where to send commands to.

Some servers in the list, like stun.l.google.com , are long-running and widely used, while others are less recognizable and warrant additional scrutiny. To decisively identify which server in the list is involved in the botnet’s C2 activity, we compared how each of the 13 STUN servers responded to controlled Binding Requests as an initial form of fingerprinting.

In a STUN Binding Success Response, a conforming STUN server echoes the transaction ID of the original Binding Request. However, one of the 13 servers responded with an all-zero transaction ID instead of echoing back the transaction ID of the request. This misbehavior suggested that the STUN server is tailored to the bot’s own STUN traffic, which also uses all-zero transaction IDs.

Figure 10: Fingerprinting STUN servers, one stands out.

Based on this finding, we performed an additional validation step: we wrote a client which pretended to be an infected system trying to join the botnet by sending registration messages to each of the STUN servers in the list. However, instead of reporting the same list of mapped ports to each server, we reported disjoint sets. The hypothesis was that if 145.249.115[.]184 , which is our suspect, is controlled by or colluding with the botnet’s operator, we would receive a connection from C2 to one of the ports we only advertised to the suspicious server.

This is exactly what happened: several hours after we started sending registration messages, one of the ports we advertised to 145.249.115[.]184 received multiple commands from C2.

Figure 11: Confirmation of colluding STUN server
Figure 12: Bot is instructed to use this host as a loader in the first C2 command

The C2 commands for Cling are hidden in the STUN transaction ID field, which is normally meant to be a random value. In this case, these 12 bytes instead encode the command that the bot should execute and its parameters. The screenshot below shows a transaction ID that encodes a UDP flood command against a target.

Figure 13: DoS command encoded in STUN Transaction ID

We monitored the commands originating from C2 for multiple days, receiving multiple tasks to self-propagate on the internet by scanning for and attacking vulnerable systems. Additionally, we received requests to perform flooding attacks against the following targets:

  • 112.151.157[.]222:8080 (South Korean ISP)
  • 192.170.240[.]137:53 (University of Chicago cluster)
  • 23.81.40[.]193:25565 (Minecraft)
  • 147.185.221[.]129:25565 (Minecraft)

The most interesting part of the C2 traffic is where the commands appeared to come from. The packets carrying operator commands originate from 74.125.250[.]129, an IP address that stun.l.google.com resolves to. In other words, the operator is not merely hiding commands inside a STUN-looking packet, but they are making those commands appear as if they are legitimate replies from one of the most recognizable STUN services on the Internet. We are not aware of any legitimate way to force a STUN server to relay a specific transaction ID, and given that the traffic is UDP and unidirectional, the most likely explanation is that the botnet’s operator is using an ASN, which does not perform Source Address Validation (RFC-2728) properly, allowing for source IP address spoofing. The consistent difference in IP TTL values between legitimate responses to STUN binding requests and responses containing C2 commands encoded in transaction IDs supports this explanation.

This matters because many defenders, firewalls and network triage workflows treat traffic from high-reputation infrastructure very differently from traffic sourced from an unknown VPS or a disposable C2 host. A UDP packet from an unfamiliar address carrying odd-looking bytes is suspicious; the same packet appearing to come from Google STUN after the infected host has already initiated STUN activity is much easier to dismiss as background NAT-traversal noise.

Figure 14: C2 command arrives from spoofed IP

Supported Commands

The sample supports multiple commands encoded in the transaction ID of the STUN Binding Success Response, namely:

  1. ‍Execute: Downloads a payload from the provided ip:port and passes it to system(3).
  2. ‍Scan and exploit: Scans IPv4 space and uses multiple exploits to attempt and expand the botnet. The provided ip:port is used to download the malware onto hosts that were successfully exploited.
  3. ‍Stop scanner: Stops the scanning activity.
  4. ‍Start TCP tunnel: Starts listening at the specified TCP port, accepting connections from the public.
  5. ‍Stop TCP tunnel: Terminates TCP tunnel. ‍
  6. Proxy relay: Connects to the provided ip:port relay server and forwards traffic between the relay and compromised device.
  7. ‍Stop proxy: Terminates the proxy child.
  8. ‍Flood: Performs a DoS attack against the specified target for the specified duration of time.
Figure 15: Bot instructed to scan and exploit to expand the botnet, uses 121[.]32.243.81:1337 to load the sample on exploited hosts

Mitigations and Recommendations

Figure 16: Alerts associated with Cling shown on N2OS Guardian
Figure 17: Asset page for vulnerable camera
  • ‍Review exposed IoT and networking devices: Identify internet-facing routers, access points, DVRs, and embedded appliances that may include vulnerable Realtek Jungle SDK components or other known command-injection flaws abused by the sample. ‍
  • Prioritize patching and exposure reduction: Patch devices affected by CVE-2021-35394 and the additional vulnerabilities listed in the propagation section. Where patching is not possible, restrict inbound access, remove unnecessary internet exposure and place devices in segmented network zones. ‍
  • Hunt for suspicious connection patterns: Look for repeated STUN Binding Requests sent at short intervals with the transaction ID set to all zeros or non-STUN UDP datagrams sent to STUN endpoints. Additionally, monitor assets for unexpected connections, which deviate from the established baseline. Network-level monitoring is especially critical for embedded devices, where host telemetry is often limited or unavailable. To see how the Nozomi Networks Platform applies these capabilities in practice, request a demo today. ‍
  • Check compromised-device artifacts: Search for malware copies named .cling, persistence entries added to init scripts, and replaced wget binaries with companion wget.r and wget.p files. ‍
  • Operationalize the IoCs and ATT&CK mapping: Use the indicators and techniques below to build detections, validate telemetry coverage, and support targeted hunting for Cling-like activity.

Conclusion

Cling shows how commodity IoT botnets are evolving beyond familiar Mirai-like patterns. Although Cling still spreads through exposed devices and command-injection vulnerabilities, its STUN-based command-and-control design sets it apart by making infected hosts communicate in ways that resemble legitimate NAT-traversal traffic.

This abuse of STUN is effective because the surrounding traffic can blend into environments where collaboration tools, browsers, and real-time communication applications already generate legitimate STUN activity. At the same time, the implementation choices observed in Cling create useful opportunities for detection: repeated Binding Requests with all-zero transaction IDs, custom UDP registration datagrams sent to the same STUN hosts, a non-conforming STUN server implementation, and host artifacts such as .cling copies or replaced wget binaries.

For defenders, the main takeaway is that reputation alone is not enough when malware deliberately shapes its traffic around legitimate infrastructure or widely used protocols. Just as importantly, unpatched internet-facing devices should be treated as potential entry points into the wider network, not isolated edge systems. Monitoring should combine protocol-aware inspection, behavioral baselining, exposure reduction, and endpoint indicators so that suspicious deviations inside otherwise common traffic patterns are not missed. The IoCs and ATT&CK mapping below can support immediate hunting and detection engineering for this activity.

MITRE ATT&CK Mapping

Initial Access

  • T1190 – Exploit Public-Facing Application: Cling is dropped through exploitation attempts against internet-exposed devices, including CVE-2021-35394 affecting Realtek Jungle SDK components and other command-injection vulnerabilities.

Execution

  • T1059 – Command and Scripting Interpreter: The exploitation payload executes shell commands on vulnerable devices to download the malware, change file permissions, and launch the binary.

Persistence

  • T1037 – Boot or Logon Initialization Scripts: The sample appends references to copied malware binaries in init-related files such as /etc/inittab, /etc/init.d/rcS, and /etc/rc.d/rc.boot to survive reboot on SysV and BusyBox-style systems.
  • T1574 – Hijack Execution Flow: The malware replaces wget with a wrapper-like copy of itself while preserving the original binary as wget.r and storing its path in wget.p, allowing the malware to execute when wget is invoked.

Command and Control

  • T1095 – Non-Application Layer Protocol: Cling receives operator commands over UDP packets sent to NAT-mapped ports learned through STUN-like communication. The commands are encoded in the STUN transaction ID field of Binding Success Response-like packets.
  • T1572 – Protocol Tunneling: The command set includes a separate TCP tunneling capability, allowing infected devices to listen on a specified TCP port and accept external connections.
  • T1090 – Proxy: The sample can connect to a specified relay server and proxy data back and forth through the compromised device.

Discovery

  • T1046 – Network Service Discovery: The scan-and-exploit command instructs infected devices to scan IPv4 space and identify additional vulnerable systems for propagation.

Impact

  • T1498 / T1498.001 – Network Denial of Service / Direct Network Flood: The malware supports flood commands that perform denial-of-service attacks against specified targets for a configured duration.

IoCs

  • ‍‍3b0ac6aaabb3bf8058ca14f9c8ccc613cfa3ea71 (mips)
  • 08636d09d9ffd1713bd6bcb965ad40b6ce3de1aa (mips)
  • hxxp://118.45.196[.]225:800/mipsel (loader host)
  • hxxp://120.193.219[.]210:800/mipsel (loader host)
  • hxxp://58.211.144[.]243:800/mipsel (loader host)
  • 145.249.115[.]184 (STUN server)
  • /usr/local/bin/.cling
  • /root/.cling
  • /usr/bin/wget.r
  • /usr/bin/wget.p
  • /bin/wget.r
  • /bin/wget.p
  • /usr/local/bin/wget.r
  • /usr/local/bin/wget.p
  • /sbin/wget.r
  • /sbin/wget.p
  • /usr/sbin/wget.r
  • /usr/sbin/wget.p

YARA

rule IOT_WORM_Cling_sample

{

       meta:

               name = "Cling - WORM"

               author = "Nozomi Networks Labs"

               description = "Detects multiple Cling variants"

               tlp = "clear"

               date = "2026-09-17"

               hash1 = "90d738a8d650e3fefda9d7efa4baa11bd89ab05fcf0eb173e04aa01a52b465e2"

               hash2 = "3a6927a3399f2a10bb2e2229482e5096e5f1c3401a87f7f1730db11243531e28"

       strings:

               $s1 = ".selfrep"

               $s2 = "User-Agent: clingwashere"

               $s3 = "/.cling\x00"

               $s4 = "mount --bind /tmp /proc/%d"

               $s5 = "POST /picsdesc.xml"

               $scan_ports = { 50 00 90 1F 55 00 61 EA 51 00 58 00 }

               $cmd_dispatch = { FF FF 42 24 FF 00 42 30 08 00 43 2C ?? ?? 60 10 80 10 02 00 }

               $stun_magic = { 12 21 04 3C ?? ?? 99 8F 42 A4 84 34 }

       condition:

               uint32(0) == 0x464C457F and

              filesize < 1MB and

              3 of them

}

References:

‍

‍

No items found.