Skip Navigation
Get a Demo
 
 
 
 
 
 
 
 
 
Resources Blog Linux security

Frankenstein was a hack: the copy/paste cryptominer

It’s good to remember that adversaries aren’t always elite uber-hackers; sometimes they’re just criminals who understand enough to use the tools they attack us with.

Del Armstrong
Originally published . Last modified .

It’s a common refrain in information security that attacks don’t need to be sophisticated in order to be effective. Armed with a rudimentary understanding of computers and software development, inexperienced attackers can cobble together disparate strings of crude code to create “good enough” threats that get the job done.

This paradigm played out in the form of a cryptocurrency mining scheme that emerged on Pastebin a few weeks back. The threat was reminiscent of Dr. Frankenstein’s monster in that it appeared to be a patchwork of code and scripts that an adversary hastily copied and pasted from a variety of sources. Central to this analysis were two fundamentally important but starkly different shell scripts: one that worked despite itself and another that was relatively well-written.

Trawling Pastebin (again)

A recent review of some files on Pastebin turned up a line that immediately caught my attention:

The reason this line stood out is that my colleague Tony Lambert recently published a blog post on the Rocke cryptocurrency-miner, mentioning (among many other things) that the attack relied on fake instances of the Linux kworker kernel thread process to hide on the system.

After reviewing this code, I found that while it’s not identical to what Tony described in his post, the similarities outnumber the differences, and it’s likely that these two samples are related in some way.

Tony’s post does a great job of hitting the attack details and extracting actionable information. In this post, I thought it would be useful to focus on the development and maintenance of a pair of critical shell scripts from the perspective of a programmer. Spoiler alert: if I was a computer science professor, I would be handing out a “D” for the first script and a “B” for the second.

A tale of two scripts

This attack consists of two shell scripts—mr.sh and 2mr.sh—collectively amounting to 334 lines of code. Together they download and install a copy of the open-source XMRig cryptocurrency miner. They also install a run-time library (initially named 1.so) that is used to hide XMRig from standard process listing commands.

The mr.sh script is primarily focused on killing any competing cryptocurrency miners already on the machine and establishing persistence on the machine via cron. It also tries to spread laterally, and it invokes 2mr.sh, which installs the actual XMRig payload and the run-time library used to hide XMRig.

Examining mr.sh

Execution starts with mr.sh, so let’s look at a few pieces of that one first.

The second line of code here sets the tone for much of what follows, and befuddlement might be the most predictable reaction. Most versions of Linux (maybe all) already have a directory named /var/tmp, so I have to ask: why try to create another one? Perhaps there’s some obscure version of Linux that lacks this directory, but we’re certainly off to an odd start as we start to look through this file.

The next line is no better: why give the world full access to the file /var/tmp/kworkerds? Even after the analysis of this program is complete, and we understand how kworkerds is used, this command still makes no sense.

Moving on. Look at this chunk of code:

This is similar to activity Tony discussed in his blog post: the program is trying to find other, competing crypto-miners and kill them. But notice line 16. In the middle of a section with a clear focus, there’s this unrelated action to create a file, and it’s completely redundant with line four!

Here the program suddenly changes (note that I’ve artificially wrapped 2 very long lines, creating line 26 and 35 for readability–further analysis of this program will show the original line numbers). Now we’re seeing nicely indented code, grouped by functionality, and even using reasonable variables (e.g. $h is a host IP). There are no redundancies or useless commands here.

After an attempt to pivot laterally on the network in lines 24 through 36, we’re back to more deletions and clean-up (note that I’ve reverted back to using the actual line numbers found in the file). Line 37 will delete only the last line in the crontab file. This seems a bit specific, but it might make sense if these attackers are worried that a competitor who’s previously compromised this machine could have added a one-line entry to the end of the crontab file.

