Link to archived challenge

Category Difficulty Solves Author
forensics medium 5 sudoBash418

Description

We’ve received reports of a t3l0s git repository open to the internet, containing a secret key.

Unfortunately, it looks like we were too late - the secret key is nowhere to be found! Can you help us out?

Players are given a single file: git-repo.tar

There is also a single hint available:

  1. git commit --amend && git push --force is not always a silver bullet.

Analysis

The archive contains a bare git repo, which can be extracted to a new directory:

$ mkdir repo
$ tar xf git-repo.tar -C repo
$ cd repo

Based on the challenge description and hint, we can assume we should look for a “removed” commit.

Solution

We can list unreachable objects (including commits) using git fsck:

$ git fsck --unreachable
Checking object directories: 100% (256/256), done.
Checking objects: 100% (13/13), done.
unreachable tree 43108c1907c8021913c952d24fb9c6b27455eebd
unreachable commit e4dd42d2292550453969f61dc188f73fdefe110c
unreachable blob 4dfc65d0f476d7f4d13885d879034f5889bb3e4b
Verifying commits in commit graph: 100% (3/3), done.

Then show the commit contents:

$ git show e4dd42d2292550453969f61dc188f73fdefe110c
commit e4dd42d2292550453969f61dc188f73fdefe110c
Author: webdev2103 <webdev2103@t3l0s.internal>
Date:   Tue Mar 14 01:47:50 2023 -0600

    Add session middleware for security

diff --git a/.env b/.env
new file mode 100644
index 0000000..4dfc65d
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+SECRET_KEY=Y2x1YmVoezFnbjByNG5jM18xNV9ibDE1NV9jNWZlYzM0YX0K
...

And decode the base64-encoded key to get the flag:

$ echo Y2x1YmVoezFnbjByNG5jM18xNV9ibDE1NV9jNWZlYzM0YX0K | base64 -d
clubeh{1gn0r4nc3_15_bl155_c5fec34a}

Fully-automated Solve Script

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/bin/bash

# automatic solve script for git-remembers-all by sudoBash418

set -eu

solve() {
    local TARPATH="$1"

    # create temp dir for the repo
    WORKDIR="$(mktemp -d)"

    # extract bare repo to temp dir (ignoring the futuristic timestamps)
    echo "extracting repo"
    tar -xf "$TARPATH" -C "$WORKDIR" --warning=no-timestamp

    # find the unreachable blob
    echo "looking for unreachable objects"
    HIDDEN_BLOB="$(git -C "$WORKDIR" fsck --unreachable | grep -oE 'blob \w+')"
    echo "found hidden object: $HIDDEN_BLOB"

    # get the contents of the unreachable blob (.env)
    DOTENV_CONTENTS="$(git -C "$WORKDIR" cat-file $HIDDEN_BLOB)"
    echo "contents: $DOTENV_CONTENTS"

    # decode and print the flag
    echo -n "flag: "
    echo "$DOTENV_CONTENTS" | cut -f2 -d= | base64 -d

    # cleanup temp dir
    rm -rf "$WORKDIR"
}

if (($#!=1)); then
    echo "usage: $0 <path to git-repo.tar>"
    exit 1
fi

if [[ ! -f "$1" ]]; then
    echo "error: '$1' does not exist!"
    exit 1
fi

solve "$1"

Conclusion

This challenge is based on git’s behavior surrounding “removed” commits.
Specifically, git doesn’t necessarily delete a commit’s content when it becomes inaccessible (ex. after a git commit --amend).

This behavior is complicated further when pushing to remote repositories, where local state often differs from the remote state.
In fact, the repository used in this challenge is a simulated “remote” repository.

GitBleed is a similar issue, albeit focused more on git clone --mirror.