amccormack.net

Things I've learned and suspect I'll forget.

Solving "Obliterated File" and "Obliterated File Again" from TSG CTF 2019-05-05

Yesterday I participated in the TSG CTF and I'll be posting a few of the challenges and solutions to the blog.

The Obliterated File challenges

Both challenges involve the use of git. I have some familiarity working with the internals of git so I knew enough to start throwing commands together, even if I didn't quite understand what exactly I was doing.

The first problem has the prompt

Working on making a problem of TSG CTF, I noticed that I have staged and committed the flag file by mistake before I knew it. I googled and found the following commands, so I'm not sure but anyway typed them. It should be ok, right?

$ git filter-branch --index-filter "git rm -f --ignore-unmatch problem/flag" --prune-empty -- --all
$ git reflog expire --expire=now --all
$ git gc --aggressive --prune=now

Another challenge, Obliterated File Again was was later released as an unintentional solution was discovered for the original challenge. I ended up solving both challenges in the same way.

I've had some experience working through git plumbing commands in the past. So without really knowing what I was looking for, I started trying commands.

user@box:/tmp/ob/easy_web$ find .git/objects/ -type f
.git/objects/ba/46709ec62fd916b29f17c5e9fd2fa99b71027c
.git/objects/fa/e323e2976c63f9aab36283ded3a205b02cd8da
.git/objects/cd/50304fc39f8c0fbc7ad062ecb9a940f3baed29
.git/objects/info/packs
.git/objects/pack/pack-358c51ff6239c4616442ad260a7f71391fec6fc2.idx
.git/objects/pack/pack-358c51ff6239c4616442ad260a7f71391fec6fc2.pack
.git/objects/5d/04bb5c39d8821c57d6e109088caefbdfd9660b
.git/objects/26/6f4148e4cf37bdbfb57da379ea49b2f106e6b2
.git/objects/4e/48cb9537172cfcf4174c999ee409ca70139c3d
.git/objects/4e/342ba6d191971197bb40023855b53a0155060b
.git/objects/50/935b0c64743459d3ffdfabb31229af867b949e
.git/objects/8e/497982ba717ee0fe21acd4d6a1beb74be0f90f
.git/objects/87/16dd0de5702371cc61c4627865bcaf16ddb448

The pack file sticks out, and I know it can be used to house more git objects so I found the documentation which led me to try the verify-pack command.

user@box:/tmp/ob/easy_web$ git verify-pack -v .git/objects/pack/pack-358c51ff6239c4616442ad260a7f71391fec6fc2.pack
d516014b8de3f20d473f2adca1713337095c7873 commit 217 153 12
f1d1f81fb5444ec4d40736104d682b43611c66f5 commit 217 151 165
98d396f94fb23e9e0fb317aa041ca02691f7ec8b commit 218 156 316
...truncated ...

72e3d57df672e811ef56d4fa993a71da33a1de91 blob   59 67 9622
207cef168362ac985a373f49fdbcf1d29035b6fb tree   64 79 9689 2 91a3b5d486e8cce94c981e459db47a2fa4497e1b
non delta: 59 objects
chain length = 1: 21 objects
chain length = 2: 12 objects
chain length = 3: 5 objects
chain length = 4: 1 object
chain length = 5: 1 object
.git/objects/pack/pack-358c51ff6239c4616442ad260a7f71391fec6fc2.pack: ok

I wanted to cat-file the hashes and save the output, so I put together a basic script in python. The purpose of this code is to take a hash as a command line argument, and then run git cat-file -p <hash> and save off the output. There is probably a sneaky way to do this in bash, but python worked just fine.

The contents of fetch.py is shown below.

#!/usr/bin/python
import argparse
import subprocess

def fetch(hash):
    try:
        output = subprocess.check_output(["git", "cat-file", "-p", hash], stderr=subprocess.STDOUT)
    except Exception as e:
        if len(e.output):
            output = e.output
        else:
            output = str(e)
    with open('./output/' + hash, 'w') as f:
        f.write(output)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('hash')
    args = parser.parse_args()

    fetch(args.hash)
if __name__ == '__main__':
    main()

I then grepped all of the hashes out of the packfile and extracted the contents.

user@box:/tmp/ob/easy_web$ git verify-pack -v .git/objects/pack/pack-358c51ff6239c4616442ad260a7f71391fec6fc2.pack |\
  grep -Po '[a-f0-9]{40}'| \
  sort|uniq| xargs -I{} python fetch.py {}
[code]

