Advanced Git Source Code Acquisition

Advanced Git Source Code Acquisition

During a recent pentest while utilizing Nikto, an open source web vulnerability scanner, we discovered that was a readable, accessible file. Using Git to push to production is a little old school now everything is just dockerized, but as a PHP web app, a little old school is what we were expecting. So let’s get into Advanced Git Source Code Acquisition.

We assume the developers did something like this to deploy to production:

git push production master

If you thought to yourself:
>Ah! I’ve seen this before, there is a sweet bash script for this!

We had the same thought! We immediately attempted to use a publicly available script that can [download exposed `.git` folders from web servers](

Unfortunately, the tool did not dump the exposed `.git` folder as expected and instead was giving us errors. Boo! It seemed that some of the `.git` items were unreadable. Maybe the Apache webserver configuration was such that these needed index files weren’t accessible? A nearly correct `.htaccess` file could cause that.

**HOWEVER** the tool did download one file:
`` which references the objects in git’s object store.

An Innocent Feature Enhancement

So, what happened? Basically, Git stores objects by hash and takes the first two characters of the hash as the folder name and then the remaining characters as the file within that folder. (For a deep dive into Git storage layout, feel free to watch this excellent video of someone way more qualified explaining this in greater detail-

If you want to see this for yourself, look at a `.git/objects` directory and it will likely look something like this:

├── 01
│ └── 78acda09056bec3b89d197c713f8da3fbfa127
├── 19
│ └── 383b7cc3bd0423fcf4a9e05cdf01a6bcdc6cce
├── 1b
│ └── 398987add906c12425cbbedb974f41266678bd
├── 21
│ └── 82ea14ce1606d1361752753a78878f10cafe66


An Innocent Feature Enhancement

Equipped with the knowledge of how Git stores objects, we just needed to understand hashes and how to download them. Well, when we tried the bash script mentioned earlier, it worked well enough that when we ran git status on the repo, we received this error:

fatal: Unable to read afe5ff56fcd88250b543085faab4a4c854b7a4cf

Aha! We just figured out we can have Git tell us what it’s missing!

Now, combining all of these steps, we can:

1. Use git status to determine the missing object
2. Download the object from…
Where  XX is the first two characters of the hash and YYYYYYYY… are the rest
3. Repeat

This allowed us to slowly download all of the objects out of the exposed `.git` repo.

Here’s the script we cobbled together:

for i in `seq 1 10000`; do
git status
PREFIX=`git status 2>&1 | egrep -o ‘([0-9a-f]{40})’ | cut -b 1-2`
POSTFIX=`git status 2>&1 | egrep -o ‘([0-9a-f]{40})’ | cut -b 3-`
mkdir -p .git/objects/$PREFIX
curl -k -o .git/objects/$PREFIX/$POSTFIX$PREFIX/$POSTFIX
git status

![Git Blob Downloading](images/2021.12.20_22-08-00.png)

Woohoo! Knowing how the tool works allows us to work through an error. Though our solution wasn’t exactly elegant, it worked well enough that we eventually exfiltrated a file containing database connect strings and other sensitive files. Findings galore!

When your tools fail, get out the duct tape and start sticking things together.

Advanced Git Source Code Acquisition