Pause off my cluster: DERO cryptojacking takes a new shape
Learn how the threat actors behind the 2023 DERO cryptojacking campaign have adapted their techniques to evade detection, and the best practices for mitigation.
We have detected a new variant of an ongoing cryptojacking campaign targeting misconfigured Kubernetes clusters in our customers’ cloud environments.
In this incident, the threat actor abused anonymous access to an Internet-facing cluster to launch malicious container images hosted at Docker Hub, some of which have more than 10,000 pulls. These docker images contain a UPX-packed DERO miner named "pause". Interestingly, the threat actor has hard-coded their wallet and pool information into the miner executable, which enables the threat actor to execute the miner without any flags, probably as a defense evasion mechanism. The early stages of this campaign were documented in March of 2023, but our latest findings show that this threat actor has been working to adapt their techniques in response to this publication.
We used IOCs identified during the incident investigation as pivot points to find additional tools used by the attackers. Our analysis indicates that the threat actor employed various methods to propagate within target cloud environments and deploy miners. During our investigation, the attacker updated their Docker Hub repository images, indicating that the campaign is still active.
In this blog post, we will detail the incident, explain the changes and additions the threat actor has made to their tooling since this campaign was first documented last year, and provide best practices for defense and mitigation along with indicators of compromise (IoCs).
For more information about this incident and others impacting cloud environments, be sure to check out the Wiz Cloud Threat Landscape.
Technical analysis
Initial access
We determined the initial access vector to be an externally accessible Kubernetes API server with anonymous authentication enabled [T1190]. With anonymous auth enabled, every unauthenticated user interacting with the cluster API is assigned system:anonymous user in system:unauthenticated group. This user has only minimal permissions to operate on cluster resources; for example, list cluster version by accessing /version endpoint. Therefore, on its own, a public cluster with anonymous auth enabled is not a problem (after all, GKE and EKS employ this mode by default). However, when the system:anonymoususer or the system:unauthenticated group is assigned non-default permissions, external unauthenticated users may abuse these permissions as they see fit, which may very well include malicious purposes. This is what happened in this incident.
Kubernetes deployments
After gaining initial access and verifying that the necessary permissions were present, the attacker proceeded to deploy various cryptominer workloads [T1610]. For example, a K8s deployment named k8s-device-plugin in the kube-public namespace with pods containing an image called nohuppo:pause. Another example is a daemonset named pytorch-container in the kube-system namespace with pods containing an image called dockerproxies/pause.
Overall, we observed five different deployments scattered across namespaces (the full list of the workloads and containers can be found in the Indicators of Compromise section at the end of this post).
It is evident that the attackers used benign-looking names for name confusion to make it harder to detect the malicious deployments [T1036.005]. For example, k8s-device-plugin is a default name for NVIDIA operator deployment, and kubernetes-external-secret is a take on the operator handling external secrets. Another interesting point to note is the distribution of workloads across different control plane namespaces to blend with the legitimate control plane workloads.
These masquerading techniques [T1036.005] can of course prove effective against cursory manual inspection but fail against more comprehensive protection and detection solutions.
Malicious docker images
The malicious docker images contain a miner named "pause" [T1036.005] which is located under /var/tmp or /usr/local/bin. The miner is a UPX-packed [T1027.002] DERO miner. The image’s entrypoint.sh simply executes the miner:
#!/bin/bashecho"ok"sleep 10
./pause
The name of this container is likely intended to mimic that of the real “pause” container [T1036.005] [T1610] commonly found in Kubernetes clusters. This container normally serves as a minimal bootstrap container that sets up the network namespace for a pod, allowing all other containers in the pod to share the same network and IP address. This ensures consistent networking and resource management while consuming minimal resources. The legitimate pause container runs a minimal binary named “pause”. This binary essentially does nothing but serve to keep the container running, thereby maintaining the network namespace and other shared resources for the duration of the pod's lifecycle.
This is not the first-time attackers have chosen to mimic the “pause” container to hide malicious activity. For example, in September 2020 Microsoft documentedTeamTNT using Docker Hub images named “pause” [T1036.005] [T1610] to facilitate cryptojacking [T1496] (check out this blog to learn more about how threat actors can leverage several types of Kubernetes containers and pods).
The miner
The threat actor compiled a DERO miner [T1496], an open-source miner written in Go. However, they modified the original DERO code’s main function, hardcoding an encrypted wallet address and custom mining pool URLs into the binary [T1140].
The following snippet shows the new code that was added by the attacker, allowing them to run the miner without any suspicious command line arguments or configuration files, as a defense evasion technique.
We managed to extract the decrypted text by debugging the sample in our sandbox environment and adding a break point after the decryption function:
Further analysis allowed us to write a program that extracts and decrypts these strings statically, so we ran it on all samples and variants we found in customer environments and other sources. In total, we found two different wallet addresses among the different samples we analyzed:
The original mining pool used by the attacker, community-pools.mysrv[.]cloud which is a known Dero pool, was also used in this incident by some variants. However, in other variants, in addition to encrypted wallets, code was also added to hide additional mining pools:
Decrypting these revealed the following subdomains:
d.windowsupdatesupport[.]link
h.windowsupdatesupport[.]link
name.windowsupdatesupport[.]link
At the time of writing, these subdomains do not point to an active mining pool, but they have previously resolved to IP addresses of known DERO pool domains, according to VirusTotal. We assess that the attacker registered these domains [T1583.001] to evade detection by monitoring which may be scanning for DNS queries for known mining pools, but not for communication with their IP addresses.
Uncovering additional attacker activities
By pivoting in VirusTotal, we were able to find more tools we believe to be related to the same threat actor. These seem to indicate that besides exploiting misconfigured Kubernetes clusters as we observed in our investigated incident, the attacker has also been targeting other types of environments while using additional techniques:
A Windows sample of a UPX-packed [T1027.002] DERO miner (42e82a37cc6b44f7bc58c6ef6bf3e9e2) was uploaded to VirusTotal on February 24th, 2024. This sample hardcodes the same wallet seen in the “pause” Linux samples observed in this incident (dero1qyy8xjrdjcn2dvr6pwe40jrl3evv9vam6tpx537vux60xxkx6hs7zqgde993y).
A dropper script named ddns.sh was uploaded to VirusTotal on April 15th, 2024:
The script first checks for the existence of java-daemon , py.elf , and getpy.sh processes and terminates them if found. This is likely a measure to eliminate competing miner processes, as it is common for miners to vie for machine resources. Next, it checks if a GPU is present by checking if the nvidia-smi command exists. If this check succeeds, the script will download [T1105] GMiner from GitHub and rename it as python3.6.3 and execute it. Otherwise, if the nvidia-smi command does not exist, the script will download [T1105] a binary named cloud from an attacker-controlled server (http:// 209.141.32[.]182/cloud), rename it to python3.6, and execute it with nohup [T1564.011]. Based on VirusTotal, the binaries served by this server were the same as those observed in this incident (22de8e4b08be5c2b1cc5eb2012739786 and cc47cb1bbef442d2f6aa7bc0b0843c88). Finally, the script tampers with bash history and other bash related logs to hide evidence of its execution [T1070].
The evolution of “pause”
Since this activity was first documented by CrowdStrike last year, the attacker has evidently implemented several measures to evade detection. Firstly, they utilized UPX-packing [T1027.002] to obscure the binary, making it harder for traditional antivirus tools to statically analyze and detect the malicious code. Additionally, the attacker embedded encrypted [T1140] wallet address and mining pool information directly within the binary, bypassing detection methods that monitor command-line arguments for suspicious activity. Finally, they registered domains [T1583.001] with innocent-looking names to avoid raising suspicion and to better blend in with legitimate web traffic, while masking communication with otherwise well-known mining pools. These combined tactics demonstrate the attacker's ongoing efforts to adapt their methods and stay one step ahead of defenders.
Activity timeline
According to our analysis, the earliest indication of this activity was the creation of the domain windowsupdatesupport[.]link on May 7th, 2023. As of this writing, there are active DNS queries to this domain, suggesting that the threat is ongoing.
As for the Docker Hub users who added the malicious images:
dockerproxys joined Docker Hub on March 19th, 2024. The images hosted by this user were last updated on May 16th, 2024.
pausehubs joined Docker Hub on February 20th, 2024.
We informed Docker Hub about these accounts, and they took down dockerproxys and nohuppo.
How can organizations defend themselves?
To make sure that your organizations’ Kubernetes clusters are not susceptible to this type of attack, consider taking the following precautionary steps that implement firewalling and user access control:
Disable external cluster access: Unless external network access to the cluster is absolutely necessary, always create a private cluster without public internet exposure. This alone will prevent opportunistic attackers from launching similar attacks against your clusters.
Disable anonymous cluster access:
For managed EKS and GKE clusters: make sure there are no additional roles associated with system:anonymousor system:unauthenticated.
For unmanaged clusters: disable anonymous authentication mode if possible. If anonymous authentication is necessary, ensure that only minimal roles are associated with system:anonymous and system:unauthenticated.
How Wiz can help
Prevention
Wiz customers can use the following controls to detect instances in their environment of the toxic risk combinations exploited by the attackers as an initial access vector:
Both controls alert when an externally-accessibly Kubernetes cluster is found with anonymous authentication enabled (default on EKS and GKE) and a non-trivial role permission assigned to an anonymous user.
Customers also have an option to deploy the Wiz Admission Controller with the pre-defined policies of image signature verification and registry origin. These policies can prevent similar attacks by blocking untrusted container image execution.
Detection
Wiz customers can use the Wiz Sensor and Threat Detection Rules to be alerted of actions performed in their environment that could relate to the aforementioned attack. Wiz has multiple detection rules and single-event rules, as well as rules correlating between multiple sources. Streaming various sources (cloud logs, K8s audit logs, Wiz sensor events etc.) allows Wiz to deliver high fidelity detections and provide a full picture of an attack.
Kubernetes audit log–based rules detect initial actions by anonymous users.
The Wiz Runtime Sensor detects cryptojacking attacks by combining different event types, such as detecting sustained high CPU utilization by a suspicious process.
Summary
In this blog post, we detailed how a long-running cryptojacking campaign targeting misconfigured Kubernetes clusters has adapted over time to evade detection. We listed IoCs and provided recommendations for how to avoid these types of attacks.
This incident should encourage organizations to adopt a security-posture solution, enabling security teams to mitigate toxic risk combinations and reduce attack surfaces vulnerable to threat actors. Additionally, this should be paired with a runtime protection mechanism capable of swiftly identifying and addressing security breaches before they cause significant harm.
While there was no evidence that the threat actor moved laterally from the Kubernetes cluster to the larger cloud environment in this instance, attackers can certainly do so if strong security boundaries are not in place. To learn more about preventing lateral movement from cluster to cloud, check out our blog on the subject.
Feel free to reach out to threat.hunters@wiz.io if you’ve been impacted by this activity or wish to exchange further information and IoCs that might assist in ongoing analysis.
Learn how Wiz's latest feature identifies outdated EKS clusters, helping organizations save millions on cloud spend. Find out how to optimize costs and reinvest savings in strategic initiatives.