Skip to content

Stored XSS on Multi-word milestone reference leads to Admin-privilege escalation in certain conditions

HackerOne report #1455036 by ryhmnlfj on 2022-01-20, assigned to @mhenriksen:

Report | Attachments | How To Reproduce

Report

Summary

I found Stored XSS on Multi-word milestone reference in Markdown field.
Admin-privilege escalation can also be achieved by combining this XSS and CSP-bypass at CVE-2021-22242 under certain conditions.

However, the reproduction steps has become too long, so I submit the procedure that does not bypass CSP as the first report for convenience of confirmation and mitigation.
After submitting this first report, I will add the additional report with CSP-bypass and Admin-privilege escalation scenario as comments.

Steps to reproduce (Non-CSP-bypass)

Victim-side 1st steps
  1. Sign in to GitLab instance as victim-user.
  2. Create a new public project that everyone can create issue.
  3. After creating the new issue, log out of this victim's account and start Attacker-side steps.
Attacker-side steps
  1. Sign in to GitLab instance as attacker-user.

  2. Create a new private project.

  3. After creating a private project, make a note of the [FULL_NAMESPACE] from the URL displayed in the address bar of browser.

Full-namespace-of-private-project.png

  1. Go to "Issues > Milestones" page and click "New milestone" button.

  2. Create a new milestone with the following Title:

New Milestone <script>alert(document.domain)</script>  

Create-new-milestone.png

  1. Go to the "Issue" page in the victim's public project prepared at Victim-side 1st step 2.

  2. Prepare the description of new issue by replacing the string below.
    Replace [FULL_NAMESPACE] with the values you got in Attacker-side step 3.

[FULL_NAMESPACE]%"New Milestone <script>alert(document.domain)</script>"  

After replacing, create a new issue with this description.

Create-new-issue_milestone.png

  1. Log out of this attacker's account and start Victim-side 2nd steps.
Victim-side 2nd steps
  1. Sign in to GitLab as victim-user.
  2. Go to the issue page created at Attacker-side step 7. The XSS will be executed automatically.

XSS-result_milestone.png

What is the current bug behavior?

There are almost no restrictions on the regular expression that extract String-based multi-word milestone.

https://gitlab.com/gitlab-org/gitlab/-/blob/v14.6.3-ee/app/models/milestone.rb#L63-80

  def self.reference_pattern  
    # NOTE: The iid pattern only matches when all characters on the expression  
    # are digits, so it will match %2 but not %2.1 because that's probably a  
    # milestone name and we want it to be matched as such.  
    [@]reference_pattern ||= %r{  
      (#{Project.reference_pattern})?  
      #{Regexp.escape(reference_prefix)}  
      (?:  
        (?<milestone_iid>  
          \d+(?!\S\w)\b # Integer-based milestone iid, or  
        ) |  
        (?<milestone_name>  
          [^"\s\<]+\b |  # String-based single-word milestone title, or  
          "[^"]+"      # String-based multi-word milestone surrounded in quotes  
        )  
      )  
    }x  
  end  

This regex means that injection is possible with a similar approach to CVE-2020-13338.

          "[^"]+"      # String-based multi-word milestone surrounded in quotes  

What is the expected correct behavior?

I recommend limiting the regular expression that extract Multi-word milestone to the same extent as Single-word milestone.

Relevant logs and/or screenshots

I put references to the screenshots at the appropriate places in this report.

Output of checks

This bug happens on the official Docker installation of GitLab Enterprise Edition 14.6.3-ee.
I used Chromium 96 and Firefox 91 on Xubuntu 20.04 LTS to verify XSS.

I think it can be reproduced on gitlab.com by using CSP-bypassable vector, but I haven't tried it to prevent unexpected accidents.

Results of GitLab environment info

Output of sudo gitlab-rake gitlab:env:info:

System information  
System:		  
Proxy:		no  
Current User:	git  
Using RVM:	no  
Ruby Version:	2.7.5p203  
Gem Version:	3.1.4  
Bundler Version:2.1.4  
Rake Version:	13.0.6  
Redis Version:	6.0.16  
Git Version:	2.33.1.  
Sidekiq Version:6.3.1  
Go Version:	unknown

GitLab information  
Version:	14.6.3-ee  
Revision:	6360adc49de  
Directory:	/opt/gitlab/embedded/service/gitlab-rails  
DB Adapter:	PostgreSQL  
DB Version:	12.7  
URL:		http://mygitlab.local  
HTTP Clone URL:	http://mygitlab.local/some-group/some-project.git  
SSH Clone URL:	git@mygitlab.local:some-group/some-project.git  
Elasticsearch:	no  
Geo:		no  
Using LDAP:	no  
Using Omniauth:	yes  
Omniauth Providers: 

GitLab Shell  
Version:	13.22.1  
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

This Stored XSS can be placed in the various Markdown field, and by using cross-project reference and Multi-word milestone in combination,
the attack target can be easily spread to public project owners and maintainers.
A trial calculation of CVSS in this standard scenario is as follows:

CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:L  
8.9 (High)  

After researching for scenarios that extend the attack to admin, I have found that it is possible to attack the admin in impersonation mode.
Admin-Privilege escalation can be achieved by combining a request to stop impersonation mode with a request to User modification API.

Let's assume a scenario where this impersonation mode is often used by admin of GitLab instance and the attack is successful.
Another trial calculation of CVSS is as follows:

CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H  
9.0 (Critical)  

Though I think the impersonation mode is an interesting feature, I'm not sure if it's commonly used.
If it doesn't seem to be used much, please evaluate it as a standard scenario.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

How To Reproduce

Please add reproducibility information to this section: