Phantom
Phantom
Platform: tamuctf | Category: Misc | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-03-21 | Status: Solved Techniques: base64_blob_decoding, github_api_commit_enumeration, github_phantom_commit_recovery, git_tree_traversal
Summary
Task: GitHub repo with single empty commit, flag hidden in phantom/orphaned commit. Solution: Used GitHub API /comments endpoint to discover unreachable commit SHA, then traversed git tree via Git Data API to extract flag from blob.
Phantom — TAMU CTF 2026
Description
The flag is somewhere around here or something idk
A GitHub repository link was provided: https://github.com/tamuctf/phantom
The repository appeared nearly empty with just a single commit on main branch containing a bare README.md with only # phantom.
Analysis
Initial Reconnaissance
Cloning the repository revealed minimal content:
- Single commit ("Initial commit") on
mainbranch - README.md containing only
# phantom - No other branches, tags, notes, stash, or dangling objects locally
Standard git forensics techniques (reflog, fsck, stash) yielded nothing — the interesting data wasn't in the clone.
GitHub API Exploration
Since local inspection was fruitless, the GitHub REST API was investigated:
- Issues/PRs (
/repos/tamuctf/phantom/issues?state=all) — Found 3 issues/PRs, all decoys from other CTF participants - Refs (
/repos/tamuctf/phantom/git/refs) — Onlyrefs/heads/mainand a PR ref - Events (
/repos/tamuctf/phantom/events) — FoundCommitCommentEvententries referencing commit SHAs that didn't exist on any branch
Key Discovery: Commit Comments Endpoint
The breakthrough came from the commit comments endpoint:
GET /repos/tamuctf/phantom/comments
This revealed comments on commits with SHAs not reachable from any branch. These are phantom commits — commits that exist in GitHub's object store but have no branch/tag reference pointing to them.
Critical commit found:
- SHA:
b365313472870cbf887a42a7be75df741b60c8d3 - Author: Noah Mustoe (cobradev4, the repo owner)
- Message: "Add flag"
- Date: 2026-03-16
Solution
Step 1: Identify Phantom Commits via Comments API
bash read-only • copy allowedcurl -s "https://api.github.com/repos/tamuctf/phantom/comments" | jq '.[] | {commit_id, user: .user.login, body}'
Found reference to commit b365313472870cbf887a42a7be75df741b60c8d3.
Step 2: Fetch Phantom Commit Details
bash read-only • copy allowedcurl -s "https://api.github.com/repos/tamuctf/phantom/git/commits/b365313472870cbf887a42a7be75df741b60c8d3"
Response included:
message: "Add flag"tree.sha: f2d3d0cec7a11ef4df615ebbdbd270e03673180a
Step 3: Traverse the Tree
bash read-only • copy allowedcurl -s "https://api.github.com/repos/tamuctf/phantom/git/trees/f2d3d0cec7a11ef4df615ebbdbd270e03673180a"
Found README.md with blob SHA: 86f49cf229723174e9bc1ac822fb33617c9ada1f
Step 4: Extract the Flag from Blob
bash read-only • copy allowedcurl -s "https://api.github.com/repos/tamuctf/phantom/git/blobs/86f49cf229723174e9bc1ac822fb33617c9ada1f" | jq -r '.content' | base64 -d
Output:
# phantom
gigem{REDACTED}
Complete Solve Script
python read-only • copy allowed#!/usr/bin/env python3 import requests import base64 REPO = "tamuctf/phantom" API = f"https://api.github.com/repos/{REPO}" # Step 1: Find phantom commits via comments comments = requests.get(f"{API}/comments").json() for c in comments: print(f"Comment on commit {c['commit_id']} by {c['user']['login']}") # Step 2: Fetch the phantom commit with "Add flag" message phantom_sha = "b365313472870cbf887a42a7be75df741b60c8d3" commit = requests.get(f"{API}/git/commits/{phantom_sha}").json() print(f"Commit message: {commit['message']}") tree_sha = commit['tree']['sha'] # Step 3: Get tree contents tree = requests.get(f"{API}/git/trees/{tree_sha}").json() readme_sha = next(f['sha'] for f in tree['tree'] if f['path'] == 'README.md') # Step 4: Decode blob blob = requests.get(f"{API}/git/blobs/{readme_sha}").json() content = base64.b64decode(blob['content']).decode() print(content)
Notes
Why phantom commits exist: When commits are pushed to GitHub and then dereferenced (branch deleted, force-pushed over), GitHub retains the commit objects in its database. They're not garbage-collected immediately and remain accessible via the Git Data API if you know the SHA.
How to find them:
/repos/{owner}/{repo}/comments— Comments may reference orphaned commits/repos/{owner}/{repo}/events— Push/commit events may log old SHAs/repos/{owner}/{repo}/git/commits/{sha}— Direct access if SHA is known