In the screen-shot above, lines 44 through 62 are mostly concerned with clearing out crontab in all its variations and flavors. That seems fine, but maybe you’re wondering the same thing I did regarding line 48: why delete the last entry in /etc/crontab in line 38 if you’re going to clear the whole thing out in line 48? Also, what’s with line 56, which inexplicably sets the permissions for /var/tmp/ to 777? Afterall, 777 is the normal permission level for that directory, although it’s possible that this explicit command is designed to nullify specific permission changes made by an admin.

I’m afraid the section of code above made me laugh. Lines 81 through 86 are completely redundant and lines 79 through 80 delete any files beginning with the letter “J”.

Lines 95 through 99 are all fairly straight-forward efforts to install a crontab entry that will download this script (mr.sh) and execute it. However, on lines 100 and 101, the attacker tries to download a file (named 11) from a machine on the Internet. Upon installation, that file runs a script that executes along with the hourly crontab schedule.

Let’s look at the file 11. It’s not very complicated and runs the same command that was being copied into the crontab files in the lines above. A cynic might say that the attacker found a more complicated, noisy, and inefficient way to accomplish what was being done in the lines above. And yes, there is a typo in line 101, which is missing the wget command, but the script continues to run nonetheless.

As we can see above, the attacker returns to a hodgepodge of deleting files and killing competing processes. There are a couple of things to note. First, at line 106, we find another gratuitous chmod command, although at least we’re dealing with a file that normally wouldn’t exist this time.

Lines 107 through 110 are interesting: although this section of code is structured, using a while loop across several lines and descriptive variable names, it’s not indented—which is different from most of the other structured code we’ve found in these files.

This next section of code (shown above) takes an interesting turn. If there doesn’t currently exist a connection to one of three network addresses, line 118 will download and execute a new script named ‘2mr.sh’. We’ll look at 2mr.sh in a bit, but let’s finish mr.sh first—we’re almost done with it.

This section of code essentially builds up a cron entry to achieve persistence, but look at how different it is from the rest of this script! It’s structured and properly indented. Instead of blindly using curl and wget and hoping one of them works, it devotes a lot of effort to detecting which of those two programs are available and only using one of them.

After that moment of coding beauty, mr.sh ends with more of the usual—but notice that on line 143 they also redid the same gratuitous chmod command previously seen on line 106. Then, the last line (144) comes out of the blue and deletes one more line from crontab.

Summarizing shell number one

Ultimately, mr.sh is a hodgepodge of code: some of it is clever, and some of it shows a very poor understanding of Linux. There is no organizational structure to the program, with code focused on the same task sprinkled throughout the file. Several lines of code are repeated, in different locations for no good reason. There’s at least one typo, which the script miraculously manages to execute in spite of. The quality, or style, of the code varies from brutish to well organized and structured.

It seems clear that mr.sh is a Frankenstein construct, having been created ad-hoc over time by folks simply using copy-and-paste to blindly add code from multiple sources. The folks maintaining this file seem to have a limited interest in, or understanding of, how this program runs. As long as it runs, and seems to accomplish its task, they’re good with it.

Examining 2mr.sh

Now let’s take a quick glance at the second file, 2mr.sh. As we’ll shortly see, even though the names are similar, this file is completely different from mr.sh.

The screenshot above nicely illustrates the difference. The entirety of 2mr.sh consists of clean, structured, documented, carefully written code. Notice the use of echo statements to document the program’s progress (e.g. on line 10). Although it’s not visible in this screenshot, the program consists of four subroutines, all structured and engineered in the same way.

Just as a further example of this coding style, the screenshot above shows the bottom of the program. There are no redundancies or useless commands here. The program downloads, installs, and starts the XMRig cryptominer. It also does the same thing with the 1.so run-time library that is used to hide XMRig from observation. And it does so in a structured, consistent, and organized manner.

Summarizing shell number two

2mr.sh is basically the exact opposite of mr.sh. It’s a well crafted piece of work that’s consistent and self contained. This is the code that installs and starts the XMRig cryptominer. It’s also the code that installs the run-time library, 1.so, which cleverly hides XMRig from observation. In other words, this code is at the heart of the entire operation.

