When an Exposed .git Directory Tells the Whole Story — Solving TryHackMe's Room 404
5 min read
Summary
When an Exposed .git
Directory Tells the Whole Story — Solving TryHackMe’s Room 404
Every time I start a TryHackMe room, I try not to think about the intended solution. Instead, I treat it like a mini penetration test: enumerate first, understand the target, and let the findings guide the next step.
Room 404 turned out to be a perfect reminder that sometimes the biggest security issue isn’t an advanced exploit — it’s a simple deployment mistake.
In this post, I’ll walk through how I approached the room, what I learned, and why exposing a .git
directory can become a serious security risk.
This walkthrough focuses on the methodology and concepts behind the challenge. I won’t be revealing the room’s flag.
Step 1 — Looking at the Web Application
The first thing I always do is visit the application in my browser.
http://<TARGET_IP>:8080
The website loaded without any issues, but nothing immediately looked vulnerable. There weren’t any obvious login pages, forms, or interesting functionality to explore.
Whenever that happens, I move on to enumeration.
Step 2 — Directory Enumeration
I launched Gobuster using the common DirB wordlist.
gobuster dir -u http://<TARGET_IP>:8080 -w /usr/share/wordlists/dirb/common.txt
The scan revealed
/.git/HEAD
Finding an accessible .git
directory on a web server is usually a sign that something was misconfigured during deployment. Git repositories are meant for development, not public viewing, so when this folder is exposed, it can accidentally leak important metadata—and in some cases even the full source code of the application.
When I opened /.git/HEAD
, the browser didn’t load another page. Instead, it downloaded a small text file. Opening the file showed:
Browsing through the .git
directory,
To confirm that the .git
directory was actually accessible rather than simply returning a “Not Found” response, I used curl
to request a file from it.
curl http://<TARGET_IP>:8080/.git/refs/heads/main
The refs/heads/main
file is just a simple text file. It holds the 40-character commit hash of the latest update made to the main branch. If you run that curl
command and a long string of numbers and letters pops up, you’ve just proven two things: the .git
folder is wide open, and you now have the exact starting point.
Downloading the Repository
The room hints at using git-dumper, but I didn’t have it installed.
Get Athulya Biju’s stories in your inbox
Join Medium for free to get updates from this writer.
I used wget
to recursively download the entire hidden folder:
wget -r —no-parent -P ./git_target http://<TARGET_IP>:8080/.git/
Navigating into the folder reveals the downloaded repository:
cd git_target/:8080/
A quick ls -la .git
confirmed that all the vital Git internals (objects
, refs
, HEAD
) downloaded perfectly onto my machine.
Once inside the mirrored folder, run git status
to see how the local system interprets the state of the repository.
On branch main
Changes not staged for commit:
deleted: README.md
deleted: app.js
deleted: index.html
wget
only downloaded the hidden metadata database inside the .git
folder. It did not download the actual source code files because they sit outside of the .git
directory on the remote server.
When running git status
, Git looks at its internal database, sees that README.md
, app.js
, and index.html
are supposed to exist in the working directory, and flags them as “deleted” because the local folder is currently empty.
Reconstructing the Source Code
The entire commit history is stored within the downloaded .git
folder, Git can be instructed to rebuild the missing files from its internal database cache.
To restore everything in the current directory, use the .
parameter:
git restore .
Running ls -la
again shows that README.md
, app.js
, and index.html
have instantly materialized in the folder.
Capturing the Flag
Reading the readme files often reveals what the developers left behind.
cat README.md
README files are often worth checking because developers sometimes leave useful information there — things like project details, setup instructions, notes, or information that wasn’t meant to be exposed publicly.
For this room, that was the next place I investigated.
What I Learned
The biggest lesson I took from this room wasn’t really the commands themselves.
It was the importance of enumeration.
At the beginning, the website looked almost completely uninteresting. There wasn’t an obvious vulnerability sitting on the homepage waiting to be exploited.
But a simple directory scan revealed:
/.git/HEAD
From there, following the evidence led me to the exposed Git repository and eventually to the application’s files.
It also helped me understand something I hadn’t fully appreciated before: Git doesn’t just contain the latest version of a project. Its internal repository data can preserve information about the project’s history.
That’s why accidentally exposing .git
on a web server can be much more serious than it initially appears.
Final Thoughts
Room 404 was a good example of why I don’t want to rush through a penetration-testing lab looking for a particular exploit.
Sometimes the best approach is simply:
Enumerate → Find something interesting → Understand it → Investigate further
The .git
exposure was caused by a simple deployment mistake, but it opened the door to much more information about the application.
For me, this room reinforced the importance of looking at the small things. A seemingly harmless directory can sometimes tell you a lot about what’s happening behind a web application.
I’m still learning, but these hands-on rooms are helping me get better at thinking through problems instead of just memorizing tools and commands.