Throughout numerous Red Teams in 2022, a common theme of Source Control Supply Chain attacks in GitHub repositories has emerged. After many hours manually hunting for and exploiting these attack paths, we’ve built an all-in-one toolkit called Gato (Github Attack Toolkit) for finding and attacking repositories where these misconfigurations are present. We released the toolkit as open-source software under Apache License 2.0 on January 21st, 2023, in conjunction with a conference talk at ShmooCon 2023. To understand the tool, here’s a quick primer on CI/CD, GitHub Actions, and Self-hosted Runners:
CI/CD, or continuous integration and continuous delivery, is the process of automatically building, testing, and deploying software. The goal of CI/CD is to reduce the delivery time for new features by automating the software delivery process. CI/CD typically involves creating workflows wherein changes in code trigger pipelines of tasks. Common tasks include building and testing code, creating packages, deploying code to different environments, and many more. CI/CD workflows also can enforce coding standards, run automated tests, and catch errors before they make it to production. Several CI/CD platforms exist, like Jenkins, CircleCI, and GitLab CI/CD, but we’ve focused on exploiting GitHub Actions.
GitHub Actions allows developers to bake their CI/CD infrastructure directly into their repository. From a developer’s perspective, the platform consists of two primary components: the Actions Web UI and the Actions runners.
The GitHub Actions Web UI is a developer’s window into their CI/CD pipelines. It provides a live view of currently running pipelines and previous pipeline results. A developer also can configure it via the repositories settings. Options include access permissions, retention settings, and configuring the second core component of the platform, GitHub Actions Runners.
GitHub Actions Runners are the workhorses of the platform. They execute segments of the pipeline or workflow called jobs and fall into two primary categories according to who manages them. As the name suggests, Github manages the Github-hosted runners, but of particular interest to attackers are self-hosted runners, which developers manage. Self-hosted runners reside on internal networks, bypassing the firewalls and network access controls that usually prevent unauthorized access.
GitHub self-hosted runners
GitHub self-hosted runners can run on several operating systems, are non-ephemeral by default, and execute commands directly on the underlying host. The deployment process is simple. Just download and extract the binaries, configure the runner with a key provided by GitHub, and execute.
GitHub makes the risks of using self-hosted runners clear in their documentation. They recommend “that you only use self-hosted runners with private repositories” as they create “significant security risks for your machine and network environment, especially if your machine persists its environment between jobs.” The documentation details the following risks:
- Malicious programs running on the machine.
- Escaping the machine’s runner sandbox.
- Exposing access to the machine’s network environment.
- Persisting unwanted or dangerous data on the machine.
Or from the perspective of an attacker with access to your workflows:
- Initial Access
- Sandbox Escape
- Lateral Movement
Gato provides three modules for finding and attacking vulnerable repositories: attack, enumerate, and search.
The attack module offers the ability to create malicious workflow runs via two attack types:
- Fork Pull Request
The workflow type requires write access to the target repository. It creates a new branch, pushes a malicious workflow that executes automatically, and cleans up after itself.
The fork pull request type is particularly useful when a user does not have direct write access to a repository but can open a pull request (PR) from a fork. Depending on the user’s previous contribution history and the repositories configuration, the malicious workflow might execute automatically or require approval from a maintainer.
The enumerate module allows the enumeration of private and public organizations using a GitHub personal access token. The tool, at minimum, requires a personal access token with the repo scope. If the admin:org scope is present, Gato will perform additional enumeration actions, such as listing organization-level self-hosted runners.
The enumeration tool supports four modes of operation:
- Self Enumeration – Enumerate all organizations the authenticated user associated with the PAT is a member of.
- Organization Enumeration – Enumerate a single organization and all accessible repositories.
- Repository Enumeration – Enumerate a single repository.
- Repositories Enumeration – Enumerate a list of repositories.
The search module is a lightweight wrapper around GitHub’s code search API. It allows the user to search organizations for cases where self-hosted is present in YAML files. It can search private repositories to which the user has access. Search is a good starting point for assessing an organization because the user then can use the enumerate module to more deeply enumerate the repositories the search returned.
Gato is available for use now on GitHub. We invite you to watch our quick demonstration video as an artifact from the ShmooCon 2023 Conference talk.
Be sure to check out this other post for more details on our research into Self-Hosted GitHub Runners and their vulnerabilities. We’d also like to say a word of thanks to Kaitlin York Designs for the fantastic Gato graphic!