The most likely explanation for this difference is that 2mr.sh is a product produced by a different group than those running and maintaining mr.sh. The folks running this attack probably purchased or otherwise obtained 2mr.sh to provide the core functionality for this attack. They now use 2mr.sh combined with mr.sh. They presumably don’t touch 2mr.sh, which they apparently didn’t write. However, they seem to maintain mr.sh in an event-driven, ad-hoc, copy-and-paste fashion, adding code to it as they become aware of competing crypto-miners that are threats to their operation.

Conclusion

It’s good to remember that adversaries aren’t always elite uber-hackers; sometimes they’re just criminals who understand enough to use the tools they attack us with.

It’s likely that there are additional groups running cryptominer attacks based on the code in 2mr.sh, probably all with different harnesses of varying quality and lineage, serving the function of mr.sh in this example.

IOCs

Once nice thing about mr.sh is that it’s an insider’s compendium of IOCs for other cryptominers. Also, 2mr.sh reveals several IOCs for the folks running this attack. In case it’s useful to anybody, here are some IOCs derived from these files.

Note: Please be careful with these IOCs, in some cases they will also correspond to legitimate activity.

IP Addresses

27.155.87.59
51.38.133.232
52.15.62.13
52.15.72.79
91.236.182.1
95.142.40.81
103.99.115.220
104.160.171.94
107.174.47.156
107.174.47.181
121.18.238.56
139.99.120.75
167.99.166.61
170.178.178.57
185.161.70.34
185.222.210.59
192.99.142.232
202.144.193.110
202.144.193.184
205.185.122.99

Ports

3013
3333
13531
56415

Process Names or arguments

sysxlj
jourxlv
sustes
I2NvZGluZzogdXRmLTg
netdns
/usr/bin/.sshd
kworkerds
wc.conf
wq.conf
wm.conf

Files

/bin/nfstruncate
/boot/grub/deamon
/boot/grub/disk_genius
/etc/cron.daily/oanacroner
/etc/cron.hourly/oanacroner
/etc/cron.monthly/oanacroner
/etc/init.d/netdns
/etc/init.d/nfstruncate
/etc/rc.d/rc*.d/S01nfstruncate
/etc/voidonce.sh
/lib64/library1.so
/tmp/2t3ik
/tmp/a7b104c270
/tmp/bashf
/tmp/bashg
/tmp/config.json
/tmp/ddgs.3012
/tmp/ddgs.3013
/tmp/*httpd.conf
/tmp/*httpd.conf*
/tmp/*index_bak*
/tmp/j*
/tmp/java
/tmp/java*
/tmp/java2
/tmp/jrm
/tmp/libapache
/tmp/.mas
/tmp/pools.txt
/tmp/.python*
/tmp/qW3xT.2
/tmp/root.sh
/tmp/.tables*
/tmp/.uninstall*
/tmp/wnTKYg
/usr/lib64/library1.so
/usr/lib/libiacpkmn.so.3
/usr/lib/void.so
/usr/local/bin/dns
/usr/local/lib/libjdk.so
/usr/local/lib/libkk.so
/usr/local/lib/libntpd.so
/usr/local/lib/libntp.so
/usr/sbin/netdns
/var/tmp/j*
/var/tmp/java
/var/tmp/java*
/var/tmp/java2
/var/tmp/jrm

Note: Please be aware that I appreciate the irony of including those last 5 file IOC’s, and the similar ones in /tmp.

Complete listings of the two files

In case it’s of interest, here are the listings of the complete contents of mr.sh and 2mr.sh.

Entire contents of mr.sh

Entire contents of 2mr.sh

 

The detection engineer’s guide to Linux

 

Look beyond processes with Linux EDR

 

Contain yourself: An intro to Linux EDR

 

eBPFmon: A new tool for exploring and interacting with eBPF applications

Subscribe to our blog

 
 
Back to Top