every *2shell, one place
← all bugs

Rails Development-Mode secret_key_base RCE

aka Rails doubletap (with CVE-2019-5418)
Product
Ruby on Rails Rails (railties)
CVE
CVE-2019-5420
Disclosed
2019-03-13
CVSS
9.8
Auth
pre-auth
CISA KEV
no
Affected
5.2.x < 5.2.2.1, 6.0.0.beta1 - 6.0.0.beta2 (development mode)
Fixed
5.2.2.1, 6.0.0.beta3

Summary

In development mode Rails derived secret_key_base from the application's class name, so the key used to sign cookies and Active Storage URLs was guessable. Knowing it lets an attacker sign a Marshal-serialized object and get it deserialized, giving code execution on any dev-mode Rails app exposed to the network.

Root cause

Rails.application.secret_key_base fell back to Digest::MD5.hexdigest(self.class.name) in development/test. Signed values (e.g. Active Storage disk service keys under /rails/active_storage/disk/) are verified with this key and then deserialized with Marshal.load, so a forged value triggers a Ruby deserialization gadget chain.

Impact

Unauthenticated RCE against Rails apps running in development mode (often exposed staging/dev boxes).

Public PoC

1. Check the app is vulnerable to CVE-2019-5418 (Accept: ../../../../etc/passwd{{ file read)
2. Read credentials.yml.enc and master.key
3. Decrypt credentials.yml.enc to get secret_key_base
   (dev mode fallback: Digest::MD5.hexdigest("<AppName>::Application"))
4. Craft a signed Marshal payload for
   /rails/active_storage/disk/:encoded_key/*filename(.:format)  => CVE-2019-5420
5. Send the request; the object is deserialized and code executes

Source: mpgn / Rails-doubletap-RCE

Detection

Check for RAILS_ENV=development on internet-facing hosts and requests to /rails/active_storage/disk/ with long signed blobs. Version check railties < 5.2.2.1.

Mitigation

Upgrade to 5.2.2.1+ (dev secret is now random in tmp/development_secret.txt); never expose development mode.

References