← Back to Writeups
CUSTOMEasyWeb

Маскарад (Masquerade)

XESXOR9/10/20263 min read
#web#custom#easy#express_session_state_tracking#multi_part_flag_collection#session_cookie_reuse_with_diff#linux

Маскарад (Masquerade)

Platform: bug-makers | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-05-25 | Status: Solved Techniques: express_session_state_tracking, multi_part_flag_collection, session_cookie_reuse_with_different_user_agents

Summary

Task: Express.js app splits flag into 5 parts, each revealed by a new unique User-Agent within the same session. Solution: Reuse the connect.sid session cookie while changing the User-Agent header across 5 requests to collect all flag parts.

Маскарад (Masquerade) — bug-makers

Description

Очень хочется получить весть флаг целиком, но как бы я ни пытался, получаю только первую его часть, я даже пробовал открывать адрес через разные браузеры - результат один. Попробуй, может у тебя получится?

English summary: The author wants the full flag but only gets the first part. Even trying different browsers gives the same result — always just part #1. The challenge is to figure out how to get all parts.

Analysis

The target is an Express.js application at https://masquerade.t1.bug-makers.ru/. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Initial reconnaissance:

  • x-powered-by: Express header reveals the framework
  • Session cookie connect.sid indicates express-session with server-side storage
  • Only two endpoints exist: / (GET) and /health
  • Sending an empty User-Agent returns "Oops! Incorrect headers!"

Key observation: The challenge description contains a critical hint — "I tried different browsers - same result." Each browser creates its own independent session (new connect.sid cookie), so the server treats each browser as a fresh visitor and always returns part #1. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The mechanism: The server maintains a list of seen User-Agent strings per session. Each new unique User-Agent presented within the same session advances the counter and reveals the next flag part. The flag is split into 5 parts.

Why different browsers fail: Different browsers send different User-Agents, but they also create separate sessions. The server sees each as a brand-new visitor with 0 unique agents seen, so it always returns part #1.

The solution: Change the User-Agent header while reusing the same session cookie (connect.sid). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Use curl to make 5 requests with different User-Agent strings while preserving the session cookie:

bash
#!/bin/bash
# Solve script for Masquerade - collect all 5 flag parts

URL="https://masquerade.t1.bug-makers.ru/"
COOKIE_JAR="cookies.txt"

# Request 1: establish session, get part #1
echo "=== Part 1 ==="
curl -s -c "$COOKIE_JAR" "$URL" -A "Agent1"

# Requests 2-5: reuse session cookie with different User-Agents
for i in 2 3 4 5; do
    echo -e "\n=== Part $i ==="
    curl -s -b "$COOKIE_JAR" "$URL" -A "Agent$i"
done

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

Output:

RequestUser-AgentResponse
1Agent1You have flag part #1 BugCTF{
2Agent2You have flag part #2 h0w_m4n
3Agent3You have flag part #3 y_4gen7s
4Agent4You have flag part #4 _d0_y0u
5Agent5You have flag part #5 _hav37}

After all 5 parts are collected, any further request returns: You already have whole flag!

Concatenating all parts: BugCTF{ + h0w_m4n + y_4gen7s + _d0_y0u + _hav37} = BugCTF{REDACTED} ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

What didn't work

  • Different browsers — each creates a new session, always returns part #1
  • Various HTTP headers (Accept, Accept-Language, X-Forwarded-For, etc.) — no effect on flag parts
  • Query parameters (part, id, mask, flag, page) — no effect
  • HTTP method override — no effect
  • Path enumeration with ffuf — only / and /health found ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