CVE-2019–5420 and defence-in-depth

In this short article, I’m going to discuss a little bit on the exploitability of CVE-2019–5420.

Ruby-on-Rails offers three different environments it can run in: development, test and production. You should obviously not have code running in development or test available on the internet but it (as always) happens (for example in staging environments).

Ruby-on-Rails uses “signed-sessions” to allow people to easily scale their applications. Over time, the way the sessions were handled changed. With 5.2.2, sessions are JSON encoded data that is protected using AES GCM (aes-256-gcm) by default.

CVE-2019–5420 is actually very simple. The key used to encrypt sessions can be guessed (or brute forced) in development mode as it is based on the name of the application. This issue can potentially be used to gain code execution (RCE) according to the advisory.

However, over the years the security of Rails has kept improving and sessions don’t use marshal like they used to. With JSON, you can no longer get code execution as there is currently no known way to get from JSON to code execution (as opposed to going from marshal to code execution). That’s why defence-in-depth is so important, always be more than one bug away from a disaster!

Always be more than one bug away from a disaster!

But, you can still forge a valid session since you have the key to decrypt/encrypt the sessions…

Or can you?? Another thing that greatly improves the security of Ruby-on-Rails applications is its ecosystem. Most people writing Rails applications use the same gem/library to manage authentication: devise.

If we look at the methods used to serialize/deserialize a user/record into a session, we can see a field named salt:

And we can see the salt is also verified as part of the deserialization of the session. In short, you need both the user ID as well as the matching salt to become that user.

By looking at what the salt actually is:

You can easily see that you’re hopefully going to have a hard time guessing that value for another user (the password being“encrypted”/hashed using bcrypt). It also doesn’t really make sense to tamper with the session if you managed to find the password. Again, a very simple safeguard greatly limits the impact of this bug!

The exploitation of this issue with a non-devise session management is available for PentesterLab PRO subscribers. The exploitation of this issue to get RCE using marshal is also available as PRO exercises in PentesterLab.

Photo of Louis Nyffenegger
Written by Louis Nyffenegger
Founder and CEO @PentesterLab