On January 21, 2023 at ShmooCon 2023, Praetorian open-sourced Gato (Github Attack Toolkit), a first of its kind tool that focuses on abusing offensive TTPs targeting self-hosted GitHub Actions Runners. Since then, Praetorian and other offensive security practitioners across the information security community have leveraged Gato for so much more than just self-hosted runner attacks. When the time came for a Gato update, we wanted to account for these unintended use cases.

In particular, practitioners have found Gato useful for evaluating the attack surface of an organization’s entire GitHub Actions Attack surface. Given the additional use case and the widespread response from the community, we are releasing Gato update that will include several new features along with quality of life improvements.

Gato Version 1.5 is available now on GitHub at https://github.com/praetorian-inc/gato!

New Features in the Gato Update

GitHub Actions Secrets Enumeration

Unless you’ve carefully read through GitHub’s documentation or watched one of our conference talks on GItHub Actions, you may not know that any developer that can push code to a repository can access all repository level secrets as well as organization level secrets that are in the default group. During our assessments, we noticed that the average developer has access to far more repository level GitHub Actions secrets within their organization than we had expected. As a result, we added a feature to Gato that will list repository level secrets if the user has write access to the repository and the token has the repo scope, as figure 1 shows.

Figure 1: Gato’s enumeration module now lists secrets.

Gato will now automatically list accessible secrets when enumerating a repository. Users can then exfiltrate these secrets using a subsequent workflow. Similarly, when running Gato against an organization, Gato will list secrets from every repository as well as the organization (if the user is an organization administrator).

Secrets Exfiltration

Gato’s attack module now supports GitHub Actions secrets exfiltration. If a GitHub personal access token has the “repo“ and “workflow“ scopes, along with write access to a repository, a practitioner can now use that token to create a new branch with a workflow that can read plaintext secret values.

Gato dynamically creates a workflow file that uses all accessible secrets, and then commits it to a new branch, as figure 2 shows. This workflow uses a public key to encrypt the plaintext values and prevent the secrets from falling into the wrong hands (such as during a penetration test targeting a public repository where anyone can download GitHub Actions Run Logs).

Figure 2: Exfiltration of repository secrets using Gato.

Gato then downloads the workflow’s run log, extracts the encrypted secrets, and decrypts them. This process that enables Gato’s operator to read plaintext secrets only takes about 20-30 seconds.

API-Only Enumeration

Gato now uses GitHub’s repository contents API to perform workflow file enumeration. This speeds up Gato execution and minimizes the log footprint of Gato’s Enumeration mode.

If an organization is not enrolled in GitHub’s private beta for API request logging (https://github.blog/changelog/2023-02-01-api-requests-are-available-via-audit-log-streaming-private-beta/) then running Gato’s enumeration functionality will generate zero audit log entries.

JSON Output

Gato now supports JSON output of enumeration results. When running the enumeration module, Gato has the option to write json output of captured results to a file. Simply pass the –output-json FILE or –oJ FILE flag when running the enumeration module and Gato will write the entire enumeration output to a JSON file.

Improved Search

Operators at Praetorian and in the wider community have found Gato’s code search functionality  very useful for identifying repositories that use self-hosted runners for additional scanning. The search feature now supports passing a custom query, which is useful for finding repositories that may be vulnerable to self-hosted runner hijacking attacks due to a misconfigured pull_request_target workflow (see figure 3).

Figure 3: Custom code search query support.

GitHub Enterprise Server Support

Gato supports enumerating organizations and repositories hosted on on-premises GitHub Enterprise server instances. Simply pass a PAT from GHES to Gato and add the –api-url parameter with the path to an accessible on-premises GHES instance.

Validate Only Mode

For operators who have used NoseyParker to identify a GitHub PAT in source code, running Gato with the new validate flag will validate the GitHub PAT quickly and print organization memberships without performing any additional checks. See figure 4.

Figure 4: Validate only mode.

Quality of Life Improvements

Users can now choose to disable Gato’s color output by passing the ‘–no-color’ flag. Additionally, users can disable the Gato mascot ASCII splash by passing the ‘–suppress’ flag.

Using Gato

We designed Gato to be a tool for both offensive and defensive security practitioners. Below are some quick instructions for how to use Gato to help achieve your objectives.

Validate GitHub PAT Access

Defenders might encounter a GitHub PAT within a file share, but not otherwise know to whom it belongs. Gato can quickly determine if the PAT is valid and to which organizations the user belongs.

Example invocation:

export GH_TOKEN=<UNKNOWN_PAT>

gato enumerate –validate

Assess Blast Radius of GitHub PAT

If your security team encounters an unknown GitHub personal access token, then Gato can be used to determine the extent of access that particular PAT has. Gato’s self-enumeration functionality will first query all member organizations for a particular token, and then proceed to enumerate each accessible organization.

Offensive users can use Gato to determine how much access a single PAT has to all Organizations of which the user is a member.

Example invocation:

export GH_TOKEN=<UNKNOWN_PAT>

gato enumerate –self-enumeration

Build Detection Engineering for GitHub Actions Attacks

Offensive operators can use Gato’s attack functionality to execute malicious workflows targeting self-hosted runners or secrets. For example, Gato can help conduct offensive scenarios and build detection engineering for the resulting GitHub Audit logs.

Example Invocations:

gato a --secrets -t YourOrg/SomeRepo

gato a --workflow -t YourOrg/SomeRepo --command "whoami && cat /etc/passwd"

Verify Pipeline Secrets Exposure

The number of pipeline secrets an average developer can access often surprises organizations. Defenders can use Gato to capture a birds-eye view of the secrets attached to individual repositories. This is not currently possible through GitHub’s UI.

Example invocation:

export GH_TOKEN=<DEVELOPER_PAT>

gato enumerate –T YourOrganization

Acknowledgements

During the six months since releasing the tool we’ve learned a lot. Thank you to Praetorian security engineers Mason Davis, John Stawinski, and Jimmy Chang for working on the Gato update development and providing feedback. We also have had a lot of help from the wider community since Gato’s release.- Some of the features and bug fixes are a direct result of bug reports and feature requests. We greatly appreciate anyone who wants to suggest new features or provide feedback!