SOC, TI and IR posts

Dero miner zombies biting through Docker APIs to build a cryptojacking horde

Introduction

Imagine a container zombie outbreak where a single infected container scans the internet for an exposed Docker API, and bites exploits it by creating new malicious containers and compromising the running ones, thus transforming them into new “zombies” that will mine for Dero currency and continue “biting” new victims. No command-and-control server is required for the delivery, just an exponentially growing number of victims that are automatically infecting new ones. That’s exactly what the new Dero mining campaign does.

During a recent compromise assessment project, we detected a number of running containers with malicious activities. Some of the containers were previously recognized, while others were not. After forensically analyzing the containers, we confirmed that a threat actor was able to gain initial access to a running containerized infrastructure by exploiting an insecurely published Docker API. This led to the running containers being compromised and new ones being created not only to hijack the victim’s resources for cryptocurrency mining but also to launch external attacks to propagate to other networks. The diagram below describes the attack vector:

Infection chain

Infection chain

The entire attack vector is automated via two malware implants: the previously unknown propagation malware nginx and the Dero crypto miner. Both samples are written in Golang and packed with UPX. Kaspersky products detect these malicious implants with the following verdicts:

  • nginx: Trojan.Linux.Agent.gen;
  • Dero crypto miner: RiskTool.Linux.Miner.gen.

nginx: the propagation malware

This malware is responsible for maintaining the persistence of the crypto miner and its further propagation to external systems. This implant is designed to minimize interaction with the operator and does not require a delivery C2 server. nginx ensures that the malware spreads as long as there are users insecurely publishing their Docker APIs on the internet.

The malware is named “nginx” to masquerade as the well-known legitimate nginx web server software in an attempt to evade detection by users and security tools. In this post, we’ll refer to this malware as “nginx”.

After unpacking the nginx malware, we parsed the metadata of the Go binary and were able to determine the location of the Go source code file at compilation time: “/root/shuju/docker2375/nginx.go”.

Nginx source code file

Nginx source code file

Infecting the container

The malware starts by creating a log file at “/var/log/nginx.log”.

Log file creation

Log file creation

This log file will be used later to log the running activities of the malware, including data like the list of infected machines, the names of created malicious containers on those machines, and the exit status code if there were any errors.

Malware operations log

Malware operations log

After that, in a new process, a function called main.checkVersion loops infinitely to make sure that the content of a file located at “/usr/bin/version.dat” inside the compromised container always equals 1.4. If the file contents were changed, this function overwrites them.

Ensuring that version.dat exists and contains 1.4

Ensuring that version.dat exists and contains 1.4

If version.dat doesn’t exist, the malicious function creates this file with the content 1.4, then sleeps for 24 hours before the next iteration.

Creating version.dat if it doesn't exist

Creating version.dat if it doesn’t exist

The malware uses the version.dat file to identify the already infected containers, which we’ll describe later.
The nginx sample then executes the main.monitorCloudProcess function that loops infinitely in a new process making sure that a process named cloud, which is a Dero miner, is running. First, the malware checks whether or not the cloud process is running. If it’s not, nginx executes the main.startCloudProcess function to launch the miner.

Monitoring and executing the cloud process

Monitoring and executing the cloud process

In order to execute the miner, the main.startCloudProcess function attempts to locate it at “/usr/bin/cloud”.

Executing the miner

Executing the miner

Spreading the infection

Next, the nginx malware will go into an infinite loop of generating random IPv4 /16 network subnets to scan them and compromise more networks with the main.generateRandomSubnet function.

Infinite loop of network subnets generation and scanning

Infinite loop of network subnets generation and scanning

The subnets with the respective IP ranges will be passed to the main.scanSubnet function to be scanned via masscan, a port scanning tool installed in the container by the malware, which we will describe in more detail later. The scanner is looking for an insecure Docker API published on the internet to exploit by scanning the generated subnet via the following command: masscan -p 2375 -oL – –max-rate 360.

Scanning the generated subnet via masscan

Scanning the generated subnet via masscan

The output of masscan is parsed via regex to extract the IPv4s that have the default Docker API port 2375 open. Then the extracted IPv4s are passed to the main.checkDockerDaemon function. It checks if the remote dockerd daemon on the host with a matching IPv4 is running and responsive. To do this, the malware attempts to list all running containers on the remote host by executing a docker -H PS command. If it fails, nginx proceeds to check the next IPv4.

Remotely listing running containers

Remotely listing running containers

Container creation

After confirming that the remote dockerd daemon is running and responsive, nginx generates a container name with 12 random characters and uses it to create a malicious container on the remote target.

Container name generation

Container name generation

The malicious container is created with docker -H run -dt –name –restart always ubuntu:18.04 /bin/bash. The malware uses a –restart always flag to start the newly created containers automatically when they exit.

Malicious container created on a new host

Malicious container created on a new host

Then nginx prepares the new container to install dependencies later by updating the packages via docker -H exec apt-get -yq update.

Updating container packages

Updating container packages

Next, the malicious sample uses a docker -H exec apt-get install -yq masscan docker.io command to install masscan and docker.io in the container, which are dependencies for the malware to interact with the Docker daemon and to perform the external scan to infect other networks.

Remotely installing the malware dependencies inside the newly created container

Remotely installing the malware dependencies inside the newly created container

Then it transfers the two malicious implants, nginx and cloud, to the container by executing docker -H cp -L /usr/bin/ :/usr/bin.

