While doing recon on Algolia, I found that the session secret for facebooksearch.algolia.com has been committed to a public GitHub repository. Since the Rails app running at
facebooksearch.algolia.com 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: https://charlie.bz/blog/rails-3.2.10-remote-code-execution.
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: https://github.com/algolia/facebook-search/commit/f3adccb5532898f8088f90eb57cf991e2d499b49#diff-afe98573d9aad940bb0f531ea55734f8R12
@joernchen developed a ready to go proof of concept for this vulnerability and submitted it to the Metasploit Framework: https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/http/rails_secret_deserialization.rb
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:
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]+);/)
With that patch applied, you can run the PoC from
msfconsole by following these commands:
use exploit/multi/http/rails_secret_deserialization set secret "<grab-from-github-url>" set rhost facebooksearch.algolia.com set railsversion 4 set targeturi /auth/facebook
As a proof of concept, I ran
uid=1000(prod) gid=1000(prod) groups=1000(prod)
But since that is very generic, I also created http://facebooksearch.algolia.com/hackerone.txt with the text "PoC by michiel" to proof regular write access is possible as well.
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.