CVE-2020-8163
Ruby on Rails (often called Rails) is a web application framework written in Ruby that emphasizes convention over configuration and the principle of "don't repeat yourself" (DRY). It provides developers with a structured and efficient way to build database-backed web applications through pre-built patterns for rapid development.
With this vulnerability, when passing local variables to Rails controllers and views, an attacker can inject arbitrary code that is executed on the server.
Remote code execution flaws are among the Top 10 Open Web Application Security Project (OWASP) vulnerabilities. They are among the most potentially damaging of vulnerabilities because injected, remotely executed code:
- can access internal application objects/methods
- can often bypass security controls
- may persist across sessions
- can often pivot to gain OS-level access.
Details
Module Info
- Product: Ruby on Rails Framework
- Affected packages: actionview
- GitHub repository:
https://github.com/rails/rails/tree/main/actionview - Published package: The individual actionview gem or the entire Rails Framework gem (which includes actionview).
- Package manager: gem
Vulnerability Info
Rails allows passing local variables (using the :locals hash) when rendering templates.
If user input is passed directly as keys in this hash without sanitization, Rails improperly handles these keys in Action View, leading to arbitrary code execution.
Here is an example of passing a hash of locals:
render partial: 'greeting', locals: { name: 'Alice' }
In the _greeting.html.erb partial, the local variable name might be used like this:
<p>Hello, <%= name %>!</p>
Which is rendered like this:
<p>Hello, Alice!</p>
However, code such as this:
render template: 'example', locals: params[:locals]
Called by a malicious request like this:
/example?locals[foo;system('rm -rf /')]=bar
Would create:
{ "foo;system('rm -rf /')" => "bar" }
And Rails, because it fails to sanitize the hash, executes the malicious system('rm -rf /').
Steps to Reproduce
1. Install a version of Rails that contains this vulnerability, such as 3.2.18:
gem install rails -v 3.2.18
rails _3.2.18_ new cve_test_app
cd cve_test_app
bundle install
2. Create a vulnerable controller:
rails generate controller Pages
Modify app/controllers/pages_controller.rb:
class PagesController < ApplicationController
def show
render params[:page]
end
end
3. Add a route by editing config/routes.rb:
Rails.application.routes.draw do
get '/pages', to: 'pages#show'
end
4. Start the server:
rails server
5. Craft a malicious URL and send it with curl or a similar tool:
curl "http://localhost:3000/pages?page=../../../../../../../../etc/passwd"
6. Observe the output. With a vulnerable version of Rails, it may render sensitive system files.
Addressing the Issue
Some ways to mitigate this exploit are:
- Never pass user-controlled data directly to :locals.
- Manually sanitize the input.
- Avoid using locals and use instance variables instead.
- Use a Web Application Firewall (WAF) that filters out malicious code such as this.
Credits
- Marc Slemko
Mitigation
Users of affected versions of Ruby on Rails should follow one of the following mitigations:
- Upgrade to a corrected version.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.