Skip to content

Gitlab DOS by integrating a malicious JetBrains Teamcity CI/CD server into a project

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 #2638001 by a92847865 on 2024-08-04, assigned to @ottilia_westerlund:

Report | Attachments | How To Reproduce

Report

NOTE! Thanks for submitting a report! Please note that initial triage is handled by HackerOne staff. They are identified with a HackerOne triage badge and will escalate to the GitLab team any. Please replace all the (parenthesized) sections below with the pertinent details. Remember, the more detail you provide, the easier it is for us to triage and respond quickly, so be sure to take your time filling out the report!

Summary

You can integrate and run CI/CD pipelines with Teamcity . When testing Teamcity integration, Gitlab server will connect to a potentially attacker-controlled server to fetch information. Due to lacking of response size check in Integrations::Teamcity.read_build_page(response) method, an attacker-controlled server can send responses with large body (300MB JSON file) to Gitlab application. Then those responses are parsed by a JSON parser consuming GiBs of RAM. Triggering two requests (from Gitlab to malicious server) is enough to consume all available memory of a 1k-users self-managed Gitlab EE instance and make Gitlab instance unreachable for legitimate users.

Steps to reproduce
  1. Register two VMs: a 1k-users self-managed Gitlab EE instance VM (8 vCPU, 16GB RAM) and another fake_server smaller VM.
  2. Install latest Gitlab EE on ``1k-users self-hosted Gitlab EE instance``` VM.
  3. Create a new project.
  4. SSH into and upload these files ( fake_server.js and attack.json.gz ) to fake_server VM
  5. Start fake_server at port 80: sudo nodejs fake_server.js
  6. Open 2 tabs with the same below URL. You can find equivalent curl command using Chrome's Developer Tools and send 2 requests by curl also. It would be the way to automate this attack for larger instances. http://[your_GL's_host_name]/[optional_group_name]/[project_name]/-/settings/integrations/teamcity/edit
  7. In each tab, fill in necessary fields:
  1. Click "Test settings" button
  2. SSH into 1k-users self-hosted Gitlab instance VM, run "htop" command. You should see that Gitlab consumes all available memory and the Gitlab instance becomes unavailable.

Note: An XML file can be used instead of JSON file. If using an XML, the 'content-type' header of response in fake_server.js should be application/xml.

Impact

DOS: complete service outage to other users.

Examples

(If the bug is project related, please create an example project and export it using the project export feature)

(If you are using an older version of GitLab, this will also help determine whether the bug has been fixed in a more recent version)

(If the bug can be reproduced on GitLab.com without violating the Rules of Engagement as outlined in the program policy, please provide the full path to the project.)

What is the current bug behavior?

Integrations::Teamcity.read_build_page(response) doesn't check response's body size.
In https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/integrations/teamcity.rb#L118-128

def read_build_page(response)  
      if response.code != 200  
        # If actual build link can't be determined,  
        # send user to build summary page.  
        build_url("viewLog.html?buildTypeId=#{build_type}")  
      else  
        # If actual build link is available, go to build result page.  
        built_id = response['build']['id'] # decompress and parse response without prior size check  
        build_url("viewLog.html?buildId=#{built_id}&buildTypeId=#{build_type}")  
      end  
    end
What is the expected correct behavior?

Integrations::Teamcity.read_build_page(response) method should have a limit and check response's body size.

Relevant logs and/or screenshots

(Paste any relevant logs - please use code blocks (```) to format console output,
logs, and code as it's very hard to read otherwise.)

Output of checks

(If you are reporting a bug on GitLab.com, write: This bug happens on GitLab.com)

Results of GitLab environment info
System information  
System:         Ubuntu 20.04  
Proxy:          no  
Current User:   git  
Using RVM:      no  
Ruby Version:   3.1.5p253  
Gem Version:    3.5.11  
Bundler Version:2.5.11  
Rake Version:   13.0.6  
Redis Version:  7.0.15  
Sidekiq Version:7.1.6  
Go Version:     unknown

GitLab information  
Version:        17.2.1-ee  
Revision:       88793996279  
Directory:      /opt/gitlab/embedded/service/gitlab-rails  
DB Adapter:     PostgreSQL  
DB Version:     14.11  
URL:            http://34.16.168.95  
HTTP Clone URL: http://34.16.168.95/some-group/some-project.git  
SSH Clone URL:  git@34.16.168.95:some-group/some-project.git  
Elasticsearch:  no  
Geo:            no  
Using LDAP:     no  
Using Omniauth: yes  
Omniauth Providers: 

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

Gitaly  
- default Address:      unix:/var/opt/gitlab/gitaly/gitaly.socket  
- default Version:      17.2.1  
- default Git Version:  2.45.2  

Impact

Attacker can take down a 1k-users Gitlab EE self-manage instance by testing Jetbrains Teamcity integration in a project's settings. It would make the Gitlab EE instance unavailable to other users.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

How To Reproduce

Please add reproducibility information to this section: