Sandstorm Security Review (English Version)
一次在 Sandstorm 跳脫沙箱的滲透經驗 (中文版本)
Introduction
In early 2017, we had a pentesting target protected with Sandstorm. Sandstorm is a web-based platform which allows users to install their web apps, such as WordPress, GitLab, etc. The main feature of Sandstorm is that it containerizes every app in its own sandbox. Therefore, even though we had found several vulnerabilities of the apps, we still could not put a threat to the server.
In order to leverage the vulnerabilities, we put part of efforts into review of Sandstorm’s source codes, and tried to escape the sandbox to impact the whole server. Finally, we found a number of uncommon and interesting vulnerabilities, and received CVE IDs as follows:
- CVE-2017-6198 (Denial of Service)
- CVE-2017-6199 (Bypassing Authorization Schema)
- CVE-2017-6200 (Insecure Direct Object References)
- CVE-2017-6201 (Server-Side Request Forgery)
Exploitation Details
CVE-2017-6198
This is a DoS created by system resource exhaustion. The root cause is that Sandstorm does not have a comprehensive policy to limit the amount of resource used by every apps run on it. In src/sandstorm/supervisor.c++
only the maximum number of files opened by each process was limited. See the codes below:
voidSupervisorMain::setResourceLimits(){structrlimitlimit;memset(&limit,0,sizeof(limit));limit.rlim_cur=1024;limit.rlim_max=4096;KJ_SYSCALL(setrlimit(RLIMIT_NOFILE,&limit));}
Ref: https://github.com/sandstorm-io/sandstorm/blob/v0.202/src/sandstorm/supervisor.c++#L824
Since supervisor does not restrict the amount of subprocesses and storage usage, attackers can raise a resource exhaustion attack to crash the server by simply uploading a malicious app which keeps calling fork() (aka the “fork bomb”) or consumes huge storage space.
CVE-2017-6199
Usually Sandstorm will designate unique permissions to the specific members of a certain organization, and the default membership validation method is to check user’s email address and see whether the string after @
exists in their white list. See the codes below:
if(identity.services.email.email.toLowerCase().split("@").pop()===emailDomain){returntrue;}
Ref: https://github.com/sandstorm-io/sandstorm/blob/v0.202/shell/packages/sandstorm-db/db.js#L1112
Therefore, when an attacker fills in an email like demo@devco.re,ccc@aaa.bbb
and the system will automatically consider the attacker a member of the aaa.bbb
organization.
Another key factor that contributes to the successful attack lies in one of the features when users log on Sandstorm. Users does not need to set up passwords for Sandstorm. Each time when the users need to log onto the service, they only need to fill in their email address, and they’ll receive a set of random unique password for login. The reason why the example above works is because the system treats demo@devco.re,ccc@aaa.bbb
as a user from aaa.bbb domain, and the random password will be sent to the two email addresses, demo@devco.re
and ccc@aaa.bbb
As long as one can receive the password, they can log in to use the service.
Below is a quick demonstration:
On Sandstorm, restrict access to users from domain
aaa.bbb
only.On login page, fill in
demo@devco.re,ccc@aaa.bbb
for the email field.
(Note: at the front end, the email field is checked with HTML5 validation, but it is not further checked for validity at the back end)Retrieve random password in demo@devco.re mailbox.
Login successful.
demo@devco.re,ccc@aaa.bbb
is considered as a user and member ofaaa.bbb
organization!
In our pentesting, the target website allowed users from validated domains to install their own apps. Therefore, through this bypass exploit, further attacks could be accomplished by combining other vulnerabilities described in this blog post (CVE-2017-6198, CVE-2017-6200, CVE-2017-6201).
CVE-2017-6200
This is an interesting vulnerability. Totally two little validation flaws were exploited to initiate this attack!
On Sandstorm, owners of each Grain (Sandstorm container, in short, an app sandbox) can download their backup data for the app. But because of the two vulnerabilities in the packing process, an attacker can pack the files under the /etc
and /run
directories located on the server outside the sandbox. The security issues were as follows:
The packing process has hid
/var
,/proc
,/etc
and other sensitive directories, but did not hide/etc.host
and/run.host
these two directories. These directories are the aliases for the directories/etc
and/run
on the server respectively, which are relatively newer features.The system will pack the legitimate files, have them sorted out, and create zip packages through the standard input interface. The separation between files are determined by line-breaks (
\n
). As a result, when a line-break string appears in the file name, illegal path file names can be injected and packed with zip. Although the app checks whether there is a line-break in the file name, but the directory name was not checked.
Ref: https://github.com/sandstorm-io/sandstorm/blob/v0.202/src/sandstorm/backup.c%2B%2B#L271
By using these two vulnerabilities together, the attacker simply has to create a directory in the sandbox /var/exp\n/etc.host/passwd\n
, then backup files containing /etc/passwd
on the server can be retrieved through backup downloading function.
Screenshot of a real-world scenario:
First, create a new directory in Grain
/var/exp\n/etc.host/passwd\n
, and use the Grain Backup function to download the backup file.After unzipping the backup file, from
etc.host
we’ll see/etc/passwd
of the server outside the sandbox.
CVE-2017-6201
This is a classic SSRF (Server-Side Request Forgery) issue. Sandstorm allow installation of apps from arbitrary sources, and an attacker can simply let the server access a certain location by providing an installation URL. The problem was identified on https://[target]/install/xxxChangeItEveryTimexxx?url=http://127.0.0.1:22/
This sample link confirms whether the server’s port 22 is open.
Follow-up Updates
After we reported the vulnerabilities, Sandstorm fixed it immediately and then published an article:
https://sandstorm.io/news/2017-03-02-security-review
Through this pentesting experience, we consider Sandstorm a safe platform with outstanding security mechanisms. This is mainly attributed to its fundamental design rationale: to assume that every app installed is malicious. With this vigilant assumption, Sandstorm’s defence mechanisms for the core system become comprehensive and watertight. Apart from the server-side protection, some common client-side attacks (such as XSS, CSRF) are handled properly by Sandstorm’s unique countermeasures, such as host name randomization. That is, it is very difficult for attackers to sabotage the server by simply manipulating the apps, and so does privilege escalation through attacking at the client-side.
Nevertheless, such an impressive platform still had some minor mistakes which led to security issues. Most of the vulnerabilities found this time are improper usages of libraries or negligence of existing defence architecture while introducing new features. These types of vulnerability are also common in our other projects. We would like to take the opportunity to remind developers, always present a comprehensive security review especially when developing new features to avoid vulnerabilities caused by the gaps between defence mechanisms.