Unpacking Cloud-Based Cryptocurrency Miners That Abuse GitHub Actions and Azure Virtual Machines
We investigate cloud-based cryptocurrency miners that leverage GitHub Actions and Azure virtual machines, including the cloud infrastructure and vulnerabilities that malicious actors exploit for easy monetary gain.
As more organizations implement a DevOps thought process and methodology to boost their software development capabilities and hasten the deployment of applications to production, it also becomes more urgent to bring the need to protect and secure their cloud environments to the fore. In a previous report, we analyzed the cloud environment and focused on GitHub Actions (GHA), a widely used continuous integration (CI) tool. In that report, we examined not only GHA’s infrastructure and security posture but also the vulnerabilities and risks that cybercriminals can exploit inside the tool.
This article details how malicious actors are leveraging GitHub Actions and Azure virtual machines (VMs) for cloud-based cryptocurrency mining. We discuss how attackers can abuse the runners or servers provided by GitHub to run an organization’s pipelines and automation by maliciously downloading and installing their own cryptocurrency miners to gain profit easily. We also analyze different GHA YAML scripts found on GitHub that tried to mine all kinds of cryptocurrency by using the GHA runners. This article also takes an in-depth look at cryptocurrency miners that abuse Windows and Linux runners and GHA, the free continuous integration and continuous deployment (CI/CD) service provided by GitHub since 2019.
Cloud-based cryptocurrency mining and GitHub Actions
In a recently published research paper titled “A Floating Battleground: Navigating the Landscape of Cloud-Based Cryptocurrency Mining,” we thoroughly discussed how malicious actors have been targeting the cloud environment for cryptocurrency-mining activities and detailed how cybercriminals compromise cloud infrastructure for less lucrative CPU-based cryptocurrency-mining operations. While this malicious activity is not new, the frequency of these attacks has been increasing in parallel with the rate that new cloud services are created and offered for free. The increase of cryptocurrency mining holds especially true in situations that allow malicious actors to scale their attacks, so much so that even a few minutes or hours of compromise can generate significant profits for them. Cloud service providers (CSPs) and customers alike should therefore be aware of these attacks and learn how to identify and prevent them in their environments.
Cryptocurrency miners that abuse Windows runners
We have identified over a thousand repositories and more than 550 code samples that are abusing GitHub Actions to mine cryptocurrency using the runners provided by GitHub. We have notified and reported all these findings to the GitHub security team. We have analyzed dozens of the YAML scripts and provide our results in this article. Figure 1 shows GitHub search results from cryptocurrency miners using GHA (retrieved here).
In this section, we cover how malicious actors are leveraging Windows runners in their attempts to mine cryptocurrency, as well as the persistence techniques they use to dodge detection by GitHub to prevent their Actions from being disabled. GitHub provides the runner, a server designed to run workflows (aka Actions). Workflows are deployed on Azure and terminated after an enterprise’s automation is completed. While this service has its limits, users do not pay anything to use it, even with a free GitHub account.
Figure 2 (retrieved here) shows one of the many YAML scripts we found while analyzing hundreds of repositories on GitHub:
We unpack this workflow YAML to better understand the process involved here:
- Lines 1 and 2. The malicious actors set a trigger for GitHub Actions workflow called “CI/CD” to commence upon any push or pull request events. This means the workflow begins when you push a commit or tag, or when changes are made to a pull request in a repository.
- Lines 3 to 6. The workflow is running only one job called “CI” and named “Run Tests” using the latest version of the Windows runner provided by GitHub inside Azure. More details on the technical specifications of this GitHub-hosted runner can be found here.
- Lines 7 to 12. This part uses a multidimensional matrix strategy to create multiple job runs at the same time. The GitHub official documentation provides more details on how to use a matrix for your jobs. The maximum number of concurrent jobs is set to 50 with the max parallel directive on line 8. This allows the malicious actors to make the most out of the servers so that they can mine cryptocurrency before their incursions are discovered and shut down. Malicious actors define how the Action will handle job failures on line 9. By default, fail-fast is set to true, which means that it will cancel any other jobs, whether in progress or queued, should any of the other jobs in the matrix fail. On the other hand, attackers will set the fail-fast to false since they do not want any of the jobs to fail, and so that other jobs continue running despite failures occurring in others that are running in parallel. The next step is defining the matrix itself, used only to set the number of concurrent jobs. This is set to 60 in this case. Based on the number of entries on each directive, the total number of jobs in this two-dimensional matrix is 60 (from 6 x 10 = 60). This, however, doesn’t make sense since we saw earlier that the attackers set the max parallel to 50 jobs, implying a possible mistake in their calculation.
- Lines 13 to 23. The steps being executed by the job are stated during each run. The first one, named “Checkout,” uses a third-party action provided by GitHub to check out the current repository inside the runner before doing anything. The code for this action can be found here. The second step, starting on line 16, is called sad-path (retry_wait_seconds). This also runs another third-party GHA that now belongs to a regular GitHub user. It retries a GHA step on failure or timeout. The code for this action can be found here. Lines 19 to 23 set the details to retry the step to run the cryptocurrency miner binary by waiting for 15 seconds before the retry and only attempting to retry it twice before failing the step or after a timeout of 10 minutes. The retry GHA description can be found here. The continue-on-error command guarantees that the job exits successfully even if an error occurs.
- Line 24. This is the only command set during the entire process. This configures the cryptocurrency miner to run by setting the mining pool, the user, and TLS fingerprint, among others. One interesting aspect of this command is the parameter, max-cpu-usage 70, which limits the CPU usage to 70% to avoid detection of suspicious activity or cause any potential denial of service (DoS) on the server. After analyzing the node.exe binary and checking it with VirusTotal (VT), we found that this is flagged as a cryptocurrency miner by 51 out of 68 detections and detected by Trend Micro as Coinminer.Win64.MALXMR.SMA, a common cryptocurrency miner family.
There was another Portable Executable (PE) binary inside the repository named lang.exe, but it wasn’t being used by GitHub Actions. Nonetheless, we analyzed it and found that it was another cryptocurrency miner, only with fewer detections according to VT.
This next repository we analyzed was published on GitHub in April 2022. Similar variations of the same GHA script can be found from different users. Figure 6 shows the GHA workflow script labeled as kapten_crypto, (retrieved here). This is set to be manually triggered with the workflow dispatch directive.
Looking at the repository structure, we can clearly see how it shows that the user does not understand GitHub Actions very well, having created the GHA YAML in different locations with different names and extensions. We saw that the worflows file on the repository root as well as the one found on .GitHub/workflows and .github/Workflows were all the same. Someone familiar with GHA would know that the workflow scripts should be placed under .github/workflows inside the root directory and with their YAML/YML extension for the scripts to work. Workflows with “W” in uppercase are also accepted, but it is important to remember adding “S” at the end.
Going back to the GHA script on Figure 6, we can see a few similarities with the previous one we just analyzed. It uses the multidimensional matrix strategy that sets the max parallel jobs to 5 and disables the fail-fast approach by setting it to false on lines 7 to 12. It creates an environment variable, NUM_JOBS, and sets it to 20. Then it creates each job by labeling them using the matrix parameters on lines 13 to 15. After that, it has three main steps: download, extract, and run.
- Download (lines 17 and 18). This uses the Invoke-WebRequest PowerShell command to download the XMRig Windows binary from its GitHub repository.
- Extract (lines 19 and 20). The next step also uses a PowerShell command called Expand-Archive to extract the files from the zip.
- Run (lines 21 and 22). The last step is to run the xmrig.exe binary with a few parameters such as the URL of the mining server (-o), the mining algorithm (-a), and the user (-u), among others. A more detailed reference of the command-line options can be found here.
The following list of repositories shows similar versions of this same script. After cross-referencing the usernames or wallet addresses, we were able to identify that different GitHub users were using the same wallet, suggesting that they are either the same person or a group working together as a pool.
- https://github[.]com/janjan1999/shiba/blob/main/.github/Workflows/KaptenCrypto[.]yml
- https://github[.]com/wizman008/shiba/blob/main/.github/workflows/coins[.]yml
- https://github[.]com/gesbul1989/VERUS/blob/main/.github/workflows/baru[.]yml
- https://github[.]com/FixKRI1/miner/blob/main/.github/workflows/main[.]yml
- https://github[.]com/aldilariskhameilenia2018/mininggg/blob/main/.github/workflows/blank[.]yml
- https://github[.]com/aldilariskhameilenia2018/mining22/blob/main/.github/workflows/blank[.]yml
- https://github[.]com/Olish420/tron/blob/main/.github/workflows/tron[.]yml
- https://github[.]com/Olish420/nubatur/blob/main/.github/workflows/nubatur[.]yml
- https://github[.]com/dsdnklasmals/aaaaaaaaaaaaa/blob/main/.github/Workflows/KaptenCrypto[.]yml
- https://github[.]com/wa2nderma1/StartNew/blob/main/.github/workflows/mulai1[.]yml
- https://github[.]com/000h0/1hars/blob/circleci-project-setup/.github/workflows/main[.]yml
Cryptocurrency miners that abuse Linux runners
Linux and Windows runners are hosted on Standard_DS2_v2 virtual machines on Azure. Both have two vCPUs and 7 GB of memory, according to the GitHub documentation. Upon discussion with some fellow professionals and legitimate cryptocurrency miners, and considering that these runners are not GPU-based, we can assume that it is more profitable for the cybercriminals to leverage the Linux runners instead of the Windows ones. But without any direct comparison, one cannot say for certain why some choose the Windows runners if that were the case.
Cryptocurrency miners that abuse the Linux runners follow an approach that resembles the one that cybercriminals use to exploit Windows runners to start and run their mining scripts as shown in the following image (retrieved here).
For our purpose, we focus only on the code that is relevant to performing the mining steps:
- Lines 32-33. The script does exactly what the step describes — it downloads the XMRig binary inside the runner from the GitHub repository.
- Lines 35-36. The script extracts all *.gz files in the current folder. It will only extract the XMRig files present in that folder.
- Lines 38-41. This step runs two basic Linux commands (pwd and ls) to show the current directory and list the files. However, we think this is a needless step at this stage.
- Lines 43-50. This command starts the mining process by running the XMRig binary with the proper parameters such as the mining pool, the user, setting keepalive, and enabling TLS.
- Lines 53-54. This is essentially the same command from line 50, which doesn’t make much sense unless you know that the previous command failed, and you are running it again. But since there are no checks, we think that this command is redundant.
Fortunately, this GitHub Action, along with many others analyzed and reported in this article, has already been flagged and disabled by GitHub. We can see this by going to the Actions tab inside the repository and noting the alert in Figure 9 (retrieved here):
As we saw in the mining scripts on Figure 9 and in several attacks reported in the past, malicious actors prefer to leverage Monero as their cryptocurrency of choice since Monero CPU-based mining done at scale provides a decent ROI. They therefore deem it a worthwhile endeavor to compromise a significant number of systems and subsequently integrate them into the mining pools
Red flag: Is this something to be concerned about?
For as long as the malicious actors only use their own accounts and repositories, end users should have no cause for worry. This is a problem GitHub is cognizant of and is trying to address and mitigate as much as possible. However, it is hard to eliminate the problem entirely.
Problems arise when these GHAs are shared on GitHub Marketplace or used as a dependency for other Actions. As discussed in a prior report, anyone can create and share GHA on GitHub Marketplace. This is why it is recommended to exercise caution and discernment when choosing a shared GHA from Marketplace. We advise looking for the “uses” directive on your GHA YAML files, and for each , you can go to github.com/username/action to see its source code. For example, in Figure 2, on line 18, there is the nick-invision/retry@v2, which as we previously showed, can be found at https://github.com/nick-fields/retry.
Users can also enhance the security of their Actions by going to Settings à Actions inside each repository they own to apply proper settings such as Actions and workflow permissions, forked pull requests, and log retention expiration.
How to detect cryptocurrency miners
The first indicator of a possible cryptocurrency mining exploit is an increased resource consumption. As resource consumption can spike CPU utilization to 100%, the presence of miners slows down workloads or applications that are running; these workloads or applications might even stop working altogether because of high CPU usage. Customers and CSPs should inspect such instances to determine any evidence of cryptocurrency mining.
It is also advisable to keep an eye on your organization’s cloud expenses. Since there is a notable increase in CPU usage, the cost resulting from workloads running at 100% CPU can increase by up to 600% with on-demand pricing, as we discuss in one of our research papers. It’s important to note that this can scale very quickly depending on the number of compromised workloads for the purpose of mining cryptocurrency. This is why any abrupt increase in your cloud monthly expenses should be investigated and treated with urgency and care. Keep in mind that threat actors are also putting thresholds on their miners to stay under the radar, as we’ve demonstrated on Figure 3.
Ultimately, we recommend that organizations regularly check and monitor their GitHub Actions for any signs of abuse, as early detection of possible exploits in your cloud environment is key. It is also important to ensure that none of the following known cryptocurrency-mining pools and servers and cryptocurrency wallets are present in your GHA:
Mining pools/servers
- rx.unmineable.com
- pool.hashvault.pro
- xmrpool.eu
- sg.minexmr.com
- pool.supportxmr.com
Wallets
- TRX:TD5jXT9qUPXZM9Ameqt15ttFD45PLhrCFn.TRUST
- TRX:TM19JB5YG7KhqJ7L1rUASb1PqMDPNfkDF1.TRUS
- TRX:TT97kccRg4C74kj9ugc4zP2e8t6GSCcTWH.worker2
- TRX:TK6zMrH4pST5FbTen4XGBBa2rJckMojEnx.TRUST
- SHIB:0x94c35A97aa678e41700804FB0F409b3D66A075Dc.RIG1
- SHIB:0x5aB7E2FDE0625d93842c0675BaEdcf9AA7a08c85.TRUST
- LTC:MMtfXpcRZHAP9VpbjcGNhTUFW4rExdAVFv.RIZKI
- BNB:0xa300949238f80ac9a6fa627eade4e81e4c73bea1.TOBY
- SOL:uoXJ2QnaxJkVwNJrGGyyCiyGEhK27JyWHHMURUsfxWR.yu
- 44xyiky4qfr4X937HgbRv8A4QH2R7ynQSca4PWmBMqjffUbDv19F9DWgde51c6N6UZYi8rJP2AZNE95Jzo3eUWrnLnhFkba
- Hvs1ZQN67XB2NqwT6Dd9qbR2S1cqrACvoPGEDJvAd1o83JEpEcVKWA17ScUWTnEqVYYad8zJurahHMF7E2ecpV7c1tQwRcfG4B
- 48waHbFYRVED3gLpqEwXvS4v4ppwLas1UHAwVD8n9mxvFegC39KTGQUTXMyimssFHiGqw491FFBYMdvbmBW9m4KXG5HitDV
- 43aw7X7kKLfb54rvM8nc3MU9ndKoZMnqXMfWaoYvPrJPfauj2uUQAb1hHRtVzvuPCJT9XMWhacQSV94ADZMxLjUDAinsVVY
Trend Micro Solutions
An ounce of prevention is always better than a pound of cure, which is why it is recommended to opt for security solutions that provide comprehensive protection for your system to keep this and other threats at bay.
Trend Micro Vision One™ helps security teams gain an overall view of attempts in ongoing campaigns by providing them with a correlated view of multiple layers such as email, endpoints, servers, and cloud workloads. Security teams can gain a broader perspective and a better understanding of attack attempts and detect suspicious behavior that would otherwise seem benign when viewed from a single layer alone.
Trend Micro Cloud One™ – Workload Security helps defend systems against vulnerability exploits, malware, and unauthorized change. It can protect a variety of environments such as virtual, physical, cloud, and containers. Using advanced techniques like machine learning (ML) and virtual patching, thise solution can automatically secure new and existing workloads both against known and new threats.
Indicators of Compromise (IOCs)
File Name | SHA256 | Trend Micro Detection |
lang.exe | 297a450166fef7fbbfe17b09884ef684eba83e658ef9eb8a1ef046a993ff1d65 | Coinminer.Win64.SRBMINER.A |
node..exe | 495de38df3f28120934380d269d9c78cce52a98e8051a5dd671d3208a507f609 | Coinminer.Win64.MALXMR.SMA |