Blog section
PicoCTF

PicoCTF More SQLi Writeup: From Login Bypass to SQLite Enumeration

A concise picoCTF web exploitation walkthrough showing how SQL injection can move from authentication bypass to SQLite schema discovery and flag extraction.

PicoCTFWeb ExploitationSQL InjectionSQLite

More SQLi is a picoCTF 2023 web exploitation challenge focused on a classic SQL injection workflow. The challenge starts with a login form, but the important lesson is not just bypassing authentication. The useful part is learning how to turn that initial injection point into structured database enumeration.

This post is adapted from my original notes and rewritten into a cleaner walkthrough. The goal is to preserve the reasoning path: identify the injection point, confirm control over the query, inspect the SQLite database structure, and then extract the target value.

Challenge Overview

The application presents a simple website with a login form. Since the challenge title hints strongly at SQL injection, I started by testing whether the password field was being placed directly into a backend SQL query.

The initial test used a tautology-style payload in the password field:

Username: eiei
Password: 'or '1' IS '1';--

That input changed the logic of the backend query so the password condition evaluated as true and the rest of the original query was commented out.

SELECT id FROM users WHERE password = '1' IS '1'--' AND username = 'eiei'

Confirming Access

After submitting the payload, the application moved past the login page and showed the authenticated view. That confirmed the form was injectable and that the database response could influence the page output.

At this point, the solve could not stop at authentication bypass. For this challenge, the flag was stored somewhere in the database, so the next step was to use the injection point to learn more about the database engine and table layout.

Finding the Database Type

I tested a UNION-based payload to check whether injected SELECT output could be reflected back into the page. The query also called sqlite_version(), which confirmed that the backend was using SQLite.

TEST' UNION SELECT 7, sqlite_version(), 3--

That result was useful because SQLite exposes database metadata through sqlite_master. Once the engine was known, enumeration became straightforward.

Enumerating Tables

The next payload queried sqlite_master to recover table names and creation SQL. This is a common SQLite technique because table definitions reveal both the table names and column names needed for the final extraction step.

TEST' UNION SELECT name, sql, sqlite_version() from sqlite_master;--

The output revealed a table that contained the flag data. With the table and column names identified, the final payload could target the flag directly.

Extracting the Flag

The final UNION query selected the flag column from the discovered table. The extra null values were used to keep the UNION column count aligned with the original query.

TEST' UNION SELECT flag, null, null from more_table;--

Key Takeaways

  1. Authentication bypass is often only the first signal that SQL injection exists. The stronger workflow is to use that injection point for controlled enumeration.
  2. UNION-based injection depends on matching the original query column count, which is why placeholder values such as numbers or null are useful.
  3. For SQLite targets, sqlite_master is the main metadata table for discovering schema information.
  4. Small CTF challenges are useful because they isolate one technique and make the exploitation path easy to reason about.

Final Thoughts

This challenge is a good beginner-friendly example of moving beyond a login bypass into practical database enumeration. The solve is short, but it reinforces a repeatable pattern: confirm injection, identify the database, enumerate schema, and then extract the specific value you need.

Connect With Me

LinkedIn: https://www.linkedin.com/in/waris-damkham/
Website: waris-damkham.netlify.app