u.twoha.cc/ctf/lactf/misc_my_poor_git.md
2024-09-13 19:49:18 -05:00

6.4 KiB

title date tags
LA CTF 2024: misc/my poor git 2024-02-21
ctf
ctf-misc
git

Task

misc/my poor git

My poor git server! I think someone took a hammer to the server and ruined a few of the files!

The git repo is available at /flag.git

poor-git.chall.lac.tf

  • Author: burturt
  • Points: 465 points
  • Solves: 72 / 1074 (6.704%)

Writeup

The challenge tells us to get the flag at /flag.git, so let's try to clone this repo:

$ git clone https://poor-git.chall.lac.tf/flag.git
Cloning into 'flag'...
remote: error: Could not read b061db539557e1bb4dbcffd936a2d1412eeb1f66
remote: fatal: Failed to traverse parents of commit c2e6e9737a8a666667b27c3a1dc84a76c8f4dab3
remote: aborting due to possible repository corruption on the remote side.
fatal: protocol error: bad pack header

The clone fails since we get an error because we cannot read b061db5, a parent of commit c2e6e97.

Let's try again with a depth limit on the number of commits, to avoid trying to traverse to a parent we cannot read:

$ git clone https://poor-git.chall.lac.tf/flag.git --depth 1
Cloning into 'flag'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), 938 bytes | 938.00 KiB/s, done.

This time our clone is successful, let's see what we downloaded:

$ cd flag
$ ls -a
.  ..  .git  nothing_here.txt
$ cat nothing_here.txt
there's nothing here, go away
$ git log --oneline
217ecd3 (grafted, HEAD -> main, origin/main, origin/HEAD) remove flag again uugh

Nothing interesting. Let's try again with a higher depth:

$ cd ..
$ rm -rf flag
$ git clone https://poor-git.chall.lac.tf/flag.git --depth 2
Cloning into 'flag'...
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 6 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (6/6), 1.83 KiB | 1.83 MiB/s, done.
$ cd flag
$ git log --oneline
* 217ecd3 (HEAD -> main, origin/main, origin/HEAD) remove flag again uugh
* c2e6e97 (grafted) Merge branch 'fix'
$ git checkout c2e6e97
Note: switching to 'c2e6e97'
...blah blah blah something something detached head state...
$ ls -a
.  ..  flag.txt  .git
$ cat flag.txt
lactf{not the flag}

We get another file, but it is not the real flag. The commit that we switched to, c2e6e97, was also the same commit we got an error on when we first tried to clone the repo. If we increase the depth any more, we will get an error:

$ git clone https://poor-git.chall.lac.tf/flag.git --depth 3
Cloning into 'flag'...
fatal: the remote end hung up unexpectedly

It appears we will not be able to get the flag by just running a git clone command. Looking into how git retrieves data from a Git server leads us to some documentation on Git transfer protocols. We learn that there are two different protocols, the "dumb" protocol and the "smart" protocol.

The description of the follow-up challenge to this one mentions the dumb protocol being disabled, so we can assume that this challenge's solution uses it.

Apparently my poor git server didn't like being called "dumb", so it disabled its dumb capabilities.

In the dumb protocol, the Git client sends a series of GET requests to clone the repo. We can emulate the protocol using curl.

First, we get the list of remote references and SHA-1s from /info/refs:

$ curl https://poor-git.chall.lac.tf/flag.git/info/refs
217ecd3c93b00c6b7404473d3bdfcb222a22edf4        refs/heads/main

Now we check the HEAD reference at /HEAD:

$ curl https://poor-git.chall.lac.tf/flag.git/HEAD
ref: refs/heads/main

Next, we clone HEAD, which is available at /objects/{SHA-1[:2]}/{SHA-1[2:]}. We know the SHA-1 of HEAD from /info/refs, so our request will be GET /objects/21/7ecd3c93b00c6b7404473d3bdfcb222a22edf4. This will give us zlib-compressed data, so we need to pipe to zlib-flate -uncompress:

$ curl https://poor-git.chall.lac.tf/flag.git/objects/21/7ecd3c93b00c6b7404473d3bdfcb222a22edf4 | zlib-flate -uncompress
commit 1128tree b46f24349a27913ddfa5c8a29bc3bcc8d2722358
parent c2e6e9737a8a666667b27c3a1dc84a76c8f4dab3
author burturt <31748545+burturt@users.noreply.github.com> 1705793830 -0800
committer burturt <31748545+burturt@users.noreply.github.com> 1705793830 -0800
gpgsig -----BEGIN PGP SIGNATURE-----
 ...omitted for brevity...
 -----END PGP SIGNATURE-----

remove flag again uugh

We already were able to get this commit with just git clone, let's continue to its parent.

$ # but first, let's define a bash function to make it easier to make these requests:
$ get () { curl https://poor-git.chall.lac.tf/flag.git/objects/${1:0:2}/${1:2:9999} | zlib-flate -uncompress }
$ get c2e6e9737a8a666667b27c3a1dc84a76c8f4dab3
commit 1172tree 47442ca74fffb4c5d1293fbd7bb0bc048d8fdff4
parent ac4d7070179f49c03ed06d98c19068cc8e2d74c5
parent b061db539557e1bb4dbcffd936a2d1412eeb1f66
...omitted for brevity...
Merge branch 'fix'

This is the commit giving us errors. We can see that there are two parents of this commit, with b061db5 being unreadable (we get a 404 if we try). Let's continue to the other parent:

$ get ac4d7070179f49c03ed06d98c19068cc8e2d74c5
commit 1117tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
parent 91fede8498f1ffd14699ec8d7f43f383f3147e64
...
remove flag
$ get 91fede8498f1ffd14699ec8d7f43f383f3147e64
commit 1135tree 1ee98dd3a67505c02a1ab4739f1a46a25d116599
parent e3fde9187ea42af07d95bb3e891b6338738810ab
...
remove newline at end of file
$ get e3fde9187ea42af07d95bb3e891b6338738810ab
commit 1114tree 75e7c1f3b178941ef76997bc3a9ca19bdc0dda09
parent fd87b3b95fc02fea268ecea9dce20964b285f50b
...
add flag

This commit seems like it is what we are looking for. Now we will get the commit data instead of continuing to its parent:

$ get 75e7c1f3b178941ef76997bc3a9ca19bdc0dda09 | xxd
00000000: 7472 6565 2033 3600 3130 3036 3434 2066  tree 36.100644 f
00000010: 6c61 672e 7478 7400 741f a59a c9ec 45f9  lag.txt.t.....E.
00000020: 78d7 99bd 88b7 290b c304 abdd            x.....).....
$ # the data after the second 00 byte tells us what we need to get
$ get 741fa59ac9ec45f978d799bd88b7290bc304abdd
blob 32lactf{u51n9_dum8_g17_pr070c01z}

The last request gets us the flag: lactf{u51n9_dum8_g17_pr070c01z}

Reference