Things I've learned and suspect I'll forget.
Yesterday I participated in the TSG CTF and I'll be posting a few of the challenges and solutions to the blog.
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
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