← Back to Writeups
CUSTOMEasyForensics

Force Push

XESXOR9/2/20262 min read
#forensics#custom#easy#git_fsck_enumeration#unreachable_object_recovery#git_object_verification#linux

Force Push

Platform: CACTF2026 | Category: Forensics | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-07-27 | Status: Solved Techniques: git_fsck_enumeration, unreachable_object_recovery, git_object_verification

Summary

Task: A leaked Git repository has spotless reachable history after a committed production credential was removed. Solution: Enumerate unreachable objects with git fsck and extract the deleted file directly from its orphaned commit.

Force Push — CACTF2026

Description

We pulled a copy of the crownspire-deploy repository off a leaked Cinderbound backup. Word is the production warden's key for the reliquary got committed by mistake and then cleaned up before anyone noticed. The current history looks spotless. Recover what they tried to bury.

The ZIP contains a complete crownspire-deploy/ repository, including its .git/ directory and loose Git objects. The goal is to recover the credential removed from visible branch history. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Semantic Clue

The title Force Push points to rewritten Git history. Moving a branch reference does not immediately erase the old commit, tree, and blob objects; until garbage collection removes them, they may remain in the object database as unreachable objects.

Analysis

First, verify the downloaded evidence and inspect every reachable reference:

bash
shasum -a 256 challenge_download
git -C crownspire-deploy log --all --oneline --decorate

The archive digest is:

text
08f819507302c60599bf08be2432c06bcdf98638c4faab67e203b05b5de343e0

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The reachable main history ends at 7ae3842, and git log --all contains no secret-bearing commit. This denies the reachable-history hypothesis.

Next, ask Git to validate the complete object database while excluding reflogs from reachability:

bash
git -C crownspire-deploy fsck --full --no-reflogs --unreachable

Relevant output:

text
unreachable commit 3c8803d7146cd07c75325d6b555116200f2569ee
unreachable tree 1fe5a4a75df03ff80a3743b93b8df188ee48c06c
unreachable blob 12b14971d38c09ee73fed80613951dfdd3562291

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Inspecting the orphaned commit identifies the mistake without checking it out:

bash
git -C crownspire-deploy show --stat --format=fuller 3c8803d7146cd07c75325d6b555116200f2569ee

Its message is:

text
temp: add reliquary.creds to debug 403 on manifest push (REVERT ME)

The commit creates reliquary.creds. The matching unreachable commit, tree, and blob prove that the force-pushed content survived as loose objects even though no current reference reaches it. Reflog or alternate-reference recovery is therefore unnecessary. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Read the deleted file directly from the orphaned commit and save it without changing the working tree:

bash
git -C crownspire-deploy show \
  3c8803d7146cd07c75325d6b555116200f2569ee:reliquary.creds \
  > recovered-reliquary.creds

The recovered credential file contains an AWS_SECRET_ACCESS_KEY value in the expected flag format.

Verification

Verify both the recovered bytes and their Git object identity:

bash
shasum -a 256 recovered-reliquary.creds
git -C crownspire-deploy hash-object ../recovered-reliquary.creds

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Expected output:

text
62b22041f38c920b4c39b8c13bd8d20eaa7b19564629c5a8e917c6415389766e  recovered-reliquary.creds
12b14971d38c09ee73fed80613951dfdd3562291

The second value equals the unreachable blob reported by git fsck, confirming byte-for-byte recovery from the repository object database. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