[code]
user@box:/tmp/ob/easy_web$ grep -rni flag output/
output/02d365359d84a5d4f4317fa3549fe073a024c502:5:flag = File.open("./flag", "r") do |f|
output/02d365359d84a5d4f4317fa3549fe073a024c502:14:    db.exec "INSERT INTO accounts VALUES ('admin', '#{flag}');"
output/e518bb214047db324b2e9b09d5617d84c6cc4ebf:1:100644 blob 111eb967d40ae9bc7b2d16bbab7aaac5746ba1dc  flag
output/6eec6e57cc9eb5aa67f09fb73bdb3b933d7fdded:5:The flag is admin's password.
output/c9319554ea383df062bafa9e96915ffe62136457:3:100644 blob 111eb967d40ae9bc7b2d16bbab7aaac5746ba1dc flag
output/b8b02f91a5b2407cb4014c81440ce7620c4830bc:3:100644 blob 111eb967d40ae9bc7b2d16bbab7aaac5746ba1dc flag
output/ebc4754f23719c17eedf24af0187be86b52e71d2:5:flag = File.open("./flag", "r") do |f|
output/ebc4754f23719c17eedf24af0187be86b52e71d2:14:    db.exec "INSERT INTO accounts VALUES ('admin', '#{flag}');"
output/8ce8f78879f344df4e079a81048e7e18fdb29fed:5:100644 blob 111eb967d40ae9bc7b2d16bbab7aaac5746ba1dc  flag

Seeing the hash for the flag file, I started looking at that file

user@box:/tmp/ob/easy_web$ file output/111eb967d40ae9bc7b2d16bbab7aaac5746ba1dc
output/111eb967d40ae9bc7b2d16bbab7aaac5746ba1dc: zlib compressed data

A google search for bash zlib decompression returned this answer on stack overflow.

user@box:/tmp/ob/easy_web$ printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - output/111eb967d40ae9bc7b2d16bbab7aaac5746ba1dc|gzip -dc
TSGCTF{$_git_update-ref_-d_refs/original/refs/heads/master}
gzip: stdin: unexpected end of file

Obliterated File Again

I started off looking at the packfile again, and the problem had the same solution.

user@box:/tmp/ob/easy_web$ ls -l ./.git/objects/pack/*
-r--r--r-- 1 alex alex  3900 May  4 07:57 ./.git/objects/pack/pack-b799d65ebb2cc3fab7878fcf2a2642585de29408.idx
-r--r--r-- 1 alex alex 10125 May  4 07:57 ./.git/objects/pack/pack-b799d65ebb2cc3fab7878fcf2a2642585de29408.pack

user@box:/tmp/ob/easy_web$ git verify-pack -v .git/objects/pack/pack-b799d65ebb2cc3fab7878fcf2a2642585de29408.pack |\
  grep -Po '[a-f0-9]{40}'|\
  sort|uniq| xargs -I{} python fetch.py {}

user@box:/tmp/ob/easy_web$ grep -rni flag output/*
output/02d365359d84a5d4f4317fa3549fe073a024c502:5:flag = File.open("./flag", "r") do |f|
output/02d365359d84a5d4f4317fa3549fe073a024c502:14:    db.exec "INSERT INTO accounts VALUES ('admin', '#{flag}');"
output/1f34928d090b69867f664dcbef276d53a29483cc:3:100644 blob c1e375244c834c08d537d564e2763a7b92d5f9a8  flag
output/2aea982ed4eb63a835ce71322379720fb45e3a7a:2:100644 blob c1e375244c834c08d537d564e2763a7b92d5f9a8  flag
output/6eec6e57cc9eb5aa67f09fb73bdb3b933d7fdded:5:The flag is admin's password.
output/d5fe4dc31680a0c12730b4599ecccb369b6a0a14:3:100644 blob c1e375244c834c08d537d564e2763a7b92d5f9a8  flag
output/ebc4754f23719c17eedf24af0187be86b52e71d2:5:flag = File.open("./flag", "r") do |f|
output/ebc4754f23719c17eedf24af0187be86b52e71d2:14:    db.exec "INSERT INTO accounts VALUES ('admin', '#{flag}');"
output/ff591ccbfb2cf72a371008a82f4210209797584f:5:100644 blob c1e375244c834c08d537d564e2763a7b92d5f9a8  flag

user@box:/tmp/ob/easy_web$ file output/c1e375244c834c08d537d564e2763a7b92d5f9a8
output/c1e375244c834c08d537d564e2763a7b92d5f9a8: zlib compressed data
user@box:/tmp/ob/easy_web$ printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - output/c1e375244c834c08d537d564e2763a7b92d5f9a8|gzip -dc
TSGCTF{$_git_update-ref_-d_refs/original/refs/heads/master_S0rry_f0r_m4king_4_m1st4k3_0n_th1s_pr0bl3m}
gzip: stdin: unexpected end of file
user@box:/tmp/ob/easy_web$

published on 2019-05-05 by alex