Transferring nginx and cloud to the newly created container

Transferring nginx and cloud to the newly created container

The malware maintains persistence by adding the transferred nginx binary to /root/.bash_aliases to make sure that it will automatically execute upon shell login. This is done via a docker -H exec bash –norc -c \'echo \"/usr/bin/nginx &\" > /root/.bash_aliases\' command.

Adding the nginx malware to .bash_aliases for persistence

Adding the nginx malware to .bash_aliases for persistence

Compromising running containers

Up until this point, the malware has only created new malicious containers. Now, it will try to compromise the ubuntu:18.04-based running containers. The sample first executes the main.checkAndOperateContainers function to check all the running containers on the remote vulnerable host for two conditions: the container has an ubuntu:18.04-base and it doesn’t contain a version.dat file, which is an indicator that the container had been previously infected.

Listing and compromising existing containers on the remote target

Listing and compromising existing containers on the remote target

If these conditions are satisfied, the malware executes the main.operateOnContainer function to proceed with the same attack vector described earlier to infect the running container. The infection chain is repeated, hijacking the container resources to scan and compromise more containers and mining for the Dero cryptocurrency.

That way, the malware does not require a C2 connection and also maintains its activity as long as there is an insecurely published Docker API that can be exploited to compromise running containers and create new ones.

cloud – the Dero miner

Executing and maintaining cloud, the crypto miner, is the primary goal of the nginx sample. The miner is also written in Golang and packed with UPX. After unpacking the binary, we were able to attribute it to the open-source DeroHE CLI miner project found on GitHub. The threat actor wrapped the DeroHE CLI miner into the cloud malware, with a hardcoded mining configuration: a wallet address and a DeroHE node (derod) address.

If no addresses were passed as arguments, which is the case in this campaign, the cloud malware uses the hardcoded encrypted configuration as the default configuration. It is stored as a Base64-encoded string that, after decoding, results in an AES-CTR encrypted blob of a Base64-encoded wallet address, which is decrypted with the main.decrypt function. The configuration encryption indicates that the threat actors attempt to sophisticate the malware, as we haven’t seen this in previous campaigns.

Decrypting the crypto wallet address

Decrypting the crypto wallet address

Upon decoding this string, we uncovered the wallet address in clear text: dero1qyy8xjrdjcn2dvr6pwe40jrl3evv9vam6tpx537vux60xxkx6hs7zqgde993y.

Behavioral analysis of the decryption function

Behavioral analysis of the decryption function

Then the malware decrypts another two hardcoded AES-CTR encrypted strings to get the dero node addresses via a function named main.sockz.

Function calls to decrypt the addresses

Function calls to decrypt the addresses

The node addresses are encrypted the same way the wallet address is, but with other keys. After decryption, we were able to obtain the following addresses: d.windowsupdatesupport[.]link and h.wiNdowsupdatesupport[.]link.

Decoded addresses in memory

Decoded addresses in memory

The same wallet address and the derod node addresses had been observed before in a campaign that targeted Kubernetes clusters with Kubernetes API anonymous authentication enabled. Instead of transferring the malware to a compromised container, the threat actor pulls a malicious image named pauseyyf/pause:latest, which is published on Docker Hub and contains the miner. This image was used to create the malicious container. Unlike the current campaign, the attack vector was meant to be stealthy as threat actors didn’t attempt to move laterally or scan the internet to compromise more networks. These attacks were seen throughout 2023 and 2024 with minor changes in techniques.

Takeaways

Although attacks on containers are less frequent than on other systems, they are not less dangerous. In the case we analyzed, containerized environments were compromised through a combination of a previously known miner and a new sample that created malicious containers and infected existing ones. The two malicious implants spread without a C2 server, making any network that has a containerized infrastructure and insecurely published Docker API to the internet a potential target.

Analysis of Shodan shows that in April 2025, there were 520 published Docker APIs over port 2375 worldwide. It highlights the potential destructive consequences of the described threat and emphasizes the need for thorough monitoring and container protection.

Docker APIs published over port 2375 ports worldwide, January–April 2025 (download)

Building your containerized infrastructure from known legitimate images alone doesn’t guarantee security. Just like any other system, containerized applications can be compromised at runtime, so it’s crucial to monitor your containerized infrastructure with efficient monitoring tools like Kaspersky Container Security. It detects misconfigurations and monitors registry images, ensuring the safety of container environments. We also recommend proactively hunting for threats to detect stealthy malicious activities and incidents that might have slipped unnoticed on your network. The Kaspersky Compromise Assessment service can help you not only detect such incidents, but also remediate them and provide immediate and effective incident response activities.

Indicators of compromise

File hashes
094085675570A18A9225399438471CC9  nginx
14E7FB298049A57222254EF0F47464A7   cloud

File paths
NOTE: Certain file path IoCs may lead to false positives due to the masquerading technique used.
/usr/bin/nginx
/usr/bin/cloud
/var/log/nginx.log
/usr/bin/version.dat

Derod nodes addresses
d.windowsupdatesupport[.]link
h.wiNdowsupdatesupport[.]link

Dero wallet address
dero1qyy8xjrdjcn2dvr6pwe40jrl3evv9vam6tpx537vux60xxkx6hs7zqgde993y

Dero miner zombies biting through Docker APIs to build a cryptojacking horde

Your email address will not be published. Required fields are marked *

 

Reports
Subscribe to our weekly e-mails

The hottest research right in your inbox