Skip to content

User with Admin access to integrated Grafana can steal GitLab session cookies through malicious data-source

Please read the process on how to fix security issues before starting to work on the issue. Vulnerabilities must be fixed in a security mirror.

HackerOne report #1888690 by joaxcar on 2023-02-27, assigned to GitLab Team:

Report | Attachments | How To Reproduce

Report

Summary

A user with Admin access to Grafana enabled on a self-hosted GitLab instance (note this user might not have any access to the actual GitLab instance, the admin right is only for org level in Grafana) can create a malicious data-source that when visited will leak other users GitLab session cookies. Leading to session takeover and full access to the victim's account (with no indications that this has happened)

That was a mouth full. Let's dig into this. The pieces needed

  • When setting up a self-hosted GitLab instance there is the option to enable an integrated Grafana server. This server will run under the path https://gitlab.example.com/-/grafana. Note here that the Grafana server is running on the same origin as the actual GitLab instance.
  • Users in Grafana can have three access levels (in an organization), viewer, editor, and admin. Being an admin only gives you the right to handle the Grafana organization, inviting users and setting up data sources. It should not be confused with having any sort of access to the server, or to the actual GitLab instance. The Grafana admin can potentially lack all forms of access to GitLab.
  • When configuring a data source in Grafana you most often give the Grafana server the right to make requests to the configured third-party source (Prometheus or other servers) with the help of a proxy. The admin usually adds some sort of authorization to the server which is used when Grafana requests data from the source. One available option is to whitelist cookies, here the user can add cookies that will be taken from the request to Grafana and forwarded to the data source. Effectively forwarding cookies from the user visiting Grafana to the external source.
The attack

By configuring a data source pointing to an attacker-controlled server and whitelisting the cookie _gitlab_session an attacker can create a situation where any user visiting a dashboard with the data source will now forward the user GitLab session cookie to the attacker's server. This only works because the two servers (GitLab and Grafana) share the same domain. So the GitLab session cookie will actually be sent to the Grafana server at every page request.

The attacker can then use the session cookie to take control of the victim's account and access GitLab with full access. At worst the victim is an admin account on the GitLab server giving the attacker admin access to the instance.

Feature or bug

Omnibus actually packages an older version of Grafana, which might also be susceptible to https://nvd.nist.gov/vuln/detail/CVE-2022-39201. This CVE details how Grafana used to be allowing the grafana_session cookie to be whitelisted allowing for a similar attack on the Grafana server. This is still possible on the Omnibus Grafana server as well but is way less impactful as the attacker already has high privileges on the Grafana server. Where things get worse for GitLab is where the two servers share origin. Usually, Grafana servers are hosted on their own subdomains, giving them no access to other session cookies.

The Grafana fix (https://github.com/grafana/grafana/commit/b571acc1dc130a33f24742c1f93b93216da6cf57) outlines how they added an option to restrict the Grafana session cookie from being added to the whitelist, but this patch does not look like it exists for Grafana v7.

Steps to reproduce

I will outline a quick way of proving this, there are many ways and configurations where a user would end up with access to a Grafana admin account. This is just a quick POC

  1. Spin up a new GitLab omnibus docker
sudo docker run --detach \  
  --hostname gitlab.example.com \  
  --publish 443:443 --publish 80:80 --publish 22:22 \  
  --name gitlab \  
  --restart always \  
  --shm-size 256m \  
  gitlab/gitlab-ee:latest  
  1. Get hold of the root password
sudo docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password  
  1. Now configure Grafana by running this command
sudo docker exec -it gitlab editor /etc/gitlab/gitlab.rb  

to open the config file and make sure to enable these settings

grafana['enable'] = true  
grafana['admin_password'] = 'admin'  
grafana['allow_user_sign_up'] = true  
grafana['disable_login_form'] = false  

save the file
4. Restart the docker container

sudo docker restart gitlab  
  1. Now log in to GitLab as root
  2. Go to https://gitlab.example.com/-/grafana
  3. Log in with admin admin
  4. Go to /-/grafana/datasources/new and create a new Prometheus data source
  5. Configure a catch server as the URL (Burp collaborator), leave access as server, and add _gitlab_session in the whitelisted cookies

config.png

  1. Click save and test
  2. You will now have a call leaking your cookie in your catch server.

redacted

  1. Open a new browser
  2. Go to https://gitlab.example.com, do not log in
  3. Open devtools and go to the "Application" tab and the cookie part
  4. Replace the current _gitlab_session with the leaked one.
  5. Refresh the page and you will now be logged in as root in this browser!

Note about a real attack. Here I only described using the same account, but now when the data source is configured you can send a link to any victim user to have them visit a dashboard that uses this data source. Any user visiting dashboards or interacting with Explore in Grafana will leak the cookie.

Impact

An attacker can leak victims' session cookies. This will result in a session takeover with full access to the victim's account.

What is the current bug behavior?

Grafana and GitLab are hosted on the same origin, thus sharing cookies. There is nothing stopping users from whitelisting GitLab session cookies in proxy requests.

What is the expected correct behavior?

Users should be stopped from whitelisting GitLab session cookies.

CVSS thoughts

I think it's hard to assess the severity here. The final outcome of an attack (session takeover) is highly severe, but I don't know how to score the Grafana admin access. It is a HIGH access level in Grafana, but a NONE access level to GitLab. And the same goes for Scope, Grafana is part of Omnibus, but the vulnerable service Grafana is giving an attacker access to GitLab. So the scope is changed. I will leave the math to you :)

Output of checks

Results of GitLab environment info
System information  
System:  
Current User:	git  
Using RVM:	no  
Ruby Version:	2.7.7p221  
Gem Version:	3.1.6  
Bundler Version:2.3.15  
Rake Version:	13.0.6  
Redis Version:	6.2.8  
Sidekiq Version:6.5.7  
Go Version:	unknown

GitLab information  
Version:	15.9.1  
Revision:	de8f6619031  
Directory:	/opt/gitlab/embedded/service/gitlab-rails  
DB Adapter:	PostgreSQL  
DB Version:	13.8  
URL:		http://gitlab.example.com  
HTTP Clone URL:	http://gitlab.example.com/some-group/some-project.git  
SSH Clone URL:	git@gitlab.example.com:some-group/some-project.git  
Using LDAP:	no  
Using Omniauth:	yes  
Omniauth Providers:

GitLab Shell  
Version:	14.17.0  
Repository storages:  
- default: 	unix:/var/opt/gitlab/gitaly/gitaly.socket  
GitLab Shell path:		/opt/gitlab/embedded/service/gitlab-shell

Impact

An attacker can leak victims' session cookies. This will result in a session takeover with full access to the victim's account.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

[readacted]

How To Reproduce

Please add reproducibility information to this section:

Edited by Nick Malcolm