Shadow on the Wall

What is one of the cornerstones of the Internet? Right! Being able to access all kinds of information, without censorship. In some countries this is no longer possible, and this is why technologies such as tor and Shadowsocks are needed.

While the main
feature of tor is the onion routing and the aim of being cryptographically secure, it can easily be blocked by a firewall.

Shadowsocks

Shadowsocks simply tries to provide an undetectable tunnel to an a non-censored part of the Internet.

Shadowsocks provides a Socks5proxy locally, into which all traffic is routed. It encrypts traffic with a configurable symmetric algorithm and the messages have (pseudo) random lengths. The absence of any visible protocol information makes them appear totally random. The goal is stealth through restricted infrastructures.

Naturally, users of such tools may be exposed to increased risks. Therefore the tools aim to be undetectable by deep packet inspection firewalls. For security and privacy they have to encrypt the traffic, use random padding, ensure integrity, and should imitate other protocols so as to look like normal encrypted traffic, e.g. such as that from an encrypted website. The server should be authenticated to ensure that the user does not communicate with a malicious endpoint.

Our team member Niklas decided to have a look at Shadowsocks to see how it handles this task, and noticed some interesting things.

Detect

Shadowsocks tries to make traffic undetectable. But there are tools like ssSniff that are designed to detect Shadowsocks traffic. They were quite successful in our tests. ssSniff was able to identify the traffic of Shadowsocks as well as that of ShadowsocksR, even though ShadowsocksR implements more obfuscation techniques.

One example is the “http_simple” feature, which adds an HTTP header to encrypted messages. ssSniff measures the entropy of the first 32 data packets and the entropy of their length. Shadowsocks traffic has too much entropy as there is no unencrypted handshake. We had no false positives in our short tests but we are sure that there can be some in larger amounts of traffic.

Decrypt

Another goal was to decrypt captured Shadowsocks traffic. The protocol of Shadowsocks has multiple design issues as it uses a hash function (MD5) for key derivation instead of a cost-intensive key derivation algorithm such as bcrypt for the symmetric encryption key. In addition, it uses the calculated hash as a static key. Niklas was able to brute force traffic with an unoptimised python script. An Intel Core i5-7200U CPU @ 2.50 GHz bruteforced 197.2 thousand passwords per second in our tests.

It is unlikely that the key derivation function will be changed in the future, as all protocol implementations would have to be fixed.

A look at the python implementation of Shadowsocks showed a problem with its log file handling. The log files can be manipulated by requesting a connection to a host with a maliciously formatted name as an authenticated user. This apparently minor bug was important for the next finding.

Exploit

The autoban implementation is similar to fail2ban. Autoban.py creates iptable rules to block the connection attempts, based on errors in the Shadowsocks log file. This happens as root user, since it requires access to iptables.

If the host name

"can not parse header when ||ls&:\ntouch /etc/evil.txt\nexit\ncan not parse header when ||/bin/bash</var/log/Shadowsocks.log&:\n"

is sent to a Shadowsocks server, the autoban.py would write the command
touch /etc/evil.txt into the log file and execute it with /bin/bash</var/log/Shadowsocks.log as root.

The script autoban.py contained an additional bug. The Wiki advises to pipe the log file into autoban.py using tail. The autoban.py waits for an end of file, which tail will never send. So the autoban.py does not block any IPs but also will not execute the log file contents as root, except if it is used without tail, e.g. as a cron job with the first example of the Wiki. A fix for the command execution bug has been written but not merged to the mainline code, yet.

The issues have been submitted at GitHub.

We also had a look at the C implementation, Shadowsocks-libev. It contained a command execution vulnerability as well. This issue was fixed within one day by the developers after we reported it.

The issue lingered in the manager.c file. A command injection vulnerability could be triggered via a configuration file or UDP configuration packets sent from localhost. For example:

nc -u 127.0.0.1 8839
add: {"server_port":8003, "password":"test", "method":"||touch /tmp/evil||"}

created the file “/tmp/evil”. This vulnerability could be used for a local privilege escalation.

Shadowsocks configuration distribution

A look at the tools with which to distribute configuration settings for Shadowsocks showed further command execution vulnerabilities; they do not directly belong to the Shadowsocks implementations.

auto-ss

There is auto-ss, which logs into the website “https://www.ss-link.com/login” and parses a table containing Shadowsocks login credentials and information. It starts Shadowsocks to create a connection with the server and credentials from the parsed website.

When spawning a Shadowsocks connection, the lines 106-109 in auto_ss.py execute:

p = subprocess.Popen(
    "exec " + ss_local_cmd, shell=True, stdout=subprocess.PIPE,
    stderr=subprocess.STDOUT
)

If an attacker is able to modify the content of “https://www.ss-link.com” due to a man-in-the-middle attack or a vulnerability on the web page, the parameters could be modified to execute a command on the machine running Shadowsocks auto-ss. For example, ";<evil command>#" could be attached to, or used as a parameter to execute code on, target machines. The issue has been reported at GitHub.

Shadowsocks ConnecTion

Another tool is the Shadowsocks wrapper “Shadowsocks ConnecTion”. It crawls a web page for Shadowsocks server credentials. This page is retrieved via an unencrypted HTTP from URI “http://ss.ishadowx.com” as default. It starts Shadowsocks with the parsed credentials at line 98-101 in version 0.4, line 82-85 in version 0.5 using check_call(sss, shell=True).

If an attacker is able to modify the parsed web page due to a man-in-the-middle attack, the parameters could be modified to execute a command on the machine running Shadowsocks ConnecTion. For example, ";<evil command>#" could be attached to, or used as a parameter to execute code on, target machines. The issue has been submitted at GitHub.

Please be aware that most of the issues are still not fixed upstream.

At X41 we try to help improve the technology which keeps the Internet free for everyone. We contacted the vendors and all of them were given 30 days to fix the issues before our release. Since not all of them responded within this reasonable period of time, we publish this information now, so all users can take steps to protect themselves.

About X41 D-Sec GmbH

X41 D-Sec GmbH is an expert provider for application security services. Having extensive industry experience and expertise in the area of information security, a strong core security team of world class security experts enables X41 to perform premium security services.

Fields of expertise in the area of application security are security centric code reviews, binary reverse engineering and vulnerability discovery. Custom research and a IT security consulting and support services are core competencies of X41.