Unpack and extract objects from git packfiles

This was an unusual interesting challenge from AngstromCTF 2020. We were given a simple pcapng file:

ws3 - Misc
What the… record.pcapng Author: JoshDaBosh

Upon opening the pcapng file with Wireshark, a few packets could be seen. There was an interesting HTTP traffic, where it seemed to be a git transfer going on.

Following the TCP stream #4 shows some sort of transfer of a file happening.

Doing some research, it was found that the PACK header refers to a git pack file.
According to this resource, the 4-byte signature in a common git pack file should be P A C K, so if we analyze the hex of the file we see on the stream, it shows 000PACK.

With the above information we can now try to extract the .pack file. On Wireshark we change the conversation from Entire Conversation to 61635 -> 3000 and Show and save data as: Raw

Next, we need to identify where the .pack file starts in this hex raw view. We already know that the file starts with P A C K, which converted to hex is 5041434b, so we search this string in the Find parameter. We see one match only, which is preceded by 000 (30 in hexadecimal) .

The next step is to copy all the hex values that forms the .pack file. It starts from 5041434b and until the the end of the packet e0f329d3. We paste all the hex values content to a file named hex.txt . If we check the beginning and the end of the file it shows the correct values we determined before:

root@kali:~# head -c 8 hex.txt && echo " " && tail -c 9 hex.txt 
5041434b 
e0f329d3
root@kali:~#

Next thing is to convert all this raw hex values into an actual file. For that we can use xxd.

root@kali:~# xxd -r -p hex.txt file.pack
root@kali:~#

We then verify the headers look correct (using hexdump) and check if the file is identified as .pack file.

root@kali:~# hexdump -C file.pack | head
00000000 50 41 43 4b 00 00 00 02 00 00 00 03 94 0e 78 9c |PACK..........x.|
00000010 95 cb 4b 0a c2 30 10 80 e1 7d 4e 91 0b 28 79 27 |..K..0...}N..(y'|
00000020 03 22 22 ae bc c5 24 ce b4 15 fb 20 49 f1 fa f6 |.""...$.... I...|
00000030 0a 6e fe c5 0f 5f af 44 32 c5 14 0d 9b 04 c1 92 |.n..._.D2.......|
00000040 31 40 c9 44 4d 8a 31 07 f4 3e a2 26 cf d9 6b ab |1@.DM.1..>.&..k.|
00000050 c5 86 95 96 2e b5 81 0c c0 96 40 31 25 46 f4 f4 |..........@1%F..|
00000060 82 ec 48 a7 cc 39 14 55 b2 2f 64 9d 12 b8 f7 71 |..H..9.U./d....q|
00000070 ad f2 b9 b6 f1 81 f7 a3 f2 f2 fe e2 32 0c fd 36 |............2..6|
00000080 cc 38 7d ce 65 9d af 52 fb e4 94 77 16 82 3c 29 |.8}.e..R...w..<)|
00000090 a7 94 38 ee 3c f5 4e ff 4b d1 f6 69 3b 5c a3 52 |..8.<.N.K..i;\.R|
root@kali:~#
root@kali:~# file file.pack
file.pack: Git pack, version 2, 3 objects
root@kali:~#

Everything looks correct with the file. So what next? After doing some research I knew that in theory it was possible to extract objects from a git packet. But how?
This took me a little while to figure out, but I found a clue in this forum which contains a discussion about this article.

Firstly, the article contains a somewhat lengthy explanation about git pack files and how to extract objects from them (though it doesn’t show exactly HOW to do it).
It also says that the a .pack file uses an .idx file that contains the index used to quickly locate objects within the .pack file.

To generate the .idx file we use git with the index-pack option

root@kali:~# git index-pack file.pack
dd2596dc69ab7a5ca82616df737b391ee0f329d3
root@kali:~#
root@kali:~# ls
file.idx file.pack
root@kali:~#

Then we verified the .pack file and it showed it contains 3 objects and the pack file looks ok.

root@kali:~# git verify-pack -v file.pack
34b1647544bdcf0e896e080ec84bb8b57cccc8d0 commit 228 159 12
87872f28963e229e8271e0fab6a557a1e5fb5131 tree 73 82 171
fe3f47cbcb3ad8e946d0aad59259bdb1bc9e63f2 blob 19370 17626 253
non delta: 3 objects
file.pack: ok
root@kali:~#

Next, we can unpack the objects with the unpack-objects option in git. First, we initiate an empty repository insider the folder where the .pack file is located and then we can unpack the objects:

root@kali:~# ls
file.idx  file.pack
root@kali:~# 
root@kali:~# git init
Initialized empty Git repository in /root/.git/
root@kali:~# 
root@kali:~# git unpack-objects < *.pack
Unpacking objects: 100% (3/3), done.
root@kali:~# 

We can now go to /root/.git/objects and verified the unpacked objects:

root@kali:~# tree -a .git/objects
.git/objects
├── 34
│   └── b1647544bdcf0e896e080ec84bb8b57cccc8d0
├── 87
│   └── 872f28963e229e8271e0fab6a557a1e5fb5131
├── fe
│   └── 3f47cbcb3ad8e946d0aad59259bdb1bc9e63f2
├── info
└── pack

5 directories, 3 files
root@kali:~# 
root@kali:~# file .git/objects/87/872f28963e229e8271e0fab6a557a1e5fb5131 
.git/objects/87/872f28963e229e8271e0fab6a557a1e5fb5131: zlib compressed data
root@kali:~# 

The forum linked previously mentions using zpipe to extract files from git objects. We extract the files as shows:

root@kali:~# /root/resources/zpipe/zpipe -d < .git/objects/34/b1647544bdcf0e896e080ec84bb8b57cccc8d0 > file1
root@kali:~# 
root@kali:~# /root/resources/zpipe/zpipe -d < .git/objects/87/872f28963e229e8271e0fab6a557a1e5fb5131 > file2
root@kali:~# 
root@kali:~# /root/resources/zpipe/zpipe -d < .git/objects/fe/3f47cbcb3ad8e946d0aad59259bdb1bc9e63f2 > file3
root@kali:~# 

So what are the above files? Using strings we could see some detail about it:

root@kali:~# strings file1 
commit 228
tree 87872f28963e229e8271e0fab6a557a1e5fb5131
parent 129b99f3e90fe8faa5ed9b4e18bfb6c0cb5ce340
author JoshDaBosh <jwanggt@gmail.com> 1584054396 -0400
committer JoshDaBosh <jwanggt@gmail.com> 1584054396 -0400
suiper secret stuff
root@kali:~#
root@kali:~# strings file2
tree 73
100644 README.md
>100644 flag.jpg
root@kali:~# 
root@kali:~# strings file3
blob 19370
JFIF
 $.' ",#
(7),01444
'9=82<.342
!22222222222222222222222222222222222222222222222222
1AQaq"2
3Cbr
4c%su
&'678DTft
------------SNIP------------
root@kali:~#

file2 and file3 look interesting, as they contain strings flag.jpg and JFIF respectively, so it leads to determine that file3 contains a .jpg image as JFIF is the header value for a .jpg file.

Lastly, we verify the content of file3 with binwalk and extract the .jpg image with foremost

root@kali:~# binwalk file3
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
11            0xB             JPEG image data, JFIF standard 1.01
root@kali:~# 
root@kali:~# foremost file3 
Processing: file3
|*|
root@kali:~# 

The .jpg file is extracted under out/ directory, we open the image file and we can see the flag:

Flag: actf{git_good_git_wireshark-123323}