HexBrain

GitLab · Report #826361

SSRF on project import via the remote_attachment_url on a Note

Validstatus
highseverity
$10,000bounty
359upvotes
7 Jun 2020disclosed

How it was found

Summary

The Note model has an attachment which is provided by a CarrierWave uploader:

mount_uploader :attachment, AttachmentUploader

One of the features this provides is the ability to download and attach a file via a url, see https://github.com/carrierwaveuploader/carrierwave/blob/v1.3.1/lib/carrierwave/mount.rb#L80. This means that the Note model has a method remote_attachment_url= which can be used to perform this action.

As this attribute isn't removed by the AttributeCleaner on project import, it can be set in the project.json for a note and will be set when the note is created, downloading the file:

https://github.com/carrierwaveuploader/carrierwave/blob/v1.3.1/lib/carrierwave/mounter.rb#L72

  def remote_urls=(urls)
      return if not urls or urls == "" or urls.all?(&:blank?)

      @remote_urls = urls
      @download_error = nil
      @integrity_error = nil

      @uploaders = urls.zip(remote_request_headers || []).map do |url, header|
        uploader = blank_uploader
        uploader.download!(url, header || {})
        uploader
      end

https://github.com/carrierwaveuploader/carrierwave/blob/v1.3.1/lib/carrierwave/uploader/download.rb#L43

    def file
          if @file.blank?
            headers = @remote_headers.
              reverse_merge('User-Agent' => "CarrierWave/#{CarrierWave::VERSION}")

            @file = Kernel.open(@uri.to_s, headers)
            @file = @file.is_a?(String) ? StringIO.new(@file) : @file
          end

The downloaded file is then attached to the note and can be viewed from the newly imported project.

Any model that has a mount_uploader and is importable is potentially vulnerable to the same attack, although the majority of the others are AvatarUploader which checks the file type and prevents the response from being viewed.

Steps to reproduce

  1. Create a new project
  2. Create an issue in the project
  3. Add a note to the issue
  4. Export the project
  5. Extract the export
  6. Add remote_attachment_url to the note hash with a url
  7. Recompress the export and import it
  8. View the note on the issue

Demo {F756257}

Examples

Example of project import on gitlab.com hitting postbin:

https://gitlab.com/wbowling/ssrf1/-/issues/1#note_309127303 {F756269}

What is the current bug behavior?

When importing a model that has a mount_uploader it's possible to use the carrierwave uploader seed attributes to download a file from any host: https://github.com/carrierwaveuploader/carrierwave/wiki/How-to:-Upload-remote-image-urls-to-your-seedfile

What is the expected correct behavior?

The attributes should be prohibited and removed via the AttributeCleaner

Output of checks

This bug happens on gitlab.com

Results of GitLab environment info

System information
System:		Ubuntu 18.04
Proxy:		no
Current User:	git
Using RVM:	no
Ruby Version:	2.6.5p114
Gem Version:	2.7.10
Bundler Version:1.17.3
Rake Version:	12.3.3
Redis Version:	5.0.7
Git Version:	2.24.1
Sidekiq Version:5.2.7
Go Version:	unknown

GitLab information
Version:	12.8.7-ee
Revision:	2643fd87200
Directory:	/opt/gitlab/embedded/service/gitlab-rails
DB Adapter:	PostgreSQL
DB Version:	10.12
URL:		http://gitlab-vm.local
HTTP Clone URL:	http://gitlab-vm.local/some-group/some-project.git
SSH Clone URL:	[email protected]:some-group/some-project.git
Elasticsearch:	no
Geo:		no
Using LDAP:	no
Using Omniauth:	yes
Omniauth Providers:

GitLab Shell
Version:	11.0.0
Repository storage paths:
- default: 	/var/opt/gitlab/git-data/repositories
GitLab Shell path:		/opt/gitlab/embedded/service/gitlab-shell
Git:		/opt/gitlab/embedded/bin/git

Impact

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original