← Back to Writeups
CUSTOMEasyWeb

Forbidden Archives

XESXOR9/10/20263 min read
#web#custom#easy#comment_based_filter_bypass#like_clause_breakout#sqlite_injection

Forbidden Archives

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: comment_based_filter_bypass, like_clause_breakout, sqlite_injection

Summary

Walkthrough of the CUSTOM Web Forbidden Archives. Task: Flask+SQLite book search where a forbidden book is hidden via an is_secret=0 filter in the SQL WHERE clause. Solution: SQLi in the ?search= LIKE clause — close the parenthesis and comment out th


title: "Forbidden Archives" id: 20260711_broncoctf2026_forbidden_archives category: web difficulty: easy event: broncoctf2026 tags: ["sqlite", "sql_injection", "flask", "filter_bypass", "access_control_bypass", "web", "comment_injection"] techniques: ["comment_based_filter_bypass", "like_clause_breakout", "sqlite_injection"] tools: ["curl"] indicators: ["single GET ?search= parameter", "results filtered by an is_secret column", "OR/UNION keywords stripped but comments allowed", "Flask/Werkzeug backend with SQLite"]

Forbidden Archives — broncoctf2026

Description

I have recently gained access to these Forbidden Archives, though I've been trying to access a book titled 'All of the World's Knowledge' and it seems like there's another level of security as the high council of wizards have made it forbidden. Is there a way I can get around that?

Target: https://broncoctf-forbidden-archives.chals.io/

English summary: A Flask/Werkzeug book-search web app exposes a single GET parameter /?search=. One book, "All of the World's Knowledge", is marked forbidden and filtered out. The goal is to bypass that access control and read the book (which contains the flag).

Analysis

The site is a Flask/Werkzeug 3.1.8 app (Python 3.14.6) with a single GET search field /?search=. It queries a SQLite backend, and the query suffix is:

sql
... LIKE '%<search>%') AND is_secret = 0 LIMIT 1

The forbidden book "All of the World's Knowledge" has is_secret = 1, so the AND is_secret = 0 clause filters it out of normal results. Authorization is enforced only in the SQL WHERE clause — there is no separate access-control check — which makes it bypassable through SQL injection.

The search parameter is directly interpolated into the LIKE expression, so it is injectable. Notes:

  • robots.txt, .git/HEAD, .env all returned 404 — no exposed source or config.
  • OR- and UNION-based SQLi payloads were stripped/filtered by keyword filtering, so classic boolean/union injection did not work.
  • Jinja/SSTI probes were not fruitful.

The keyword filter blocks OR/UNION but does not block SQL comments, so a comment-based filter bypass works.

Solution

The payload closes the LIKE string and its parenthesis, then uses a SQL comment (-- ) to neutralize the trailing AND is_secret = 0 filter, returning all rows including the secret one.

Injected payload: Knowledge%') -- (note the trailing space after --, required for SQLite line comments).

Resulting query fragment:

sql
LIKE '%Knowledge%') -- %') AND is_secret = 0 LIMIT 1

Everything after -- is a comment, so the is_secret filter is gone.

bash
curl -sS --get \
  --data-urlencode "search=Knowledge%') -- " \
  'https://broncoctf-forbidden-archives.chals.io/'

The response returns the book "All of the World's Knowledge" with the flag inside a <p> in the book card.

Key Takeaways / Lessons

  • Mastering comment_based_filter_bypass, like_clause_breakout, sqlite_injection was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-07-11 • CUSTOM • Forbidden Archives • Difficulty: Easy